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"
52 #ifdef HAVE_SYS_TIME_H
55 #ifdef HAVE_WINSOCK2_H
61 #include <oic_malloc.h>
67 * Logging tag for module name
69 #define TAG PCF("UMUTEX")
73 * Android has pthread_condattr_setclock() only in version >= 5.0, older
74 * version do have a function called __pthread_cond_timedwait_relative()
75 * which waits *for* the given timespec, this function is not visible in
76 * android version >= 5.0 anymore. This is the same way as it is handled in
78 * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
80 static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
81 __attribute__ ((weakref("pthread_condattr_setclock")));
83 static int camutex_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t*, const struct timespec*)
84 __attribute__ ((weakref("__pthread_cond_timedwait_relative")));
85 #endif /* __ANDROID__ */
87 static const uint64_t USECS_PER_SEC = 1000000;
88 static const uint64_t NANOSECS_PER_USECS = 1000;
89 static const uint64_t NANOSECS_PER_SEC = 1000000000L;
91 typedef struct _tagMutexInfo_t
94 CRITICAL_SECTION mutex;
96 pthread_mutex_t mutex;
100 typedef struct _tagEventInfo_t
103 CONDITION_VARIABLE cond;
106 pthread_condattr_t condattr;
110 ca_mutex ca_mutex_new(void)
112 ca_mutex retVal = NULL;
113 ca_mutex_internal *mutexInfo = (ca_mutex_internal*) OICMalloc(sizeof(ca_mutex_internal));
114 if (NULL != mutexInfo)
117 InitializeCriticalSection(&mutexInfo->mutex);
118 retVal = (ca_mutex)mutexInfo;
120 // create the mutex with the attributes set
121 int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
124 retVal = (ca_mutex) mutexInfo;
128 OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
135 OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
141 bool ca_mutex_free(ca_mutex mutex)
145 ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
149 DeleteCriticalSection(&mutexInfo->mutex);
153 int ret = pthread_mutex_destroy(&mutexInfo->mutex);
161 OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
167 OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
173 void ca_mutex_lock(ca_mutex mutex)
175 ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
179 EnterCriticalSection(&mutexInfo->mutex);
181 int ret = pthread_mutex_lock(&mutexInfo->mutex);
184 OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
191 OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
196 void ca_mutex_unlock(ca_mutex mutex)
198 ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
202 LeaveCriticalSection(&mutexInfo->mutex);
204 int ret = pthread_mutex_unlock(&mutexInfo->mutex);
207 OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
215 OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
220 ca_cond ca_cond_new(void)
222 ca_cond retVal = NULL;
223 ca_cond_internal *eventInfo = (ca_cond_internal*) OICMalloc(sizeof(ca_cond_internal));
224 if (NULL != eventInfo)
227 InitializeConditionVariable(&eventInfo->cond);
228 retVal = (ca_cond) eventInfo;
230 int ret = pthread_condattr_init(&(eventInfo->condattr));
233 OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
239 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
241 if (camutex_condattr_setclock)
243 ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
246 ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
247 #endif /* __ANDROID__ */
250 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
252 pthread_condattr_destroy(&(eventInfo->condattr));
257 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
258 ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
261 retVal = (ca_cond) eventInfo;
265 OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
266 pthread_condattr_destroy(&(eventInfo->condattr));
273 OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
279 void ca_cond_free(ca_cond cond)
281 ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
282 if (eventInfo != NULL)
287 int ret = pthread_cond_destroy(&(eventInfo->cond));
288 int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
289 if (0 == ret && 0 == ret2)
295 OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
296 __func__, ret, ret2);
302 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
306 void ca_cond_signal(ca_cond cond)
308 ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
309 if (eventInfo != NULL)
312 WakeConditionVariable(&eventInfo->cond);
314 int ret = pthread_cond_signal(&(eventInfo->cond));
317 OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
323 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
327 void ca_cond_broadcast(ca_cond cond)
329 ca_cond_internal* eventInfo = (ca_cond_internal*) cond;
330 if (eventInfo != NULL)
333 WakeAllConditionVariable(&eventInfo->cond);
335 int ret = pthread_cond_broadcast(&(eventInfo->cond));
338 OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
344 OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
348 void ca_cond_wait(ca_cond cond, ca_mutex mutex)
350 ca_cond_wait_for(cond, mutex, 0L);
353 #ifndef TIMEVAL_TO_TIMESPEC
354 #define TIMEVAL_TO_TIMESPEC(tv, ts) { \
355 (ts)->tv_sec = (tv)->tv_sec; \
356 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
361 struct timespec ca_get_current_time()
363 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
365 clock_gettime(CLOCK_MONOTONIC, &ts);
369 gettimeofday(&tv, NULL);
371 TIMEVAL_TO_TIMESPEC(&tv, &ts);
376 void ca_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
378 time_t secPart = microseconds/USECS_PER_SEC;
379 uint64_t nsecPart = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
380 uint64_t totalNs = ts->tv_nsec + nsecPart;
381 time_t secOfNs = totalNs/NANOSECS_PER_SEC;
383 ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
384 ts->tv_sec += secPart + secOfNs;
388 CAWaitResult_t ca_cond_wait_for(ca_cond cond, ca_mutex mutex, uint64_t microseconds)
390 CAWaitResult_t retVal = CA_WAIT_INVAL;
392 ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
393 ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
395 if (NULL == mutexInfo)
397 OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
398 return CA_WAIT_INVAL;
401 if (NULL == eventInfo)
403 OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
404 return CA_WAIT_INVAL;
407 if (microseconds > 0)
410 // Wait for the given time
411 DWORD milli = (DWORD)(microseconds / 1000);
412 if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, milli))
414 if (GetLastError() == ERROR_TIMEOUT)
416 retVal = CA_WAIT_TIMEDOUT;
420 OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() with Timeout failed %i", GetLastError());
421 retVal = CA_WAIT_INVAL;
425 retVal = CA_WAIT_SUCCESS;
429 struct timespec abstime = { .tv_sec = 0 };
432 if (camutex_cond_timedwait_relative)
434 abstime.tv_sec = microseconds / USECS_PER_SEC;
435 abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
436 //Wait for the given time
437 ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
441 abstime = ca_get_current_time();
442 ca_add_microseconds_to_timespec(&abstime, microseconds);
444 //Wait for the given time
445 ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
452 retVal = CA_WAIT_SUCCESS;
455 retVal = CA_WAIT_TIMEDOUT;
458 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
459 retVal = CA_WAIT_INVAL;
462 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
463 retVal = CA_WAIT_INVAL;
472 if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, INFINITE))
474 OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() w/o Timeout failed %i", GetLastError());
475 retVal = CA_WAIT_INVAL;
478 retVal = CA_WAIT_SUCCESS;
482 int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
483 retVal = ret == 0 ? CA_WAIT_SUCCESS : CA_WAIT_INVAL;