Adding changes in octhread related to Process Event
[platform/upstream/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
36 static const uint64_t USECS_PER_MSEC = 1000;
37
38 typedef struct _tagMutexInfo_t
39 {
40     CRITICAL_SECTION mutex;
41
42     /**
43      * Catch some of the incorrect mutex usage, by tracking the mutex owner,
44      * on Debug builds.
45      */
46 #ifndef NDEBUG
47     DWORD owner;
48     uint32_t recursionCount;
49 #endif
50 } oc_mutex_internal;
51
52 #ifndef NDEBUG
53 static DWORD oc_get_current_thread_id()
54 {
55     DWORD id = GetCurrentThreadId();
56     assert(OC_INVALID_THREAD_ID != id);
57     return id;
58 }
59 #endif
60
61 typedef struct _tagEventInfo_t
62 {
63     CONDITION_VARIABLE cond;
64 } oc_cond_internal;
65
66 typedef struct _tagThreadInfo_t
67 {
68     HANDLE handle;
69 } oc_thread_internal;
70
71 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
72 {
73     OCThreadResult_t res = OC_THREAD_SUCCESS;
74     oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
75     if (NULL != threadInfo)
76     {
77         threadInfo->handle = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)start_routine, arg, 0, NULL);
78         if (threadInfo->handle == NULL)
79         {
80             res = OC_THREAD_CREATE_FAILURE;
81             *t = NULL;
82             OICFree(threadInfo);
83             OIC_LOG_V(ERROR, TAG, "%s: CreateThread failed: %i", __func__, GetLastError());
84         }
85         else
86         {
87             *t = (oc_thread)threadInfo;
88         }
89     }
90     else
91     {
92         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
93         *t = NULL;
94         res = OC_THREAD_ALLOCATION_FAILURE;
95     }
96
97    return res;
98 }
99
100 OCThreadResult_t oc_thread_free(oc_thread t)
101 {
102     OCThreadResult_t res = OC_THREAD_INVALID_PARAMETER;
103     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
104     if (threadInfo)
105     {
106         OC_VERIFY(CloseHandle(threadInfo->handle));
107         OICFree(threadInfo);
108         res = OC_THREAD_SUCCESS;
109     }
110     else
111     {
112         OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
113     }
114     return res;
115 }
116
117 OCThreadResult_t oc_thread_wait(oc_thread t)
118 {
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)
123     {
124         OIC_LOG(ERROR, TAG, "Failed to join thread");
125         res = OC_THREAD_WAIT_FAILURE;
126     }
127     else
128     {
129         CloseHandle(threadInfo->handle);
130     }
131     return res;
132 }
133
134 oc_mutex oc_mutex_new(void)
135 {
136     oc_mutex retVal = NULL;
137     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
138     if (NULL != mutexInfo)
139     {
140 #ifndef NDEBUG
141         mutexInfo->owner = OC_INVALID_THREAD_ID;
142         mutexInfo->recursionCount = 0;
143 #endif
144         InitializeCriticalSection(&mutexInfo->mutex);
145         retVal = (oc_mutex)mutexInfo;
146     }
147     else
148     {
149         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
150     }
151
152     return retVal;
153 }
154
155 oc_mutex oc_mutex_new_recursive(void)
156 {
157     return oc_mutex_new();
158 }
159
160 bool oc_mutex_free(oc_mutex mutex)
161 {
162     bool bRet = false;
163     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
164     if (mutexInfo)
165     {
166         DeleteCriticalSection(&mutexInfo->mutex);
167         OICFree(mutexInfo);
168         bRet=true;
169     }
170     else
171     {
172         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
173     }
174
175     return bRet;
176 }
177
178 void oc_mutex_lock(oc_mutex mutex)
179 {
180     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
181     if (mutexInfo)
182     {
183         EnterCriticalSection(&mutexInfo->mutex);
184
185 #ifndef NDEBUG
186         /**
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.
190          */
191         if (mutexInfo->recursionCount != 0)
192         {
193             oc_mutex_assert_owner(mutex, true);
194         }
195         else
196         {
197             mutexInfo->owner = oc_get_current_thread_id();
198         }
199
200         mutexInfo->recursionCount++;
201 #endif
202     }
203     else
204     {
205         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
206     }
207 }
208
209 void oc_mutex_unlock(oc_mutex mutex)
210 {
211     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
212     if (mutexInfo)
213     {
214 #ifndef NDEBUG
215         oc_mutex_assert_owner(mutex, true);
216
217         /**
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.
221          */
222         mutexInfo->recursionCount--;
223
224         if (mutexInfo->recursionCount == 0)
225         {
226             mutexInfo->owner = OC_INVALID_THREAD_ID;
227         }
228 #endif
229
230         LeaveCriticalSection(&mutexInfo->mutex);
231     }
232     else
233     {
234         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
235     }
236 }
237
238 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
239 {
240 #ifdef NDEBUG
241     (void)(mutex);
242     (void)(currentThreadIsOwner);
243 #else
244     assert(NULL != mutex);
245     const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
246
247     DWORD currentThreadID = oc_get_current_thread_id();
248     if (currentThreadIsOwner)
249     {
250         assert(mutexInfo->owner == currentThreadID);
251         assert(mutexInfo->recursionCount != 0);
252     }
253     else
254     {
255         assert(mutexInfo->owner != currentThreadID);
256     }
257 #endif
258 }
259
260 oc_cond oc_cond_new(void)
261 {
262     oc_cond retVal = NULL;
263     oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
264     if (NULL != eventInfo)
265     {
266         InitializeConditionVariable(&eventInfo->cond);
267         retVal = (oc_cond) eventInfo;
268     }
269     else
270     {
271         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
272     }
273
274     return retVal;
275 }
276
277 void oc_cond_free(oc_cond cond)
278 {
279     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
280     if (eventInfo != NULL)
281     {
282         OICFree(cond);
283     }
284     else
285     {
286         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
287     }
288 }
289
290 void oc_cond_signal(oc_cond cond)
291 {
292     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
293     if (eventInfo != NULL)
294     {
295         WakeConditionVariable(&eventInfo->cond);
296     }
297     else
298     {
299         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
300     }
301 }
302
303 void oc_cond_broadcast(oc_cond cond)
304 {
305     oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
306     if (eventInfo != NULL)
307     {
308         WakeAllConditionVariable(&eventInfo->cond);
309     }
310     else
311     {
312         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
313     }
314 }
315
316 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
317 {
318     oc_cond_wait_for(cond, mutex, 0L);
319 }
320
321 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
322 {
323     OCWaitResult_t retVal = OC_WAIT_INVAL;
324
325     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
326     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
327
328     if (NULL == mutexInfo)
329     {
330         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
331         return OC_WAIT_INVAL;
332     }
333
334     if (NULL == eventInfo)
335     {
336         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
337         return OC_WAIT_INVAL;
338     }
339
340     DWORD milli = 0;
341     if (microseconds > 0)
342     {
343         milli = (DWORD)(microseconds / USECS_PER_MSEC);
344     }
345     else
346     {
347         milli = INFINITE;
348     }
349
350 #ifndef NDEBUG
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;
356 #endif
357
358     // Wait for the given time        
359     if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, milli))
360     {
361         if (GetLastError() == ERROR_TIMEOUT)
362         {
363             retVal = OC_WAIT_TIMEDOUT;
364         }
365         else
366         {
367             OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() failed %i", GetLastError());
368             retVal = OC_WAIT_INVAL;
369         }
370     }
371     else
372     {
373         retVal = OC_WAIT_SUCCESS;
374     }
375
376
377 #ifndef NDEBUG
378     oc_mutex_assert_owner(mutex, false);
379     assert(mutexInfo->recursionCount == 0);
380     mutexInfo->recursionCount = 1;
381     mutexInfo->owner = oc_get_current_thread_id();
382 #endif
383
384     return retVal;
385 }
386