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