]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/apr/locks/unix/proc_mutex.c
Update apr to 1.7.0. See contrib/apr/CHANGES for a summary of changes.
[FreeBSD/FreeBSD.git] / contrib / apr / locks / unix / proc_mutex.c
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
24 APR_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
31 static 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
40 static 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))
58 static 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
94 static 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
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;
110
111    for( ; *p; p++)
112    {
113       retval = retval * a + (*p);
114       a *= b;
115    }
116
117    return retval;
118 }
119
120 static 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
193 static 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
207 static 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)
225 static 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
255 static 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
266 static 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
293 static struct sembuf proc_mutex_op_on;
294 static struct sembuf proc_mutex_op_try;
295 static struct sembuf proc_mutex_op_off;
296
297 static 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
310 static 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
322 static 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
348 static 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
362 static 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)
380 static 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
410 static 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
424 static 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
442 static 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  */
484 typedef 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
509 static 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
518 static 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
526 static 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
566 static 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
583 static 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
679 static 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
691 static 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
841 static apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex)
842 {
843     return proc_mutex_pthread_acquire_ex(mutex, -1);
844 }
845
846 static 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
852 static 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
858 static 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
917 static 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
933 static 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
979 static 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
999 static struct flock proc_mutex_lock_it;
1000 static struct flock proc_mutex_unlock_it;
1001
1002 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
1003
1004 static 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
1018 static 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
1041 static 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
1075 static 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
1089 static 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
1110 static 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
1124 static 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
1140 static 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
1163 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
1164
1165 static 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
1190 static 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
1223 static 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
1237 static 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
1254 static 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
1268 static 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
1298 static 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
1314 static 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
1335 void 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
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)
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
1519 APR_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    
1532 static 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
1548 APR_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
1566 APR_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
1573 APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
1574 {
1575     return mutex->meth->acquire(mutex);
1576 }
1577
1578 APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
1579 {
1580     return mutex->meth->tryacquire(mutex);
1581 }
1582
1583 APR_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
1593 APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
1594 {
1595     return mutex->meth->release(mutex);
1596 }
1597
1598 APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
1599 {
1600     return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
1601 }
1602
1603 APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex)
1604 {
1605     return mutex->meth->mech;
1606 }
1607
1608 APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
1609 {
1610     return mutex->meth->name;
1611 }
1612
1613 APR_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
1630 APR_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
1636 APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
1637
1638 /* Implement OS-specific accessors defined in apr_portable.h */
1639
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)
1643 {
1644     *ospmutex = pmutex->os;
1645     if (mech) {
1646         *mech = pmutex->meth->mech;
1647     }
1648     return APR_SUCCESS;
1649 }
1650
1651 APR_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
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,
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
1688 APR_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