IOT-1828 Fix oc_mutex_assert_owner bug
[iotivity.git] / resource / c_common / octhread / src / windows / octhread.c
1 /* *****************************************************************
2 *
3 * Copyright 2016 Intel Corporation
4 *
5 *
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
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 *
18 ******************************************************************/
19
20
21 /**
22  * @file
23  * This file provides APIs related to mutex, semaphores, and threads.
24  */
25 #include "iotivity_config.h"
26 #include "octhread.h"
27 #include <string.h>
28 #include <time.h>
29 #include <winsock2.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <oic_malloc.h>
33
34 #include "logger.h"
35 #include "iotivity_debug.h"
36
37 #define TAG "OIC_UMUTEX"
38
39 static const uint64_t USECS_PER_MSEC = 1000;
40
41 typedef struct _tagMutexInfo_t
42 {
43     CRITICAL_SECTION mutex;
44
45     /**
46      * Catch some of the incorrect mutex usage, by tracking the mutex owner,
47      * on Debug builds.
48      */
49 #ifndef NDEBUG
50     DWORD owner;
51 #endif
52 } oc_mutex_internal;
53
54 #ifndef NDEBUG
55 static DWORD oc_get_current_thread_id()
56 {
57     DWORD id = GetCurrentThreadId();
58     assert(OC_INVALID_THREAD_ID != id);
59     return id;
60 }
61 #endif
62
63 typedef struct _tagEventInfo_t
64 {
65     CONDITION_VARIABLE cond;
66 } oc_cond_internal;
67
68 typedef struct _tagThreadInfo_t
69 {
70     HANDLE handle;
71 } oc_thread_internal;
72
73 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
74 {
75     OCThreadResult_t res = OC_THREAD_SUCCESS;
76     oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
77     if (NULL != threadInfo)
78     {
79         threadInfo->handle = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
80         if (threadInfo->handle == NULL)
81         {
82             res = OC_THREAD_CREATE_FAILURE;
83             *t = NULL;
84             OICFree(threadInfo);
85             OIC_LOG_V(ERROR, TAG, "%s: CreateThread failed: %i", __func__, GetLastError());
86         }
87         else
88         {
89             *t = (oc_thread)threadInfo;
90         }
91     }
92     else
93     {
94         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
95         *t = NULL;
96         res = OC_THREAD_ALLOCATION_FAILURE;
97     }
98
99    return res;
100 }
101
102 OCThreadResult_t oc_thread_free(oc_thread t)
103 {
104     OCThreadResult_t res = OC_THREAD_INVALID_PARAMETER;
105     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
106     if (threadInfo)
107     {
108         OC_VERIFY(CloseHandle(threadInfo->handle));
109         OICFree(threadInfo);
110         res = OC_THREAD_SUCCESS;
111     }
112     else
113     {
114         OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
115     }
116     return res;
117 }
118
119 OCThreadResult_t oc_thread_wait(oc_thread t)
120 {
121     OCThreadResult_t res = OC_THREAD_SUCCESS;
122     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
123     DWORD joinres = WaitForSingleObject(threadInfo->handle, INFINITE);
124     assert(WAIT_OBJECT_0 == joinres);
125     if (WAIT_OBJECT_0 != joinres)
126     {
127         OIC_LOG(ERROR, TAG, "Failed to join thread");
128         res = OC_THREAD_WAIT_FAILURE;
129     }
130     return res;
131 }
132
133 oc_mutex oc_mutex_new(void)
134 {
135     oc_mutex retVal = NULL;
136     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
137     if (NULL != mutexInfo)
138     {
139 #ifndef NDEBUG
140         mutexInfo->owner = OC_INVALID_THREAD_ID;
141 #endif
142         InitializeCriticalSection(&mutexInfo->mutex);
143         retVal = (oc_mutex)mutexInfo;
144     }
145     else
146     {
147         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
148     }
149
150     return retVal;
151 }
152
153 bool oc_mutex_free(oc_mutex mutex)
154 {
155     bool bRet = false;
156     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
157     if (mutexInfo)
158     {
159         DeleteCriticalSection(&mutexInfo->mutex);
160         OICFree(mutexInfo);
161         bRet=true;
162     }
163     else
164     {
165         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
166     }
167
168     return bRet;
169 }
170
171 void oc_mutex_lock(oc_mutex mutex)
172 {
173     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
174     if (mutexInfo)
175     {
176         EnterCriticalSection(&mutexInfo->mutex);
177
178 #ifndef NDEBUG
179         /**
180          * Updating the owner field must be performed while owning the lock,
181          * to solve race conditions with other threads using the same lock.
182          */
183         mutexInfo->owner = oc_get_current_thread_id();
184 #endif
185     }
186     else
187     {
188         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
189     }
190 }
191
192 void oc_mutex_unlock(oc_mutex mutex)
193 {
194     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
195     if (mutexInfo)
196     {
197 #ifndef NDEBUG
198         /**
199          * Updating the owner field must be performed while owning the lock,
200          * to solve race conditions with other threads using the same lock.
201          */
202         mutexInfo->owner = OC_INVALID_THREAD_ID;
203 #endif
204
205         LeaveCriticalSection(&mutexInfo->mutex);
206     }
207     else
208     {
209         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
210     }
211 }
212
213 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
214 {
215 #ifdef NDEBUG
216     (void)(mutex);
217     (void)(currentThreadIsOwner);
218 #else
219     assert(NULL != mutex);
220     const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
221
222     DWORD currentThreadID = oc_get_current_thread_id();
223     if (currentThreadIsOwner)
224     {
225         assert(mutexInfo->owner == currentThreadID);
226     }
227     else
228     {
229         assert(mutexInfo->owner != currentThreadID);
230     }
231 #endif
232 }
233
234 oc_cond oc_cond_new(void)
235 {
236     oc_cond retVal = NULL;
237     oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
238     if (NULL != eventInfo)
239     {
240         InitializeConditionVariable(&eventInfo->cond);
241         retVal = (oc_cond) eventInfo;
242     }
243     else
244     {
245         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
246     }
247
248     return retVal;
249 }
250
251 void oc_cond_free(oc_cond cond)
252 {
253     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
254     if (eventInfo != NULL)
255     {
256         OICFree(cond);
257     }
258     else
259     {
260         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
261     }
262 }
263
264 void oc_cond_signal(oc_cond cond)
265 {
266     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
267     if (eventInfo != NULL)
268     {
269         WakeConditionVariable(&eventInfo->cond);
270     }
271     else
272     {
273         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
274     }
275 }
276
277 void oc_cond_broadcast(oc_cond cond)
278 {
279     oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
280     if (eventInfo != NULL)
281     {
282         WakeAllConditionVariable(&eventInfo->cond);
283     }
284     else
285     {
286         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
287     }
288 }
289
290 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
291 {
292     oc_cond_wait_for(cond, mutex, 0L);
293 }
294
295 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
296 {
297     OCWaitResult_t retVal = OC_WAIT_INVAL;
298
299     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
300     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
301
302     if (NULL == mutexInfo)
303     {
304         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
305         return OC_WAIT_INVAL;
306     }
307
308     if (NULL == eventInfo)
309     {
310         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
311         return OC_WAIT_INVAL;
312     }
313
314     DWORD milli = 0;
315     if (microseconds > 0)
316     {
317         milli = (DWORD)(microseconds / USECS_PER_MSEC);
318     }
319     else
320     {
321         milli = INFINITE;
322     }
323
324 #ifndef NDEBUG
325     // The conditional variable wait API used will atomically release the mutex, but the
326     // best we can do here is to just clear the owner info before the API is called.
327     mutexInfo->owner = OC_INVALID_THREAD_ID;
328 #endif
329
330     // Wait for the given time        
331     if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, milli))
332     {
333         if (GetLastError() == ERROR_TIMEOUT)
334         {
335             retVal = OC_WAIT_TIMEDOUT;
336         }
337         else
338         {
339             OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() failed %i", GetLastError());
340             retVal = OC_WAIT_INVAL;
341         }
342     }
343     else
344     {
345         retVal = OC_WAIT_SUCCESS;
346     }
347
348 #ifndef NDEBUG
349     mutexInfo->owner = oc_get_current_thread_id();
350 #endif
351
352     return retVal;
353 }
354