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