7214ebf7f97761a1fafc8cf3669819bb05620d6f
[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 "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("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     pthread_t owner;
92     uint32_t recursionCount;
93 } oc_mutex_internal;
94
95 typedef struct _tagEventInfo_t
96 {
97     pthread_cond_t cond;
98     pthread_condattr_t condattr;
99 } oc_cond_internal;
100
101 typedef struct _tagThreadInfo_t
102 {
103     pthread_t thread;
104     pthread_attr_t  threadattr;
105 } oc_thread_internal;
106
107 static pthread_t oc_get_current_thread_id()
108 {
109     pthread_t id = pthread_self();
110     assert(OC_INVALID_THREAD_ID != id);
111     return id;
112 }
113
114 #ifndef __TIZENRT__
115 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
116 #else
117 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg,
118                                    const char *task_name, int stack_size)
119 #endif
120 {
121     OCThreadResult_t res = OC_THREAD_SUCCESS;
122     oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
123     if (NULL != threadInfo)
124     {
125 #ifdef __TIZENRT__
126         pthread_attr_t attr;
127         pthread_attr_init(&attr);
128         struct sched_param prio;
129         prio.sched_priority = 90;
130         (void)pthread_attr_setschedparam(&attr, &prio);
131         (void)pthread_attr_setstacksize(&attr, stack_size);
132         int result = pthread_create(&threadInfo->thread, &attr, start_routine, arg);
133         pthread_setname_np(threadInfo->thread, task_name);
134 #else
135         int result = pthread_create(&threadInfo->thread, NULL, start_routine, arg);
136 #endif
137         if (result != 0)
138         {
139             res = OC_THREAD_CREATE_FAILURE;
140             *t = NULL;
141             OICFree(threadInfo);
142             OIC_LOG_V(ERROR, TAG, "%s: pthread_create failed", __func__);
143         }
144         else
145         {
146             *t = (oc_thread)threadInfo;
147         }
148     }
149     else
150     {
151         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
152         *t = NULL;
153         res = OC_THREAD_ALLOCATION_FAILURE;
154     }
155     return res;
156 }
157
158 OCThreadResult_t oc_thread_free(oc_thread t)
159 {
160     OCThreadResult_t res = OC_THREAD_SUCCESS;
161     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
162     if (threadInfo)
163     {
164         OICFree(threadInfo);
165     }
166     else
167     {
168         OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
169         res = OC_THREAD_INVALID;
170     }
171     return res;
172 }
173
174 OCThreadResult_t oc_thread_wait(oc_thread t)
175 {
176     OCThreadResult_t res = OC_THREAD_SUCCESS;
177     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
178     int joinres = pthread_join(threadInfo->thread, NULL);
179     if (0 != joinres)
180     {
181         OIC_LOG_V(ERROR, TAG, "Failed to join thread with error %d", joinres);
182         res = OC_THREAD_WAIT_FAILURE;
183     }
184
185     return res;
186 }
187
188 OCThreadResult_t oc_thread_detach(oc_thread t)
189 {
190     OCThreadResult_t res = OC_THREAD_SUCCESS;
191 #ifndef __TIZENRT__
192     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
193     int detachres = pthread_detach(threadInfo->thread);
194     if (0 != detachres)
195     {
196         OIC_LOG_V(ERROR, TAG, "Failed to detach thread with error %d", detachres);
197         res = OC_THREAD_DETACH_FAILURE;
198     }
199 #endif
200     return res;
201 }
202
203 #ifdef __TIZEN__
204 OCThreadResult_t oc_thread_cancel(oc_thread t)
205 {
206     OCThreadResult_t res = OC_THREAD_SUCCESS;
207     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
208     int ret = pthread_cancel(threadInfo->thread);
209     if (0 != ret)
210     {
211         OIC_LOG_V(ERROR, TAG, "Failed to cancel thread with error %d", ret);
212         res = OC_THREAD_CANCEL_FAILURE;
213     }
214
215     return res;
216 }
217 #endif
218
219 oc_mutex oc_mutex_new(void)
220 {
221     oc_mutex retVal = NULL;
222     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
223     if (NULL != mutexInfo)
224     {
225         // create the mutex with the attributes set
226         int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
227         if (0 == ret)
228         {
229             retVal = (oc_mutex) mutexInfo;
230         }
231         else
232         {
233             OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
234             OICFree(mutexInfo);
235         }
236     }
237     else
238     {
239         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
240     }
241
242     return retVal;
243 }
244
245 bool oc_mutex_free(oc_mutex mutex)
246 {
247     bool bRet=false;
248     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
249     if (mutexInfo)
250     {
251         int ret = pthread_mutex_destroy(&mutexInfo->mutex);
252         if (0 == ret)
253         {
254             OICFree(mutexInfo);
255             bRet=true;
256         }
257         else
258         {
259             OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
260         }
261     }
262     else
263     {
264         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
265     }
266
267     return bRet;
268 }
269
270 void oc_mutex_lock(oc_mutex mutex)
271 {
272     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
273     if (mutexInfo)
274     {
275         int ret = pthread_mutex_lock(&mutexInfo->mutex);
276         if(ret != 0)
277         {
278             OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
279             exit(ret);
280         }
281     }
282     else
283     {
284         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
285     }
286 }
287
288 void oc_mutex_unlock(oc_mutex mutex)
289 {
290     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
291     if (mutexInfo)
292     {
293 #if defined(__TIZENRT__)
294         if (mutexInfo->mutex.pid == 0)
295         {
296             return;
297         }
298 #endif
299         int ret = pthread_mutex_unlock(&mutexInfo->mutex);
300         if (ret != 0)
301         {
302             OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
303             exit(ret);
304         }
305     }
306     else
307     {
308         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
309     }
310 }
311
312 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
313 {
314     assert(NULL != mutex);
315     const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
316
317     pthread_t currentThreadID = oc_get_current_thread_id();
318     if (currentThreadIsOwner)
319     {
320         assert(pthread_equal(mutexInfo->owner, currentThreadID));
321         assert(mutexInfo->recursionCount != 0);
322     }
323     else
324     {
325         assert(!pthread_equal(mutexInfo->owner, currentThreadID));
326     }
327 }
328
329 oc_cond oc_cond_new(void)
330 {
331     oc_cond retVal = NULL;
332     oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
333     if (NULL != eventInfo)
334     {
335         int ret = pthread_condattr_init(&(eventInfo->condattr));
336         if(0 != ret)
337         {
338             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
339                     __func__, ret);
340             OICFree(eventInfo);
341             return retVal;
342         }
343
344 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
345 #ifdef __ANDROID__
346         if (camutex_condattr_setclock)
347         {
348             ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
349 #else
350         {
351             ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
352 #endif /*  __ANDROID__ */
353             if(0 != ret)
354             {
355                 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
356                         __func__, ret);
357                 pthread_condattr_destroy(&(eventInfo->condattr));
358                 OICFree(eventInfo);
359                 return retVal;
360             }
361         }
362 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
363         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
364         if (0 == ret)
365         {
366             retVal = (oc_cond) eventInfo;
367         }
368         else
369         {
370             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
371             pthread_condattr_destroy(&(eventInfo->condattr));
372             OICFree(eventInfo);
373         }
374     }
375     else
376     {
377         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
378     }
379
380     return retVal;
381 }
382
383 void oc_cond_free(oc_cond cond)
384 {
385     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
386     if (eventInfo != NULL)
387     {
388         int ret = pthread_cond_destroy(&(eventInfo->cond));
389         int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
390         if (0 == ret && 0 == ret2)
391         {
392             OICFree(cond);
393         }
394         else
395         {
396             OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
397                     __func__, ret, ret2);
398         }
399     }
400     else
401     {
402         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
403     }
404 }
405
406 void oc_cond_signal(oc_cond cond)
407 {
408     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
409     if (eventInfo != NULL)
410     {
411         int ret = pthread_cond_signal(&(eventInfo->cond));
412         if (0 != ret)
413         {
414             OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
415         }
416     }
417     else
418     {
419         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
420     }
421 }
422
423 void oc_cond_broadcast(oc_cond cond)
424 {
425     oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
426     if (eventInfo != NULL)
427     {
428         int ret = pthread_cond_broadcast(&(eventInfo->cond));
429         if (0 != ret)
430         {
431             OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
432         }
433     }
434     else
435     {
436         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
437     }
438 }
439
440 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
441 {
442     oc_cond_wait_for(cond, mutex, 0L);
443 }
444
445 #ifndef TIMEVAL_TO_TIMESPEC
446 #define TIMEVAL_TO_TIMESPEC(tv, ts) {               \
447     (ts)->tv_sec = (tv)->tv_sec;                    \
448     (ts)->tv_nsec = (tv)->tv_usec * 1000;           \
449 }
450 #endif
451
452 struct timespec oc_get_current_time()
453 {
454 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
455     struct timespec ts;
456     clock_gettime(CLOCK_MONOTONIC, &ts);
457     return ts;
458 #else
459     struct timeval tv;
460     gettimeofday(&tv, NULL);
461     struct timespec ts;
462     TIMEVAL_TO_TIMESPEC(&tv, &ts);
463     return ts;
464 #endif
465 }
466
467 void oc_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
468 {
469     time_t secPart = microseconds/USECS_PER_SEC;
470     uint64_t nsecPart = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
471     uint64_t totalNs = ts->tv_nsec + nsecPart;
472     time_t secOfNs = totalNs/NANOSECS_PER_SEC;
473
474     ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
475     ts->tv_sec += secPart + secOfNs;
476 }
477
478 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
479 {
480     OCWaitResult_t retVal = OC_WAIT_INVAL;
481
482     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
483     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
484
485     if (NULL == mutexInfo)
486     {
487         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
488         return OC_WAIT_INVAL;
489     }
490
491     if (NULL == eventInfo)
492     {
493         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
494         return OC_WAIT_INVAL;
495     }
496
497     if (microseconds > 0)
498     {
499         int ret = 0;
500         struct timespec abstime = { .tv_sec = 0 };
501
502 #ifdef __ANDROID__
503         if (camutex_cond_timedwait_relative)
504         {
505             abstime.tv_sec = microseconds / USECS_PER_SEC;
506             abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
507             //Wait for the given time
508             ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
509         } else
510 #endif
511         {
512              abstime = oc_get_current_time();
513             oc_add_microseconds_to_timespec(&abstime, microseconds);
514
515             //Wait for the given time
516             ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
517         }
518
519         switch (ret)
520         {
521             case 0:
522                 // Success
523                 retVal = OC_WAIT_SUCCESS;
524                 break;
525             case ETIMEDOUT:
526                 retVal = OC_WAIT_TIMEDOUT;
527                 break;
528             case EINVAL:
529                 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
530                 retVal = OC_WAIT_INVAL;
531                 break;
532             default:
533                 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
534                 retVal = OC_WAIT_INVAL;
535                 break;
536         }
537     }
538     else
539     {
540         // Wait forever
541         int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
542         retVal = ret == 0 ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;
543     }
544     return retVal;
545 }
546