1 /* *****************************************************************
3 * Copyright 2016 Intel Corporation
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 ******************************************************************/
23 * This file provides APIs related to mutex, semaphores, and threads.
25 #include "iotivity_config.h"
32 #include <oic_malloc.h>
36 static const uint64_t USECS_PER_MSEC = 1000;
38 typedef struct _tagMutexInfo_t
40 CRITICAL_SECTION mutex;
43 * Catch some of the incorrect mutex usage, by tracking the mutex owner,
48 uint32_t recursionCount;
53 static DWORD oc_get_current_thread_id()
55 DWORD id = GetCurrentThreadId();
56 assert(OC_INVALID_THREAD_ID != id);
61 typedef struct _tagEventInfo_t
63 CONDITION_VARIABLE cond;
66 typedef struct _tagThreadInfo_t
71 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
73 OCThreadResult_t res = OC_THREAD_SUCCESS;
74 oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
75 if (NULL != threadInfo)
77 threadInfo->handle = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
78 if (threadInfo->handle == NULL)
80 res = OC_THREAD_CREATE_FAILURE;
83 OIC_LOG_V(ERROR, TAG, "%s: CreateThread failed: %i", __func__, GetLastError());
87 *t = (oc_thread)threadInfo;
92 OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
94 res = OC_THREAD_ALLOCATION_FAILURE;
100 OCThreadResult_t oc_thread_free(oc_thread t)
102 OCThreadResult_t res = OC_THREAD_INVALID_PARAMETER;
103 oc_thread_internal *threadInfo = (oc_thread_internal*) t;
106 OC_VERIFY(CloseHandle(threadInfo->handle));
108 res = OC_THREAD_SUCCESS;
112 OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
117 OCThreadResult_t oc_thread_wait(oc_thread t)
119 OCThreadResult_t res = OC_THREAD_SUCCESS;
120 oc_thread_internal *threadInfo = (oc_thread_internal*) t;
121 DWORD joinres = WaitForSingleObject(threadInfo->handle, INFINITE);
122 if (WAIT_OBJECT_0 != joinres)
124 OIC_LOG(ERROR, TAG, "Failed to join thread");
125 res = OC_THREAD_WAIT_FAILURE;
129 CloseHandle(threadInfo->handle);
134 oc_mutex oc_mutex_new(void)
136 oc_mutex retVal = NULL;
137 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
138 if (NULL != mutexInfo)
141 mutexInfo->owner = OC_INVALID_THREAD_ID;
142 mutexInfo->recursionCount = 0;
144 InitializeCriticalSection(&mutexInfo->mutex);
145 retVal = (oc_mutex)mutexInfo;
149 OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
155 oc_mutex oc_mutex_new_recursive(void)
157 return oc_mutex_new();
160 bool oc_mutex_free(oc_mutex mutex)
163 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
166 DeleteCriticalSection(&mutexInfo->mutex);
172 OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
178 void oc_mutex_lock(oc_mutex mutex)
180 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
183 EnterCriticalSection(&mutexInfo->mutex);
187 * Updating the recursionCount and owner fields must be performed
188 * while owning the lock, to solve race conditions with other
189 * threads using the same lock.
191 if (mutexInfo->recursionCount != 0)
193 oc_mutex_assert_owner(mutex, true);
197 mutexInfo->owner = oc_get_current_thread_id();
200 mutexInfo->recursionCount++;
205 OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
209 void oc_mutex_unlock(oc_mutex mutex)
211 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
215 oc_mutex_assert_owner(mutex, true);
218 * Updating the recursionCount and owner fields must be performed
219 * while owning the lock, to solve race conditions with other
220 * threads using the same lock.
222 mutexInfo->recursionCount--;
224 if (mutexInfo->recursionCount == 0)
226 mutexInfo->owner = OC_INVALID_THREAD_ID;
230 LeaveCriticalSection(&mutexInfo->mutex);
234 OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
238 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
242 (void)(currentThreadIsOwner);
244 assert(NULL != mutex);
245 const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
247 DWORD currentThreadID = oc_get_current_thread_id();
248 if (currentThreadIsOwner)
250 assert(mutexInfo->owner == currentThreadID);
251 assert(mutexInfo->recursionCount != 0);
255 assert(mutexInfo->owner != currentThreadID);
260 oc_cond oc_cond_new(void)
262 oc_cond retVal = NULL;
263 oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
264 if (NULL != eventInfo)
266 InitializeConditionVariable(&eventInfo->cond);
267 retVal = (oc_cond) eventInfo;
271 OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
277 void oc_cond_free(oc_cond cond)
279 oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
280 if (eventInfo != NULL)
286 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
290 void oc_cond_signal(oc_cond cond)
292 oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
293 if (eventInfo != NULL)
295 WakeConditionVariable(&eventInfo->cond);
299 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
303 void oc_cond_broadcast(oc_cond cond)
305 oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
306 if (eventInfo != NULL)
308 WakeAllConditionVariable(&eventInfo->cond);
312 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
316 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
318 oc_cond_wait_for(cond, mutex, 0L);
321 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
323 OCWaitResult_t retVal = OC_WAIT_INVAL;
325 oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
326 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
328 if (NULL == mutexInfo)
330 OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
331 return OC_WAIT_INVAL;
334 if (NULL == eventInfo)
336 OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
337 return OC_WAIT_INVAL;
341 if (microseconds > 0)
343 milli = (DWORD)(microseconds / USECS_PER_MSEC);
351 // Recursively-acquired locks are not supported for use with condition variables.
352 oc_mutex_assert_owner(mutex, true);
353 assert(mutexInfo->recursionCount == 1);
354 mutexInfo->recursionCount = 0;
355 mutexInfo->owner = OC_INVALID_THREAD_ID;
358 // Wait for the given time
359 if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, milli))
361 if (GetLastError() == ERROR_TIMEOUT)
363 retVal = OC_WAIT_TIMEDOUT;
367 OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() failed %i", GetLastError());
368 retVal = OC_WAIT_INVAL;
373 retVal = OC_WAIT_SUCCESS;
378 oc_mutex_assert_owner(mutex, false);
379 assert(mutexInfo->recursionCount == 0);
380 mutexInfo->recursionCount = 1;
381 mutexInfo->owner = oc_get_current_thread_id();