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