Imported Upstream version 1.0.0
[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 <string.h>
40 #include <pthread.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <time.h>
44 #include <sys/time.h>
45 #include <assert.h>
46 #include <oic_malloc.h>
47
48 #include "camutex.h"
49 #include "logger.h"
50
51 /**
52  * TAG
53  * Logging tag for module name
54  */
55 #define TAG PCF("UMUTEX")
56
57 #ifdef __ANDROID__
58 /**
59  * Android has pthread_condattr_setclock() only in version >= 5.0, older
60  * version do have a function called __pthread_cond_timedwait_relative()
61  * which waits *for* the given timespec, this function is not visible in
62  * android version >= 5.0 anymore. This is the same way as it is handled in
63  * QT 5.5.0 in
64  * http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/thread/qwaitcondition_unix.cpp?h=v5.5.0#n54
65  */
66 static int camutex_condattr_setclock(pthread_condattr_t *, clockid_t)
67         __attribute__ ((weakref("pthread_condattr_setclock")));
68
69 static int camutex_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t*, const struct timespec*)
70         __attribute__ ((weakref("__pthread_cond_timedwait_relative")));
71 #endif /* __ANDROID__ */
72
73 static const uint64_t USECS_PER_SEC         = 1000000;
74 static const uint64_t NANOSECS_PER_USECS    = 1000;
75 static const uint64_t NANOSECS_PER_SEC      = 1000000000L;
76
77 typedef struct _tagMutexInfo_t
78 {
79     pthread_mutex_t mutex;
80 } ca_mutex_internal;
81
82 typedef struct _tagEventInfo_t
83 {
84     pthread_cond_t cond;
85     pthread_condattr_t condattr;
86 } ca_cond_internal;
87
88 ca_mutex ca_mutex_new(void)
89 {
90     ca_mutex retVal = NULL;
91     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) OICMalloc(sizeof(ca_mutex_internal));
92     if (NULL != mutexInfo)
93     {
94         // create the mutex with the attributes set
95         int ret=pthread_mutex_init(&(mutexInfo->mutex), PTHREAD_MUTEX_DEFAULT);
96         if (0 == ret)
97         {
98             retVal = (ca_mutex) mutexInfo;
99         }
100         else
101         {
102             OIC_LOG_V(ERROR, TAG, "%s Failed to initialize mutex !", __func__);
103             OICFree(mutexInfo);
104         }
105     }
106
107     return retVal;
108 }
109
110 bool ca_mutex_free(ca_mutex mutex)
111 {
112     bool bRet=false;
113
114     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
115     if (mutexInfo)
116     {
117         int ret = pthread_mutex_destroy(&mutexInfo->mutex);
118         if (0 == ret)
119         {
120             OICFree(mutexInfo);
121             bRet=true;
122         }
123         else
124         {
125             OIC_LOG_V(ERROR, TAG, "%s Failed to free mutex !", __func__);
126         }
127     }
128     else
129     {
130         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
131     }
132
133     return bRet;
134 }
135
136 void ca_mutex_lock(ca_mutex mutex)
137 {
138     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
139     if (mutexInfo)
140     {
141         int ret = pthread_mutex_lock(&mutexInfo->mutex);
142         assert(0 == ret);
143         if(ret != 0)
144         {
145             OIC_LOG_V(ERROR, TAG, "Pthread Mutex lock failed: %d", ret);
146             exit(ret);
147         }
148     }
149     else
150     {
151         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
152         return;
153     }
154 }
155
156 bool ca_mutex_trylock(ca_mutex mutex)
157 {
158     if (NULL == mutex)
159     {
160         OIC_LOG_V(ERROR, TAG, "%s Invalid mutex !", __func__);
161         return false;
162     }
163
164     bool bRet = false;
165
166     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
167
168     int result = pthread_mutex_trylock(&mutexInfo->mutex);
169
170     switch (result)
171     {
172         case 0:
173             // Success
174             bRet = true;
175             break;
176         case EINVAL:
177             OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
178             break;
179         case EBUSY:
180         default:
181             break;
182     }
183
184     return bRet;
185 }
186
187 void ca_mutex_unlock(ca_mutex mutex)
188 {
189     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
190     if (mutexInfo)
191     {
192         int ret = pthread_mutex_unlock(&mutexInfo->mutex);
193
194         assert ( 0 == ret);
195         if(ret != 0)
196         {
197             OIC_LOG_V(ERROR, TAG, "Pthread Mutex unlock failed: %d", ret);
198             exit(ret);
199         }
200         (void)ret;
201     }
202     else
203     {
204           OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex !", __func__);
205           return;
206     }
207 }
208
209 ca_cond ca_cond_new(void)
210 {
211     ca_cond retVal = NULL;
212     ca_cond_internal *eventInfo = (ca_cond_internal*) OICMalloc(sizeof(ca_cond_internal));
213     if (NULL != eventInfo)
214     {
215         int ret = pthread_condattr_init(&(eventInfo->condattr));
216         if(0 != ret)
217         {
218             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable attribute %d!",
219                     __func__, ret);
220             OICFree(eventInfo);
221             return retVal;
222         }
223
224 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
225 #ifdef __ANDROID__
226         if (camutex_condattr_setclock) {
227             ret = camutex_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
228 #else
229         {
230             ret = pthread_condattr_setclock(&(eventInfo->condattr), CLOCK_MONOTONIC);
231 #endif /*  __ANDROID__ */
232             if(0 != ret)
233             {
234                 OIC_LOG_V(ERROR, TAG, "%s: Failed to set condition variable clock %d!",
235                         __func__, ret);
236                 pthread_condattr_destroy(&(eventInfo->condattr));
237                 OICFree(eventInfo);
238                 return retVal;
239             }
240         }
241 #endif /* defined(__ANDROID__) || _POSIX_TIMERS > 0 */
242         ret = pthread_cond_init(&(eventInfo->cond), &(eventInfo->condattr));
243         if (0 == ret)
244         {
245             retVal = (ca_cond) eventInfo;
246         }
247         else
248         {
249             OIC_LOG_V(ERROR, TAG, "%s: Failed to initialize condition variable %d!", __func__, ret);
250             pthread_condattr_destroy(&(eventInfo->condattr));
251             OICFree(eventInfo);
252         }
253     }
254
255     return retVal;
256 }
257
258 void ca_cond_free(ca_cond cond)
259 {
260     ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
261     if (eventInfo != NULL)
262     {
263         int ret = pthread_cond_destroy(&(eventInfo->cond));
264         int ret2 = pthread_condattr_destroy(&(eventInfo->condattr));
265         if (0 == ret && 0 == ret2)
266         {
267             OICFree(cond);
268         }
269         else
270         {
271             OIC_LOG_V(ERROR, TAG, "%s: Failed to destroy condition variable %d, %d",
272                     __func__, ret, ret2);
273         }
274     }
275     else
276     {
277         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
278     }
279 }
280
281 void ca_cond_signal(ca_cond cond)
282 {
283     ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
284     if (eventInfo != NULL)
285     {
286         int ret = pthread_cond_signal(&(eventInfo->cond));
287         if (0 != ret)
288         {
289             OIC_LOG_V(ERROR, TAG, "%s: Failed to signal condition variable", __func__);
290         }
291     }
292     else
293     {
294         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
295     }
296 }
297
298 void ca_cond_broadcast(ca_cond cond)
299 {
300     ca_cond_internal* eventInfo = (ca_cond_internal*) cond;
301     if (eventInfo != NULL)
302     {
303         int ret = pthread_cond_broadcast(&(eventInfo->cond));
304         if (0 != ret)
305         {
306             OIC_LOG_V(ERROR, TAG, "%s: failed to signal condition variable", __func__);
307         }
308     }
309     else
310     {
311         OIC_LOG_V(ERROR, TAG, "%s: Invalid parameter", __func__);
312     }
313 }
314
315 void ca_cond_wait(ca_cond cond, ca_mutex mutex)
316 {
317     ca_cond_wait_for(cond, mutex, 0L);
318 }
319
320 struct timespec ca_get_current_time()
321 {
322 #if defined(__ANDROID__) || _POSIX_TIMERS > 0
323     struct timespec ts;
324     clock_gettime(CLOCK_MONOTONIC, &ts);
325     return ts;
326 #else
327     struct timeval tv;
328     gettimeofday(&tv, NULL);
329     struct timespec ts;
330     TIMEVAL_TO_TIMESPEC(&tv, &ts);
331     return ts;
332 #endif
333 }
334
335 void ca_add_microseconds_to_timespec(struct timespec* ts, uint64_t microseconds)
336 {
337     time_t secPart = microseconds/USECS_PER_SEC;
338     uint64_t nsecPart = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
339     uint64_t totalNs = ts->tv_nsec + nsecPart;
340     time_t secOfNs = totalNs/NANOSECS_PER_SEC;
341
342     ts->tv_nsec = (totalNs)% NANOSECS_PER_SEC;
343     ts->tv_sec += secPart + secOfNs;
344 }
345
346 CAWaitResult_t ca_cond_wait_for(ca_cond cond, ca_mutex mutex, uint64_t microseconds)
347 {
348     CAWaitResult_t retVal = CA_WAIT_INVAL;
349
350     ca_cond_internal *eventInfo = (ca_cond_internal*) cond;
351     ca_mutex_internal *mutexInfo = (ca_mutex_internal*) mutex;
352
353     if (NULL == mutexInfo)
354     {
355         OIC_LOG_V(ERROR, TAG, "%s: Invalid mutex", __func__);
356         return CA_WAIT_INVAL;
357     }
358
359     if (NULL == eventInfo)
360     {
361         OIC_LOG_V(ERROR, TAG, "%s: Invalid condition", __func__);
362         return CA_WAIT_INVAL;
363     }
364
365     if (microseconds > 0)
366     {
367         int ret;
368         struct timespec abstime;
369
370 #ifdef __ANDROID__
371         if (camutex_cond_timedwait_relative) {
372             abstime.tv_sec = microseconds / USECS_PER_SEC;
373             abstime.tv_nsec = (microseconds % USECS_PER_SEC) * NANOSECS_PER_USECS;
374             //Wait for the given time
375             ret = camutex_cond_timedwait_relative(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
376         } else
377 #endif
378         {
379              abstime = ca_get_current_time();
380             ca_add_microseconds_to_timespec(&abstime, microseconds);
381
382             //Wait for the given time
383             ret = pthread_cond_timedwait(&(eventInfo->cond), &(mutexInfo->mutex), &abstime);
384         }
385
386         switch (ret)
387         {
388             case 0:
389                 // Success
390                 retVal = CA_WAIT_SUCCESS;
391                 break;
392             case ETIMEDOUT:
393                 retVal = CA_WAIT_TIMEDOUT;
394                 break;
395             case EINVAL:
396                 OIC_LOG_V(ERROR, TAG, "%s: condition, mutex, or abstime is Invalid", __func__);
397                 retVal = CA_WAIT_INVAL;
398                 break;
399             default:
400                 OIC_LOG_V(ERROR, TAG, "%s: pthread_cond_timedwait returned %d", __func__, retVal);
401                 retVal = CA_WAIT_INVAL;
402                 break;
403         }
404     }
405     else
406     {
407         // Wait forever
408         int ret = pthread_cond_wait(&eventInfo->cond, &mutexInfo->mutex);
409         retVal = ret == 0 ? CA_WAIT_SUCCESS : CA_WAIT_INVAL;
410     }
411
412     return retVal;
413 }
414