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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "apr_strings.h"
19 #include "apr_arch_proc_mutex.h"
20 #include "apr_arch_file_io.h" /* for apr_mkstemp() */
22 #include "apr_atomic.h"
24 APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
26 return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup);
29 #if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \
30 APR_HAS_SYSVSEM_SERIALIZE
31 static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex,
39 #if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_PROC_PTHREAD_SERIALIZE
40 static apr_status_t proc_mutex_no_perms_set(apr_proc_mutex_t *mutex,
41 apr_fileperms_t perms,
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))
58 static apr_status_t proc_mutex_spinsleep_timedacquire(apr_proc_mutex_t *mutex,
59 apr_interval_time_t timeout)
61 #define SLEEP_TIME apr_time_from_msec(10)
64 rv = apr_proc_mutex_trylock(mutex);
65 if (!APR_STATUS_IS_EBUSY(rv)) {
66 if (rv == APR_SUCCESS) {
67 mutex->curr_locked = 1;
75 if (timeout > SLEEP_TIME) {
76 apr_sleep(SLEEP_TIME);
77 timeout -= SLEEP_TIME;
88 #if APR_HAS_POSIXSEM_SERIALIZE
91 #define SEM_FAILED (-1)
94 static apr_status_t proc_mutex_posix_cleanup(void *mutex_)
96 apr_proc_mutex_t *mutex = mutex_;
98 if (sem_close(mutex->os.psem_interproc) < 0) {
105 static 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;
113 retval = retval * a + (*p);
120 static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex,
123 #define APR_POSIXSEM_NAME_MIN 13
128 * This bogusness is to follow what appears to be the
129 * lowest common denominator in Posix semaphore naming:
131 * - be at most 14 chars
132 * - be unique and not match anything on the filesystem
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.
140 * To make this as robust as possible, we initially try something
141 * larger (and hopefully more unique) and gracefully fail down to the
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.
150 apr_ssize_t flen = strlen(fname);
151 char *p = apr_pstrndup(new_mutex->pool, fname, strlen(fname));
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);
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);
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';
176 psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
177 } while (psem == (sem_t *)SEM_FAILED && errno == EINTR);
180 if (psem == (sem_t *)SEM_FAILED) {
183 /* Ahhh. The joys of Posix sems. Predelete it... */
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);
193 static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex)
198 rc = sem_wait(mutex->os.psem_interproc);
199 } while (rc < 0 && errno == EINTR);
203 mutex->curr_locked = 1;
207 static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex)
212 rc = sem_trywait(mutex->os.psem_interproc);
213 } while (rc < 0 && errno == EINTR);
215 if (errno == EAGAIN) {
220 mutex->curr_locked = 1;
224 #if defined(HAVE_SEM_TIMEDWAIT)
225 static apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex,
226 apr_interval_time_t timeout)
229 apr_status_t rv = proc_mutex_posix_tryacquire(mutex);
230 return (rv == APR_EBUSY) ? APR_TIMEUP : rv;
234 struct timespec abstime;
236 timeout += apr_time_now();
237 abstime.tv_sec = apr_time_sec(timeout);
238 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
241 rc = sem_timedwait(mutex->os.psem_interproc, &abstime);
242 } while (rc < 0 && errno == EINTR);
244 if (errno == ETIMEDOUT) {
250 mutex->curr_locked = 1;
255 static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
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. */
266 static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
268 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL)
269 APR_PROCESS_LOCK_MECH_IS_GLOBAL,
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,
279 proc_mutex_spinsleep_timedacquire,
281 proc_mutex_posix_release,
282 proc_mutex_posix_cleanup,
283 proc_mutex_no_child_init,
284 proc_mutex_no_perms_set,
289 #endif /* Posix sem implementation */
291 #if APR_HAS_SYSVSEM_SERIALIZE
293 static struct sembuf proc_mutex_op_on;
294 static struct sembuf proc_mutex_op_try;
295 static struct sembuf proc_mutex_op_off;
297 static void proc_mutex_sysv_setup(void)
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;
310 static apr_status_t proc_mutex_sysv_cleanup(void *mutex_)
312 apr_proc_mutex_t *mutex=mutex_;
315 if (mutex->os.crossproc != -1) {
317 semctl(mutex->os.crossproc, 0, IPC_RMID, ick);
322 static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex,
328 new_mutex->os.crossproc = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
329 if (new_mutex->os.crossproc == -1) {
331 proc_mutex_sysv_cleanup(new_mutex);
335 if (semctl(new_mutex->os.crossproc, 0, SETVAL, ick) < 0) {
337 proc_mutex_sysv_cleanup(new_mutex);
338 new_mutex->os.crossproc = -1;
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);
348 static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex)
353 rc = semop(mutex->os.crossproc, &proc_mutex_op_on, 1);
354 } while (rc < 0 && errno == EINTR);
358 mutex->curr_locked = 1;
362 static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex)
367 rc = semop(mutex->os.crossproc, &proc_mutex_op_try, 1);
368 } while (rc < 0 && errno == EINTR);
370 if (errno == EAGAIN) {
375 mutex->curr_locked = 1;
379 #if defined(HAVE_SEMTIMEDOP)
380 static apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex,
381 apr_interval_time_t timeout)
384 apr_status_t rv = proc_mutex_sysv_tryacquire(mutex);
385 return (rv == APR_EBUSY) ? APR_TIMEUP : rv;
389 struct timespec reltime;
391 reltime.tv_sec = apr_time_sec(timeout);
392 reltime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
395 rc = semtimedop(mutex->os.crossproc, &proc_mutex_op_on, 1,
397 } while (rc < 0 && errno == EINTR);
399 if (errno == EAGAIN) {
405 mutex->curr_locked = 1;
410 static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
414 mutex->curr_locked = 0;
416 rc = semop(mutex->os.crossproc, &proc_mutex_op_off, 1);
417 } while (rc < 0 && errno == EINTR);
424 static apr_status_t proc_mutex_sysv_perms_set(apr_proc_mutex_t *mutex,
425 apr_fileperms_t perms,
432 buf.sem_perm.uid = uid;
433 buf.sem_perm.gid = gid;
434 buf.sem_perm.mode = apr_unix_perms2mode(perms);
436 if (semctl(mutex->os.crossproc, 0, IPC_SET, ick) < 0) {
442 static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
444 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL)
445 APR_PROCESS_LOCK_MECH_IS_GLOBAL,
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,
455 proc_mutex_spinsleep_timedacquire,
457 proc_mutex_sysv_release,
458 proc_mutex_sysv_cleanup,
459 proc_mutex_no_child_init,
460 proc_mutex_sysv_perms_set,
465 #endif /* SysV sem implementation */
467 #if APR_HAS_PROC_PTHREAD_SERIALIZE
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))
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
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
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;
509 static APR_INLINE int proc_pthread_mutex_inc(apr_proc_mutex_t *mutex)
511 if (mutex->pthread_refcounting) {
512 apr_atomic_inc32(&proc_pthread_mutex_refcount(mutex));
518 static APR_INLINE int proc_pthread_mutex_dec(apr_proc_mutex_t *mutex)
520 if (mutex->pthread_refcounting) {
521 return apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex));
526 static apr_status_t proc_pthread_mutex_unref(void *mutex_)
528 apr_proc_mutex_t *mutex=mutex_;
531 #if APR_USE_PROC_PTHREAD_MUTEX_COND
532 if (proc_pthread_mutex_is_cond(mutex)) {
533 mutex->curr_locked = 0;
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
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
554 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
556 if ((rv = pthread_mutex_destroy(&proc_pthread_mutex(mutex)))) {
557 #ifdef HAVE_ZOS_PTHREADS
566 static apr_status_t proc_mutex_pthread_cleanup(void *mutex_)
568 apr_proc_mutex_t *mutex=mutex_;
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))) {
577 if (munmap(mutex->os.pthread_interproc, sizeof(proc_pthread_mutex_t))) {
583 static apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex,
588 pthread_mutexattr_t mattr;
590 fd = open("/dev/zero", O_RDWR);
595 new_mutex->os.pthread_interproc = mmap(NULL, sizeof(proc_pthread_mutex_t),
596 PROT_READ | PROT_WRITE, MAP_SHARED,
598 if (new_mutex->os.pthread_interproc == MAP_FAILED) {
599 new_mutex->os.pthread_interproc = NULL;
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;
612 if ((rv = pthread_mutexattr_init(&mattr))) {
613 #ifdef HAVE_ZOS_PTHREADS
616 proc_mutex_pthread_cleanup(new_mutex);
619 if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) {
620 #ifdef HAVE_ZOS_PTHREADS
623 proc_mutex_pthread_cleanup(new_mutex);
624 pthread_mutexattr_destroy(&mattr);
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);
632 rv = pthread_mutexattr_setrobust_np(&mattr, PTHREAD_MUTEX_ROBUST_NP);
635 #ifdef HAVE_ZOS_PTHREADS
638 proc_mutex_pthread_cleanup(new_mutex);
639 pthread_mutexattr_destroy(&mattr);
642 if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) {
643 #ifdef HAVE_ZOS_PTHREADS
646 proc_mutex_pthread_cleanup(new_mutex);
647 pthread_mutexattr_destroy(&mattr);
650 #endif /* HAVE_PTHREAD_MUTEX_ROBUST[_NP] */
652 if ((rv = pthread_mutex_init(&proc_pthread_mutex(new_mutex), &mattr))) {
653 #ifdef HAVE_ZOS_PTHREADS
656 proc_mutex_pthread_cleanup(new_mutex);
657 pthread_mutexattr_destroy(&mattr);
661 proc_pthread_mutex_refcount(new_mutex) = 1; /* first/parent reference */
662 new_mutex->curr_locked = 0; /* mutex created now */
664 if ((rv = pthread_mutexattr_destroy(&mattr))) {
665 #ifdef HAVE_ZOS_PTHREADS
668 proc_mutex_pthread_cleanup(new_mutex);
672 apr_pool_cleanup_register(new_mutex->pool,
674 apr_proc_mutex_cleanup,
675 apr_pool_cleanup_null);
679 static apr_status_t proc_mutex_pthread_child_init(apr_proc_mutex_t **mutex,
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);
691 static apr_status_t proc_mutex_pthread_acquire_ex(apr_proc_mutex_t *mutex,
692 apr_interval_time_t timeout)
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
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));
709 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
717 if (!proc_pthread_mutex_cond_locked(mutex)) {
724 struct timespec abstime;
727 timeout += apr_time_now();
728 abstime.tv_sec = apr_time_sec(timeout);
729 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
732 proc_pthread_mutex_cond_num_waiters(mutex)++;
735 rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex),
736 &proc_pthread_mutex(mutex));
738 #ifdef HAVE_ZOS_PTHREADS
745 rv = pthread_cond_timedwait(&proc_pthread_mutex_cond(mutex),
746 &proc_pthread_mutex(mutex),
749 #ifdef HAVE_ZOS_PTHREADS
752 if (rv == ETIMEDOUT) {
758 } while (proc_pthread_mutex_cond_locked(mutex));
759 proc_pthread_mutex_cond_num_waiters(mutex)--;
761 if (rv != APR_SUCCESS) {
762 pthread_mutex_unlock(&proc_pthread_mutex(mutex));
766 proc_pthread_mutex_cond_locked(mutex) = 1;
768 rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex));
770 #ifdef HAVE_ZOS_PTHREADS
777 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
780 rv = pthread_mutex_lock(&proc_pthread_mutex(mutex));
782 #ifdef HAVE_ZOS_PTHREADS
788 rv = pthread_mutex_trylock(&proc_pthread_mutex(mutex));
790 #ifdef HAVE_ZOS_PTHREADS
799 #if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
801 struct timespec abstime;
803 timeout += apr_time_now();
804 abstime.tv_sec = apr_time_sec(timeout);
805 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
807 rv = pthread_mutex_timedlock(&proc_pthread_mutex(mutex), &abstime);
809 #ifdef HAVE_ZOS_PTHREADS
812 if (rv == ETIMEDOUT) {
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));
825 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
832 #else /* !HAVE_PTHREAD_MUTEX_TIMEDLOCK */
833 return proc_mutex_spinsleep_timedacquire(mutex, timeout);
837 mutex->curr_locked = 1;
841 static apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex)
843 return proc_mutex_pthread_acquire_ex(mutex, -1);
846 static apr_status_t proc_mutex_pthread_tryacquire(apr_proc_mutex_t *mutex)
848 apr_status_t rv = proc_mutex_pthread_acquire_ex(mutex, 0);
849 return (rv == APR_TIMEUP) ? APR_EBUSY : rv;
852 static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex,
853 apr_interval_time_t timeout)
855 return proc_mutex_pthread_acquire_ex(mutex, (timeout <= 0) ? 0 : timeout);
858 static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex)
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
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));
875 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
883 if (!proc_pthread_mutex_cond_locked(mutex)) {
886 else if (!proc_pthread_mutex_cond_num_waiters(mutex)) {
890 rv = pthread_cond_signal(&proc_pthread_mutex_cond(mutex));
891 #ifdef HAVE_ZOS_PTHREADS
897 if (rv != APR_SUCCESS) {
898 pthread_mutex_unlock(&proc_pthread_mutex(mutex));
902 proc_pthread_mutex_cond_locked(mutex) = 0;
904 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
906 mutex->curr_locked = 0;
907 if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
908 #ifdef HAVE_ZOS_PTHREADS
917 static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
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,
932 #if APR_USE_PROC_PTHREAD_MUTEX_COND
933 static apr_status_t proc_mutex_pthread_cond_create(apr_proc_mutex_t *new_mutex,
937 pthread_condattr_t cattr;
939 rv = proc_mutex_pthread_create(new_mutex, fname);
940 if (rv != APR_SUCCESS) {
944 if ((rv = pthread_condattr_init(&cattr))) {
945 #ifdef HAVE_ZOS_PTHREADS
948 apr_pool_cleanup_run(new_mutex->pool, new_mutex,
949 apr_proc_mutex_cleanup);
952 if ((rv = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))) {
953 #ifdef HAVE_ZOS_PTHREADS
956 pthread_condattr_destroy(&cattr);
957 apr_pool_cleanup_run(new_mutex->pool, new_mutex,
958 apr_proc_mutex_cleanup);
961 if ((rv = pthread_cond_init(&proc_pthread_mutex_cond(new_mutex),
963 #ifdef HAVE_ZOS_PTHREADS
966 pthread_condattr_destroy(&cattr);
967 apr_pool_cleanup_run(new_mutex->pool, new_mutex,
968 apr_proc_mutex_cleanup);
971 pthread_condattr_destroy(&cattr);
973 proc_pthread_mutex_cond_locked(new_mutex) = 0;
974 proc_pthread_mutex_cond_num_waiters(new_mutex) = 0;
979 static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_cond_methods =
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,
997 #if APR_HAS_FCNTL_SERIALIZE
999 static struct flock proc_mutex_lock_it;
1000 static struct flock proc_mutex_unlock_it;
1002 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
1004 static void proc_mutex_fcntl_setup(void)
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 */
1018 static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_)
1020 apr_status_t status = APR_SUCCESS;
1021 apr_proc_mutex_t *mutex=mutex_;
1023 if (mutex->curr_locked == 1) {
1024 status = proc_mutex_fcntl_release(mutex);
1025 if (status != APR_SUCCESS)
1029 if (mutex->interproc) {
1030 status = apr_file_close(mutex->interproc);
1032 if (!mutex->interproc_closing
1033 && mutex->os.crossproc != -1
1034 && close(mutex->os.crossproc) == -1
1035 && status == APR_SUCCESS) {
1041 static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex,
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,
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,
1060 if (rv != APR_SUCCESS) {
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,
1070 apr_proc_mutex_cleanup,
1071 apr_pool_cleanup_null);
1075 static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex)
1080 rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_lock_it);
1081 } while (rc < 0 && errno == EINTR);
1085 mutex->curr_locked=1;
1089 static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex)
1094 rc = fcntl(mutex->os.crossproc, F_SETLK, &proc_mutex_lock_it);
1095 } while (rc < 0 && errno == EINTR);
1097 #if FCNTL_TRYACQUIRE_EACCES
1098 if (errno == EACCES) {
1100 if (errno == EAGAIN) {
1106 mutex->curr_locked = 1;
1110 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
1114 mutex->curr_locked=0;
1116 rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_unlock_it);
1117 } while (rc < 0 && errno == EINTR);
1124 static apr_status_t proc_mutex_fcntl_perms_set(apr_proc_mutex_t *mutex,
1125 apr_fileperms_t perms,
1131 if (!(perms & APR_FPROT_GSETID))
1133 if (fchown(mutex->os.crossproc, uid, gid) < 0) {
1140 static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
1142 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL)
1143 APR_PROCESS_LOCK_MECH_IS_GLOBAL,
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,
1159 #endif /* fcntl implementation */
1161 #if APR_HAS_FLOCK_SERIALIZE
1163 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
1165 static apr_status_t proc_mutex_flock_cleanup(void *mutex_)
1167 apr_status_t status = APR_SUCCESS;
1168 apr_proc_mutex_t *mutex=mutex_;
1170 if (mutex->curr_locked == 1) {
1171 status = proc_mutex_flock_release(mutex);
1172 if (status != APR_SUCCESS)
1175 if (mutex->interproc) { /* if it was opened properly */
1176 status = apr_file_close(mutex->interproc);
1178 if (!mutex->interproc_closing
1179 && mutex->os.crossproc != -1
1180 && close(mutex->os.crossproc) == -1
1181 && status == APR_SUCCESS) {
1185 unlink(mutex->fname);
1190 static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex,
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,
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,
1209 if (rv != APR_SUCCESS) {
1210 proc_mutex_flock_cleanup(new_mutex);
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);
1223 static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex)
1228 rc = flock(mutex->os.crossproc, LOCK_EX);
1229 } while (rc < 0 && errno == EINTR);
1233 mutex->curr_locked = 1;
1237 static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex)
1242 rc = flock(mutex->os.crossproc, LOCK_EX | LOCK_NB);
1243 } while (rc < 0 && errno == EINTR);
1245 if (errno == EWOULDBLOCK || errno == EAGAIN) {
1250 mutex->curr_locked = 1;
1254 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
1258 mutex->curr_locked = 0;
1260 rc = flock(mutex->os.crossproc, LOCK_UN);
1261 } while (rc < 0 && errno == EINTR);
1268 static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex,
1272 apr_proc_mutex_t *new_mutex;
1276 fname = (*mutex)->fname;
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) {
1291 new_mutex->os.crossproc = new_mutex->interproc->filedes;
1292 new_mutex->interproc_closing = 1;
1298 static apr_status_t proc_mutex_flock_perms_set(apr_proc_mutex_t *mutex,
1299 apr_fileperms_t perms,
1305 if (!(perms & APR_FPROT_GSETID))
1307 if (fchown(mutex->os.crossproc, uid, gid) < 0) {
1314 static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
1316 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL)
1317 APR_PROCESS_LOCK_MECH_IS_GLOBAL,
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,
1333 #endif /* flock implementation */
1335 void apr_proc_mutex_unix_setup_lock(void)
1337 /* setup only needed for sysvsem and fnctl */
1338 #if APR_HAS_SYSVSEM_SERIALIZE
1339 proc_mutex_sysv_setup();
1341 #if APR_HAS_FCNTL_SERIALIZE
1342 proc_mutex_fcntl_setup();
1346 static 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)
1350 #if APR_HAS_PROC_PTHREAD_SERIALIZE
1351 new_mutex->os.pthread_interproc = NULL;
1353 #if APR_HAS_POSIXSEM_SERIALIZE
1354 new_mutex->os.psem_interproc = NULL;
1356 #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
1357 new_mutex->os.crossproc = -1;
1359 #if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
1360 new_mutex->interproc = NULL;
1361 new_mutex->interproc_closing = 0;
1366 case APR_LOCK_FCNTL:
1367 #if APR_HAS_FCNTL_SERIALIZE
1368 new_mutex->meth = &mutex_fcntl_methods;
1370 if (ospmutex->crossproc == -1) {
1373 new_mutex->os.crossproc = ospmutex->crossproc;
1376 return APR_ENOTIMPL;
1379 case APR_LOCK_FLOCK:
1380 #if APR_HAS_FLOCK_SERIALIZE
1381 new_mutex->meth = &mutex_flock_methods;
1383 if (ospmutex->crossproc == -1) {
1386 new_mutex->os.crossproc = ospmutex->crossproc;
1389 return APR_ENOTIMPL;
1392 case APR_LOCK_SYSVSEM:
1393 #if APR_HAS_SYSVSEM_SERIALIZE
1394 new_mutex->meth = &mutex_sysv_methods;
1396 if (ospmutex->crossproc == -1) {
1399 new_mutex->os.crossproc = ospmutex->crossproc;
1402 return APR_ENOTIMPL;
1405 case APR_LOCK_POSIXSEM:
1406 #if APR_HAS_POSIXSEM_SERIALIZE
1407 new_mutex->meth = &mutex_posixsem_methods;
1409 if (ospmutex->psem_interproc == NULL) {
1412 new_mutex->os.psem_interproc = ospmutex->psem_interproc;
1415 return APR_ENOTIMPL;
1418 case APR_LOCK_PROC_PTHREAD:
1419 #if APR_HAS_PROC_PTHREAD_SERIALIZE
1420 new_mutex->meth = &mutex_proc_pthread_methods;
1422 if (ospmutex->pthread_interproc == NULL) {
1425 new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
1428 return APR_ENOTIMPL;
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;
1439 new_mutex->meth = &mutex_proc_pthread_methods;
1442 if (ospmutex->pthread_interproc == NULL) {
1445 new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
1448 #elif APR_HAS_SYSVSEM_SERIALIZE && defined(HAVE_SEMTIMEDOP)
1449 new_mutex->meth = &mutex_sysv_methods;
1451 if (ospmutex->crossproc == -1) {
1454 new_mutex->os.crossproc = ospmutex->crossproc;
1457 #elif APR_HAS_POSIXSEM_SERIALIZE && defined(HAVE_SEM_TIMEDWAIT)
1458 new_mutex->meth = &mutex_posixsem_methods;
1460 if (ospmutex->psem_interproc == NULL) {
1463 new_mutex->os.psem_interproc = ospmutex->psem_interproc;
1468 case APR_LOCK_DEFAULT:
1469 #if APR_USE_FLOCK_SERIALIZE
1470 new_mutex->meth = &mutex_flock_methods;
1472 if (ospmutex->crossproc == -1) {
1475 new_mutex->os.crossproc = ospmutex->crossproc;
1477 #elif APR_USE_SYSVSEM_SERIALIZE
1478 new_mutex->meth = &mutex_sysv_methods;
1480 if (ospmutex->crossproc == -1) {
1483 new_mutex->os.crossproc = ospmutex->crossproc;
1485 #elif APR_USE_FCNTL_SERIALIZE
1486 new_mutex->meth = &mutex_fcntl_methods;
1488 if (ospmutex->crossproc == -1) {
1491 new_mutex->os.crossproc = ospmutex->crossproc;
1493 #elif APR_USE_PROC_PTHREAD_SERIALIZE
1494 new_mutex->meth = &mutex_proc_pthread_methods;
1496 if (ospmutex->pthread_interproc == NULL) {
1499 new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
1501 #elif APR_USE_POSIXSEM_SERIALIZE
1502 new_mutex->meth = &mutex_posixsem_methods;
1504 if (ospmutex->psem_interproc == NULL) {
1507 new_mutex->os.psem_interproc = ospmutex->psem_interproc;
1510 return APR_ENOTIMPL;
1514 return APR_ENOTIMPL;
1519 APR_DECLARE(const char *) apr_proc_mutex_defname(void)
1522 apr_proc_mutex_t mutex;
1524 if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT,
1525 NULL)) != APR_SUCCESS) {
1529 return apr_proc_mutex_name(&mutex);
1532 static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname)
1536 if ((rv = proc_mutex_choose_method(new_mutex, mech,
1537 NULL)) != APR_SUCCESS) {
1541 if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) {
1548 APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
1550 apr_lockmech_e mech,
1553 apr_proc_mutex_t *new_mutex;
1556 new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
1557 new_mutex->pool = pool;
1559 if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS)
1566 APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
1570 return (*mutex)->meth->child_init(mutex, pool, fname);
1573 APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
1575 return mutex->meth->acquire(mutex);
1578 APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
1580 return mutex->meth->tryacquire(mutex);
1583 APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex,
1584 apr_interval_time_t timeout)
1586 #if APR_HAS_TIMEDLOCKS
1587 return mutex->meth->timedacquire(mutex, timeout);
1589 return APR_ENOTIMPL;
1593 APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
1595 return mutex->meth->release(mutex);
1598 APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
1600 return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
1603 APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex)
1605 return mutex->meth->mech;
1608 APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
1610 return mutex->meth->name;
1613 APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
1615 /* POSIX sems use the fname field but don't use a file,
1617 #if APR_HAS_FLOCK_SERIALIZE
1618 if (mutex->meth == &mutex_flock_methods) {
1619 return mutex->fname;
1622 #if APR_HAS_FCNTL_SERIALIZE
1623 if (mutex->meth == &mutex_fcntl_methods) {
1624 return mutex->fname;
1630 APR_PERMS_SET_IMPLEMENT(proc_mutex)
1632 apr_proc_mutex_t *mutex = (apr_proc_mutex_t *)theproc_mutex;
1633 return mutex->meth->perms_set(mutex, perms, uid, gid);
1636 APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
1638 /* Implement OS-specific accessors defined in apr_portable.h */
1640 APR_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)
1644 *ospmutex = pmutex->os;
1646 *mech = pmutex->meth->mech;
1651 APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
1652 apr_proc_mutex_t *pmutex)
1654 return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL);
1657 APR_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,
1668 if ((*pmutex) == NULL) {
1669 (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool,
1670 sizeof(apr_proc_mutex_t));
1671 (*pmutex)->pool = pool;
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,
1681 if (rv == APR_SUCCESS && register_cleanup) {
1682 apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup,
1683 apr_pool_cleanup_null);
1688 APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
1689 apr_os_proc_mutex_t *ospmutex,
1692 return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT,