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    apr_pool_cleanup_register(new_mutex->pool,
81                              new_mutex, thread_mutex_cleanup,
82                              apr_pool_cleanup_null);
83
84    *mutex = new_mutex;
85    return APR_SUCCESS;
86}
87
88APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
89{
90    apr_status_t rv;
91
92    rv = pthread_mutex_lock(&mutex->mutex);
93#ifdef HAVE_ZOS_PTHREADS
94    if (rv) {
95        rv = errno;
96    }
97#endif
98
99    return rv;
100}
101
102APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex)
103{
104    apr_status_t rv;
105
106    rv = pthread_mutex_trylock(&mutex->mutex);
107    if (rv) {
108#ifdef HAVE_ZOS_PTHREADS
109        rv = errno;
110#endif
111        return (rv == EBUSY) ? APR_EBUSY : rv;
112    }
113
114    return APR_SUCCESS;
115}
116
117APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex)
118{
119    apr_status_t status;
120
121    status = pthread_mutex_unlock(&mutex->mutex);
122#ifdef HAVE_ZOS_PTHREADS
123    if (status) {
124        status = errno;
125    }
126#endif
127
128    return status;
129}
130
131APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex)
132{
133    return apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup);
134}
135
136APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex)
137
138#endif /* APR_HAS_THREADS */
139