1 //******************************************************************
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 //*********************************************************************
26 * This file provides APIs related to mutex and semaphores.
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
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
39 #include "iotivity_config.h"
53 #ifdef HAVE_SYS_TIME_H
59 #include <oic_malloc.h>
64 * Logging tag for module name
66 #define TAG PCF("UMUTEX")
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
75 * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
77 static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
78 __attribute__ ((weakref("pthread_condattr_setclock")));
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__ */
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;
88 typedef struct _tagMutexInfo_t
90 pthread_mutex_t mutex;
92 uint32_t recursionCount;
95 typedef struct _tagEventInfo_t
98 pthread_condattr_t condattr;
101 typedef struct _tagThreadInfo_t
104 pthread_attr_t threadattr;
105 } oc_thread_internal;
107 static pthread_t oc_get_current_thread_id()
109 pthread_t id = pthread_self();
110 assert(OC_INVALID_THREAD_ID != id);
115 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg)
117 OCThreadResult_t oc_thread_new(oc_thread *t, void *(*start_routine)(void *), void *arg,
118 const char *task_name, int stack_size)
121 OCThreadResult_t res = OC_THREAD_SUCCESS;
122 oc_thread_internal *threadInfo = (oc_thread_internal*)OICMalloc(sizeof(oc_thread_internal));
123 if (NULL != threadInfo)
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);
135 int result = pthread_create(&threadInfo->thread, NULL, start_routine, arg);
139 res = OC_THREAD_CREATE_FAILURE;
142 OIC_LOG_V(ERROR, TAG, "%s: pthread_create failed", __func__);
146 *t = (oc_thread)threadInfo;
151 OIC_LOG_V(ERROR, TAG, "%s Failed to allocate thread!", __func__);
153 res = OC_THREAD_ALLOCATION_FAILURE;
158 OCThreadResult_t oc_thread_free(oc_thread t)
160 OCThreadResult_t res = OC_THREAD_SUCCESS;
161 oc_thread_internal *threadInfo = (oc_thread_internal*) t;
168 OIC_LOG_V(ERROR, TAG, "%s Invalid thread !", __func__);
169 res = OC_THREAD_INVALID;
174 OCThreadResult_t oc_thread_wait(oc_thread t)
176 OCThreadResult_t res = OC_THREAD_SUCCESS;
177 oc_thread_internal *threadInfo = (oc_thread_internal*) t;
178 int joinres = pthread_join(threadInfo->thread, NULL);
181 OIC_LOG_V(ERROR, TAG, "Failed to join thread with error %d", joinres);
182 res = OC_THREAD_WAIT_FAILURE;
188 OCThreadResult_t oc_thread_detach(oc_thread t)
190 OCThreadResult_t res = OC_THREAD_SUCCESS;
192 oc_thread_internal *threadInfo = (oc_thread_internal*) t;
193 int detachres = pthread_detach(threadInfo->thread);
196 OIC_LOG_V(ERROR, TAG, "Failed to detach thread with error %d", detachres);
197 res = OC_THREAD_DETACH_FAILURE;
204 OCThreadResult_t oc_thread_cancel(oc_thread t)
206 OCThreadResult_t res = OC_THREAD_SUCCESS;
207 oc_thread_internal *threadInfo = (oc_thread_internal*) t;
208 int ret = pthread_cancel(threadInfo->thread);
211 OIC_LOG_V(ERROR, TAG, "Failed to cancel thread with error %d", ret);
212 res = OC_THREAD_CANCEL_FAILURE;
219 oc_mutex oc_mutex_new(void)
221 oc_mutex retVal = NULL;
222 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) OICMalloc(sizeof(oc_mutex_internal));
223 if (NULL != mutexInfo)
225 // create the mutex with the attributes set
226 int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
229 retVal = (oc_mutex) mutexInfo;
233 OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
239 OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
245 bool oc_mutex_free(oc_mutex mutex)
248 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
251 int ret = pthread_mutex_destroy(&mutexInfo->mutex);
259 OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
264 OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
270 void oc_mutex_lock(oc_mutex mutex)
272 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
275 int ret = pthread_mutex_lock(&mutexInfo->mutex);
278 OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
284 OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
288 void oc_mutex_unlock(oc_mutex mutex)
290 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
293 #if defined(__TIZENRT__)
294 if (mutexInfo->mutex.pid == 0)
299 int ret = pthread_mutex_unlock(&mutexInfo->mutex);
302 OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
308 OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
312 void oc_mutex_assert_owner(const oc_mutex mutex, bool currentThreadIsOwner)
314 assert(NULL != mutex);
315 const oc_mutex_internal *mutexInfo = (const oc_mutex_internal*) mutex;
317 pthread_t currentThreadID = oc_get_current_thread_id();
318 if (currentThreadIsOwner)
320 assert(pthread_equal(mutexInfo->owner, currentThreadID));
321 assert(mutexInfo->recursionCount != 0);
325 assert(!pthread_equal(mutexInfo->owner, currentThreadID));
329 oc_cond oc_cond_new(void)
331 oc_cond retVal = NULL;
332 oc_cond_internal *eventInfo = (oc_cond_internal*) OICMalloc(sizeof(oc_cond_internal));
333 if (NULL != eventInfo)
335 int ret = pthread_condattr_init(&(eventInfo->condattr));
338 OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
344 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
346 if (camutex_condattr_setclock)
348 ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
351 ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
352 #endif /* __ANDROID__ */
355 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
357 pthread_condattr_destroy(&(eventInfo->condattr));
362 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
363 ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
366 retVal = (oc_cond) eventInfo;
370 OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
371 pthread_condattr_destroy(&(eventInfo->condattr));
377 OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
383 void oc_cond_free(oc_cond cond)
385 oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
386 if (eventInfo != NULL)
388 int ret = pthread_cond_destroy(&(eventInfo->cond));
389 int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
390 if (0 == ret && 0 == ret2)
396 OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
397 __func__, ret, ret2);
402 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
406 void oc_cond_signal(oc_cond cond)
408 oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
409 if (eventInfo != NULL)
411 int ret = pthread_cond_signal(&(eventInfo->cond));
414 OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
419 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
423 void oc_cond_broadcast(oc_cond cond)
425 oc_cond_internal* eventInfo = (oc_cond_internal*) cond;
426 if (eventInfo != NULL)
428 int ret = pthread_cond_broadcast(&(eventInfo->cond));
431 OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
436 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
440 void oc_cond_wait(oc_cond cond, oc_mutex mutex)
442 oc_cond_wait_for(cond, mutex, 0L);
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; \
452 struct timespec oc_get_current_time()
454 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
456 clock_gettime(CLOCK_MONOTONIC, &ts);
460 gettimeofday(&tv, NULL);
462 TIMEVAL_TO_TIMESPEC(&tv, &ts);
467 void oc_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
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;
474 ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
475 ts->tv_sec += secPart + secOfNs;
478 OCWaitResult_t oc_cond_wait_for(oc_cond cond, oc_mutex mutex, uint64_t microseconds)
480 OCWaitResult_t retVal = OC_WAIT_INVAL;
482 oc_cond_internal *eventInfo = (oc_cond_internal*) cond;
483 oc_mutex_internal *mutexInfo = (oc_mutex_internal*) mutex;
485 if (NULL == mutexInfo)
487 OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
488 return OC_WAIT_INVAL;
491 if (NULL == eventInfo)
493 OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
494 return OC_WAIT_INVAL;
497 if (microseconds > 0)
500 struct timespec abstime = { .tv_sec = 0 };
503 if (camutex_cond_timedwait_relative)
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);
512 abstime = oc_get_current_time();
513 oc_add_microseconds_to_timespec(&abstime, microseconds);
515 //Wait for the given time
516 ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
523 retVal = OC_WAIT_SUCCESS;
526 retVal = OC_WAIT_TIMEDOUT;
529 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
530 retVal = OC_WAIT_INVAL;
533 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
534 retVal = OC_WAIT_INVAL;
541 int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
542 retVal = ret == 0 ? OC_WAIT_SUCCESS : OC_WAIT_INVAL;