]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr/locks/unix/proc_mutex.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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
23 APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
24 {
25     return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup);
26 }
27
28 #if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \
29     APR_HAS_PROC_PTHREAD_SERIALIZE || APR_HAS_SYSVSEM_SERIALIZE
30 static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex,
31                                              apr_pool_t *cont,
32                                              const char *fname)
33 {
34     return APR_SUCCESS;
35 }
36 #endif    
37
38 #if APR_HAS_POSIXSEM_SERIALIZE
39
40 #ifndef SEM_FAILED
41 #define SEM_FAILED (-1)
42 #endif
43
44 static apr_status_t proc_mutex_posix_cleanup(void *mutex_)
45 {
46     apr_proc_mutex_t *mutex = mutex_;
47     
48     if (sem_close(mutex->psem_interproc) < 0) {
49         return errno;
50     }
51
52     return APR_SUCCESS;
53 }    
54
55 static unsigned int rshash (char *p) {
56     /* hash function from Robert Sedgwicks 'Algorithms in C' book */
57    unsigned int b    = 378551;
58    unsigned int a    = 63689;
59    unsigned int retval = 0;
60
61    for( ; *p; p++)
62    {
63       retval = retval * a + (*p);
64       a *= b;
65    }
66
67    return retval;
68 }
69
70 static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex,
71                                             const char *fname)
72 {
73     #define APR_POSIXSEM_NAME_MIN 13
74     sem_t *psem;
75     char semname[32];
76     
77     new_mutex->interproc = apr_palloc(new_mutex->pool,
78                                       sizeof(*new_mutex->interproc));
79     /*
80      * This bogusness is to follow what appears to be the
81      * lowest common denominator in Posix semaphore naming:
82      *   - start with '/'
83      *   - be at most 14 chars
84      *   - be unique and not match anything on the filesystem
85      *
86      * Because of this, we use fname to generate a (unique) hash
87      * and use that as the name of the semaphore. If no filename was
88      * given, we create one based on the time. We tuck the name
89      * away, since it might be useful for debugging. We use 2 hashing
90      * functions to try to avoid collisions.
91      *
92      * To  make this as robust as possible, we initially try something
93      * larger (and hopefully more unique) and gracefully fail down to the
94      * LCD above.
95      *
96      * NOTE: Darwin (Mac OS X) seems to be the most restrictive
97      * implementation. Versions previous to Darwin 6.2 had the 14
98      * char limit, but later rev's allow up to 31 characters.
99      *
100      */
101     if (fname) {
102         apr_ssize_t flen = strlen(fname);
103         char *p = apr_pstrndup(new_mutex->pool, fname, strlen(fname));
104         unsigned int h1, h2;
105         h1 = apr_hashfunc_default((const char *)p, &flen);
106         h2 = rshash(p);
107         apr_snprintf(semname, sizeof(semname), "/ApR.%xH%x", h1, h2);
108     } else {
109         apr_time_t now;
110         unsigned long sec;
111         unsigned long usec;
112         now = apr_time_now();
113         sec = apr_time_sec(now);
114         usec = apr_time_usec(now);
115         apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec);
116     }
117     psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
118     if (psem == (sem_t *)SEM_FAILED) {
119         if (errno == ENAMETOOLONG) {
120             /* Oh well, good try */
121             semname[APR_POSIXSEM_NAME_MIN] = '\0';
122         } else {
123             return errno;
124         }
125         psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
126     }
127
128     if (psem == (sem_t *)SEM_FAILED) {
129         return errno;
130     }
131     /* Ahhh. The joys of Posix sems. Predelete it... */
132     sem_unlink(semname);
133     new_mutex->psem_interproc = psem;
134     new_mutex->fname = apr_pstrdup(new_mutex->pool, semname);
135     apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
136                               apr_proc_mutex_cleanup, 
137                               apr_pool_cleanup_null);
138     return APR_SUCCESS;
139 }
140
141 static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex)
142 {
143     if (sem_wait(mutex->psem_interproc) < 0) {
144         return errno;
145     }
146     mutex->curr_locked = 1;
147     return APR_SUCCESS;
148 }
149
150 static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex)
151 {
152     if (sem_trywait(mutex->psem_interproc) < 0) {
153         if (errno == EAGAIN) {
154             return APR_EBUSY;
155         }
156         return errno;
157     }
158     mutex->curr_locked = 1;
159     return APR_SUCCESS;
160 }
161
162 static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
163 {
164     mutex->curr_locked = 0;
165     if (sem_post(mutex->psem_interproc) < 0) {
166         /* any failure is probably fatal, so no big deal to leave
167          * ->curr_locked at 0. */
168         return errno;
169     }
170     return APR_SUCCESS;
171 }
172
173 static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
174 {
175 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL)
176     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
177 #else
178     0,
179 #endif
180     proc_mutex_posix_create,
181     proc_mutex_posix_acquire,
182     proc_mutex_posix_tryacquire,
183     proc_mutex_posix_release,
184     proc_mutex_posix_cleanup,
185     proc_mutex_no_child_init,
186     "posixsem"
187 };
188
189 #endif /* Posix sem implementation */
190
191 #if APR_HAS_SYSVSEM_SERIALIZE
192
193 static struct sembuf proc_mutex_op_on;
194 static struct sembuf proc_mutex_op_try;
195 static struct sembuf proc_mutex_op_off;
196
197 static void proc_mutex_sysv_setup(void)
198 {
199     proc_mutex_op_on.sem_num = 0;
200     proc_mutex_op_on.sem_op = -1;
201     proc_mutex_op_on.sem_flg = SEM_UNDO;
202     proc_mutex_op_try.sem_num = 0;
203     proc_mutex_op_try.sem_op = -1;
204     proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT;
205     proc_mutex_op_off.sem_num = 0;
206     proc_mutex_op_off.sem_op = 1;
207     proc_mutex_op_off.sem_flg = SEM_UNDO;
208 }
209
210 static apr_status_t proc_mutex_sysv_cleanup(void *mutex_)
211 {
212     apr_proc_mutex_t *mutex=mutex_;
213     union semun ick;
214     
215     if (mutex->interproc->filedes != -1) {
216         ick.val = 0;
217         semctl(mutex->interproc->filedes, 0, IPC_RMID, ick);
218     }
219     return APR_SUCCESS;
220 }    
221
222 static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex,
223                                            const char *fname)
224 {
225     union semun ick;
226     apr_status_t rv;
227     
228     new_mutex->interproc = apr_palloc(new_mutex->pool, sizeof(*new_mutex->interproc));
229     new_mutex->interproc->filedes = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
230
231     if (new_mutex->interproc->filedes < 0) {
232         rv = errno;
233         proc_mutex_sysv_cleanup(new_mutex);
234         return rv;
235     }
236     ick.val = 1;
237     if (semctl(new_mutex->interproc->filedes, 0, SETVAL, ick) < 0) {
238         rv = errno;
239         proc_mutex_sysv_cleanup(new_mutex);
240         return rv;
241     }
242     new_mutex->curr_locked = 0;
243     apr_pool_cleanup_register(new_mutex->pool,
244                               (void *)new_mutex, apr_proc_mutex_cleanup, 
245                               apr_pool_cleanup_null);
246     return APR_SUCCESS;
247 }
248
249 static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex)
250 {
251     int rc;
252
253     do {
254         rc = semop(mutex->interproc->filedes, &proc_mutex_op_on, 1);
255     } while (rc < 0 && errno == EINTR);
256     if (rc < 0) {
257         return errno;
258     }
259     mutex->curr_locked = 1;
260     return APR_SUCCESS;
261 }
262
263 static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex)
264 {
265     int rc;
266
267     do {
268         rc = semop(mutex->interproc->filedes, &proc_mutex_op_try, 1);
269     } while (rc < 0 && errno == EINTR);
270     if (rc < 0) {
271         if (errno == EAGAIN) {
272             return APR_EBUSY;
273         }
274         return errno;
275     }
276     mutex->curr_locked = 1;
277     return APR_SUCCESS;
278 }
279
280 static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
281 {
282     int rc;
283
284     mutex->curr_locked = 0;
285     do {
286         rc = semop(mutex->interproc->filedes, &proc_mutex_op_off, 1);
287     } while (rc < 0 && errno == EINTR);
288     if (rc < 0) {
289         return errno;
290     }
291     return APR_SUCCESS;
292 }
293
294 static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
295 {
296 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL)
297     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
298 #else
299     0,
300 #endif
301     proc_mutex_sysv_create,
302     proc_mutex_sysv_acquire,
303     proc_mutex_sysv_tryacquire,
304     proc_mutex_sysv_release,
305     proc_mutex_sysv_cleanup,
306     proc_mutex_no_child_init,
307     "sysvsem"
308 };
309
310 #endif /* SysV sem implementation */
311
312 #if APR_HAS_PROC_PTHREAD_SERIALIZE
313
314 static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_)
315 {
316     apr_proc_mutex_t *mutex=mutex_;
317     apr_status_t rv;
318
319     if (mutex->curr_locked == 1) {
320         if ((rv = pthread_mutex_unlock(mutex->pthread_interproc))) {
321 #ifdef HAVE_ZOS_PTHREADS
322             rv = errno;
323 #endif
324             return rv;
325         }
326     }
327     /* curr_locked is set to -1 until the mutex has been created */
328     if (mutex->curr_locked != -1) {
329         if ((rv = pthread_mutex_destroy(mutex->pthread_interproc))) {
330 #ifdef HAVE_ZOS_PTHREADS
331             rv = errno;
332 #endif
333             return rv;
334         }
335     }
336     if (munmap((caddr_t)mutex->pthread_interproc, sizeof(pthread_mutex_t))) {
337         return errno;
338     }
339     return APR_SUCCESS;
340 }
341
342 static apr_status_t proc_mutex_proc_pthread_create(apr_proc_mutex_t *new_mutex,
343                                                    const char *fname)
344 {
345     apr_status_t rv;
346     int fd;
347     pthread_mutexattr_t mattr;
348
349     fd = open("/dev/zero", O_RDWR);
350     if (fd < 0) {
351         return errno;
352     }
353
354     new_mutex->pthread_interproc = (pthread_mutex_t *)mmap(
355                                        (caddr_t) 0, 
356                                        sizeof(pthread_mutex_t), 
357                                        PROT_READ | PROT_WRITE, MAP_SHARED,
358                                        fd, 0); 
359     if (new_mutex->pthread_interproc == (pthread_mutex_t *) (caddr_t) -1) {
360         close(fd);
361         return errno;
362     }
363     close(fd);
364
365     new_mutex->curr_locked = -1; /* until the mutex has been created */
366
367     if ((rv = pthread_mutexattr_init(&mattr))) {
368 #ifdef HAVE_ZOS_PTHREADS
369         rv = errno;
370 #endif
371         proc_mutex_proc_pthread_cleanup(new_mutex);
372         return rv;
373     }
374     if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) {
375 #ifdef HAVE_ZOS_PTHREADS
376         rv = errno;
377 #endif
378         proc_mutex_proc_pthread_cleanup(new_mutex);
379         pthread_mutexattr_destroy(&mattr);
380         return rv;
381     }
382
383 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
384     if ((rv = pthread_mutexattr_setrobust_np(&mattr, 
385                                                PTHREAD_MUTEX_ROBUST_NP))) {
386 #ifdef HAVE_ZOS_PTHREADS
387         rv = errno;
388 #endif
389         proc_mutex_proc_pthread_cleanup(new_mutex);
390         pthread_mutexattr_destroy(&mattr);
391         return rv;
392     }
393     if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) {
394 #ifdef HAVE_ZOS_PTHREADS
395         rv = errno;
396 #endif
397         proc_mutex_proc_pthread_cleanup(new_mutex);
398         pthread_mutexattr_destroy(&mattr);
399         return rv;
400     }
401 #endif /* HAVE_PTHREAD_MUTEX_ROBUST */
402
403     if ((rv = pthread_mutex_init(new_mutex->pthread_interproc, &mattr))) {
404 #ifdef HAVE_ZOS_PTHREADS
405         rv = errno;
406 #endif
407         proc_mutex_proc_pthread_cleanup(new_mutex);
408         pthread_mutexattr_destroy(&mattr);
409         return rv;
410     }
411
412     new_mutex->curr_locked = 0; /* mutex created now */
413
414     if ((rv = pthread_mutexattr_destroy(&mattr))) {
415 #ifdef HAVE_ZOS_PTHREADS
416         rv = errno;
417 #endif
418         proc_mutex_proc_pthread_cleanup(new_mutex);
419         return rv;
420     }
421
422     apr_pool_cleanup_register(new_mutex->pool,
423                               (void *)new_mutex,
424                               apr_proc_mutex_cleanup, 
425                               apr_pool_cleanup_null);
426     return APR_SUCCESS;
427 }
428
429 static apr_status_t proc_mutex_proc_pthread_acquire(apr_proc_mutex_t *mutex)
430 {
431     apr_status_t rv;
432
433     if ((rv = pthread_mutex_lock(mutex->pthread_interproc))) {
434 #ifdef HAVE_ZOS_PTHREADS
435         rv = errno;
436 #endif
437 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
438         /* Okay, our owner died.  Let's try to make it consistent again. */
439         if (rv == EOWNERDEAD) {
440             pthread_mutex_consistent_np(mutex->pthread_interproc);
441         }
442         else
443             return rv;
444 #else
445         return rv;
446 #endif
447     }
448     mutex->curr_locked = 1;
449     return APR_SUCCESS;
450 }
451
452 static apr_status_t proc_mutex_proc_pthread_tryacquire(apr_proc_mutex_t *mutex)
453 {
454     apr_status_t rv;
455  
456     if ((rv = pthread_mutex_trylock(mutex->pthread_interproc))) {
457 #ifdef HAVE_ZOS_PTHREADS 
458         rv = errno;
459 #endif
460         if (rv == EBUSY) {
461             return APR_EBUSY;
462         }
463 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
464         /* Okay, our owner died.  Let's try to make it consistent again. */
465         if (rv == EOWNERDEAD) {
466             pthread_mutex_consistent_np(mutex->pthread_interproc);
467             rv = APR_SUCCESS;
468         }
469         else
470             return rv;
471 #else
472         return rv;
473 #endif
474     }
475     mutex->curr_locked = 1;
476     return rv;
477 }
478
479 static apr_status_t proc_mutex_proc_pthread_release(apr_proc_mutex_t *mutex)
480 {
481     apr_status_t rv;
482
483     mutex->curr_locked = 0;
484     if ((rv = pthread_mutex_unlock(mutex->pthread_interproc))) {
485 #ifdef HAVE_ZOS_PTHREADS
486         rv = errno;
487 #endif
488         return rv;
489     }
490     return APR_SUCCESS;
491 }
492
493 static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
494 {
495     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
496     proc_mutex_proc_pthread_create,
497     proc_mutex_proc_pthread_acquire,
498     proc_mutex_proc_pthread_tryacquire,
499     proc_mutex_proc_pthread_release,
500     proc_mutex_proc_pthread_cleanup,
501     proc_mutex_no_child_init,
502     "pthread"
503 };
504
505 #endif
506
507 #if APR_HAS_FCNTL_SERIALIZE
508
509 static struct flock proc_mutex_lock_it;
510 static struct flock proc_mutex_unlock_it;
511
512 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
513
514 static void proc_mutex_fcntl_setup(void)
515 {
516     proc_mutex_lock_it.l_whence = SEEK_SET;   /* from current point */
517     proc_mutex_lock_it.l_start = 0;           /* -"- */
518     proc_mutex_lock_it.l_len = 0;             /* until end of file */
519     proc_mutex_lock_it.l_type = F_WRLCK;      /* set exclusive/write lock */
520     proc_mutex_lock_it.l_pid = 0;             /* pid not actually interesting */
521     proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */
522     proc_mutex_unlock_it.l_start = 0;         /* -"- */
523     proc_mutex_unlock_it.l_len = 0;           /* until end of file */
524     proc_mutex_unlock_it.l_type = F_UNLCK;    /* set exclusive/write lock */
525     proc_mutex_unlock_it.l_pid = 0;           /* pid not actually interesting */
526 }
527
528 static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_)
529 {
530     apr_status_t status;
531     apr_proc_mutex_t *mutex=mutex_;
532
533     if (mutex->curr_locked == 1) {
534         status = proc_mutex_fcntl_release(mutex);
535         if (status != APR_SUCCESS)
536             return status;
537     }
538         
539     return apr_file_close(mutex->interproc);
540 }    
541
542 static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex,
543                                             const char *fname)
544 {
545     int rv;
546  
547     if (fname) {
548         new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
549         rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
550                            APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
551                            APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD,
552                            new_mutex->pool);
553     }
554     else {
555         new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
556         rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
557                              APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
558                              new_mutex->pool);
559     }
560  
561     if (rv != APR_SUCCESS) {
562         return rv;
563     }
564
565     new_mutex->curr_locked = 0;
566     unlink(new_mutex->fname);
567     apr_pool_cleanup_register(new_mutex->pool,
568                               (void*)new_mutex,
569                               apr_proc_mutex_cleanup, 
570                               apr_pool_cleanup_null);
571     return APR_SUCCESS; 
572 }
573
574 static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex)
575 {
576     int rc;
577
578     do {
579         rc = fcntl(mutex->interproc->filedes, F_SETLKW, &proc_mutex_lock_it);
580     } while (rc < 0 && errno == EINTR);
581     if (rc < 0) {
582         return errno;
583     }
584     mutex->curr_locked=1;
585     return APR_SUCCESS;
586 }
587
588 static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex)
589 {
590     int rc;
591
592     do {
593         rc = fcntl(mutex->interproc->filedes, F_SETLK, &proc_mutex_lock_it);
594     } while (rc < 0 && errno == EINTR);
595     if (rc < 0) {
596 #if FCNTL_TRYACQUIRE_EACCES
597         if (errno == EACCES) {
598 #else
599         if (errno == EAGAIN) {
600 #endif
601             return APR_EBUSY;
602         }
603         return errno;
604     }
605     mutex->curr_locked = 1;
606     return APR_SUCCESS;
607 }
608
609 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
610 {
611     int rc;
612
613     mutex->curr_locked=0;
614     do {
615         rc = fcntl(mutex->interproc->filedes, F_SETLKW, &proc_mutex_unlock_it);
616     } while (rc < 0 && errno == EINTR);
617     if (rc < 0) {
618         return errno;
619     }
620     return APR_SUCCESS;
621 }
622
623 static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
624 {
625 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL)
626     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
627 #else
628     0,
629 #endif
630     proc_mutex_fcntl_create,
631     proc_mutex_fcntl_acquire,
632     proc_mutex_fcntl_tryacquire,
633     proc_mutex_fcntl_release,
634     proc_mutex_fcntl_cleanup,
635     proc_mutex_no_child_init,
636     "fcntl"
637 };
638
639 #endif /* fcntl implementation */
640
641 #if APR_HAS_FLOCK_SERIALIZE
642
643 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
644
645 static apr_status_t proc_mutex_flock_cleanup(void *mutex_)
646 {
647     apr_status_t status;
648     apr_proc_mutex_t *mutex=mutex_;
649
650     if (mutex->curr_locked == 1) {
651         status = proc_mutex_flock_release(mutex);
652         if (status != APR_SUCCESS)
653             return status;
654     }
655     if (mutex->interproc) { /* if it was opened properly */
656         apr_file_close(mutex->interproc);
657     }
658     unlink(mutex->fname);
659     return APR_SUCCESS;
660 }    
661
662 static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex,
663                                             const char *fname)
664 {
665     int rv;
666  
667     if (fname) {
668         new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
669         rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
670                            APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
671                            APR_UREAD | APR_UWRITE,
672                            new_mutex->pool);
673     }
674     else {
675         new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
676         rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
677                              APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
678                              new_mutex->pool);
679     }
680  
681     if (rv != APR_SUCCESS) {
682         proc_mutex_flock_cleanup(new_mutex);
683         return errno;
684     }
685     new_mutex->curr_locked = 0;
686     apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
687                               apr_proc_mutex_cleanup,
688                               apr_pool_cleanup_null);
689     return APR_SUCCESS;
690 }
691
692 static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex)
693 {
694     int rc;
695
696     do {
697         rc = flock(mutex->interproc->filedes, LOCK_EX);
698     } while (rc < 0 && errno == EINTR);
699     if (rc < 0) {
700         return errno;
701     }
702     mutex->curr_locked = 1;
703     return APR_SUCCESS;
704 }
705
706 static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex)
707 {
708     int rc;
709
710     do {
711         rc = flock(mutex->interproc->filedes, LOCK_EX | LOCK_NB);
712     } while (rc < 0 && errno == EINTR);
713     if (rc < 0) {
714         if (errno == EWOULDBLOCK || errno == EAGAIN) {
715             return APR_EBUSY;
716         }
717         return errno;
718     }
719     mutex->curr_locked = 1;
720     return APR_SUCCESS;
721 }
722
723 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
724 {
725     int rc;
726
727     mutex->curr_locked = 0;
728     do {
729         rc = flock(mutex->interproc->filedes, LOCK_UN);
730     } while (rc < 0 && errno == EINTR);
731     if (rc < 0) {
732         return errno;
733     }
734     return APR_SUCCESS;
735 }
736
737 static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex,
738                                                 apr_pool_t *pool, 
739                                                 const char *fname)
740 {
741     apr_proc_mutex_t *new_mutex;
742     int rv;
743
744     new_mutex = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t));
745
746     memcpy(new_mutex, *mutex, sizeof *new_mutex);
747     new_mutex->pool = pool;
748     if (!fname) {
749         fname = (*mutex)->fname;
750     }
751     new_mutex->fname = apr_pstrdup(pool, fname);
752     rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
753                        APR_FOPEN_WRITE, 0, new_mutex->pool);
754     if (rv != APR_SUCCESS) {
755         return rv;
756     }
757     *mutex = new_mutex;
758     return APR_SUCCESS;
759 }
760
761 static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
762 {
763 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL)
764     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
765 #else
766     0,
767 #endif
768     proc_mutex_flock_create,
769     proc_mutex_flock_acquire,
770     proc_mutex_flock_tryacquire,
771     proc_mutex_flock_release,
772     proc_mutex_flock_cleanup,
773     proc_mutex_flock_child_init,
774     "flock"
775 };
776
777 #endif /* flock implementation */
778
779 void apr_proc_mutex_unix_setup_lock(void)
780 {
781     /* setup only needed for sysvsem and fnctl */
782 #if APR_HAS_SYSVSEM_SERIALIZE
783     proc_mutex_sysv_setup();
784 #endif
785 #if APR_HAS_FCNTL_SERIALIZE
786     proc_mutex_fcntl_setup();
787 #endif
788 }
789
790 static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech)
791 {
792     switch (mech) {
793     case APR_LOCK_FCNTL:
794 #if APR_HAS_FCNTL_SERIALIZE
795         new_mutex->inter_meth = &mutex_fcntl_methods;
796 #else
797         return APR_ENOTIMPL;
798 #endif
799         break;
800     case APR_LOCK_FLOCK:
801 #if APR_HAS_FLOCK_SERIALIZE
802         new_mutex->inter_meth = &mutex_flock_methods;
803 #else
804         return APR_ENOTIMPL;
805 #endif
806         break;
807     case APR_LOCK_SYSVSEM:
808 #if APR_HAS_SYSVSEM_SERIALIZE
809         new_mutex->inter_meth = &mutex_sysv_methods;
810 #else
811         return APR_ENOTIMPL;
812 #endif
813         break;
814     case APR_LOCK_POSIXSEM:
815 #if APR_HAS_POSIXSEM_SERIALIZE
816         new_mutex->inter_meth = &mutex_posixsem_methods;
817 #else
818         return APR_ENOTIMPL;
819 #endif
820         break;
821     case APR_LOCK_PROC_PTHREAD:
822 #if APR_HAS_PROC_PTHREAD_SERIALIZE
823         new_mutex->inter_meth = &mutex_proc_pthread_methods;
824 #else
825         return APR_ENOTIMPL;
826 #endif
827         break;
828     case APR_LOCK_DEFAULT:
829 #if APR_USE_FLOCK_SERIALIZE
830         new_mutex->inter_meth = &mutex_flock_methods;
831 #elif APR_USE_SYSVSEM_SERIALIZE
832         new_mutex->inter_meth = &mutex_sysv_methods;
833 #elif APR_USE_FCNTL_SERIALIZE
834         new_mutex->inter_meth = &mutex_fcntl_methods;
835 #elif APR_USE_PROC_PTHREAD_SERIALIZE
836         new_mutex->inter_meth = &mutex_proc_pthread_methods;
837 #elif APR_USE_POSIXSEM_SERIALIZE
838         new_mutex->inter_meth = &mutex_posixsem_methods;
839 #else
840         return APR_ENOTIMPL;
841 #endif
842         break;
843     default:
844         return APR_ENOTIMPL;
845     }
846     return APR_SUCCESS;
847 }
848
849 APR_DECLARE(const char *) apr_proc_mutex_defname(void)
850 {
851     apr_status_t rv;
852     apr_proc_mutex_t mutex;
853
854     if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT)) != APR_SUCCESS) {
855         return "unknown";
856     }
857     mutex.meth = mutex.inter_meth;
858
859     return apr_proc_mutex_name(&mutex);
860 }
861    
862 static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname)
863 {
864     apr_status_t rv;
865
866     if ((rv = proc_mutex_choose_method(new_mutex, mech)) != APR_SUCCESS) {
867         return rv;
868     }
869
870     new_mutex->meth = new_mutex->inter_meth;
871
872     if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) {
873         return rv;
874     }
875
876     return APR_SUCCESS;
877 }
878
879 APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
880                                                 const char *fname,
881                                                 apr_lockmech_e mech,
882                                                 apr_pool_t *pool)
883 {
884     apr_proc_mutex_t *new_mutex;
885     apr_status_t rv;
886
887     new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
888     new_mutex->pool = pool;
889
890     if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS)
891         return rv;
892
893     *mutex = new_mutex;
894     return APR_SUCCESS;
895 }
896
897 APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
898                                                     const char *fname,
899                                                     apr_pool_t *pool)
900 {
901     return (*mutex)->meth->child_init(mutex, pool, fname);
902 }
903
904 APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
905 {
906     return mutex->meth->acquire(mutex);
907 }
908
909 APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
910 {
911     return mutex->meth->tryacquire(mutex);
912 }
913
914 APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
915 {
916     return mutex->meth->release(mutex);
917 }
918
919 APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
920 {
921     return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
922 }
923
924 APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
925 {
926     return mutex->meth->name;
927 }
928
929 APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
930 {
931     /* POSIX sems use the fname field but don't use a file,
932      * so be careful. */
933 #if APR_HAS_FLOCK_SERIALIZE
934     if (mutex->meth == &mutex_flock_methods) {
935         return mutex->fname;
936     }
937 #endif
938 #if APR_HAS_FCNTL_SERIALIZE
939     if (mutex->meth == &mutex_fcntl_methods) {
940         return mutex->fname;
941     }
942 #endif
943     return NULL;
944 }
945
946 APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
947
948 /* Implement OS-specific accessors defined in apr_portable.h */
949
950 APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
951                                                 apr_proc_mutex_t *pmutex)
952 {
953 #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE
954     ospmutex->crossproc = pmutex->interproc->filedes;
955 #endif
956 #if APR_HAS_PROC_PTHREAD_SERIALIZE
957     ospmutex->pthread_interproc = pmutex->pthread_interproc;
958 #endif
959     return APR_SUCCESS;
960 }
961
962 APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
963                                                 apr_os_proc_mutex_t *ospmutex,
964                                                 apr_pool_t *pool)
965 {
966     if (pool == NULL) {
967         return APR_ENOPOOL;
968     }
969     if ((*pmutex) == NULL) {
970         (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool,
971                                                     sizeof(apr_proc_mutex_t));
972         (*pmutex)->pool = pool;
973     }
974 #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE
975     apr_os_file_put(&(*pmutex)->interproc, &ospmutex->crossproc, 0, pool);
976 #endif
977 #if APR_HAS_PROC_PTHREAD_SERIALIZE
978     (*pmutex)->pthread_interproc = ospmutex->pthread_interproc;
979 #endif
980     return APR_SUCCESS;
981 }
982