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