replace : iotivity -> iotivity-sec
[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 #ifdef __TIZEN__
180 OCThreadResult_t oc_thread_cancel(oc_thread t)
181 {
182     OCThreadResult_t res = OC_THREAD_SUCCESS;
183     oc_thread_internal *threadInfo = (oc_thread_internal*) t;
184     int ret = pthread_cancel(threadInfo->thread);
185     if (0 != ret)
186     {
187         OIC_LOG_V(ERROR, TAG, "Failed to cancel thread with error %d", ret);
188         res = OC_THREAD_CANCEL_FAILURE;
189     }
190
191     return res;
192 }
193 #endif
194
195 oc_mutex oc_mutex_new(void)
196 {
197     oc_mutex retVal = NULL;
198     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
199     if (NULL != mutexInfo)
200     {
201         // create the mutex with the attributes set
202         int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
203         if (0 == ret)
204         {
205             retVal = (oc_mutex) mutexInfo;
206         }
207         else
208         {
209             OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
210             OICFree(mutexInfo);
211         }
212     }
213     else
214     {
215         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
216     }
217
218     return retVal;
219 }
220
221 bool oc_mutex_free(oc_mutex mutex)
222 {
223     bool bRet=false;
224     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
225     if (mutexInfo)
226     {
227         int ret = pthread_mutex_destroy(&mutexInfo->mutex);
228         if (0 == ret)
229         {
230             OICFree(mutexInfo);
231             bRet=true;
232         }
233         else
234         {
235             OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
236         }
237     }
238     else
239     {
240         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
241     }
242
243     return bRet;
244 }
245
246 void oc_mutex_lock(oc_mutex mutex)
247 {
248     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
249     if (mutexInfo)
250     {
251         int ret = pthread_mutex_lock(&mutexInfo->mutex);
252         if(ret != 0)
253         {
254             OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
255             exit(ret);
256         }
257     }
258     else
259     {
260         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
261     }
262 }
263
264 void oc_mutex_unlock(oc_mutex mutex)
265 {
266     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
267     if (mutexInfo)
268     {
269 #if defined(__TIZENRT__)
270         if (mutexInfo->mutex.pid == 0)
271         {
272             return;
273         }
274 #endif
275         int ret = pthread_mutex_unlock(&mutexInfo->mutex);
276         if (ret != 0)
277         {
278             OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock 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 oc_cond oc_cond_new(void)
289 {
290     oc_cond retVal = NULL;
291     oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
292     if (NULL != eventInfo)
293     {
294         int ret = pthread_condattr_init(&(eventInfo->condattr));
295         if(0 != ret)
296         {
297             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
298                     __func__, ret);
299             OICFree(eventInfo);
300             return retVal;
301         }
302
303 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
304 #ifdef __ANDROID__
305         if (camutex_condattr_setclock)
306         {
307             ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
308 #else
309         {
310             ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
311 #endif /*  __ANDROID__ */
312             if(0 != ret)
313             {
314                 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
315                         __func__, ret);
316                 pthread_condattr_destroy(&(eventInfo->condattr));
317                 OICFree(eventInfo);
318                 return retVal;
319             }
320         }
321 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
322         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
323         if (0 == ret)
324         {
325             retVal = (oc_cond) eventInfo;
326         }
327         else
328         {
329             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
330             pthread_condattr_destroy(&(eventInfo->condattr));
331             OICFree(eventInfo);
332         }
333     }
334     else
335     {
336         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
337     }
338
339     return retVal;
340 }
341
342 void oc_cond_free(oc_cond cond)
343 {
344     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
345     if (eventInfo != NULL)
346     {
347         int ret = pthread_cond_destroy(&(eventInfo->cond));
348         int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
349         if (0 == ret && 0 == ret2)
350         {
351             OICFree(cond);
352         }
353         else
354         {
355             OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
356                     __func__, ret, ret2);
357         }
358     }
359     else
360     {
361         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
362     }
363 }
364
365 void oc_cond_signal(oc_cond cond)
366 {
367     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
368     if (eventInfo != NULL)
369     {
370         int ret = pthread_cond_signal(&(eventInfo->cond));
371         if (0 != ret)
372         {
373             OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
374         }
375     }
376     else
377     {
378         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
379     }
380 }
381
382 void oc_cond_broadcast(oc_cond cond)
383 {
384     oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
385     if (eventInfo != NULL)
386     {
387         int ret = pthread_cond_broadcast(&(eventInfo->cond));
388         if (0 != ret)
389         {
390             OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
391         }
392     }
393     else
394     {
395         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
396     }
397 }
398
399 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
400 {
401     oc_cond_wait_for(cond, mutex, 0L);
402 }
403
404 #ifndef TIMEVAL_TO_TIMESPEC
405 #define TIMEVAL_TO_TIMESPEC(tv, ts) {               \
406     (ts)->tv_sec = (tv)->tv_sec;                    \
407     (ts)->tv_nsec = (tv)->tv_usec * 1000;           \
408 }
409 #endif
410
411 struct timespec oc_get_current_time()
412 {
413 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
414     struct timespec ts;
415     clock_gettime(CLOCK_MONOTONIC, &ts);
416     return ts;
417 #else
418     struct timeval tv;
419     gettimeofday(&tv, NULL);
420     struct timespec ts;
421     TIMEVAL_TO_TIMESPEC(&tv, &ts);
422     return ts;
423 #endif
424 }
425
426 void oc_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
427 {
428     time_t secPart = microseconds/USECS_PER_SEC;
429     uint64_t nsecPart = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
430     uint64_t totalNs = ts->tv_nsec + nsecPart;
431     time_t secOfNs = totalNs/NANOSECS_PER_SEC;
432
433     ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
434     ts->tv_sec += secPart + secOfNs;
435 }
436
437 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
438 {
439     OCWaitResult_t retVal = OC_WAIT_INVAL;
440
441     oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
442     oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
443
444     if (NULL == mutexInfo)
445     {
446         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
447         return OC_WAIT_INVAL;
448     }
449
450     if (NULL == eventInfo)
451     {
452         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
453         return OC_WAIT_INVAL;
454     }
455
456     if (microseconds > 0)
457     {
458         int ret = 0;
459         struct timespec abstime = { .tv_sec = 0 };
460
461 #ifdef __ANDROID__
462         if (camutex_cond_timedwait_relative)
463         {
464             abstime.tv_sec = microseconds / USECS_PER_SEC;
465             abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
466             //Wait for the given time
467             ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
468         } else
469 #endif
470         {
471              abstime = oc_get_current_time();
472             oc_add_microseconds_to_timespec(&abstime, microseconds);
473
474             //Wait for the given time
475             ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
476         }
477
478         switch (ret)
479         {
480             case 0:
481                 // Success
482                 retVal = OC_WAIT_SUCCESS;
483                 break;
484             case ETIMEDOUT:
485                 retVal = OC_WAIT_TIMEDOUT;
486                 break;
487             case EINVAL:
488                 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
489                 retVal = OC_WAIT_INVAL;
490                 break;
491             default:
492                 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
493                 retVal = OC_WAIT_INVAL;
494                 break;
495         }
496     }
497     else
498     {
499         // Wait forever
500         int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
501         retVal = ret == 0 ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;
502     }
503     return retVal;
504 }
505