IOT-1828 Fix oc_mutex_assert_owner bug
[iotivity.git] / resource / c_common / octhread / src / posix / octhread.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20 //
21 //
22 //*********************************************************************
23
24 /**
25  * @file
26  * This file provides APIs related to mutex and semaphores.
27  */
28
29 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
30 // causes header files to expose definitions
31 // corresponding to the POSIX.1b, Real-time extensions
32 // (IEEE Std 1003.1b-1993) specification
33 //
34 // For this specific file, see use of clock_gettime and PTHREAD_MUTEX_DEFAULT
35 #ifndef _POSIX_C_SOURCE
36 #define _POSIX_C_SOURCE 200809L
37 #endif
38
39 #include "iotivity_config.h"
40 #include "octhread.h"
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #endif
44 #ifdef HAVE_PTHREAD_H
45 #include <pthread.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #ifdef HAVE_TIME_H
51 #include <time.h>
52 #endif
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif
56 #include <stdio.h>
57 #include <errno.h>
58 #include <assert.h>
59 #include <oic_malloc.h>
60 #include "logger.h"
61
62 /**
63  * TAG
64  * Logging tag for module name
65  */
66 #define TAG PCF("OIC_UMUTEX")
67
68 #ifdef __ANDROID__
69 /**
70  * Android has pthread_condattr_setclock() only in version >= 5.0, older
71  * version do have a function called __pthread_cond_timedwait_relative()
72  * which waits *for* the given timespec, this function is not visible in
73  * android version >= 5.0 anymore. This is the same way as it is handled in
74  * QT 5.5.0 in
75  * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
76  */
77 static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
78         __attribute__ ((weakref("pthread_condattr_setclock")));
79
80 static int camutex_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t*, const struct timespec*)
81         __attribute__ ((weakref("__pthread_cond_timedwait_relative")));
82 #endif /* __ANDROID__ */
83
84 static const uint64_t USECS_PER_SEC         = 1000000;
85 static const uint64_t NANOSECS_PER_USECS    = 1000;
86 static const uint64_t NANOSECS_PER_SEC      = 1000000000L;
87
88 typedef struct _tagMutexInfo_t
89 {
90     pthread_mutex_t mutex;
91
92     /**
93      * Catch some of the incorrect mutex usage, by tracking the mutex owner,
94      * on Debug builds.
95      */
96 #ifndef NDEBUG
97     pthread_t owner;
98 #endif
99 } oc_mutex_internal;
100
101 typedef struct _tagEventInfo_t
102 {
103     pthread_cond_t cond;
104     pthread_condattr_t condattr;
105 } oc_cond_internal;
106
107 typedef struct _tagThreadInfo_t
108 {
109     pthread_t thread;
110     pthread_attr_t  threadattr;
111 } oc_thread_internal;
112
113 #ifndef NDEBUG
114 static pthread_t oc_get_current_thread_id()
115 {
116     pthread_t id = pthread_self();
117     assert(OC_INVALID_THREAD_ID != id);
118     return id;
119 }
120 #endif
121
122 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
123 {
124     OCThreadResult_t res = OC_THREAD_SUCCESS;
125     oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
126     if (NULL != threadInfo)
127     {
128         int result = pthread_create(&threadInfo->thread, NULL, start_routine, arg);
129         if (result != 0)
130         {
131             res = OC_THREAD_CREATE_FAILURE;
132             *t = NULL;
133             OICFree(threadInfo);
134             OIC_LOG_V(ERROR, TAG, "%s: pthread_create failed", __func__);
135         }
136         else
137         {
138             *t = (oc_thread)threadInfo;
139         }
140     }
141     else
142     {
143         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
144         *t = NULL;
145         res = OC_THREAD_ALLOCATION_FAILURE;
146     }
147     return res;
148 }
149
150 OCThreadResult_t oc_thread_free(oc_thread t)
151 {
152     OCThreadResult_t res = OC_THREAD_SUCCESS;
153     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
154     if (threadInfo)
155     {
156         OICFree(threadInfo);
157     }
158     else
159     {
160         OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
161         res = OC_THREAD_INVALID;
162     }
163     return res;
164 }
165
166 OCThreadResult_t oc_thread_wait(oc_thread t)
167 {
168     OCThreadResult_t res = OC_THREAD_SUCCESS;
169     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
170     int joinres = pthread_join(threadInfo->thread, NULL);
171     if (0 != joinres)
172     {
173         OIC_LOG_V(ERROR, TAG, "Failed to join thread with error %d", joinres);
174         res = OC_THREAD_WAIT_FAILURE;
175     }
176
177     return res;
178 }
179
180 oc_mutex oc_mutex_new(void)
181 {
182     oc_mutex retVal = NULL;
183     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
184     if (NULL != mutexInfo)
185     {
186         // create the mutex with the attributes set
187         int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
188         if (0 == ret)
189         {
190 #ifndef NDEBUG
191             mutexInfo->owner = OC_INVALID_THREAD_ID;
192 #endif
193             retVal = (oc_mutex) mutexInfo;
194         }
195         else
196         {
197             OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
198             OICFree(mutexInfo);
199         }
200     }
201     else
202     {
203         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
204     }
205
206     return retVal;
207 }
208
209 bool oc_mutex_free(oc_mutex mutex)
210 {
211     bool bRet=false;
212     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
213     if (mutexInfo)
214     {
215         int ret = pthread_mutex_destroy(&mutexInfo->mutex);
216         if (0 == ret)
217         {
218             OICFree(mutexInfo);
219             bRet=true;
220         }
221         else
222         {
223             OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
224         }
225     }
226     else
227     {
228         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
229     }
230
231     return bRet;
232 }
233
234 void oc_mutex_lock(oc_mutex mutex)
235 {
236     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
237     if (mutexInfo)
238     {
239         int ret = pthread_mutex_lock(&mutexInfo->mutex);
240         if(ret != 0)
241         {
242             OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
243             exit(ret);
244         }
245
246 #ifndef NDEBUG
247         /**
248          * Updating the owner field must be performed while owning the lock,
249          * to solve race conditions with other threads using the same lock.
250          */
251         mutexInfo->owner = oc_get_current_thread_id();
252 #endif
253     }
254     else
255     {
256         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
257     }
258 }
259
260 void oc_mutex_unlock(oc_mutex mutex)
261 {
262     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
263     if (mutexInfo)
264     {
265 #ifndef NDEBUG
266         /**
267          * Updating the owner field must be performed while owning the lock,
268          * to solve race conditions with other threads using the same lock.
269          */
270         mutexInfo->owner = OC_INVALID_THREAD_ID;
271 #endif
272
273         int ret = pthread_mutex_unlock(&mutexInfo->mutex);
274         if(ret != 0)
275         {
276             OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
277             exit(ret);
278         }
279         (void)ret;
280     }
281     else
282     {
283         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
284     }
285 }
286
287 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
288 {
289 #ifdef NDEBUG
290     (void)mutex;
291     (void)currentThreadIsOwner;
292 #else
293     assert(NULL != mutex);
294     const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
295
296     pthread_t currentThreadID = oc_get_current_thread_id();
297     if (currentThreadIsOwner)
298     {
299         assert(pthread_equal(mutexInfo->owner, currentThreadID));
300     }
301     else
302     {
303         assert(!pthread_equal(mutexInfo->owner, currentThreadID));
304     }
305 #endif
306 }
307
308 oc_cond oc_cond_new(void)
309 {
310     oc_cond retVal = NULL;
311     oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
312     if (NULL != eventInfo)
313     {
314         int ret = pthread_condattr_init(&(eventInfo->condattr));
315         if(0 != ret)
316         {
317             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
318                     __func__, ret);
319             OICFree(eventInfo);
320             return retVal;
321         }
322
323 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
324 #ifdef __ANDROID__
325         if (camutex_condattr_setclock)
326         {
327             ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
328 #else
329         {
330             ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
331 #endif /*  __ANDROID__ */
332             if(0 != ret)
333             {
334                 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
335                         __func__, ret);
336                 pthread_condattr_destroy(&(eventInfo->condattr));
337                 OICFree(eventInfo);
338                 return retVal;
339             }
340         }
341 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
342         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
343         if (0 == ret)
344         {
345             retVal = (oc_cond) eventInfo;
346         }
347         else
348         {
349             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
350             pthread_condattr_destroy(&(eventInfo->condattr));
351             OICFree(eventInfo);
352         }
353     }
354     else
355     {
356         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
357     }
358
359     return retVal;
360 }
361
362 void oc_cond_free(oc_cond cond)
363 {
364     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
365     if (eventInfo != NULL)
366     {
367         int ret = pthread_cond_destroy(&(eventInfo->cond));
368         int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
369         if (0 == ret && 0 == ret2)
370         {
371             OICFree(cond);
372         }
373         else
374         {
375             OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
376                     __func__, ret, ret2);
377         }
378     }
379     else
380     {
381         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
382     }
383 }
384
385 void oc_cond_signal(oc_cond cond)
386 {
387     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
388     if (eventInfo != NULL)
389     {
390         int ret = pthread_cond_signal(&(eventInfo->cond));
391         if (0 != ret)
392         {
393             OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
394         }
395     }
396     else
397     {
398         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
399     }
400 }
401
402 void oc_cond_broadcast(oc_cond cond)
403 {
404     oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
405     if (eventInfo != NULL)
406     {
407         int ret = pthread_cond_broadcast(&(eventInfo->cond));
408         if (0 != ret)
409         {
410             OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
411         }
412     }
413     else
414     {
415         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
416     }
417 }
418
419 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
420 {
421     oc_cond_wait_for(cond, mutex, 0L);
422 }
423
424 #ifndef TIMEVAL_TO_TIMESPEC
425 #define TIMEVAL_TO_TIMESPEC(tv, ts) {               \
426     (ts)->tv_sec = (tv)->tv_sec;                    \
427     (ts)->tv_nsec = (tv)->tv_usec * 1000;           \
428 }
429 #endif
430
431 struct timespec oc_get_current_time()
432 {
433 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
434     struct timespec ts;
435     clock_gettime(CLOCK_MONOTONIC, &ts);
436     return ts;
437 #else
438     struct timeval tv;
439     gettimeofday(&tv, NULL);
440     struct timespec ts;
441     TIMEVAL_TO_TIMESPEC(&tv, &ts);
442     return ts;
443 #endif
444 }
445
446 void oc_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
447 {
448     time_t secPart = microseconds/USECS_PER_SEC;
449     uint64_t nsecPart = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
450     uint64_t totalNs = ts->tv_nsec + nsecPart;
451     time_t secOfNs = totalNs/NANOSECS_PER_SEC;
452
453     ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
454     ts->tv_sec += secPart + secOfNs;
455 }
456
457 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
458 {
459     OCWaitResult_t retVal = OC_WAIT_INVAL;
460
461     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
462     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
463
464     if (NULL == mutexInfo)
465     {
466         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
467         return OC_WAIT_INVAL;
468     }
469
470     if (NULL == eventInfo)
471     {
472         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
473         return OC_WAIT_INVAL;
474     }
475
476     if (microseconds > 0)
477     {
478         int ret = 0;
479         struct timespec abstime = { .tv_sec = 0 };
480
481 #ifdef __ANDROID__
482         if (camutex_cond_timedwait_relative)
483         {
484             abstime.tv_sec = microseconds / USECS_PER_SEC;
485             abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
486             //Wait for the given time
487             ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
488         } else
489 #endif
490         {
491              abstime = oc_get_current_time();
492             oc_add_microseconds_to_timespec(&abstime, microseconds);
493
494             // Wait for the given time
495 #ifndef NDEBUG
496             // The conditional variable wait API used will atomically release the mutex, but the
497             // best we can do here is to just clear the owner info before the API is called.
498             mutexInfo->owner = OC_INVALID_THREAD_ID;
499 #endif
500             ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
501 #ifndef NDEBUG
502             mutexInfo->owner = oc_get_current_thread_id();
503 #endif
504         }
505
506         switch (ret)
507         {
508             case 0:
509                 // Success
510                 retVal = OC_WAIT_SUCCESS;
511                 break;
512             case ETIMEDOUT:
513                 retVal = OC_WAIT_TIMEDOUT;
514                 break;
515             case EINVAL:
516                 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
517                 retVal = OC_WAIT_INVAL;
518                 break;
519             default:
520                 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
521                 retVal = OC_WAIT_INVAL;
522                 break;
523         }
524     }
525     else
526     {
527         // Wait forever
528 #ifndef NDEBUG
529         // The conditional variable wait API used will atomically release the mutex, but the
530         // best we can do here is to just clear the owner info before the API is called.
531         mutexInfo->owner = OC_INVALID_THREAD_ID;
532 #endif
533         int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
534         retVal = (ret == 0) ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;
535 #ifndef NDEBUG
536         mutexInfo->owner = oc_get_current_thread_id();
537 #endif
538     }
539     return retVal;
540 }
541