Remove unused pkg dependancy
[platform/upstream/iotivity.git] / resource / csdk / connectivity / common / src / camutex_pthreads.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 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #ifdef HAVE_PTHREAD_H
44 #include <pthread.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #ifdef HAVE_TIME_H
50 #include <time.h>
51 #endif
52 #ifdef HAVE_SYS_TIME_H
53 #include <sys/time.h>
54 #endif
55 #ifdef HAVE_WINSOCK2_H
56 #include <winsock2.h>
57 #endif
58 #include <stdio.h>
59 #include <errno.h>
60 #include <assert.h>
61 #include <oic_malloc.h>
62 #include "camutex.h"
63 #include "logger.h"
64
65 /**
66  * TAG
67  * Logging tag for module name
68  */
69 #define TAG PCF("UMUTEX")
70
71 #ifdef __ANDROID__
72 /**
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
77  * QT 5.5.0 in
78  * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
79  */
80 static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
81         __attribute__ ((weakref("pthread_condattr_setclock")));
82
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__ */
86
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;
90
91 typedef struct _tagMutexInfo_t
92 {
93 #if defined(_WIN32)
94     CRITICAL_SECTION mutex;
95 #else
96     pthread_mutex_t mutex;
97 #endif
98 } ca_mutex_internal;
99
100 typedef struct _tagEventInfo_t
101 {
102 #if defined(_WIN32)
103     CONDITION_VARIABLE cond;
104 #else
105     pthread_cond_t cond;
106     pthread_condattr_t condattr;
107 #endif
108 } ca_cond_internal;
109
110 ca_mutex ca_mutex_new(void)
111 {
112     ca_mutex retVal = NULL;
113     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) OICMalloc(sizeof(ca_mutex_internal));
114     if (NULL != mutexInfo)
115     {
116 #if defined(_WIN32)
117         InitializeCriticalSection(&mutexInfo->mutex);
118         retVal = (ca_mutex)mutexInfo;
119 #else
120         // create the mutex with the attributes set
121         int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
122         if (0 == ret)
123         {
124             retVal = (ca_mutex) mutexInfo;
125         }
126         else
127         {
128             OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
129             OICFree(mutexInfo);
130         }
131 #endif
132     }
133     else
134     {
135         OIC_LOG_V(ERROR, TAG, "%s Failed to allocate mutex!", __func__);
136     }
137
138     return retVal;
139 }
140
141 bool ca_mutex_free(ca_mutex mutex)
142 {
143     bool bRet=false;
144
145     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
146     if (mutexInfo)
147     {
148 #if defined(_WIN32)
149         DeleteCriticalSection(&mutexInfo->mutex);
150         OICFree(mutexInfo);
151         bRet=true;
152 #else
153         int ret = pthread_mutex_destroy(&mutexInfo->mutex);
154         if (0 == ret)
155         {
156             OICFree(mutexInfo);
157             bRet=true;
158         }
159         else
160         {
161             OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
162         }
163 #endif
164     }
165     else
166     {
167         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
168     }
169
170     return bRet;
171 }
172
173 void ca_mutex_lock(ca_mutex mutex)
174 {
175     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
176     if (mutexInfo)
177     {
178 #if defined(_WIN32)
179         EnterCriticalSection(&mutexInfo->mutex);
180 #else
181         int ret = pthread_mutex_lock(&mutexInfo->mutex);
182         if(ret != 0)
183         {
184             OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
185             exit(ret);
186         }
187 #endif
188     }
189     else
190     {
191         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
192         return;
193     }
194 }
195
196 void ca_mutex_unlock(ca_mutex mutex)
197 {
198     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
199     if (mutexInfo)
200     {
201 #if defined(_WIN32)
202         LeaveCriticalSection(&mutexInfo->mutex);
203 #else
204         int ret = pthread_mutex_unlock(&mutexInfo->mutex);
205         if(ret != 0)
206         {
207             OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
208             exit(ret);
209         }
210         (void)ret;
211 #endif
212     }
213     else
214     {
215         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
216         return;
217     }
218 }
219
220 ca_cond ca_cond_new(void)
221 {
222     ca_cond retVal = NULL;
223     ca_cond_internal *eventInfo = (ca_cond_internal*) OICMalloc(sizeof(ca_cond_internal));
224     if (NULL != eventInfo)
225     {
226 #if defined(_WIN32)
227         InitializeConditionVariable(&eventInfo->cond);
228         retVal = (ca_cond) eventInfo;
229 #else
230         int ret = pthread_condattr_init(&(eventInfo->condattr));
231         if(0 != ret)
232         {
233             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
234                     __func__, ret);
235             OICFree(eventInfo);
236             return retVal;
237         }
238
239 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
240 #ifdef __ANDROID__
241         if (camutex_condattr_setclock)
242         {
243             ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
244 #else
245         {
246             ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
247 #endif /*  __ANDROID__ */
248             if(0 != ret)
249             {
250                 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
251                         __func__, ret);
252                 pthread_condattr_destroy(&(eventInfo->condattr));
253                 OICFree(eventInfo);
254                 return retVal;
255             }
256         }
257 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
258         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
259         if (0 == ret)
260         {
261             retVal = (ca_cond) eventInfo;
262         }
263         else
264         {
265             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
266             pthread_condattr_destroy(&(eventInfo->condattr));
267             OICFree(eventInfo);
268         }
269 #endif
270     }
271     else
272     {
273         OIC_LOG_V(ERROR, TAG, "%s: Failed to allocate condition variable!", __func__);
274     }
275
276     return retVal;
277 }
278
279 void ca_cond_free(ca_cond cond)
280 {
281     ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
282     if (eventInfo != NULL)
283     {
284 #if defined(_WIN32)
285         OICFree(cond);
286 #else
287         int ret = pthread_cond_destroy(&(eventInfo->cond));
288         int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
289         if (0 == ret && 0 == ret2)
290         {
291             OICFree(cond);
292         }
293         else
294         {
295             OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
296                     __func__, ret, ret2);
297         }
298 #endif
299     }
300     else
301     {
302         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
303     }
304 }
305
306 void ca_cond_signal(ca_cond cond)
307 {
308     ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
309     if (eventInfo != NULL)
310     {
311 #if defined(_WIN32)
312         WakeConditionVariable(&eventInfo->cond);
313 #else
314         int ret = pthread_cond_signal(&(eventInfo->cond));
315         if (0 != ret)
316         {
317             OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
318         }
319 #endif
320     }
321     else
322     {
323         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
324     }
325 }
326
327 void ca_cond_broadcast(ca_cond cond)
328 {
329     ca_cond_internal* eventInfo = (ca_cond_internal*) cond;
330     if (eventInfo != NULL)
331     {
332 #if defined(_WIN32)
333         WakeAllConditionVariable(&eventInfo->cond);
334 #else
335         int ret = pthread_cond_broadcast(&(eventInfo->cond));
336         if (0 != ret)
337         {
338             OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
339         }
340 #endif
341     }
342     else
343     {
344         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
345     }
346 }
347
348 void ca_cond_wait(ca_cond cond, ca_mutex mutex)
349 {
350     ca_cond_wait_for(cond, mutex, 0L);
351 }
352
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;           \
357 }
358 #endif
359
360 #if !defined(_WIN32)
361 struct timespec ca_get_current_time()
362 {
363 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
364     struct timespec ts;
365     clock_gettime(CLOCK_MONOTONIC, &ts);
366     return ts;
367 #else
368     struct timeval tv;
369     gettimeofday(&tv, NULL);
370     struct timespec ts;
371     TIMEVAL_TO_TIMESPEC(&tv, &ts);
372     return ts;
373 #endif
374 }
375
376 void ca_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
377 {
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;
382
383     ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
384     ts->tv_sec += secPart + secOfNs;
385 }
386 #endif
387
388 CAWaitResult_t ca_cond_wait_for(ca_cond cond, ca_mutex mutex, uint64_t microseconds)
389 {
390     CAWaitResult_t retVal = CA_WAIT_INVAL;
391
392     ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
393     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
394
395     if (NULL == mutexInfo)
396     {
397         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
398         return CA_WAIT_INVAL;
399     }
400
401     if (NULL == eventInfo)
402     {
403         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
404         return CA_WAIT_INVAL;
405     }
406
407     if (microseconds > 0)
408     {
409 #if defined(_WIN32)
410         // Wait for the given time
411         DWORD milli = (DWORD)(microseconds / 1000);
412         if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, milli))
413         {
414             if (GetLastError() == ERROR_TIMEOUT)
415             {
416                 retVal = CA_WAIT_TIMEDOUT;
417             }
418             else
419             {
420                 OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() with Timeout failed %i", GetLastError());
421                 retVal = CA_WAIT_INVAL;
422             }
423         }else
424         {
425             retVal = CA_WAIT_SUCCESS;
426         }
427 #else
428         int ret = 0;
429         struct timespec abstime = { .tv_sec = 0 };
430
431 #ifdef __ANDROID__
432         if (camutex_cond_timedwait_relative)
433         {
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);
438         } else
439 #endif
440         {
441              abstime = ca_get_current_time();
442             ca_add_microseconds_to_timespec(&abstime, microseconds);
443
444             //Wait for the given time
445             ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
446         }
447
448         switch (ret)
449         {
450             case 0:
451                 // Success
452                 retVal = CA_WAIT_SUCCESS;
453                 break;
454             case ETIMEDOUT:
455                 retVal = CA_WAIT_TIMEDOUT;
456                 break;
457             case EINVAL:
458                 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
459                 retVal = CA_WAIT_INVAL;
460                 break;
461             default:
462                 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
463                 retVal = CA_WAIT_INVAL;
464                 break;
465         }
466 #endif
467     }
468     else
469     {
470 #if defined(_WIN32)
471         // Wait forever
472         if (!SleepConditionVariableCS(&eventInfo->cond, &mutexInfo->mutex, INFINITE))
473         {
474             OIC_LOG_V(ERROR, TAG, "SleepConditionVariableCS() w/o Timeout failed %i", GetLastError());
475             retVal = CA_WAIT_INVAL;
476         }else
477         {
478             retVal = CA_WAIT_SUCCESS;
479         }
480 #else
481         // Wait forever
482         int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
483         retVal = ret == 0 ? CA_WAIT_SUCCESS : CA_WAIT_INVAL;
484 #endif
485     }
486     return retVal;
487 }
488