#endif
#include "iotivity_config.h"
+#include "iotivity_debug.h"
#include "octhread.h"
#ifdef HAVE_STRING_H
#include <string.h>
*/
#ifndef NDEBUG
pthread_t owner;
+ uint32_t recursionCount;
#endif
} oc_mutex_internal;
{
#ifndef NDEBUG
mutexInfo->owner = OC_INVALID_THREAD_ID;
+ mutexInfo->recursionCount = 0;
#endif
retVal = (oc_mutex) mutexInfo;
}
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;
exit(ret);
}
-#ifndef NDEBUG
- /**
- * Updating the owner field must be performed while owning the lock,
- * to solve race conditions with other threads using the same lock.
- */
- mutexInfo->owner = oc_get_current_thread_id();
-#endif
+#ifndef NDEBUG\r
+ /**\r
+ * Updating the recursionCount and owner fields must be performed\r
+ * while owning the lock, to solve race conditions with other\r
+ * threads using the same lock.\r
+ */\r
+ if (mutexInfo->recursionCount != 0)\r
+ {\r
+ oc_mutex_assert_owner(mutex, true);\r
+ }\r
+ else\r
+ {\r
+ mutexInfo->owner = oc_get_current_thread_id();\r
+ }\r
+\r
+ mutexInfo->recursionCount++;\r
+#endif\r
}
else
{
oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
if (mutexInfo)
{
-#ifndef NDEBUG
- /**
- * Updating the owner field must be performed while owning the lock,
- * to solve race conditions with other threads using the same lock.
- */
- mutexInfo->owner = OC_INVALID_THREAD_ID;
-#endif
+#ifndef NDEBUG\r
+ oc_mutex_assert_owner(mutex, true);\r
+\r
+ /**\r
+ * Updating the recursionCount and owner fields must be performed\r
+ * while owning the lock, to solve race conditions with other\r
+ * threads using the same lock.\r
+ */\r
+ mutexInfo->recursionCount--;\r
+\r
+ if (mutexInfo->recursionCount == 0)\r
+ {\r
+ mutexInfo->owner = OC_INVALID_THREAD_ID;\r
+ }\r
+#endif\r
int ret = pthread_mutex_unlock(&mutexInfo->mutex);
if(ret != 0)
if (currentThreadIsOwner)
{
assert(pthread_equal(mutexInfo->owner, currentThreadID));
+ assert(mutexInfo->recursionCount != 0);
}
else
{
abstime = oc_get_current_time();
oc_add_microseconds_to_timespec(&abstime, microseconds);
+#ifndef NDEBUG\r
+ // Recursively-acquired locks are not supported for use with condition variables.\r
+ oc_mutex_assert_owner(mutex, true);\r
+ assert(mutexInfo->recursionCount == 1);\r
+ mutexInfo->recursionCount = 0;\r
+ mutexInfo->owner = OC_INVALID_THREAD_ID;\r
+#endif\r
+
// Wait for the given time
-#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
ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
-#ifndef NDEBUG
- mutexInfo->owner = oc_get_current_thread_id();
-#endif
+
+#ifndef NDEBUG\r
+ oc_mutex_assert_owner(mutex, false);\r
+ assert(mutexInfo->recursionCount == 0);\r
+ mutexInfo->recursionCount = 1;\r
+ mutexInfo->owner = oc_get_current_thread_id();\r
+#endif\r
}
switch (ret)
}
else
{
+#ifndef NDEBUG\r
+ // Recursively-acquired locks are not supported for use with condition variables.\r
+ oc_mutex_assert_owner(mutex, true);\r
+ assert(mutexInfo->recursionCount == 1);\r
+ mutexInfo->recursionCount = 0;\r
+ mutexInfo->owner = OC_INVALID_THREAD_ID;\r
+#endif\r
+
// 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;
-#ifndef NDEBUG
- mutexInfo->owner = oc_get_current_thread_id();
-#endif
+
+#ifndef NDEBUG\r
+ oc_mutex_assert_owner(mutex, false);\r
+ assert(mutexInfo->recursionCount == 0);\r
+ mutexInfo->recursionCount = 1;\r
+ mutexInfo->owner = oc_get_current_thread_id();\r
+#endif\r
}
return retVal;
}
*/
#ifndef NDEBUG
DWORD owner;
+ uint32_t recursionCount;
#endif
} oc_mutex_internal;
{
#ifndef NDEBUG
mutexInfo->owner = OC_INVALID_THREAD_ID;
+ mutexInfo->recursionCount = 0;
#endif
InitializeCriticalSection(&mutexInfo->mutex);
retVal = (oc_mutex)mutexInfo;
return retVal;
}
+oc_mutex oc_mutex_new_recursive(void)
+{
+ return oc_mutex_new();
+}
+
bool oc_mutex_free(oc_mutex mutex)
{
bool bRet = false;
{
EnterCriticalSection(&mutexInfo->mutex);
-#ifndef NDEBUG
- /**
- * Updating the owner field must be performed while owning the lock,
- * to solve race conditions with other threads using the same lock.
- */
- mutexInfo->owner = oc_get_current_thread_id();
-#endif
+#ifndef NDEBUG\r
+ /**\r
+ * Updating the recursionCount and owner fields must be performed\r
+ * while owning the lock, to solve race conditions with other\r
+ * threads using the same lock.\r
+ */\r
+ if (mutexInfo->recursionCount != 0)\r
+ {\r
+ oc_mutex_assert_owner(mutex, true);\r
+ }\r
+ else\r
+ {\r
+ mutexInfo->owner = oc_get_current_thread_id();\r
+ }\r
+\r
+ mutexInfo->recursionCount++;\r
+#endif\r
}
else
{
void oc_mutex_unlock(oc_mutex mutex)
{
oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
+
if (mutexInfo)
{
-#ifndef NDEBUG
- /**
- * Updating the owner field must be performed while owning the lock,
- * to solve race conditions with other threads using the same lock.
- */
- mutexInfo->owner = OC_INVALID_THREAD_ID;
-#endif
+#ifndef NDEBUG\r
+ oc_mutex_assert_owner(mutex, true);\r
+\r
+ /**\r
+ * Updating the recursionCount and owner fields must be performed\r
+ * while owning the lock, to solve race conditions with other\r
+ * threads using the same lock.\r
+ */\r
+ mutexInfo->recursionCount--;\r
+\r
+ if (mutexInfo->recursionCount == 0)\r
+ {\r
+ mutexInfo->owner = OC_INVALID_THREAD_ID;\r
+ }\r
+#endif\r
LeaveCriticalSection(&mutexInfo->mutex);
}
if (currentThreadIsOwner)
{
assert(mutexInfo->owner == currentThreadID);
+ assert(mutexInfo->recursionCount != 0);
}
else
{
milli = INFINITE;
}
-#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
+#ifndef NDEBUG\r
+ // Recursively-acquired locks are not supported for use with condition variables.\r
+ oc_mutex_assert_owner(mutex, true);\r
+ assert(mutexInfo->recursionCount == 1);\r
+ mutexInfo->recursionCount = 0;\r
+ mutexInfo->owner = OC_INVALID_THREAD_ID;\r
+#endif\r
// Wait for the given time
if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, milli))
retVal = OC_WAIT_SUCCESS;
}
-#ifndef NDEBUG
- mutexInfo->owner = oc_get_current_thread_id();
-#endif
+#ifndef NDEBUG\r
+ oc_mutex_assert_owner(mutex, false);\r
+ assert(mutexInfo->recursionCount == 0);\r
+ mutexInfo->recursionCount = 1;\r
+ mutexInfo->owner = oc_get_current_thread_id();\r
+#endif\r
return retVal;
}
-