iotivity 0.9.0
[platform/upstream/iotivity.git] / service / protocol-plugin / lib / cpluff / libcpluff / thread_posix.c
1 /*-------------------------------------------------------------------------
2  * C-Pluff, a plug-in framework for C
3  * Copyright 2007 Johannes Lehtinen
4  * 
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *-----------------------------------------------------------------------*/
23
24 /** @file
25  * Posix implementation for generic mutex functions
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <pthread.h>
33 #include "cpluff.h"
34 #include "defines.h"
35 #include "util.h"
36 #include "internal.h"
37 #include "thread.h"
38
39
40 /* ------------------------------------------------------------------------
41  * Data types
42  * ----------------------------------------------------------------------*/
43
44 // A generic recursive mutex implementation 
45 struct cpi_mutex_t {
46
47         /// The current lock count 
48         int lock_count;
49         
50         /// The underlying operating system mutex 
51         pthread_mutex_t os_mutex;
52         
53         /// The condition variable for signaling availability 
54         pthread_cond_t os_cond_lock;
55         
56         /// The condition variable for broadcasting a wake request
57         pthread_cond_t os_cond_wake;
58
59         /// The locking thread if currently locked 
60         pthread_t os_thread;
61         
62 };
63
64
65 /* ------------------------------------------------------------------------
66  * Function definitions
67  * ----------------------------------------------------------------------*/
68
69 CP_HIDDEN cpi_mutex_t * cpi_create_mutex(void) {
70         cpi_mutex_t *mutex;
71         
72         if ((mutex = malloc(sizeof(cpi_mutex_t))) == NULL) {
73                 return NULL;
74         }
75         memset(mutex, 0, sizeof(cpi_mutex_t));
76         if (pthread_mutex_init(&(mutex->os_mutex), NULL)) {
77                 return NULL;
78         } else if (pthread_cond_init(&(mutex->os_cond_lock), NULL)) {
79                 int ec;
80                 
81                 ec = pthread_mutex_destroy(&(mutex->os_mutex));
82                 assert(!ec);
83                 return NULL;
84         } else if (pthread_cond_init(&(mutex->os_cond_wake), NULL)) {
85                 int ec;
86                 
87                 ec = pthread_mutex_destroy(&(mutex->os_mutex));
88                 assert(!ec);
89                 ec = pthread_cond_destroy(&(mutex->os_cond_wake));
90                 assert(!ec);
91                 return NULL;
92         }
93         return mutex;
94 }
95
96 CP_HIDDEN void cpi_destroy_mutex(cpi_mutex_t *mutex) {
97         int ec;
98         
99         assert(mutex != NULL);
100         assert(mutex->lock_count == 0);
101         ec = pthread_mutex_destroy(&(mutex->os_mutex));
102         assert(!ec);
103         ec = pthread_cond_destroy(&(mutex->os_cond_lock));
104         assert(!ec);
105         ec = pthread_cond_destroy(&(mutex->os_cond_wake));
106         assert(!ec);
107         free(mutex);
108 }
109
110 static void lock_mutex(pthread_mutex_t *mutex) {
111         int ec;
112         
113         if ((ec = pthread_mutex_lock(mutex))) {
114                 cpi_fatalf(_("Could not lock a mutex due to error %d."), ec);
115         }
116 }
117
118 static void unlock_mutex(pthread_mutex_t *mutex) {
119         int ec;
120         
121         if ((ec = pthread_mutex_unlock(mutex))) {
122                 cpi_fatalf(_("Could not unlock a mutex due to error %d."), ec);
123         }
124 }
125
126 static void lock_mutex_holding(cpi_mutex_t *mutex) {
127         pthread_t self = pthread_self();
128         
129         while (mutex->lock_count != 0
130                         && !pthread_equal(self, mutex->os_thread)) {
131                 int ec;
132                 
133                 if ((ec = pthread_cond_wait(&(mutex->os_cond_lock), &(mutex->os_mutex)))) {
134                         cpi_fatalf(_("Could not wait for a condition variable due to error %d."), ec);
135                 }
136         }
137         mutex->os_thread = self;
138         mutex->lock_count++;
139 }
140
141 CP_HIDDEN void cpi_lock_mutex(cpi_mutex_t *mutex) {
142         assert(mutex != NULL);
143         lock_mutex(&(mutex->os_mutex));
144         lock_mutex_holding(mutex);
145         unlock_mutex(&(mutex->os_mutex));
146 }
147
148 CP_HIDDEN void cpi_unlock_mutex(cpi_mutex_t *mutex) {
149         pthread_t self = pthread_self();
150         
151         assert(mutex != NULL);
152         lock_mutex(&(mutex->os_mutex));
153         if (mutex->lock_count > 0
154                 && pthread_equal(self, mutex->os_thread)) {
155                 if (--mutex->lock_count == 0) {
156                         int ec;
157                         
158                         if ((ec = pthread_cond_signal(&(mutex->os_cond_lock)))) {
159                                 cpi_fatalf(_("Could not signal a condition variable due to error %d."), ec);
160                         }
161                 }
162         } else {
163                 cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at unlocking a mutex."));
164         }
165         unlock_mutex(&(mutex->os_mutex));
166 }
167
168 CP_HIDDEN void cpi_wait_mutex(cpi_mutex_t *mutex) {
169         pthread_t self = pthread_self();
170         
171         assert(mutex != NULL);
172         lock_mutex(&(mutex->os_mutex));
173         if (mutex->lock_count > 0
174                 && pthread_equal(self, mutex->os_thread)) {
175                 int ec;
176                 int lc = mutex->lock_count;
177                 
178                 // Release mutex
179                 mutex->lock_count = 0;
180                 if ((ec = pthread_cond_signal(&(mutex->os_cond_lock)))) {
181                         cpi_fatalf(_("Could not signal a condition variable due to error %d."), ec);
182                 }
183                 
184                 // Wait for signal
185                 if ((ec = pthread_cond_wait(&(mutex->os_cond_wake), &(mutex->os_mutex)))) {
186                         cpi_fatalf(_("Could not wait for a condition variable due to error %d."), ec);
187                 }
188                 
189                 // Re-acquire mutex and restore lock count for this thread
190                 lock_mutex_holding(mutex);
191                 mutex->lock_count = lc;
192                 
193         } else {
194                 cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at waiting on a mutex."));
195         }
196         unlock_mutex(&(mutex->os_mutex));
197 }
198
199 CP_HIDDEN void cpi_signal_mutex(cpi_mutex_t *mutex) {
200         pthread_t self = pthread_self();
201         
202         assert(mutex != NULL);
203         lock_mutex(&(mutex->os_mutex));
204         if (mutex->lock_count > 0
205                 && pthread_equal(self, mutex->os_thread)) {
206                 int ec;
207                 
208                 // Signal the mutex
209                 if ((ec = pthread_cond_broadcast(&(mutex->os_cond_wake)))) {
210                         cpi_fatalf(_("Could not broadcast a condition variable due to error %d."), ec);
211                 }
212                 
213         } else {
214                 cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at signaling a mutex."));
215         }
216         unlock_mutex(&(mutex->os_mutex));
217 }
218
219 #if !defined(NDEBUG)
220 CP_HIDDEN int cpi_is_mutex_locked(cpi_mutex_t *mutex) {
221         int locked;
222         
223         lock_mutex(&(mutex->os_mutex));
224         locked = (mutex->lock_count != 0);
225         unlock_mutex(&(mutex->os_mutex));
226         return locked;
227 }
228 #endif