proc_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.h" 18#include "apr_strings.h" 19#include "apr_arch_proc_mutex.h" 20#include "apr_arch_file_io.h" /* for apr_mkstemp() */ 21#include "apr_hash.h" 22#include "apr_atomic.h" 23 24APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) 25{ 26 return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup); 27} 28 29#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \ 30 APR_HAS_SYSVSEM_SERIALIZE 31static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex, 32 apr_pool_t *cont, 33 const char *fname) 34{ 35 return APR_SUCCESS; 36} 37#endif 38 39#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_PROC_PTHREAD_SERIALIZE 40static apr_status_t proc_mutex_no_perms_set(apr_proc_mutex_t *mutex, 41 apr_fileperms_t perms, 42 apr_uid_t uid, 43 apr_gid_t gid) 44{ 45 return APR_ENOTIMPL; 46} 47#endif 48 49#if APR_HAS_FCNTL_SERIALIZE \ 50 || APR_HAS_FLOCK_SERIALIZE \ 51 || (APR_HAS_SYSVSEM_SERIALIZE \ 52 && !defined(HAVE_SEMTIMEDOP)) \ 53 || (APR_HAS_POSIXSEM_SERIALIZE \ 54 && !defined(HAVE_SEM_TIMEDWAIT)) \ 55 || (APR_HAS_PROC_PTHREAD_SERIALIZE \ 56 && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) \ 57 && !defined(HAVE_PTHREAD_CONDATTR_SETPSHARED)) 58static apr_status_t proc_mutex_spinsleep_timedacquire(apr_proc_mutex_t *mutex, 59 apr_interval_time_t timeout) 60{ 61#define SLEEP_TIME apr_time_from_msec(10) 62 apr_status_t rv; 63 for (;;) { 64 rv = apr_proc_mutex_trylock(mutex); 65 if (!APR_STATUS_IS_EBUSY(rv)) { 66 if (rv == APR_SUCCESS) { 67 mutex->curr_locked = 1; 68 } 69 break; 70 } 71 if (timeout <= 0) { 72 rv = APR_TIMEUP; 73 break; 74 } 75 if (timeout > SLEEP_TIME) { 76 apr_sleep(SLEEP_TIME); 77 timeout -= SLEEP_TIME; 78 } 79 else { 80 apr_sleep(timeout); 81 timeout = 0; 82 } 83 } 84 return rv; 85} 86#endif 87 88#if APR_HAS_POSIXSEM_SERIALIZE 89 90#ifndef SEM_FAILED 91#define SEM_FAILED (-1) 92#endif 93 94static apr_status_t proc_mutex_posix_cleanup(void *mutex_) 95{ 96 apr_proc_mutex_t *mutex = mutex_; 97 98 if (sem_close(mutex->os.psem_interproc) < 0) { 99 return errno; 100 } 101 102 return APR_SUCCESS; 103} 104 105static unsigned int rshash (char *p) { 106 /* hash function from Robert Sedgwicks 'Algorithms in C' book */ 107 unsigned int b = 378551; 108 unsigned int a = 63689; 109 unsigned int retval = 0; 110 111 for( ; *p; p++) 112 { 113 retval = retval * a + (*p); 114 a *= b; 115 } 116 117 return retval; 118} 119 120static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex, 121 const char *fname) 122{ 123 #define APR_POSIXSEM_NAME_MIN 13 124 sem_t *psem; 125 char semname[32]; 126 127 /* 128 * This bogusness is to follow what appears to be the 129 * lowest common denominator in Posix semaphore naming: 130 * - start with '/' 131 * - be at most 14 chars 132 * - be unique and not match anything on the filesystem 133 * 134 * Because of this, we use fname to generate a (unique) hash 135 * and use that as the name of the semaphore. If no filename was 136 * given, we create one based on the time. We tuck the name 137 * away, since it might be useful for debugging. We use 2 hashing 138 * functions to try to avoid collisions. 139 * 140 * To make this as robust as possible, we initially try something 141 * larger (and hopefully more unique) and gracefully fail down to the 142 * LCD above. 143 * 144 * NOTE: Darwin (Mac OS X) seems to be the most restrictive 145 * implementation. Versions previous to Darwin 6.2 had the 14 146 * char limit, but later rev's allow up to 31 characters. 147 * 148 */ 149 if (fname) { 150 apr_ssize_t flen = strlen(fname); 151 char *p = apr_pstrndup(new_mutex->pool, fname, strlen(fname)); 152 unsigned int h1, h2; 153 h1 = (apr_hashfunc_default((const char *)p, &flen) & 0xffffffff); 154 h2 = (rshash(p) & 0xffffffff); 155 apr_snprintf(semname, sizeof(semname), "/ApR.%xH%x", h1, h2); 156 } else { 157 apr_time_t now; 158 unsigned long sec; 159 unsigned long usec; 160 now = apr_time_now(); 161 sec = apr_time_sec(now); 162 usec = apr_time_usec(now); 163 apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec); 164 } 165 do { 166 psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1); 167 } while (psem == (sem_t *)SEM_FAILED && errno == EINTR); 168 if (psem == (sem_t *)SEM_FAILED) { 169 if (errno == ENAMETOOLONG) { 170 /* Oh well, good try */ 171 semname[APR_POSIXSEM_NAME_MIN] = '\0'; 172 } else { 173 return errno; 174 } 175 do { 176 psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1); 177 } while (psem == (sem_t *)SEM_FAILED && errno == EINTR); 178 } 179 180 if (psem == (sem_t *)SEM_FAILED) { 181 return errno; 182 } 183 /* Ahhh. The joys of Posix sems. Predelete it... */ 184 sem_unlink(semname); 185 new_mutex->os.psem_interproc = psem; 186 new_mutex->fname = apr_pstrdup(new_mutex->pool, semname); 187 apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex, 188 apr_proc_mutex_cleanup, 189 apr_pool_cleanup_null); 190 return APR_SUCCESS; 191} 192 193static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex) 194{ 195 int rc; 196 197 do { 198 rc = sem_wait(mutex->os.psem_interproc); 199 } while (rc < 0 && errno == EINTR); 200 if (rc < 0) { 201 return errno; 202 } 203 mutex->curr_locked = 1; 204 return APR_SUCCESS; 205} 206 207static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex) 208{ 209 int rc; 210 211 do { 212 rc = sem_trywait(mutex->os.psem_interproc); 213 } while (rc < 0 && errno == EINTR); 214 if (rc < 0) { 215 if (errno == EAGAIN) { 216 return APR_EBUSY; 217 } 218 return errno; 219 } 220 mutex->curr_locked = 1; 221 return APR_SUCCESS; 222} 223 224#if defined(HAVE_SEM_TIMEDWAIT) 225static apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex, 226 apr_interval_time_t timeout) 227{ 228 if (timeout <= 0) { 229 apr_status_t rv = proc_mutex_posix_tryacquire(mutex); 230 return (rv == APR_EBUSY) ? APR_TIMEUP : rv; 231 } 232 else { 233 int rc; 234 struct timespec abstime; 235 236 timeout += apr_time_now(); 237 abstime.tv_sec = apr_time_sec(timeout); 238 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ 239 240 do { 241 rc = sem_timedwait(mutex->os.psem_interproc, &abstime); 242 } while (rc < 0 && errno == EINTR); 243 if (rc < 0) { 244 if (errno == ETIMEDOUT) { 245 return APR_TIMEUP; 246 } 247 return errno; 248 } 249 } 250 mutex->curr_locked = 1; 251 return APR_SUCCESS; 252} 253#endif 254 255static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex) 256{ 257 mutex->curr_locked = 0; 258 if (sem_post(mutex->os.psem_interproc) < 0) { 259 /* any failure is probably fatal, so no big deal to leave 260 * ->curr_locked at 0. */ 261 return errno; 262 } 263 return APR_SUCCESS; 264} 265 266static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods = 267{ 268#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL) 269 APR_PROCESS_LOCK_MECH_IS_GLOBAL, 270#else 271 0, 272#endif 273 proc_mutex_posix_create, 274 proc_mutex_posix_acquire, 275 proc_mutex_posix_tryacquire, 276#if defined(HAVE_SEM_TIMEDWAIT) 277 proc_mutex_posix_timedacquire, 278#else 279 proc_mutex_spinsleep_timedacquire, 280#endif 281 proc_mutex_posix_release, 282 proc_mutex_posix_cleanup, 283 proc_mutex_no_child_init, 284 proc_mutex_no_perms_set, 285 APR_LOCK_POSIXSEM, 286 "posixsem" 287}; 288 289#endif /* Posix sem implementation */ 290 291#if APR_HAS_SYSVSEM_SERIALIZE 292 293static struct sembuf proc_mutex_op_on; 294static struct sembuf proc_mutex_op_try; 295static struct sembuf proc_mutex_op_off; 296 297static void proc_mutex_sysv_setup(void) 298{ 299 proc_mutex_op_on.sem_num = 0; 300 proc_mutex_op_on.sem_op = -1; 301 proc_mutex_op_on.sem_flg = SEM_UNDO; 302 proc_mutex_op_try.sem_num = 0; 303 proc_mutex_op_try.sem_op = -1; 304 proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT; 305 proc_mutex_op_off.sem_num = 0; 306 proc_mutex_op_off.sem_op = 1; 307 proc_mutex_op_off.sem_flg = SEM_UNDO; 308} 309 310static apr_status_t proc_mutex_sysv_cleanup(void *mutex_) 311{ 312 apr_proc_mutex_t *mutex=mutex_; 313 union semun ick; 314 315 if (mutex->os.crossproc != -1) { 316 ick.val = 0; 317 semctl(mutex->os.crossproc, 0, IPC_RMID, ick); 318 } 319 return APR_SUCCESS; 320} 321 322static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex, 323 const char *fname) 324{ 325 union semun ick; 326 apr_status_t rv; 327 328 new_mutex->os.crossproc = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600); 329 if (new_mutex->os.crossproc == -1) { 330 rv = errno; 331 proc_mutex_sysv_cleanup(new_mutex); 332 return rv; 333 } 334 ick.val = 1; 335 if (semctl(new_mutex->os.crossproc, 0, SETVAL, ick) < 0) { 336 rv = errno; 337 proc_mutex_sysv_cleanup(new_mutex); 338 new_mutex->os.crossproc = -1; 339 return rv; 340 } 341 new_mutex->curr_locked = 0; 342 apr_pool_cleanup_register(new_mutex->pool, 343 (void *)new_mutex, apr_proc_mutex_cleanup, 344 apr_pool_cleanup_null); 345 return APR_SUCCESS; 346} 347 348static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex) 349{ 350 int rc; 351 352 do { 353 rc = semop(mutex->os.crossproc, &proc_mutex_op_on, 1); 354 } while (rc < 0 && errno == EINTR); 355 if (rc < 0) { 356 return errno; 357 } 358 mutex->curr_locked = 1; 359 return APR_SUCCESS; 360} 361 362static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex) 363{ 364 int rc; 365 366 do { 367 rc = semop(mutex->os.crossproc, &proc_mutex_op_try, 1); 368 } while (rc < 0 && errno == EINTR); 369 if (rc < 0) { 370 if (errno == EAGAIN) { 371 return APR_EBUSY; 372 } 373 return errno; 374 } 375 mutex->curr_locked = 1; 376 return APR_SUCCESS; 377} 378 379#if defined(HAVE_SEMTIMEDOP) 380static apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex, 381 apr_interval_time_t timeout) 382{ 383 if (timeout <= 0) { 384 apr_status_t rv = proc_mutex_sysv_tryacquire(mutex); 385 return (rv == APR_EBUSY) ? APR_TIMEUP : rv; 386 } 387 else { 388 int rc; 389 struct timespec reltime; 390 391 reltime.tv_sec = apr_time_sec(timeout); 392 reltime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ 393 394 do { 395 rc = semtimedop(mutex->os.crossproc, &proc_mutex_op_on, 1, 396 &reltime); 397 } while (rc < 0 && errno == EINTR); 398 if (rc < 0) { 399 if (errno == EAGAIN) { 400 return APR_TIMEUP; 401 } 402 return errno; 403 } 404 } 405 mutex->curr_locked = 1; 406 return APR_SUCCESS; 407} 408#endif 409 410static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex) 411{ 412 int rc; 413 414 mutex->curr_locked = 0; 415 do { 416 rc = semop(mutex->os.crossproc, &proc_mutex_op_off, 1); 417 } while (rc < 0 && errno == EINTR); 418 if (rc < 0) { 419 return errno; 420 } 421 return APR_SUCCESS; 422} 423 424static apr_status_t proc_mutex_sysv_perms_set(apr_proc_mutex_t *mutex, 425 apr_fileperms_t perms, 426 apr_uid_t uid, 427 apr_gid_t gid) 428{ 429 430 union semun ick; 431 struct semid_ds buf; 432 buf.sem_perm.uid = uid; 433 buf.sem_perm.gid = gid; 434 buf.sem_perm.mode = apr_unix_perms2mode(perms); 435 ick.buf = &buf; 436 if (semctl(mutex->os.crossproc, 0, IPC_SET, ick) < 0) { 437 return errno; 438 } 439 return APR_SUCCESS; 440} 441 442static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods = 443{ 444#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL) 445 APR_PROCESS_LOCK_MECH_IS_GLOBAL, 446#else 447 0, 448#endif 449 proc_mutex_sysv_create, 450 proc_mutex_sysv_acquire, 451 proc_mutex_sysv_tryacquire, 452#if defined(HAVE_SEMTIMEDOP) 453 proc_mutex_sysv_timedacquire, 454#else 455 proc_mutex_spinsleep_timedacquire, 456#endif 457 proc_mutex_sysv_release, 458 proc_mutex_sysv_cleanup, 459 proc_mutex_no_child_init, 460 proc_mutex_sysv_perms_set, 461 APR_LOCK_SYSVSEM, 462 "sysvsem" 463}; 464 465#endif /* SysV sem implementation */ 466 467#if APR_HAS_PROC_PTHREAD_SERIALIZE 468 469#ifndef APR_USE_PROC_PTHREAD_MUTEX_COND 470#define APR_USE_PROC_PTHREAD_MUTEX_COND \ 471 (defined(HAVE_PTHREAD_CONDATTR_SETPSHARED) \ 472 && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) 473#endif 474 475/* The mmap()ed pthread_interproc is the native pthread_mutex_t followed 476 * by a refcounter to track children using it. We want to avoid calling 477 * pthread_mutex_destroy() on the shared mutex area while it is in use by 478 * another process, because this may mark the shared pthread_mutex_t as 479 * invalid for everyone, including forked children (unlike "sysvsem" for 480 * example), causing unexpected errors or deadlocks (PR 49504). So the 481 * last process (parent or child) referencing the mutex will effectively 482 * destroy it. 483 */ 484typedef struct { 485#define proc_pthread_cast(m) \ 486 ((proc_pthread_mutex_t *)(m)->os.pthread_interproc) 487 pthread_mutex_t mutex; 488#define proc_pthread_mutex(m) \ 489 (proc_pthread_cast(m)->mutex) 490#if APR_USE_PROC_PTHREAD_MUTEX_COND 491 pthread_cond_t cond; 492#define proc_pthread_mutex_cond(m) \ 493 (proc_pthread_cast(m)->cond) 494 apr_int32_t cond_locked; 495#define proc_pthread_mutex_cond_locked(m) \ 496 (proc_pthread_cast(m)->cond_locked) 497 apr_uint32_t cond_num_waiters; 498#define proc_pthread_mutex_cond_num_waiters(m) \ 499 (proc_pthread_cast(m)->cond_num_waiters) 500#define proc_pthread_mutex_is_cond(m) \ 501 ((m)->pthread_refcounting && proc_pthread_mutex_cond_locked(m) != -1) 502#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ 503 apr_uint32_t refcount; 504#define proc_pthread_mutex_refcount(m) \ 505 (proc_pthread_cast(m)->refcount) 506} proc_pthread_mutex_t; 507 508 509static APR_INLINE int proc_pthread_mutex_inc(apr_proc_mutex_t *mutex) 510{ 511 if (mutex->pthread_refcounting) { 512 apr_atomic_inc32(&proc_pthread_mutex_refcount(mutex)); 513 return 1; 514 } 515 return 0; 516} 517 518static APR_INLINE int proc_pthread_mutex_dec(apr_proc_mutex_t *mutex) 519{ 520 if (mutex->pthread_refcounting) { 521 return apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex)); 522 } 523 return 0; 524} 525 526static apr_status_t proc_pthread_mutex_unref(void *mutex_) 527{ 528 apr_proc_mutex_t *mutex=mutex_; 529 apr_status_t rv; 530 531#if APR_USE_PROC_PTHREAD_MUTEX_COND 532 if (proc_pthread_mutex_is_cond(mutex)) { 533 mutex->curr_locked = 0; 534 } 535 else 536#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ 537 if (mutex->curr_locked == 1) { 538 if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) { 539#ifdef HAVE_ZOS_PTHREADS 540 rv = errno; 541#endif 542 return rv; 543 } 544 } 545 if (!proc_pthread_mutex_dec(mutex)) { 546#if APR_USE_PROC_PTHREAD_MUTEX_COND 547 if (proc_pthread_mutex_is_cond(mutex) && 548 (rv = pthread_cond_destroy(&proc_pthread_mutex_cond(mutex)))) { 549#ifdef HAVE_ZOS_PTHREADS 550 rv = errno; 551#endif 552 return rv; 553 } 554#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ 555 556 if ((rv = pthread_mutex_destroy(&proc_pthread_mutex(mutex)))) { 557#ifdef HAVE_ZOS_PTHREADS 558 rv = errno; 559#endif 560 return rv; 561 } 562 } 563 return APR_SUCCESS; 564} 565 566static apr_status_t proc_mutex_pthread_cleanup(void *mutex_) 567{ 568 apr_proc_mutex_t *mutex=mutex_; 569 apr_status_t rv; 570 571 /* curr_locked is set to -1 until the mutex has been created */ 572 if (mutex->curr_locked != -1) { 573 if ((rv = proc_pthread_mutex_unref(mutex))) { 574 return rv; 575 } 576 } 577 if (munmap(mutex->os.pthread_interproc, sizeof(proc_pthread_mutex_t))) { 578 return errno; 579 } 580 return APR_SUCCESS; 581} 582 583static apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex, 584 const char *fname) 585{ 586 apr_status_t rv; 587 int fd; 588 pthread_mutexattr_t mattr; 589 590 fd = open("/dev/zero", O_RDWR); 591 if (fd < 0) { 592 return errno; 593 } 594 595 new_mutex->os.pthread_interproc = mmap(NULL, sizeof(proc_pthread_mutex_t), 596 PROT_READ | PROT_WRITE, MAP_SHARED, 597 fd, 0); 598 if (new_mutex->os.pthread_interproc == MAP_FAILED) { 599 new_mutex->os.pthread_interproc = NULL; 600 rv = errno; 601 close(fd); 602 return rv; 603 } 604 close(fd); 605 606 new_mutex->pthread_refcounting = 1; 607 new_mutex->curr_locked = -1; /* until the mutex has been created */ 608#if APR_USE_PROC_PTHREAD_MUTEX_COND 609 proc_pthread_mutex_cond_locked(new_mutex) = -1; 610#endif 611 612 if ((rv = pthread_mutexattr_init(&mattr))) { 613#ifdef HAVE_ZOS_PTHREADS 614 rv = errno; 615#endif 616 proc_mutex_pthread_cleanup(new_mutex); 617 return rv; 618 } 619 if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) { 620#ifdef HAVE_ZOS_PTHREADS 621 rv = errno; 622#endif 623 proc_mutex_pthread_cleanup(new_mutex); 624 pthread_mutexattr_destroy(&mattr); 625 return rv; 626 } 627 628#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP) 629#ifdef HAVE_PTHREAD_MUTEX_ROBUST 630 rv = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST); 631#else 632 rv = pthread_mutexattr_setrobust_np(&mattr, PTHREAD_MUTEX_ROBUST_NP); 633#endif 634 if (rv) { 635#ifdef HAVE_ZOS_PTHREADS 636 rv = errno; 637#endif 638 proc_mutex_pthread_cleanup(new_mutex); 639 pthread_mutexattr_destroy(&mattr); 640 return rv; 641 } 642 if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) { 643#ifdef HAVE_ZOS_PTHREADS 644 rv = errno; 645#endif 646 proc_mutex_pthread_cleanup(new_mutex); 647 pthread_mutexattr_destroy(&mattr); 648 return rv; 649 } 650#endif /* HAVE_PTHREAD_MUTEX_ROBUST[_NP] */ 651 652 if ((rv = pthread_mutex_init(&proc_pthread_mutex(new_mutex), &mattr))) { 653#ifdef HAVE_ZOS_PTHREADS 654 rv = errno; 655#endif 656 proc_mutex_pthread_cleanup(new_mutex); 657 pthread_mutexattr_destroy(&mattr); 658 return rv; 659 } 660 661 proc_pthread_mutex_refcount(new_mutex) = 1; /* first/parent reference */ 662 new_mutex->curr_locked = 0; /* mutex created now */ 663 664 if ((rv = pthread_mutexattr_destroy(&mattr))) { 665#ifdef HAVE_ZOS_PTHREADS 666 rv = errno; 667#endif 668 proc_mutex_pthread_cleanup(new_mutex); 669 return rv; 670 } 671 672 apr_pool_cleanup_register(new_mutex->pool, 673 (void *)new_mutex, 674 apr_proc_mutex_cleanup, 675 apr_pool_cleanup_null); 676 return APR_SUCCESS; 677} 678 679static apr_status_t proc_mutex_pthread_child_init(apr_proc_mutex_t **mutex, 680 apr_pool_t *pool, 681 const char *fname) 682{ 683 (*mutex)->curr_locked = 0; 684 if (proc_pthread_mutex_inc(*mutex)) { 685 apr_pool_cleanup_register(pool, *mutex, proc_pthread_mutex_unref, 686 apr_pool_cleanup_null); 687 } 688 return APR_SUCCESS; 689} 690 691static apr_status_t proc_mutex_pthread_acquire_ex(apr_proc_mutex_t *mutex, 692 apr_interval_time_t timeout) 693{ 694 apr_status_t rv; 695 696#if APR_USE_PROC_PTHREAD_MUTEX_COND 697 if (proc_pthread_mutex_is_cond(mutex)) { 698 if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) { 699#ifdef HAVE_ZOS_PTHREADS 700 rv = errno; 701#endif 702#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP) 703 /* Okay, our owner died. Let's try to make it consistent again. */ 704 if (rv == EOWNERDEAD) { 705 proc_pthread_mutex_dec(mutex); 706#ifdef HAVE_PTHREAD_MUTEX_ROBUST 707 pthread_mutex_consistent(&proc_pthread_mutex(mutex)); 708#else 709 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex)); 710#endif 711 } 712 else 713#endif 714 return rv; 715 } 716 717 if (!proc_pthread_mutex_cond_locked(mutex)) { 718 rv = APR_SUCCESS; 719 } 720 else if (!timeout) { 721 rv = APR_TIMEUP; 722 } 723 else { 724 struct timespec abstime; 725 726 if (timeout > 0) { 727 timeout += apr_time_now(); 728 abstime.tv_sec = apr_time_sec(timeout); 729 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ 730 } 731 732 proc_pthread_mutex_cond_num_waiters(mutex)++; 733 do { 734 if (timeout < 0) { 735 rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex), 736 &proc_pthread_mutex(mutex)); 737 if (rv) { 738#ifdef HAVE_ZOS_PTHREADS 739 rv = errno; 740#endif 741 break; 742 } 743 } 744 else { 745 rv = pthread_cond_timedwait(&proc_pthread_mutex_cond(mutex), 746 &proc_pthread_mutex(mutex), 747 &abstime); 748 if (rv) { 749#ifdef HAVE_ZOS_PTHREADS 750 rv = errno; 751#endif 752 if (rv == ETIMEDOUT) { 753 rv = APR_TIMEUP; 754 } 755 break; 756 } 757 } 758 } while (proc_pthread_mutex_cond_locked(mutex)); 759 proc_pthread_mutex_cond_num_waiters(mutex)--; 760 } 761 if (rv != APR_SUCCESS) { 762 pthread_mutex_unlock(&proc_pthread_mutex(mutex)); 763 return rv; 764 } 765 766 proc_pthread_mutex_cond_locked(mutex) = 1; 767 768 rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)); 769 if (rv) { 770#ifdef HAVE_ZOS_PTHREADS 771 rv = errno; 772#endif 773 return rv; 774 } 775 } 776 else 777#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ 778 { 779 if (timeout < 0) { 780 rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)); 781 if (rv) { 782#ifdef HAVE_ZOS_PTHREADS 783 rv = errno; 784#endif 785 } 786 } 787 else if (!timeout) { 788 rv = pthread_mutex_trylock(&proc_pthread_mutex(mutex)); 789 if (rv) { 790#ifdef HAVE_ZOS_PTHREADS 791 rv = errno; 792#endif 793 if (rv == EBUSY) { 794 return APR_TIMEUP; 795 } 796 } 797 } 798 else 799#if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) 800 { 801 struct timespec abstime; 802 803 timeout += apr_time_now(); 804 abstime.tv_sec = apr_time_sec(timeout); 805 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ 806 807 rv = pthread_mutex_timedlock(&proc_pthread_mutex(mutex), &abstime); 808 if (rv) { 809#ifdef HAVE_ZOS_PTHREADS 810 rv = errno; 811#endif 812 if (rv == ETIMEDOUT) { 813 return APR_TIMEUP; 814 } 815 } 816 } 817 if (rv) { 818#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP) 819 /* Okay, our owner died. Let's try to make it consistent again. */ 820 if (rv == EOWNERDEAD) { 821 proc_pthread_mutex_dec(mutex); 822#ifdef HAVE_PTHREAD_MUTEX_ROBUST 823 pthread_mutex_consistent(&proc_pthread_mutex(mutex)); 824#else 825 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex)); 826#endif 827 } 828 else 829#endif 830 return rv; 831 } 832#else /* !HAVE_PTHREAD_MUTEX_TIMEDLOCK */ 833 return proc_mutex_spinsleep_timedacquire(mutex, timeout); 834#endif 835 } 836 837 mutex->curr_locked = 1; 838 return APR_SUCCESS; 839} 840 841static apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex) 842{ 843 return proc_mutex_pthread_acquire_ex(mutex, -1); 844} 845 846static apr_status_t proc_mutex_pthread_tryacquire(apr_proc_mutex_t *mutex) 847{ 848 apr_status_t rv = proc_mutex_pthread_acquire_ex(mutex, 0); 849 return (rv == APR_TIMEUP) ? APR_EBUSY : rv; 850} 851 852static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex, 853 apr_interval_time_t timeout) 854{ 855 return proc_mutex_pthread_acquire_ex(mutex, (timeout <= 0) ? 0 : timeout); 856} 857 858static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex) 859{ 860 apr_status_t rv; 861 862#if APR_USE_PROC_PTHREAD_MUTEX_COND 863 if (proc_pthread_mutex_is_cond(mutex)) { 864 if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) { 865#ifdef HAVE_ZOS_PTHREADS 866 rv = errno; 867#endif 868#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP) 869 /* Okay, our owner died. Let's try to make it consistent again. */ 870 if (rv == EOWNERDEAD) { 871 proc_pthread_mutex_dec(mutex); 872#ifdef HAVE_PTHREAD_MUTEX_ROBUST 873 pthread_mutex_consistent(&proc_pthread_mutex(mutex)); 874#else 875 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex)); 876#endif 877 } 878 else 879#endif 880 return rv; 881 } 882 883 if (!proc_pthread_mutex_cond_locked(mutex)) { 884 rv = APR_EINVAL; 885 } 886 else if (!proc_pthread_mutex_cond_num_waiters(mutex)) { 887 rv = APR_SUCCESS; 888 } 889 else { 890 rv = pthread_cond_signal(&proc_pthread_mutex_cond(mutex)); 891#ifdef HAVE_ZOS_PTHREADS 892 if (rv) { 893 rv = errno; 894 } 895#endif 896 } 897 if (rv != APR_SUCCESS) { 898 pthread_mutex_unlock(&proc_pthread_mutex(mutex)); 899 return rv; 900 } 901 902 proc_pthread_mutex_cond_locked(mutex) = 0; 903 } 904#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */ 905 906 mutex->curr_locked = 0; 907 if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) { 908#ifdef HAVE_ZOS_PTHREADS 909 rv = errno; 910#endif 911 return rv; 912 } 913 914 return APR_SUCCESS; 915} 916 917static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods = 918{ 919 APR_PROCESS_LOCK_MECH_IS_GLOBAL, 920 proc_mutex_pthread_create, 921 proc_mutex_pthread_acquire, 922 proc_mutex_pthread_tryacquire, 923 proc_mutex_pthread_timedacquire, 924 proc_mutex_pthread_release, 925 proc_mutex_pthread_cleanup, 926 proc_mutex_pthread_child_init, 927 proc_mutex_no_perms_set, 928 APR_LOCK_PROC_PTHREAD, 929 "pthread" 930}; 931 932#if APR_USE_PROC_PTHREAD_MUTEX_COND 933static apr_status_t proc_mutex_pthread_cond_create(apr_proc_mutex_t *new_mutex, 934 const char *fname) 935{ 936 apr_status_t rv; 937 pthread_condattr_t cattr; 938 939 rv = proc_mutex_pthread_create(new_mutex, fname); 940 if (rv != APR_SUCCESS) { 941 return rv; 942 } 943 944 if ((rv = pthread_condattr_init(&cattr))) { 945#ifdef HAVE_ZOS_PTHREADS 946 rv = errno; 947#endif 948 apr_pool_cleanup_run(new_mutex->pool, new_mutex, 949 apr_proc_mutex_cleanup); 950 return rv; 951 } 952 if ((rv = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))) { 953#ifdef HAVE_ZOS_PTHREADS 954 rv = errno; 955#endif 956 pthread_condattr_destroy(&cattr); 957 apr_pool_cleanup_run(new_mutex->pool, new_mutex, 958 apr_proc_mutex_cleanup); 959 return rv; 960 } 961 if ((rv = pthread_cond_init(&proc_pthread_mutex_cond(new_mutex), 962 &cattr))) { 963#ifdef HAVE_ZOS_PTHREADS 964 rv = errno; 965#endif 966 pthread_condattr_destroy(&cattr); 967 apr_pool_cleanup_run(new_mutex->pool, new_mutex, 968 apr_proc_mutex_cleanup); 969 return rv; 970 } 971 pthread_condattr_destroy(&cattr); 972 973 proc_pthread_mutex_cond_locked(new_mutex) = 0; 974 proc_pthread_mutex_cond_num_waiters(new_mutex) = 0; 975 976 return APR_SUCCESS; 977} 978 979static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_cond_methods = 980{ 981 APR_PROCESS_LOCK_MECH_IS_GLOBAL, 982 proc_mutex_pthread_cond_create, 983 proc_mutex_pthread_acquire, 984 proc_mutex_pthread_tryacquire, 985 proc_mutex_pthread_timedacquire, 986 proc_mutex_pthread_release, 987 proc_mutex_pthread_cleanup, 988 proc_mutex_pthread_child_init, 989 proc_mutex_no_perms_set, 990 APR_LOCK_PROC_PTHREAD, 991 "pthread" 992}; 993#endif 994 995#endif 996 997#if APR_HAS_FCNTL_SERIALIZE 998 999static struct flock proc_mutex_lock_it; 1000static struct flock proc_mutex_unlock_it; 1001 1002static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *); 1003 1004static void proc_mutex_fcntl_setup(void) 1005{ 1006 proc_mutex_lock_it.l_whence = SEEK_SET; /* from current point */ 1007 proc_mutex_lock_it.l_start = 0; /* -"- */ 1008 proc_mutex_lock_it.l_len = 0; /* until end of file */ 1009 proc_mutex_lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ 1010 proc_mutex_lock_it.l_pid = 0; /* pid not actually interesting */ 1011 proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */ 1012 proc_mutex_unlock_it.l_start = 0; /* -"- */ 1013 proc_mutex_unlock_it.l_len = 0; /* until end of file */ 1014 proc_mutex_unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ 1015 proc_mutex_unlock_it.l_pid = 0; /* pid not actually interesting */ 1016} 1017 1018static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_) 1019{ 1020 apr_status_t status = APR_SUCCESS; 1021 apr_proc_mutex_t *mutex=mutex_; 1022 1023 if (mutex->curr_locked == 1) { 1024 status = proc_mutex_fcntl_release(mutex); 1025 if (status != APR_SUCCESS) 1026 return status; 1027 } 1028 1029 if (mutex->interproc) { 1030 status = apr_file_close(mutex->interproc); 1031 } 1032 if (!mutex->interproc_closing 1033 && mutex->os.crossproc != -1 1034 && close(mutex->os.crossproc) == -1 1035 && status == APR_SUCCESS) { 1036 status = errno; 1037 } 1038 return status; 1039} 1040 1041static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex, 1042 const char *fname) 1043{ 1044 int rv; 1045 1046 if (fname) { 1047 new_mutex->fname = apr_pstrdup(new_mutex->pool, fname); 1048 rv = apr_file_open(&new_mutex->interproc, new_mutex->fname, 1049 APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, 1050 APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, 1051 new_mutex->pool); 1052 } 1053 else { 1054 new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX"); 1055 rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname, 1056 APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, 1057 new_mutex->pool); 1058 } 1059 1060 if (rv != APR_SUCCESS) { 1061 return rv; 1062 } 1063 1064 new_mutex->os.crossproc = new_mutex->interproc->filedes; 1065 new_mutex->interproc_closing = 1; 1066 new_mutex->curr_locked = 0; 1067 unlink(new_mutex->fname); 1068 apr_pool_cleanup_register(new_mutex->pool, 1069 (void*)new_mutex, 1070 apr_proc_mutex_cleanup, 1071 apr_pool_cleanup_null); 1072 return APR_SUCCESS; 1073} 1074 1075static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex) 1076{ 1077 int rc; 1078 1079 do { 1080 rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_lock_it); 1081 } while (rc < 0 && errno == EINTR); 1082 if (rc < 0) { 1083 return errno; 1084 } 1085 mutex->curr_locked=1; 1086 return APR_SUCCESS; 1087} 1088 1089static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex) 1090{ 1091 int rc; 1092 1093 do { 1094 rc = fcntl(mutex->os.crossproc, F_SETLK, &proc_mutex_lock_it); 1095 } while (rc < 0 && errno == EINTR); 1096 if (rc < 0) { 1097#if FCNTL_TRYACQUIRE_EACCES 1098 if (errno == EACCES) { 1099#else 1100 if (errno == EAGAIN) { 1101#endif 1102 return APR_EBUSY; 1103 } 1104 return errno; 1105 } 1106 mutex->curr_locked = 1; 1107 return APR_SUCCESS; 1108} 1109 1110static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex) 1111{ 1112 int rc; 1113 1114 mutex->curr_locked=0; 1115 do { 1116 rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_unlock_it); 1117 } while (rc < 0 && errno == EINTR); 1118 if (rc < 0) { 1119 return errno; 1120 } 1121 return APR_SUCCESS; 1122} 1123 1124static apr_status_t proc_mutex_fcntl_perms_set(apr_proc_mutex_t *mutex, 1125 apr_fileperms_t perms, 1126 apr_uid_t uid, 1127 apr_gid_t gid) 1128{ 1129 1130 if (mutex->fname) { 1131 if (!(perms & APR_FPROT_GSETID)) 1132 gid = -1; 1133 if (fchown(mutex->os.crossproc, uid, gid) < 0) { 1134 return errno; 1135 } 1136 } 1137 return APR_SUCCESS; 1138} 1139 1140static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods = 1141{ 1142#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL) 1143 APR_PROCESS_LOCK_MECH_IS_GLOBAL, 1144#else 1145 0, 1146#endif 1147 proc_mutex_fcntl_create, 1148 proc_mutex_fcntl_acquire, 1149 proc_mutex_fcntl_tryacquire, 1150 proc_mutex_spinsleep_timedacquire, 1151 proc_mutex_fcntl_release, 1152 proc_mutex_fcntl_cleanup, 1153 proc_mutex_no_child_init, 1154 proc_mutex_fcntl_perms_set, 1155 APR_LOCK_FCNTL, 1156 "fcntl" 1157}; 1158 1159#endif /* fcntl implementation */ 1160 1161#if APR_HAS_FLOCK_SERIALIZE 1162 1163static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *); 1164 1165static apr_status_t proc_mutex_flock_cleanup(void *mutex_) 1166{ 1167 apr_status_t status = APR_SUCCESS; 1168 apr_proc_mutex_t *mutex=mutex_; 1169 1170 if (mutex->curr_locked == 1) { 1171 status = proc_mutex_flock_release(mutex); 1172 if (status != APR_SUCCESS) 1173 return status; 1174 } 1175 if (mutex->interproc) { /* if it was opened properly */ 1176 status = apr_file_close(mutex->interproc); 1177 } 1178 if (!mutex->interproc_closing 1179 && mutex->os.crossproc != -1 1180 && close(mutex->os.crossproc) == -1 1181 && status == APR_SUCCESS) { 1182 status = errno; 1183 } 1184 if (mutex->fname) { 1185 unlink(mutex->fname); 1186 } 1187 return status; 1188} 1189 1190static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex, 1191 const char *fname) 1192{ 1193 int rv; 1194 1195 if (fname) { 1196 new_mutex->fname = apr_pstrdup(new_mutex->pool, fname); 1197 rv = apr_file_open(&new_mutex->interproc, new_mutex->fname, 1198 APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, 1199 APR_UREAD | APR_UWRITE, 1200 new_mutex->pool); 1201 } 1202 else { 1203 new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX"); 1204 rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname, 1205 APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL, 1206 new_mutex->pool); 1207 } 1208 1209 if (rv != APR_SUCCESS) { 1210 proc_mutex_flock_cleanup(new_mutex); 1211 return rv; 1212 } 1213 1214 new_mutex->os.crossproc = new_mutex->interproc->filedes; 1215 new_mutex->interproc_closing = 1; 1216 new_mutex->curr_locked = 0; 1217 apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex, 1218 apr_proc_mutex_cleanup, 1219 apr_pool_cleanup_null); 1220 return APR_SUCCESS; 1221} 1222 1223static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex) 1224{ 1225 int rc; 1226 1227 do { 1228 rc = flock(mutex->os.crossproc, LOCK_EX); 1229 } while (rc < 0 && errno == EINTR); 1230 if (rc < 0) { 1231 return errno; 1232 } 1233 mutex->curr_locked = 1; 1234 return APR_SUCCESS; 1235} 1236 1237static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex) 1238{ 1239 int rc; 1240 1241 do { 1242 rc = flock(mutex->os.crossproc, LOCK_EX | LOCK_NB); 1243 } while (rc < 0 && errno == EINTR); 1244 if (rc < 0) { 1245 if (errno == EWOULDBLOCK || errno == EAGAIN) { 1246 return APR_EBUSY; 1247 } 1248 return errno; 1249 } 1250 mutex->curr_locked = 1; 1251 return APR_SUCCESS; 1252} 1253 1254static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex) 1255{ 1256 int rc; 1257 1258 mutex->curr_locked = 0; 1259 do { 1260 rc = flock(mutex->os.crossproc, LOCK_UN); 1261 } while (rc < 0 && errno == EINTR); 1262 if (rc < 0) { 1263 return errno; 1264 } 1265 return APR_SUCCESS; 1266} 1267 1268static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex, 1269 apr_pool_t *pool, 1270 const char *fname) 1271{ 1272 apr_proc_mutex_t *new_mutex; 1273 int rv; 1274 1275 if (!fname) { 1276 fname = (*mutex)->fname; 1277 if (!fname) { 1278 return APR_SUCCESS; 1279 } 1280 } 1281 1282 new_mutex = (apr_proc_mutex_t *)apr_pmemdup(pool, *mutex, 1283 sizeof(apr_proc_mutex_t)); 1284 new_mutex->pool = pool; 1285 new_mutex->fname = apr_pstrdup(pool, fname); 1286 rv = apr_file_open(&new_mutex->interproc, new_mutex->fname, 1287 APR_FOPEN_WRITE, 0, new_mutex->pool); 1288 if (rv != APR_SUCCESS) { 1289 return rv; 1290 } 1291 new_mutex->os.crossproc = new_mutex->interproc->filedes; 1292 new_mutex->interproc_closing = 1; 1293 1294 *mutex = new_mutex; 1295 return APR_SUCCESS; 1296} 1297 1298static apr_status_t proc_mutex_flock_perms_set(apr_proc_mutex_t *mutex, 1299 apr_fileperms_t perms, 1300 apr_uid_t uid, 1301 apr_gid_t gid) 1302{ 1303 1304 if (mutex->fname) { 1305 if (!(perms & APR_FPROT_GSETID)) 1306 gid = -1; 1307 if (fchown(mutex->os.crossproc, uid, gid) < 0) { 1308 return errno; 1309 } 1310 } 1311 return APR_SUCCESS; 1312} 1313 1314static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods = 1315{ 1316#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL) 1317 APR_PROCESS_LOCK_MECH_IS_GLOBAL, 1318#else 1319 0, 1320#endif 1321 proc_mutex_flock_create, 1322 proc_mutex_flock_acquire, 1323 proc_mutex_flock_tryacquire, 1324 proc_mutex_spinsleep_timedacquire, 1325 proc_mutex_flock_release, 1326 proc_mutex_flock_cleanup, 1327 proc_mutex_flock_child_init, 1328 proc_mutex_flock_perms_set, 1329 APR_LOCK_FLOCK, 1330 "flock" 1331}; 1332 1333#endif /* flock implementation */ 1334 1335void apr_proc_mutex_unix_setup_lock(void) 1336{ 1337 /* setup only needed for sysvsem and fnctl */ 1338#if APR_HAS_SYSVSEM_SERIALIZE 1339 proc_mutex_sysv_setup(); 1340#endif 1341#if APR_HAS_FCNTL_SERIALIZE 1342 proc_mutex_fcntl_setup(); 1343#endif 1344} 1345 1346static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, 1347 apr_lockmech_e mech, 1348 apr_os_proc_mutex_t *ospmutex) 1349{ 1350#if APR_HAS_PROC_PTHREAD_SERIALIZE 1351 new_mutex->os.pthread_interproc = NULL; 1352#endif 1353#if APR_HAS_POSIXSEM_SERIALIZE 1354 new_mutex->os.psem_interproc = NULL; 1355#endif 1356#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE 1357 new_mutex->os.crossproc = -1; 1358 1359#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE 1360 new_mutex->interproc = NULL; 1361 new_mutex->interproc_closing = 0; 1362#endif 1363#endif 1364 1365 switch (mech) { 1366 case APR_LOCK_FCNTL: 1367#if APR_HAS_FCNTL_SERIALIZE 1368 new_mutex->meth = &mutex_fcntl_methods; 1369 if (ospmutex) { 1370 if (ospmutex->crossproc == -1) { 1371 return APR_EINVAL; 1372 } 1373 new_mutex->os.crossproc = ospmutex->crossproc; 1374 } 1375#else 1376 return APR_ENOTIMPL; 1377#endif 1378 break; 1379 case APR_LOCK_FLOCK: 1380#if APR_HAS_FLOCK_SERIALIZE 1381 new_mutex->meth = &mutex_flock_methods; 1382 if (ospmutex) { 1383 if (ospmutex->crossproc == -1) { 1384 return APR_EINVAL; 1385 } 1386 new_mutex->os.crossproc = ospmutex->crossproc; 1387 } 1388#else 1389 return APR_ENOTIMPL; 1390#endif 1391 break; 1392 case APR_LOCK_SYSVSEM: 1393#if APR_HAS_SYSVSEM_SERIALIZE 1394 new_mutex->meth = &mutex_sysv_methods; 1395 if (ospmutex) { 1396 if (ospmutex->crossproc == -1) { 1397 return APR_EINVAL; 1398 } 1399 new_mutex->os.crossproc = ospmutex->crossproc; 1400 } 1401#else 1402 return APR_ENOTIMPL; 1403#endif 1404 break; 1405 case APR_LOCK_POSIXSEM: 1406#if APR_HAS_POSIXSEM_SERIALIZE 1407 new_mutex->meth = &mutex_posixsem_methods; 1408 if (ospmutex) { 1409 if (ospmutex->psem_interproc == NULL) { 1410 return APR_EINVAL; 1411 } 1412 new_mutex->os.psem_interproc = ospmutex->psem_interproc; 1413 } 1414#else 1415 return APR_ENOTIMPL; 1416#endif 1417 break; 1418 case APR_LOCK_PROC_PTHREAD: 1419#if APR_HAS_PROC_PTHREAD_SERIALIZE 1420 new_mutex->meth = &mutex_proc_pthread_methods; 1421 if (ospmutex) { 1422 if (ospmutex->pthread_interproc == NULL) { 1423 return APR_EINVAL; 1424 } 1425 new_mutex->os.pthread_interproc = ospmutex->pthread_interproc; 1426 } 1427#else 1428 return APR_ENOTIMPL; 1429#endif 1430 break; 1431 case APR_LOCK_DEFAULT_TIMED: 1432#if APR_HAS_PROC_PTHREAD_SERIALIZE \ 1433 && (APR_USE_PROC_PTHREAD_MUTEX_COND \ 1434 || defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) \ 1435 && defined(HAVE_PTHREAD_MUTEX_ROBUST) 1436#if APR_USE_PROC_PTHREAD_MUTEX_COND 1437 new_mutex->meth = &mutex_proc_pthread_cond_methods; 1438#else 1439 new_mutex->meth = &mutex_proc_pthread_methods; 1440#endif 1441 if (ospmutex) { 1442 if (ospmutex->pthread_interproc == NULL) { 1443 return APR_EINVAL; 1444 } 1445 new_mutex->os.pthread_interproc = ospmutex->pthread_interproc; 1446 } 1447 break; 1448#elif APR_HAS_SYSVSEM_SERIALIZE && defined(HAVE_SEMTIMEDOP) 1449 new_mutex->meth = &mutex_sysv_methods; 1450 if (ospmutex) { 1451 if (ospmutex->crossproc == -1) { 1452 return APR_EINVAL; 1453 } 1454 new_mutex->os.crossproc = ospmutex->crossproc; 1455 } 1456 break; 1457#elif APR_HAS_POSIXSEM_SERIALIZE && defined(HAVE_SEM_TIMEDWAIT) 1458 new_mutex->meth = &mutex_posixsem_methods; 1459 if (ospmutex) { 1460 if (ospmutex->psem_interproc == NULL) { 1461 return APR_EINVAL; 1462 } 1463 new_mutex->os.psem_interproc = ospmutex->psem_interproc; 1464 } 1465 break; 1466#endif 1467 /* fall trough */ 1468 case APR_LOCK_DEFAULT: 1469#if APR_USE_FLOCK_SERIALIZE 1470 new_mutex->meth = &mutex_flock_methods; 1471 if (ospmutex) { 1472 if (ospmutex->crossproc == -1) { 1473 return APR_EINVAL; 1474 } 1475 new_mutex->os.crossproc = ospmutex->crossproc; 1476 } 1477#elif APR_USE_SYSVSEM_SERIALIZE 1478 new_mutex->meth = &mutex_sysv_methods; 1479 if (ospmutex) { 1480 if (ospmutex->crossproc == -1) { 1481 return APR_EINVAL; 1482 } 1483 new_mutex->os.crossproc = ospmutex->crossproc; 1484 } 1485#elif APR_USE_FCNTL_SERIALIZE 1486 new_mutex->meth = &mutex_fcntl_methods; 1487 if (ospmutex) { 1488 if (ospmutex->crossproc == -1) { 1489 return APR_EINVAL; 1490 } 1491 new_mutex->os.crossproc = ospmutex->crossproc; 1492 } 1493#elif APR_USE_PROC_PTHREAD_SERIALIZE 1494 new_mutex->meth = &mutex_proc_pthread_methods; 1495 if (ospmutex) { 1496 if (ospmutex->pthread_interproc == NULL) { 1497 return APR_EINVAL; 1498 } 1499 new_mutex->os.pthread_interproc = ospmutex->pthread_interproc; 1500 } 1501#elif APR_USE_POSIXSEM_SERIALIZE 1502 new_mutex->meth = &mutex_posixsem_methods; 1503 if (ospmutex) { 1504 if (ospmutex->psem_interproc == NULL) { 1505 return APR_EINVAL; 1506 } 1507 new_mutex->os.psem_interproc = ospmutex->psem_interproc; 1508 } 1509#else 1510 return APR_ENOTIMPL; 1511#endif 1512 break; 1513 default: 1514 return APR_ENOTIMPL; 1515 } 1516 return APR_SUCCESS; 1517} 1518 1519APR_DECLARE(const char *) apr_proc_mutex_defname(void) 1520{ 1521 apr_status_t rv; 1522 apr_proc_mutex_t mutex; 1523 1524 if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT, 1525 NULL)) != APR_SUCCESS) { 1526 return "unknown"; 1527 } 1528 1529 return apr_proc_mutex_name(&mutex); 1530} 1531 1532static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname) 1533{ 1534 apr_status_t rv; 1535 1536 if ((rv = proc_mutex_choose_method(new_mutex, mech, 1537 NULL)) != APR_SUCCESS) { 1538 return rv; 1539 } 1540 1541 if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) { 1542 return rv; 1543 } 1544 1545 return APR_SUCCESS; 1546} 1547 1548APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, 1549 const char *fname, 1550 apr_lockmech_e mech, 1551 apr_pool_t *pool) 1552{ 1553 apr_proc_mutex_t *new_mutex; 1554 apr_status_t rv; 1555 1556 new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); 1557 new_mutex->pool = pool; 1558 1559 if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS) 1560 return rv; 1561 1562 *mutex = new_mutex; 1563 return APR_SUCCESS; 1564} 1565 1566APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex, 1567 const char *fname, 1568 apr_pool_t *pool) 1569{ 1570 return (*mutex)->meth->child_init(mutex, pool, fname); 1571} 1572 1573APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) 1574{ 1575 return mutex->meth->acquire(mutex); 1576} 1577 1578APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) 1579{ 1580 return mutex->meth->tryacquire(mutex); 1581} 1582 1583APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, 1584 apr_interval_time_t timeout) 1585{ 1586#if APR_HAS_TIMEDLOCKS 1587 return mutex->meth->timedacquire(mutex, timeout); 1588#else 1589 return APR_ENOTIMPL; 1590#endif 1591} 1592 1593APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) 1594{ 1595 return mutex->meth->release(mutex); 1596} 1597 1598APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex) 1599{ 1600 return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex); 1601} 1602 1603APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex) 1604{ 1605 return mutex->meth->mech; 1606} 1607 1608APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex) 1609{ 1610 return mutex->meth->name; 1611} 1612 1613APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex) 1614{ 1615 /* POSIX sems use the fname field but don't use a file, 1616 * so be careful. */ 1617#if APR_HAS_FLOCK_SERIALIZE 1618 if (mutex->meth == &mutex_flock_methods) { 1619 return mutex->fname; 1620 } 1621#endif 1622#if APR_HAS_FCNTL_SERIALIZE 1623 if (mutex->meth == &mutex_fcntl_methods) { 1624 return mutex->fname; 1625 } 1626#endif 1627 return NULL; 1628} 1629 1630APR_PERMS_SET_IMPLEMENT(proc_mutex) 1631{ 1632 apr_proc_mutex_t *mutex = (apr_proc_mutex_t *)theproc_mutex; 1633 return mutex->meth->perms_set(mutex, perms, uid, gid); 1634} 1635 1636APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex) 1637 1638/* Implement OS-specific accessors defined in apr_portable.h */ 1639 1640APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, 1641 apr_proc_mutex_t *pmutex, 1642 apr_lockmech_e *mech) 1643{ 1644 *ospmutex = pmutex->os; 1645 if (mech) { 1646 *mech = pmutex->meth->mech; 1647 } 1648 return APR_SUCCESS; 1649} 1650 1651APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex, 1652 apr_proc_mutex_t *pmutex) 1653{ 1654 return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL); 1655} 1656 1657APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex, 1658 apr_os_proc_mutex_t *ospmutex, 1659 apr_lockmech_e mech, 1660 int register_cleanup, 1661 apr_pool_t *pool) 1662{ 1663 apr_status_t rv; 1664 if (pool == NULL) { 1665 return APR_ENOPOOL; 1666 } 1667 1668 if ((*pmutex) == NULL) { 1669 (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool, 1670 sizeof(apr_proc_mutex_t)); 1671 (*pmutex)->pool = pool; 1672 } 1673 rv = proc_mutex_choose_method(*pmutex, mech, ospmutex); 1674#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE 1675 if (rv == APR_SUCCESS) { 1676 rv = apr_os_file_put(&(*pmutex)->interproc, &(*pmutex)->os.crossproc, 1677 0, pool); 1678 } 1679#endif 1680 1681 if (rv == APR_SUCCESS && register_cleanup) { 1682 apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup, 1683 apr_pool_cleanup_null); 1684 } 1685 return rv; 1686} 1687 1688APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex, 1689 apr_os_proc_mutex_t *ospmutex, 1690 apr_pool_t *pool) 1691{ 1692 return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT, 1693 0, pool); 1694} 1695 1696