df530b3f991e0ec7e4788015d6df86fd6ecea42c
[platform/upstream/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 "iotivity_debug.h"
41 #include "octhread.h"
42 #ifdef HAVE_STRING_H
43 #include <string.h>
44 #endif
45 #ifdef HAVE_PTHREAD_H
46 #include <pthread.h>
47 #endif
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #ifdef HAVE_TIME_H
52 #include <time.h>
53 #endif
54 #ifdef HAVE_SYS_TIME_H
55 #include <sys/time.h>
56 #endif
57 #include <stdio.h>
58 #include <errno.h>
59 #include <assert.h>
60 #include <oic_malloc.h>
61 #include "logger.h"
62
63 /**
64  * TAG
65  * Logging tag for module name
66  */
67 #define TAG PCF("UMUTEX")
68
69 #ifdef __ANDROID__
70 /**
71  * Android has pthread_condattr_setclock() only in version >= 5.0, older
72  * version do have a function called __pthread_cond_timedwait_relative()
73  * which waits *for* the given timespec, this function is not visible in
74  * android version >= 5.0 anymore. This is the same way as it is handled in
75  * QT 5.5.0 in
76  * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
77  */
78 static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
79         __attribute__ ((weakref("pthread_condattr_setclock")));
80
81 static int camutex_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t*, const struct timespec*)
82         __attribute__ ((weakref("__pthread_cond_timedwait_relative")));
83 #endif /* __ANDROID__ */
84
85 static const uint64_t USECS_PER_SEC         = 1000000;
86 static const uint64_t NANOSECS_PER_USECS    = 1000;
87 static const uint64_t NANOSECS_PER_SEC      = 1000000000L;
88
89 typedef struct _tagMutexInfo_t
90 {
91     pthread_mutex_t mutex;
92
93     /**
94      * Catch some of the incorrect mutex usage, by tracking the mutex owner,
95      * on Debug builds.
96      */
97 #ifndef NDEBUG
98     pthread_t owner;
99     uint32_t recursionCount;
100 #endif
101 } oc_mutex_internal;
102
103 typedef struct _tagEventInfo_t
104 {
105     pthread_cond_t cond;
106     pthread_condattr_t condattr;
107 } oc_cond_internal;
108
109 typedef struct _tagThreadInfo_t
110 {
111     pthread_t thread;
112     pthread_attr_t  threadattr;
113 } oc_thread_internal;
114
115 #ifndef NDEBUG
116 static pthread_t oc_get_current_thread_id()
117 {
118     pthread_t id = pthread_self();
119     assert(OC_INVALID_THREAD_ID != id);
120     return id;
121 }
122 #endif
123
124 #ifndef __TIZENRT__
125 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
126 #else
127 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg,
128                                    const char *task_name, int stack_size)
129 #endif
130 {
131     OCThreadResult_t res = OC_THREAD_SUCCESS;
132     oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
133     if (NULL != threadInfo)
134     {
135 #ifdef __TIZENRT__
136         pthread_attr_t attr;
137         pthread_attr_init(&attr);
138         struct sched_param prio;
139         prio.sched_priority = 90;
140         (void)pthread_attr_setschedparam(&attr, &prio);
141         (void)pthread_attr_setstacksize(&attr, stack_size);
142         int result = pthread_create(&threadInfo->thread, &attr, start_routine, arg);
143         pthread_setname_np(threadInfo->thread, task_name);
144 #else
145         int result = pthread_create(&threadInfo->thread, NULL, start_routine, arg);
146 #endif
147         if (result != 0)
148         {
149             res = OC_THREAD_CREATE_FAILURE;
150             *t = NULL;
151             OICFree(threadInfo);
152             OIC_LOG_V(ERROR, TAG, "%s: pthread_create failed", __func__);
153         }
154         else
155         {
156             *t = (oc_thread)threadInfo;
157         }
158     }
159     else
160     {
161         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
162         *t = NULL;
163         res = OC_THREAD_ALLOCATION_FAILURE;
164     }
165     return res;
166 }
167
168 OCThreadResult_t oc_thread_free(oc_thread t)
169 {
170     OCThreadResult_t res = OC_THREAD_SUCCESS;
171     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
172     if (threadInfo)
173     {
174         OICFree(threadInfo);
175     }
176     else
177     {
178         OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
179         res = OC_THREAD_INVALID;
180     }
181     return res;
182 }
183
184 OCThreadResult_t oc_thread_wait(oc_thread t)
185 {
186     OCThreadResult_t res = OC_THREAD_SUCCESS;
187     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
188     int joinres = pthread_join(threadInfo->thread, NULL);
189     if (0 != joinres)
190     {
191         OIC_LOG_V(ERROR, TAG, "Failed to join thread with error %d", joinres);
192         res = OC_THREAD_WAIT_FAILURE;
193     }
194
195     return res;
196 }
197
198 OCThreadResult_t oc_thread_detach(oc_thread t)
199 {
200     OCThreadResult_t res = OC_THREAD_SUCCESS;
201 #ifndef __TIZENRT__
202     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
203     int detachres = pthread_detach(threadInfo->thread);
204     if (0 != detachres)
205     {
206         OIC_LOG_V(ERROR, TAG, "Failed to detach thread with error %d", detachres);
207         res = OC_THREAD_DETACH_FAILURE;
208     }
209 #endif
210     return res;
211 }
212
213 #ifdef __TIZEN__
214 OCThreadResult_t oc_thread_cancel(oc_thread t)
215 {
216     OCThreadResult_t res = OC_THREAD_SUCCESS;
217     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
218     int ret = pthread_cancel(threadInfo->thread);
219     if (0 != ret)
220     {
221         OIC_LOG_V(ERROR, TAG, "Failed to cancel thread with error %d", ret);
222         res = OC_THREAD_CANCEL_FAILURE;
223     }
224
225     return res;
226 }
227 #endif
228
229 oc_mutex oc_mutex_new(void)
230 {
231     oc_mutex retVal = NULL;
232     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
233     if (NULL != mutexInfo)
234     {
235         // create the mutex with the attributes set
236         int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
237         if (0 == ret)
238         {
239 #ifndef NDEBUG
240             mutexInfo->owner = OC_INVALID_THREAD_ID;
241             mutexInfo->recursionCount = 0;
242 #endif
243             retVal = (oc_mutex) mutexInfo;
244         }
245         else
246         {
247             OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
248             OICFree(mutexInfo);
249         }
250     }
251     else
252     {
253         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
254     }
255
256     return retVal;
257 }
258
259 oc_mutex oc_mutex_new_recursive(void)
260 {
261     oc_mutex retVal = NULL;
262     int ret = -1;
263
264     // Allocate new mutex.
265     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
266     if (NULL == mutexInfo)
267     {
268         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
269         goto exit;
270     }
271
272     // Set up the mutex attributes.
273     pthread_mutexattr_t ma;
274     ret = pthread_mutexattr_init(&ma);
275     if (0 != ret)
276     {
277         OIC_LOG_V(ERROR, TAG, "%s Failed in pthread_mutexattr_init - error %d!",
278             __func__, ret);
279         goto exit;
280     }
281
282     ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
283     if (0 != ret)
284     {
285         OIC_LOG_V(ERROR, TAG, "%s Failed in pthread_mutexattr_settype - error %d!",
286             __func__, ret);
287         pthread_mutexattr_destroy(&ma);
288         goto exit;
289     }
290
291     // Initialize the mutex and destroy the attributes.
292     ret = pthread_mutex_init(&(mutexInfo->mutex), &ma);
293     OC_VERIFY(0 == pthread_mutexattr_destroy(&ma));
294     if (0 != ret)
295     {
296         OIC_LOG_V(ERROR, TAG, "%s Failed in pthread_mutex_init - error %d!",
297             __func__, ret);
298         goto exit;
299     }
300
301 #ifndef NDEBUG
302     mutexInfo->owner = OC_INVALID_THREAD_ID;
303     mutexInfo->recursionCount = 0;
304 #endif
305
306 exit:
307     if (0 == ret)
308     {
309         retVal = (oc_mutex) mutexInfo;
310     }
311     else
312     {
313         OICFree(mutexInfo);
314     }
315
316     return retVal;
317 }
318
319 bool oc_mutex_free(oc_mutex mutex)
320 {
321     bool bRet=false;
322     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
323     if (mutexInfo)
324     {
325         int ret = pthread_mutex_destroy(&mutexInfo->mutex);
326         if (0 == ret)
327         {
328             OICFree(mutexInfo);
329             bRet=true;
330         }
331         else
332         {
333             OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
334         }
335     }
336     else
337     {
338         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
339     }
340
341     return bRet;
342 }
343
344 void oc_mutex_lock(oc_mutex mutex)
345 {
346     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
347     if (mutexInfo)
348     {
349         int ret = pthread_mutex_lock(&mutexInfo->mutex);
350         if(ret != 0)
351         {
352             OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
353             exit(ret);
354         }
355
356 #ifndef NDEBUG
357         /**
358          * Updating the recursionCount and owner fields must be performed
359          * while owning the lock, to solve race conditions with other
360          * threads using the same lock.
361          */
362         if (mutexInfo->recursionCount != 0)
363         {
364             oc_mutex_assert_owner(mutex, true);
365         }
366         else
367         {
368             mutexInfo->owner = oc_get_current_thread_id();
369         }
370
371         mutexInfo->recursionCount++;
372 #endif
373     }
374     else
375     {
376         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
377     }
378 }
379
380 void oc_mutex_unlock(oc_mutex mutex)
381 {
382     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
383     if (mutexInfo)
384     {
385 #if defined(__TIZENRT__)
386         if (mutexInfo->mutex.pid == 0)
387         {
388             return;
389         }
390 #endif
391
392 #ifndef NDEBUG
393         oc_mutex_assert_owner(mutex, true);
394
395         /**
396          * Updating the recursionCount and owner fields must be performed
397          * while owning the lock, to solve race conditions with other
398          * threads using the same lock.
399          */
400         mutexInfo->recursionCount--;
401
402         if (mutexInfo->recursionCount == 0)
403         {
404             mutexInfo->owner = OC_INVALID_THREAD_ID;
405         }
406 #endif
407
408         int ret = pthread_mutex_unlock(&mutexInfo->mutex);
409         if (ret != 0)
410         {
411             OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
412             exit(ret);
413         }
414     }
415     else
416     {
417         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
418     }
419 }
420
421 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
422 {
423 #ifdef NDEBUG
424     (void)mutex;
425     (void)currentThreadIsOwner;
426 #else
427     assert(NULL != mutex);
428     const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
429
430     pthread_t currentThreadID = oc_get_current_thread_id();
431     if (currentThreadIsOwner)
432     {
433         assert(pthread_equal(mutexInfo->owner, currentThreadID));
434         assert(mutexInfo->recursionCount != 0);
435     }
436     else
437     {
438         assert(!pthread_equal(mutexInfo->owner, currentThreadID));
439     }
440 #endif
441 }
442
443 oc_cond oc_cond_new(void)
444 {
445     oc_cond retVal = NULL;
446     oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
447     if (NULL != eventInfo)
448     {
449         int ret = pthread_condattr_init(&(eventInfo->condattr));
450         if(0 != ret)
451         {
452             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
453                     __func__, ret);
454             OICFree(eventInfo);
455             return retVal;
456         }
457
458 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
459 #ifdef __ANDROID__
460         if (camutex_condattr_setclock)
461         {
462             ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
463 #else
464         {
465             ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
466 #endif /*  __ANDROID__ */
467             if(0 != ret)
468             {
469                 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
470                         __func__, ret);
471                 pthread_condattr_destroy(&(eventInfo->condattr));
472                 OICFree(eventInfo);
473                 return retVal;
474             }
475         }
476 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
477         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
478         if (0 == ret)
479         {
480             retVal = (oc_cond) eventInfo;
481         }
482         else
483         {
484             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
485             pthread_condattr_destroy(&(eventInfo->condattr));
486             OICFree(eventInfo);
487         }
488     }
489     else
490     {
491         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
492     }
493
494     return retVal;
495 }
496
497 void oc_cond_free(oc_cond cond)
498 {
499     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
500     if (eventInfo != NULL)
501     {
502         int ret = pthread_cond_destroy(&(eventInfo->cond));
503         int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
504         if (0 == ret && 0 == ret2)
505         {
506             OICFree(cond);
507         }
508         else
509         {
510             OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
511                     __func__, ret, ret2);
512         }
513     }
514     else
515     {
516         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
517     }
518 }
519
520 void oc_cond_signal(oc_cond cond)
521 {
522     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
523     if (eventInfo != NULL)
524     {
525         int ret = pthread_cond_signal(&(eventInfo->cond));
526         if (0 != ret)
527         {
528             OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
529         }
530     }
531     else
532     {
533         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
534     }
535 }
536
537 void oc_cond_broadcast(oc_cond cond)
538 {
539     oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
540     if (eventInfo != NULL)
541     {
542         int ret = pthread_cond_broadcast(&(eventInfo->cond));
543         if (0 != ret)
544         {
545             OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
546         }
547     }
548     else
549     {
550         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
551     }
552 }
553
554 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
555 {
556     oc_cond_wait_for(cond, mutex, 0L);
557 }
558
559 #ifndef TIMEVAL_TO_TIMESPEC
560 #define TIMEVAL_TO_TIMESPEC(tv, ts) {               \
561     (ts)->tv_sec = (tv)->tv_sec;                    \
562     (ts)->tv_nsec = (tv)->tv_usec * 1000;           \
563 }
564 #endif
565
566 struct timespec oc_get_current_time()
567 {
568 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
569     struct timespec ts;
570     clock_gettime(CLOCK_MONOTONIC, &ts);
571     return ts;
572 #else
573     struct timeval tv;
574     gettimeofday(&tv, NULL);
575     struct timespec ts;
576     TIMEVAL_TO_TIMESPEC(&tv, &ts);
577     return ts;
578 #endif
579 }
580
581 void oc_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
582 {
583     time_t secPart = microseconds/USECS_PER_SEC;
584     uint64_t nsecPart = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
585     uint64_t totalNs = ts->tv_nsec + nsecPart;
586     time_t secOfNs = totalNs/NANOSECS_PER_SEC;
587
588     ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
589     ts->tv_sec += secPart + secOfNs;
590 }
591
592 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
593 {
594     OCWaitResult_t retVal = OC_WAIT_INVAL;
595
596     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
597     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
598
599     if (NULL == mutexInfo)
600     {
601         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
602         return OC_WAIT_INVAL;
603     }
604
605     if (NULL == eventInfo)
606     {
607         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
608         return OC_WAIT_INVAL;
609     }
610
611     if (microseconds > 0)
612     {
613         int ret = 0;
614         struct timespec abstime = { .tv_sec = 0 };
615
616 #ifdef __ANDROID__
617         if (camutex_cond_timedwait_relative)
618         {
619             abstime.tv_sec = microseconds / USECS_PER_SEC;
620             abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
621             //Wait for the given time
622             ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
623         } else
624 #endif
625         {
626              abstime = oc_get_current_time();
627             oc_add_microseconds_to_timespec(&abstime, microseconds);
628
629 #ifndef NDEBUG
630             // Recursively-acquired locks are not supported for use with condition variables.
631             oc_mutex_assert_owner(mutex, true);
632             assert(mutexInfo->recursionCount == 1);
633             mutexInfo->recursionCount = 0;
634             mutexInfo->owner = OC_INVALID_THREAD_ID;
635 #endif
636
637             // Wait for the given time
638             ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
639
640 #ifndef NDEBUG
641             oc_mutex_assert_owner(mutex, false);
642             assert(mutexInfo->recursionCount == 0);
643             mutexInfo->recursionCount = 1;
644             mutexInfo->owner = oc_get_current_thread_id();
645 #endif
646         }
647
648         switch (ret)
649         {
650             case 0:
651                 // Success
652                 retVal = OC_WAIT_SUCCESS;
653                 break;
654             case ETIMEDOUT:
655                 retVal = OC_WAIT_TIMEDOUT;
656                 break;
657             case EINVAL:
658                 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
659                 retVal = OC_WAIT_INVAL;
660                 break;
661             default:
662                 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
663                 retVal = OC_WAIT_INVAL;
664                 break;
665         }
666     }
667     else
668     {
669 #ifndef NDEBUG
670         // Recursively-acquired locks are not supported for use with condition variables.
671         oc_mutex_assert_owner(mutex, true);
672         assert(mutexInfo->recursionCount == 1);
673         mutexInfo->recursionCount = 0;
674         mutexInfo->owner = OC_INVALID_THREAD_ID;
675 #endif
676
677         // Wait forever
678 #ifndef NDEBUG
679         // The conditional variable wait API used will atomically release the mutex, but the
680         // best we can do here is to just clear the owner info before the API is called.
681         mutexInfo->owner = OC_INVALID_THREAD_ID;
682 #endif
683         int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
684         retVal = (ret == 0) ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;
685
686 #ifndef NDEBUG
687         oc_mutex_assert_owner(mutex, false);
688         assert(mutexInfo->recursionCount == 0);
689         mutexInfo->recursionCount = 1;
690         mutexInfo->owner = oc_get_current_thread_id();
691 #endif
692     }
693     return retVal;
694 }
695