#endif
#include "iotivity_config.h"
+#include "iotivity_debug.h"
#include "octhread.h"
#ifdef HAVE_STRING_H
#include <string.h>
typedef struct _tagMutexInfo_t
{
pthread_mutex_t mutex;
+
+ /**
+ * Catch some of the incorrect mutex usage, by tracking the mutex owner,
+ * on Debug builds.
+ */
+#ifndef NDEBUG
pthread_t owner;
uint32_t recursionCount;
+#endif
} oc_mutex_internal;
typedef struct _tagEventInfo_t
pthread_attr_t threadattr;
} oc_thread_internal;
+#ifndef NDEBUG
static pthread_t oc_get_current_thread_id()
{
pthread_t id = pthread_self();
assert(OC_INVALID_THREAD_ID != id);
return id;
}
+#endif
#ifndef __TIZENRT__
OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
if (0 == ret)
{
+#ifndef NDEBUG
+ mutexInfo->owner = OC_INVALID_THREAD_ID;
+ mutexInfo->recursionCount = 0;
+#endif
retVal = (oc_mutex) mutexInfo;
}
else
return retVal;
}
+oc_mutex oc_mutex_new_recursive(void)
+{
+ oc_mutex retVal = NULL;
+ int ret = -1;
+
+ // Allocate new mutex.
+ oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
+ if (NULL == mutexInfo)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
+ goto exit;
+ }
+
+ // Set up the mutex attributes.
+ pthread_mutexattr_t ma;
+ ret = pthread_mutexattr_init(&ma);
+ if (0 != ret)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s Failed in pthread_mutexattr_init - error %d!",
+ __func__, ret);
+ goto exit;
+ }
+
+ ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
+ if (0 != ret)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s Failed in pthread_mutexattr_settype - error %d!",
+ __func__, ret);
+ pthread_mutexattr_destroy(&ma);
+ goto exit;
+ }
+
+ // Initialize the mutex and destroy the attributes.
+ ret = pthread_mutex_init(&(mutexInfo->mutex), &ma);
+ OC_VERIFY(0 == pthread_mutexattr_destroy(&ma));
+ if (0 != ret)
+ {
+ OIC_LOG_V(ERROR, TAG, "%s Failed in pthread_mutex_init - error %d!",
+ __func__, ret);
+ goto exit;
+ }
+
+#ifndef NDEBUG
+ mutexInfo->owner = OC_INVALID_THREAD_ID;
+ mutexInfo->recursionCount = 0;
+#endif
+
+exit:
+ if (0 == ret)
+ {
+ retVal = (oc_mutex) mutexInfo;
+ }
+ else
+ {
+ OICFree(mutexInfo);
+ }
+
+ return retVal;
+}
+
bool oc_mutex_free(oc_mutex mutex)
{
bool bRet=false;
OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
exit(ret);
}
+
+#ifndef NDEBUG
+ /**
+ * Updating the recursionCount and owner fields must be performed
+ * while owning the lock, to solve race conditions with other
+ * threads using the same lock.
+ */
+ if (mutexInfo->recursionCount != 0)
+ {
+ oc_mutex_assert_owner(mutex, true);
+ }
+ else
+ {
+ mutexInfo->owner = oc_get_current_thread_id();
+ }
+
+ mutexInfo->recursionCount++;
+#endif
}
else
{
return;
}
#endif
+
+#ifndef NDEBUG
+ oc_mutex_assert_owner(mutex, true);
+
+ /**
+ * Updating the recursionCount and owner fields must be performed
+ * while owning the lock, to solve race conditions with other
+ * threads using the same lock.
+ */
+ mutexInfo->recursionCount--;
+
+ if (mutexInfo->recursionCount == 0)
+ {
+ mutexInfo->owner = OC_INVALID_THREAD_ID;
+ }
+#endif
+
int ret = pthread_mutex_unlock(&mutexInfo->mutex);
if (ret != 0)
{
void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
{
+#ifdef NDEBUG
+ (void)mutex;
+ (void)currentThreadIsOwner;
+#else
assert(NULL != mutex);
const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
{
assert(!pthread_equal(mutexInfo->owner, currentThreadID));
}
+#endif
}
oc_cond oc_cond_new(void)
abstime = oc_get_current_time();
oc_add_microseconds_to_timespec(&abstime, microseconds);
- //Wait for the given time
+#ifndef NDEBUG
+ // Recursively-acquired locks are not supported for use with condition variables.
+ oc_mutex_assert_owner(mutex, true);
+ assert(mutexInfo->recursionCount == 1);
+ mutexInfo->recursionCount = 0;
+ mutexInfo->owner = OC_INVALID_THREAD_ID;
+#endif
+
+ // Wait for the given time
ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
+
+#ifndef NDEBUG
+ oc_mutex_assert_owner(mutex, false);
+ assert(mutexInfo->recursionCount == 0);
+ mutexInfo->recursionCount = 1;
+ mutexInfo->owner = oc_get_current_thread_id();
+#endif
}
switch (ret)
}
else
{
+#ifndef NDEBUG
+ // Recursively-acquired locks are not supported for use with condition variables.
+ oc_mutex_assert_owner(mutex, true);
+ assert(mutexInfo->recursionCount == 1);
+ mutexInfo->recursionCount = 0;
+ mutexInfo->owner = OC_INVALID_THREAD_ID;
+#endif
+
// Wait forever
+#ifndef NDEBUG
+ // The conditional variable wait API used will atomically release the mutex, but the
+ // best we can do here is to just clear the owner info before the API is called.
+ mutexInfo->owner = OC_INVALID_THREAD_ID;
+#endif
int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
- retVal = ret == 0 ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;
+ retVal = (ret == 0) ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;
+
+#ifndef NDEBUG
+ oc_mutex_assert_owner(mutex, false);
+ assert(mutexInfo->recursionCount == 0);
+ mutexInfo->recursionCount = 1;
+ mutexInfo->owner = oc_get_current_thread_id();
+#endif
}
return retVal;
}