1 /*-------------------------------------------------------------------------
2 * C-Pluff, a plug-in framework for C
3 * Copyright 2007 Johannes Lehtinen
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:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
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 *-----------------------------------------------------------------------*/
25 * Posix implementation for generic mutex functions
40 /* ------------------------------------------------------------------------
42 * ----------------------------------------------------------------------*/
44 // A generic recursive mutex implementation
47 /// The current lock count
50 /// The underlying operating system mutex
51 pthread_mutex_t os_mutex;
53 /// The condition variable for signaling availability
54 pthread_cond_t os_cond_lock;
56 /// The condition variable for broadcasting a wake request
57 pthread_cond_t os_cond_wake;
59 /// The locking thread if currently locked
65 /* ------------------------------------------------------------------------
66 * Function definitions
67 * ----------------------------------------------------------------------*/
69 CP_HIDDEN cpi_mutex_t * cpi_create_mutex(void) {
72 if ((mutex = malloc(sizeof(cpi_mutex_t))) == NULL) {
75 memset(mutex, 0, sizeof(cpi_mutex_t));
76 if (pthread_mutex_init(&(mutex->os_mutex), NULL)) {
78 } else if (pthread_cond_init(&(mutex->os_cond_lock), NULL)) {
81 ec = pthread_mutex_destroy(&(mutex->os_mutex));
84 } else if (pthread_cond_init(&(mutex->os_cond_wake), NULL)) {
87 ec = pthread_mutex_destroy(&(mutex->os_mutex));
89 ec = pthread_cond_destroy(&(mutex->os_cond_wake));
96 CP_HIDDEN void cpi_destroy_mutex(cpi_mutex_t *mutex) {
99 assert(mutex != NULL);
100 assert(mutex->lock_count == 0);
101 ec = pthread_mutex_destroy(&(mutex->os_mutex));
103 ec = pthread_cond_destroy(&(mutex->os_cond_lock));
105 ec = pthread_cond_destroy(&(mutex->os_cond_wake));
110 static void lock_mutex(pthread_mutex_t *mutex) {
113 if ((ec = pthread_mutex_lock(mutex))) {
114 cpi_fatalf(_("Could not lock a mutex due to error %d."), ec);
118 static void unlock_mutex(pthread_mutex_t *mutex) {
121 if ((ec = pthread_mutex_unlock(mutex))) {
122 cpi_fatalf(_("Could not unlock a mutex due to error %d."), ec);
126 static void lock_mutex_holding(cpi_mutex_t *mutex) {
127 pthread_t self = pthread_self();
129 while (mutex->lock_count != 0
130 && !pthread_equal(self, mutex->os_thread)) {
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);
137 mutex->os_thread = self;
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));
148 CP_HIDDEN void cpi_unlock_mutex(cpi_mutex_t *mutex) {
149 pthread_t self = pthread_self();
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) {
158 if ((ec = pthread_cond_signal(&(mutex->os_cond_lock)))) {
159 cpi_fatalf(_("Could not signal a condition variable due to error %d."), ec);
163 cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at unlocking a mutex."));
165 unlock_mutex(&(mutex->os_mutex));
168 CP_HIDDEN void cpi_wait_mutex(cpi_mutex_t *mutex) {
169 pthread_t self = pthread_self();
171 assert(mutex != NULL);
172 lock_mutex(&(mutex->os_mutex));
173 if (mutex->lock_count > 0
174 && pthread_equal(self, mutex->os_thread)) {
176 int lc = mutex->lock_count;
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);
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);
189 // Re-acquire mutex and restore lock count for this thread
190 lock_mutex_holding(mutex);
191 mutex->lock_count = lc;
194 cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at waiting on a mutex."));
196 unlock_mutex(&(mutex->os_mutex));
199 CP_HIDDEN void cpi_signal_mutex(cpi_mutex_t *mutex) {
200 pthread_t self = pthread_self();
202 assert(mutex != NULL);
203 lock_mutex(&(mutex->os_mutex));
204 if (mutex->lock_count > 0
205 && pthread_equal(self, mutex->os_thread)) {
209 if ((ec = pthread_cond_broadcast(&(mutex->os_cond_wake)))) {
210 cpi_fatalf(_("Could not broadcast a condition variable due to error %d."), ec);
214 cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at signaling a mutex."));
216 unlock_mutex(&(mutex->os_mutex));
220 CP_HIDDEN int cpi_is_mutex_locked(cpi_mutex_t *mutex) {
223 lock_mutex(&(mutex->os_mutex));
224 locked = (mutex->lock_count != 0);
225 unlock_mutex(&(mutex->os_mutex));