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