Commit af20dae2 authored by Charlie Lenahan's avatar Charlie Lenahan Committed by Erich Keane

Add pthread implementation for connectivity/common/umutex

Implements a pthread implementation of the u_mutex , u_cond
for platforms that can't/don't want glib.

Renames u_mutex => ca_mutex , u_cond => ca_cond

Add missing unittests.

changes u_cond_wait_until() decl because old implementation
didn't accomadate for code to handle spurious wakeups properly,
and whether condition was signaled or time expired.

Change-Id: Ibd106dad494ebac3ca85aba306f1f1fe7dcc47e2
Signed-off-by: default avatarCharlie Lenahan <charlie.lenahan@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/741Tested-by: default avatarjenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: default avatarJon A. Cruz <jonc@osg.samsung.com>
Reviewed-by: default avatarErich Keane <erich.keane@intel.com>
parent 37b6344c
......@@ -13,6 +13,7 @@ root_dir = './../'
ca_common_path = root_dir + 'common/'
ca_common_src_path = ca_common_path + 'src/'
no_glib = 'darwin,ios'
env.AppendUnique(CPPPATH = [
'common/inc/',
......@@ -47,13 +48,23 @@ if ca_os == 'arduino':
env.get('BUILD_DIR') + 'logger.c.o',
]
else:
platform_src = [
ca_common_src_path + 'logger.c',
ca_common_src_path + 'oic_logger.c',
ca_common_src_path + 'oic_console_logger.c',
ca_common_src_path + 'umutex.c',
ca_common_src_path + 'uthreadpool.c',
]
if ca_os in no_glib:
platform_src = [
ca_common_src_path + 'logger.c',
ca_common_src_path + 'oic_logger.c',
ca_common_src_path + 'oic_console_logger.c',
ca_common_src_path + 'uthreadpool.c',
ca_common_src_path + 'camutex_pthread.c'
]
else:
platform_src = [
ca_common_src_path + 'logger.c',
ca_common_src_path + 'oic_logger.c',
ca_common_src_path + 'oic_console_logger.c',
ca_common_src_path + 'uthreadpool.c',
ca_common_src_path + 'camutex_glib.c'
]
env.AppendUnique(CA_SRC = ca_common_src)
env.AppendUnique(CA_SRC = platform_src)
......
......@@ -24,8 +24,8 @@
* This file provides APIs related to mutex and semaphores.
*/
#ifndef __UMUTEX_H_
#define __UMUTEX_H_
#ifndef _CAMUTEX_H_
#define _CAMUTEX_H_
#include "cacommon.h"
......@@ -34,115 +34,118 @@ extern "C"
{
#endif /* __cplusplus */
typedef void *u_mutex;
typedef void *u_cond;
typedef struct ca_mutex_internal *ca_mutex;
typedef struct ca_cond_internal *ca_cond;
/**
* @fn u_mutex_new
* @brief Creates new mutex
* Enums for ca_cond_wait_until return values
*/
typedef enum
{
CA_WAIT_SUCCESS = 0, /**< Condition Signal */
CA_WAIT_INVAL = -1, /**< Invalid Condition */
CA_WAIT_TIMEDOUT = -2 /**< Condition Timed Out */
} CAWaitResult_t;
/**
* Creates new mutex.
*
* @return Reference to newly created mutex, otherwise NULL.
*
*/
u_mutex u_mutex_new(void);
ca_mutex ca_mutex_new(void);
/**
* @fn u_mutex_lock
* @brief Lock the mutex
* Lock the mutex.
*
* @param mutex The mutex to be locked
*
*/
void u_mutex_lock(u_mutex mutex);
void ca_mutex_lock(ca_mutex mutex);
/**
* @fn u_mutex_trylock
* @brief Checks if the mutex can be locked
* Checks if the mutex can be locked.
*
* @param mutex The mutex to be locked
*
* @return true if the mutex is not locked currently, otherwise false.
*
*/
bool u_mutex_trylock(u_mutex mutex);
bool ca_mutex_trylock(ca_mutex mutex);
/**
* @fn u_mutex_unlock
* @brief Unlock the mutex
* Unlock the mutex.
*
* @param mutex The mutex to be unlocked
*
*/
void u_mutex_unlock(u_mutex mutex);
void ca_mutex_unlock(ca_mutex mutex);
/**
* @fn u_mutex_free
* @brief Free the mutex
* Free the mutex.
*
* @param mutex The mutex to be freed
*
*/
void u_mutex_free(u_mutex mutex);
bool ca_mutex_free(ca_mutex mutex);
/**
* @fn u_cond_new
* @brief Creates new condition
* Creates new condition.
*
* @return Reference to newly created @u_cond, otherwise NULL.
* @return Reference to newly created @ca_cond, otherwise NULL.
*
*/
u_cond u_cond_new(void);
ca_cond ca_cond_new(void);
/**
* @fn u_cond_signal
* @brief One of threads is woken up if multiple threads are waiting for @cond
* One of threads is woken up if multiple threads are waiting for @cond.
*
* @param cond The condtion to be signaled
*
*/
void u_cond_signal(u_cond cond);
void ca_cond_signal(ca_cond cond);
/**
* @fn u_cond_broadcast
* @brief All of threads are woken up if multiple threads are waiting for @cond
* All of threads are woken up if multiple threads are waiting for @cond.
*
* @param cond The condtion to be signaled
*
*/
void u_cond_broadcast(u_cond cond);
void ca_cond_broadcast(ca_cond cond);
/**
* @fn u_cond_wait
* @brief Waits until this thread woken up on @cond
* Waits until this thread woken up on @cond.
*
* @param cond The condtion to be wait for to signal
* @param mutex The mutex which is currently locked from calling thread
*
*/
void u_cond_wait(u_cond cond, u_mutex mutex);
void ca_cond_wait(ca_cond cond, ca_mutex mutex);
/**
* @fn u_cond_wait
* @brief Waits until this thread woken up on @cond,
* but not longer than until the time specified by microseconds.
* The mutex is unlocked before falling asleep and locked again before resuming.
* If microseconds is 0 or under, u_cond_wait_until() acts like u_cond_wait().
* Waits until this thread woken up on @cond,
* but not longer than until the time specified by microseconds.
* The mutex is unlocked before falling asleep and locked again before resuming.
* If microseconds is 0 or under, ca_cond_wait_until() acts like ca_cond_wait().
*
* @param cond The condtion to be wait for to signal
* @param mutex The mutex which is currently locked from calling thread
* @param microseconds relative time for waiting, microseconds
* @param microseconds absolute time for waiting, microseconds
*
* @return CA_WAIT_SUCCESS if the condition was signaled.
* CA_WAIT_TIMEDDOUT if wait period exceeded
* CA_WAIT_INVAL for invalid parameters
*
*/
void u_cond_wait_until(u_cond cond, u_mutex mutex, int32_t microseconds);
CAWaitResult_t ca_cond_wait_until(ca_cond cond, ca_mutex mutex, uint64_t microseconds);
/**
* @fn u_cond_free
* @brief Free the condition
* Free the condition.
*
* @param cond The condition to be freed
*
*/
void u_cond_free(u_cond cond);
void ca_cond_free(ca_cond cond);
#ifdef __cplusplus
} /* extern "C" */
......
......@@ -23,7 +23,7 @@
* This file provides APIs related to mutex and semaphores.
*/
#include "umutex.h"
#include "camutex.h"
#include <glib.h>
#include <string.h>
#include "logger.h"
......@@ -34,18 +34,18 @@
*/
#define TAG PCF("UMUTEX")
u_mutex u_mutex_new(void)
ca_mutex ca_mutex_new(void)
{
GMutex *mutexLock = g_new(GMutex, 1);
g_mutex_init(mutexLock);
return (u_mutex) mutexLock;
return (ca_mutex) mutexLock;
}
void u_mutex_lock(u_mutex mutex)
void ca_mutex_lock(ca_mutex mutex)
{
if (NULL == mutex)
{
OIC_LOG(ERROR, TAG , "u_mutex_lock, Invalid mutex !");
OIC_LOG(ERROR, TAG , "ca_mutex_lock, Invalid mutex !");
return;
}
......@@ -53,11 +53,11 @@ void u_mutex_lock(u_mutex mutex)
g_mutex_lock(mutexLock);
}
bool u_mutex_trylock(u_mutex mutex)
bool ca_mutex_trylock(ca_mutex mutex)
{
if (NULL == mutex)
{
OIC_LOG(ERROR, TAG, "u_mutex_trylock, Invalid mutex !");
OIC_LOG(ERROR, TAG, "ca_mutex_trylock, Invalid mutex !");
return false;
}
......@@ -66,11 +66,11 @@ bool u_mutex_trylock(u_mutex mutex)
return(g_mutex_trylock(mutexLock));
}
void u_mutex_unlock(u_mutex mutex)
void ca_mutex_unlock(ca_mutex mutex)
{
if (NULL == mutex)
{
OIC_LOG(ERROR, TAG, "u_mutex_unlock, Invalid mutex !");
OIC_LOG(ERROR, TAG, "ca_mutex_unlock, Invalid mutex !");
return;
}
......@@ -78,31 +78,32 @@ void u_mutex_unlock(u_mutex mutex)
g_mutex_unlock(mutexLock);
}
void u_mutex_free(u_mutex mutex)
bool ca_mutex_free(ca_mutex mutex)
{
if (NULL == mutex)
{
OIC_LOG(ERROR, TAG, "u_mutex_free, Invalid mutex !");
return;
OIC_LOG(ERROR, TAG, "ca_mutex_free, Invalid mutex !");
return false;
}
GMutex *mutexLock = (GMutex *) mutex;
g_mutex_clear(mutexLock);
g_free(mutexLock);
return true;
}
u_cond u_cond_new(void)
ca_cond ca_cond_new(void)
{
GCond *condition = g_new(GCond, 1);
g_cond_init(condition);
return (u_cond) condition;
return (ca_cond) condition;
}
void u_cond_signal(u_cond cond)
void ca_cond_signal(ca_cond cond)
{
if (NULL == cond)
{
OIC_LOG(ERROR, TAG, "u_cond_signal, Invalid condition !");
OIC_LOG(ERROR, TAG, "ca_cond_signal, Invalid condition !");
return;
}
......@@ -110,11 +111,11 @@ void u_cond_signal(u_cond cond)
g_cond_signal(condition);
}
void u_cond_broadcast(u_cond cond)
void ca_cond_broadcast(ca_cond cond)
{
if (NULL == cond)
{
OIC_LOG(ERROR, TAG, "u_cond_broadcast, Invalid condition !");
OIC_LOG(ERROR, TAG, "ca_cond_broadcast, Invalid condition !");
return;
}
......@@ -122,17 +123,17 @@ void u_cond_broadcast(u_cond cond)
g_cond_broadcast(condition);
}
void u_cond_wait(u_cond cond, u_mutex mutex)
void ca_cond_wait(ca_cond cond, ca_mutex mutex)
{
if (NULL == mutex)
{
OIC_LOG(ERROR, TAG, "u_cond_wait, Invalid mutex !");
OIC_LOG(ERROR, TAG, "ca_cond_wait, Invalid mutex !");
return;
}
if (NULL == cond)
{
OIC_LOG(ERROR, TAG, "u_cond_wait, Invalid condition !");
OIC_LOG(ERROR, TAG, "ca_cond_wait, Invalid condition !");
return;
}
......@@ -141,40 +142,38 @@ void u_cond_wait(u_cond cond, u_mutex mutex)
g_cond_wait(condition, mutexLock);
}
void u_cond_wait_until(u_cond cond, u_mutex mutex, int32_t microseconds)
CAWaitResult_t ca_cond_wait_until(ca_cond cond, ca_mutex mutex, uint64_t microseconds)
{
if (NULL == mutex)
{
OIC_LOG(ERROR, TAG, "u_cond_wait, Invalid mutex !");
return;
OIC_LOG(ERROR, TAG, "ca_cond_wait, Invalid mutex !");
return CA_WAIT_INVAL;
}
if (NULL == cond)
{
OIC_LOG(ERROR, TAG, "u_cond_wait, Invalid condition !");
return;
OIC_LOG(ERROR, TAG, "ca_cond_wait, Invalid condition !");
return CA_WAIT_INVAL;
}
GMutex *mutexLock = (GMutex *) mutex;
GCond *condition = (GCond *) cond;
if (microseconds <= 0)
if (microseconds == 0)
{
g_cond_wait(condition, mutexLock);
return;
return CA_WAIT_SUCCESS;
}
gint64 end_time;
end_time = g_get_monotonic_time() + microseconds;
g_cond_wait_until(condition, mutexLock, end_time);
gboolean bRet = g_cond_wait_until(condition, mutexLock, microseconds);
return bRet ? CA_WAIT_SUCCESS : CA_WAIT_TIMEDOUT;
}
void u_cond_free(u_cond cond)
void ca_cond_free(ca_cond cond)
{
if (NULL == cond)
{
OIC_LOG(ERROR, TAG, "u_cond_free, Invalid condition !");
OIC_LOG(ERROR, TAG, "ca_cond_free, Invalid condition !");
return;
}
......
//******************************************************************
//
// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
//
//*********************************************************************
/**
* @file
* This file provides APIs related to mutex and semaphores.
*/
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <oic_malloc.h>
#include "camutex.h"
#include "logger.h"
/**
* TAG
* Logging tag for module name
*/
#define TAG PCF("UMUTEX")
static const uint64_t USECS_PER_SEC = 1000000;
static const uint64_t NANOSECS_PER_USECS = 1000;
typedef struct _tagMutexInfo_t
{
pthread_mutex_t mutex;
} ca_mutex_internal;
typedef struct _tagEventInfo_t
{
pthread_cond_t cond;
} ca_cond_internal;
ca_mutex ca_mutex_new(void)
{
ca_mutex retVal = NULL;
ca_mutex_internal *mutexInfo = (ca_mutex_internal*) OICMalloc(sizeof(ca_mutex_internal));
if (NULL != mutexInfo)
{
// create the mutex with the attributes set
int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
if (0 == ret)
{
retVal = (ca_mutex) mutexInfo;
}
else
{
OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
OICFree(mutexInfo);
}
}
return retVal;
}
bool ca_mutex_free(ca_mutex mutex)
{
bool bRet=false;
ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
if (mutexInfo)
{
int ret = pthread_mutex_destroy(&mutexInfo->mutex);
if (0 == ret)
{
OICFree(mutexInfo);
bRet=true;
}
else
{
OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
}
}
else
{
OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
}
return bRet;
}
void ca_mutex_lock(ca_mutex mutex)
{
ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
if (mutexInfo)
{
int ret = pthread_mutex_lock(&mutexInfo->mutex);
assert(0 == ret);
}
else
{
OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
return;
}
}
bool ca_mutex_trylock(ca_mutex mutex)
{
if (NULL == mutex)
{
OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
return false;
}
bool bRet = false;
ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
int result = pthread_mutex_trylock(&mutexInfo->mutex);
switch (result)
{
case 0:
// Success
bRet = true;
break;
case EINVAL:
OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
break;
case EBUSY:
default:
break;
}
return bRet;
}
void ca_mutex_unlock(ca_mutex mutex)
{
ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
if (mutexInfo)
{
int ret = pthread_mutex_unlock(&mutexInfo->mutex);
assert(ret == 0);
}
else
{
OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
return;
}
}
ca_cond ca_cond_new(void)
{
ca_cond retVal = NULL;
ca_cond_internal *eventInfo = (ca_cond_internal*) OICMalloc(sizeof(ca_cond_internal));
if (NULL != eventInfo)
{
int ret = pthread_cond_init(&(eventInfo->cond), NULL);
if (0 == ret)
{
retVal = (ca_cond) eventInfo;
}
else
{
OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
OICFree(eventInfo);
}
}
return retVal;
}
void ca_cond_free(ca_cond cond)
{
ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
if (eventInfo != NULL)
{
int ret = pthread_cond_destroy(&(eventInfo->cond));
if (0 == ret)
{
OICFree(cond);
}
else
{
OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d", __func__, ret);
}
}
else
{
OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
}
}
void ca_cond_signal(ca_cond cond)
{
ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
if (eventInfo != NULL)
{
int ret = pthread_cond_signal(&(eventInfo->cond));
if (0 != ret)
{
OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
}
}
else
{
OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
}
}