thread_mutex.c revision 362181
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_arch_thread_mutex.h"
18#define APR_WANT_MEMFUNC
19#include "apr_want.h"
20
21#if APR_HAS_THREADS
22
23static apr_status_t thread_mutex_cleanup(void *data)
24{
25    apr_thread_mutex_t *mutex = data;
26    apr_status_t rv;
27
28    rv = pthread_mutex_destroy(&mutex->mutex);
29#ifdef HAVE_ZOS_PTHREADS
30    if (rv) {
31        rv = errno;
32    }
33#endif
34    return rv;
35}
36
37APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
38                                                  unsigned int flags,
39                                                  apr_pool_t *pool)
40{
41    apr_thread_mutex_t *new_mutex;
42    apr_status_t rv;
43
44#ifndef HAVE_PTHREAD_MUTEX_RECURSIVE
45    if (flags & APR_THREAD_MUTEX_NESTED) {
46        return APR_ENOTIMPL;
47    }
48#endif
49
50    new_mutex = apr_pcalloc(pool, sizeof(apr_thread_mutex_t));
51    new_mutex->pool = pool;
52
53#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
54    if (flags & APR_THREAD_MUTEX_NESTED) {
55        pthread_mutexattr_t mattr;
56
57        rv = pthread_mutexattr_init(&mattr);
58        if (rv) return rv;
59
60        rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
61        if (rv) {
62            pthread_mutexattr_destroy(&mattr);
63            return rv;
64        }
65
66        rv = pthread_mutex_init(&new_mutex->mutex, &mattr);
67
68        pthread_mutexattr_destroy(&mattr);
69    } else
70#endif
71        rv = pthread_mutex_init(&new_mutex->mutex, NULL);
72
73    if (rv) {
74#ifdef HAVE_ZOS_PTHREADS
75        rv = errno;
76#endif
77        return rv;
78    }
79
80#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
81    if (flags & APR_THREAD_MUTEX_TIMED) {
82        rv = apr_thread_cond_create(&new_mutex->cond, pool);
83        if (rv) {
84#ifdef HAVE_ZOS_PTHREADS
85            rv = errno;
86#endif
87            pthread_mutex_destroy(&new_mutex->mutex);
88            return rv;
89        }
90    }
91#endif
92
93    apr_pool_cleanup_register(new_mutex->pool,
94                              new_mutex, thread_mutex_cleanup,
95                              apr_pool_cleanup_null);
96
97    *mutex = new_mutex;
98    return APR_SUCCESS;
99}
100
101APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
102{
103    apr_status_t rv;
104
105    if (mutex->cond) {
106        apr_status_t rv2;
107
108        rv = pthread_mutex_lock(&mutex->mutex);
109        if (rv) {
110#ifdef HAVE_ZOS_PTHREADS
111            rv = errno;
112#endif
113            return rv;
114        }
115
116        if (mutex->locked) {
117            mutex->num_waiters++;
118            rv = apr_thread_cond_wait(mutex->cond, mutex);
119            mutex->num_waiters--;
120        }
121        else {
122            mutex->locked = 1;
123        }
124
125        rv2 = pthread_mutex_unlock(&mutex->mutex);
126        if (rv2 && !rv) {
127#ifdef HAVE_ZOS_PTHREADS
128            rv = errno;
129#else
130            rv = rv2;
131#endif
132        }
133
134        return rv;
135    }
136
137    rv = pthread_mutex_lock(&mutex->mutex);
138#ifdef HAVE_ZOS_PTHREADS
139    if (rv) {
140        rv = errno;
141    }
142#endif
143
144    return rv;
145}
146
147APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
148{
149    apr_status_t rv;
150
151    if (mutex->cond) {
152        apr_status_t rv2;
153
154        rv = pthread_mutex_lock(&mutex->mutex);
155        if (rv) {
156#ifdef HAVE_ZOS_PTHREADS
157            rv = errno;
158#endif
159            return rv;
160        }
161
162        if (mutex->locked) {
163            rv = APR_EBUSY;
164        }
165        else {
166            mutex->locked = 1;
167        }
168
169        rv2 = pthread_mutex_unlock(&mutex->mutex);
170        if (rv2) {
171#ifdef HAVE_ZOS_PTHREADS
172            rv = errno;
173#else
174            rv = rv2;
175#endif
176        }
177
178        return rv;
179    }
180
181    rv = pthread_mutex_trylock(&mutex->mutex);
182    if (rv) {
183#ifdef HAVE_ZOS_PTHREADS
184        rv = errno;
185#endif
186        return (rv == EBUSY) ? APR_EBUSY : rv;
187    }
188
189    return APR_SUCCESS;
190}
191
192APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex,
193                                                 apr_interval_time_t timeout)
194{
195    apr_status_t rv = APR_ENOTIMPL;
196#if APR_HAS_TIMEDLOCKS
197
198#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK
199    if (timeout <= 0) {
200        rv = pthread_mutex_trylock(&mutex->mutex);
201        if (rv) {
202#ifdef HAVE_ZOS_PTHREADS
203            rv = errno;
204#endif
205            if (rv == EBUSY) {
206                rv = APR_TIMEUP;
207            }
208        }
209    }
210    else {
211        struct timespec abstime;
212
213        timeout += apr_time_now();
214        abstime.tv_sec = apr_time_sec(timeout);
215        abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
216
217        rv = pthread_mutex_timedlock(&mutex->mutex, &abstime);
218        if (rv) {
219#ifdef HAVE_ZOS_PTHREADS
220            rv = errno;
221#endif
222            if (rv == ETIMEDOUT) {
223                rv = APR_TIMEUP;
224            }
225        }
226    }
227
228#else /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
229
230    if (mutex->cond) {
231        rv = pthread_mutex_lock(&mutex->mutex);
232        if (rv) {
233#ifdef HAVE_ZOS_PTHREADS
234            rv = errno;
235#endif
236            return rv;
237        }
238
239        if (mutex->locked) {
240            if (timeout <= 0) {
241                rv = APR_TIMEUP;
242            }
243            else {
244                mutex->num_waiters++;
245                do {
246                    rv = apr_thread_cond_timedwait(mutex->cond, mutex,
247                                                   timeout);
248                    if (rv) {
249#ifdef HAVE_ZOS_PTHREADS
250                        rv = errno;
251#endif
252                        break;
253                    }
254                } while (mutex->locked);
255                mutex->num_waiters--;
256            }
257            if (rv) {
258                pthread_mutex_unlock(&mutex->mutex);
259                return rv;
260            }
261        }
262
263        mutex->locked = 1;
264
265        rv = pthread_mutex_unlock(&mutex->mutex);
266        if (rv) {
267#ifdef HAVE_ZOS_PTHREADS
268            rv = errno;
269#endif
270            return rv;
271        }
272    }
273
274#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
275
276#endif /* APR_HAS_TIMEDLOCKS */
277    return rv;
278}
279
280APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
281{
282    apr_status_t status;
283
284    if (mutex->cond) {
285        status = pthread_mutex_lock(&mutex->mutex);
286        if (status) {
287#ifdef HAVE_ZOS_PTHREADS
288            status = errno;
289#endif
290            return status;
291        }
292
293        if (!mutex->locked) {
294            status = APR_EINVAL;
295        }
296        else if (mutex->num_waiters) {
297            status = apr_thread_cond_signal(mutex->cond);
298        }
299        if (status) {
300            pthread_mutex_unlock(&mutex->mutex);
301            return status;
302        }
303
304        mutex->locked = 0;
305    }
306
307    status = pthread_mutex_unlock(&mutex->mutex);
308#ifdef HAVE_ZOS_PTHREADS
309    if (status) {
310        status = errno;
311    }
312#endif
313
314    return status;
315}
316
317APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
318{
319    apr_status_t rv, rv2 = APR_SUCCESS;
320
321    if (mutex->cond) {
322        rv2 = apr_thread_cond_destroy(mutex->cond);
323    }
324    rv = apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup);
325    if (rv == APR_SUCCESS) {
326        rv = rv2;
327    }
328
329    return rv;
330}
331
332APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex)
333
334#endif /* APR_HAS_THREADS */
335