1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr.h"
18251875Speter#include "apr_strings.h"
19251875Speter#include "apr_arch_proc_mutex.h"
20251875Speter#include "apr_arch_file_io.h" /* for apr_mkstemp() */
21251875Speter#include "apr_hash.h"
22362181Sdim#include "apr_atomic.h"
23251875Speter
24251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
25251875Speter{
26251875Speter    return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup);
27251875Speter}
28251875Speter
29251875Speter#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \
30362181Sdim    APR_HAS_SYSVSEM_SERIALIZE
31251875Speterstatic apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex,
32251875Speter                                             apr_pool_t *cont,
33251875Speter                                             const char *fname)
34251875Speter{
35251875Speter    return APR_SUCCESS;
36251875Speter}
37251875Speter#endif
38251875Speter
39362181Sdim#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_PROC_PTHREAD_SERIALIZE
40362181Sdimstatic apr_status_t proc_mutex_no_perms_set(apr_proc_mutex_t *mutex,
41362181Sdim                                            apr_fileperms_t perms,
42362181Sdim                                            apr_uid_t uid,
43362181Sdim                                            apr_gid_t gid)
44362181Sdim{
45362181Sdim    return APR_ENOTIMPL;
46362181Sdim}
47362181Sdim#endif
48362181Sdim
49362181Sdim#if APR_HAS_FCNTL_SERIALIZE \
50362181Sdim    || APR_HAS_FLOCK_SERIALIZE \
51362181Sdim    || (APR_HAS_SYSVSEM_SERIALIZE \
52362181Sdim        && !defined(HAVE_SEMTIMEDOP)) \
53362181Sdim    || (APR_HAS_POSIXSEM_SERIALIZE \
54362181Sdim        && !defined(HAVE_SEM_TIMEDWAIT)) \
55362181Sdim    || (APR_HAS_PROC_PTHREAD_SERIALIZE \
56362181Sdim        && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) \
57362181Sdim        && !defined(HAVE_PTHREAD_CONDATTR_SETPSHARED))
58362181Sdimstatic apr_status_t proc_mutex_spinsleep_timedacquire(apr_proc_mutex_t *mutex,
59362181Sdim                                                  apr_interval_time_t timeout)
60362181Sdim{
61362181Sdim#define SLEEP_TIME apr_time_from_msec(10)
62362181Sdim    apr_status_t rv;
63362181Sdim    for (;;) {
64362181Sdim        rv = apr_proc_mutex_trylock(mutex);
65362181Sdim        if (!APR_STATUS_IS_EBUSY(rv)) {
66362181Sdim            if (rv == APR_SUCCESS) {
67362181Sdim                mutex->curr_locked = 1;
68362181Sdim            }
69362181Sdim            break;
70362181Sdim        }
71362181Sdim        if (timeout <= 0) {
72362181Sdim            rv = APR_TIMEUP;
73362181Sdim            break;
74362181Sdim        }
75362181Sdim        if (timeout > SLEEP_TIME) {
76362181Sdim            apr_sleep(SLEEP_TIME);
77362181Sdim            timeout -= SLEEP_TIME;
78362181Sdim        }
79362181Sdim        else {
80362181Sdim            apr_sleep(timeout);
81362181Sdim            timeout = 0;
82362181Sdim        }
83362181Sdim    }
84362181Sdim    return rv;
85362181Sdim}
86362181Sdim#endif
87362181Sdim
88251875Speter#if APR_HAS_POSIXSEM_SERIALIZE
89251875Speter
90251875Speter#ifndef SEM_FAILED
91251875Speter#define SEM_FAILED (-1)
92251875Speter#endif
93251875Speter
94251875Speterstatic apr_status_t proc_mutex_posix_cleanup(void *mutex_)
95251875Speter{
96251875Speter    apr_proc_mutex_t *mutex = mutex_;
97251875Speter
98362181Sdim    if (sem_close(mutex->os.psem_interproc) < 0) {
99251875Speter        return errno;
100251875Speter    }
101251875Speter
102251875Speter    return APR_SUCCESS;
103251875Speter}
104251875Speter
105251875Speterstatic unsigned int rshash (char *p) {
106251875Speter    /* hash function from Robert Sedgwicks 'Algorithms in C' book */
107251875Speter   unsigned int b    = 378551;
108251875Speter   unsigned int a    = 63689;
109251875Speter   unsigned int retval = 0;
110251875Speter
111251875Speter   for( ; *p; p++)
112251875Speter   {
113251875Speter      retval = retval * a + (*p);
114251875Speter      a *= b;
115251875Speter   }
116251875Speter
117251875Speter   return retval;
118251875Speter}
119251875Speter
120251875Speterstatic apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex,
121251875Speter                                            const char *fname)
122251875Speter{
123251875Speter    #define APR_POSIXSEM_NAME_MIN 13
124251875Speter    sem_t *psem;
125251875Speter    char semname[32];
126251875Speter
127251875Speter    /*
128251875Speter     * This bogusness is to follow what appears to be the
129251875Speter     * lowest common denominator in Posix semaphore naming:
130251875Speter     *   - start with '/'
131251875Speter     *   - be at most 14 chars
132251875Speter     *   - be unique and not match anything on the filesystem
133251875Speter     *
134251875Speter     * Because of this, we use fname to generate a (unique) hash
135251875Speter     * and use that as the name of the semaphore. If no filename was
136251875Speter     * given, we create one based on the time. We tuck the name
137251875Speter     * away, since it might be useful for debugging. We use 2 hashing
138251875Speter     * functions to try to avoid collisions.
139251875Speter     *
140251875Speter     * To  make this as robust as possible, we initially try something
141251875Speter     * larger (and hopefully more unique) and gracefully fail down to the
142251875Speter     * LCD above.
143251875Speter     *
144251875Speter     * NOTE: Darwin (Mac OS X) seems to be the most restrictive
145251875Speter     * implementation. Versions previous to Darwin 6.2 had the 14
146251875Speter     * char limit, but later rev's allow up to 31 characters.
147251875Speter     *
148251875Speter     */
149251875Speter    if (fname) {
150251875Speter        apr_ssize_t flen = strlen(fname);
151251875Speter        char *p = apr_pstrndup(new_mutex->pool, fname, strlen(fname));
152251875Speter        unsigned int h1, h2;
153266735Speter        h1 = (apr_hashfunc_default((const char *)p, &flen) & 0xffffffff);
154266735Speter        h2 = (rshash(p) & 0xffffffff);
155251875Speter        apr_snprintf(semname, sizeof(semname), "/ApR.%xH%x", h1, h2);
156251875Speter    } else {
157251875Speter        apr_time_t now;
158251875Speter        unsigned long sec;
159251875Speter        unsigned long usec;
160251875Speter        now = apr_time_now();
161251875Speter        sec = apr_time_sec(now);
162251875Speter        usec = apr_time_usec(now);
163251875Speter        apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec);
164251875Speter    }
165286503Speter    do {
166286503Speter        psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
167286503Speter    } while (psem == (sem_t *)SEM_FAILED && errno == EINTR);
168251875Speter    if (psem == (sem_t *)SEM_FAILED) {
169251875Speter        if (errno == ENAMETOOLONG) {
170251875Speter            /* Oh well, good try */
171251875Speter            semname[APR_POSIXSEM_NAME_MIN] = '\0';
172251875Speter        } else {
173251875Speter            return errno;
174251875Speter        }
175286503Speter        do {
176286503Speter            psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
177286503Speter        } while (psem == (sem_t *)SEM_FAILED && errno == EINTR);
178251875Speter    }
179251875Speter
180251875Speter    if (psem == (sem_t *)SEM_FAILED) {
181251875Speter        return errno;
182251875Speter    }
183251875Speter    /* Ahhh. The joys of Posix sems. Predelete it... */
184251875Speter    sem_unlink(semname);
185362181Sdim    new_mutex->os.psem_interproc = psem;
186251875Speter    new_mutex->fname = apr_pstrdup(new_mutex->pool, semname);
187251875Speter    apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
188251875Speter                              apr_proc_mutex_cleanup,
189251875Speter                              apr_pool_cleanup_null);
190251875Speter    return APR_SUCCESS;
191251875Speter}
192251875Speter
193251875Speterstatic apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex)
194251875Speter{
195286503Speter    int rc;
196286503Speter
197286503Speter    do {
198362181Sdim        rc = sem_wait(mutex->os.psem_interproc);
199286503Speter    } while (rc < 0 && errno == EINTR);
200286503Speter    if (rc < 0) {
201251875Speter        return errno;
202251875Speter    }
203251875Speter    mutex->curr_locked = 1;
204251875Speter    return APR_SUCCESS;
205251875Speter}
206251875Speter
207251875Speterstatic apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex)
208251875Speter{
209286503Speter    int rc;
210286503Speter
211286503Speter    do {
212362181Sdim        rc = sem_trywait(mutex->os.psem_interproc);
213286503Speter    } while (rc < 0 && errno == EINTR);
214286503Speter    if (rc < 0) {
215251875Speter        if (errno == EAGAIN) {
216251875Speter            return APR_EBUSY;
217251875Speter        }
218251875Speter        return errno;
219251875Speter    }
220251875Speter    mutex->curr_locked = 1;
221251875Speter    return APR_SUCCESS;
222251875Speter}
223251875Speter
224362181Sdim#if defined(HAVE_SEM_TIMEDWAIT)
225362181Sdimstatic apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex,
226362181Sdim                                              apr_interval_time_t timeout)
227362181Sdim{
228362181Sdim    if (timeout <= 0) {
229362181Sdim        apr_status_t rv = proc_mutex_posix_tryacquire(mutex);
230362181Sdim        return (rv == APR_EBUSY) ? APR_TIMEUP : rv;
231362181Sdim    }
232362181Sdim    else {
233362181Sdim        int rc;
234362181Sdim        struct timespec abstime;
235362181Sdim
236362181Sdim        timeout += apr_time_now();
237362181Sdim        abstime.tv_sec = apr_time_sec(timeout);
238362181Sdim        abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
239362181Sdim
240362181Sdim        do {
241362181Sdim            rc = sem_timedwait(mutex->os.psem_interproc, &abstime);
242362181Sdim        } while (rc < 0 && errno == EINTR);
243362181Sdim        if (rc < 0) {
244362181Sdim            if (errno == ETIMEDOUT) {
245362181Sdim                return APR_TIMEUP;
246362181Sdim            }
247362181Sdim            return errno;
248362181Sdim        }
249362181Sdim    }
250362181Sdim    mutex->curr_locked = 1;
251362181Sdim    return APR_SUCCESS;
252362181Sdim}
253362181Sdim#endif
254362181Sdim
255251875Speterstatic apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
256251875Speter{
257251875Speter    mutex->curr_locked = 0;
258362181Sdim    if (sem_post(mutex->os.psem_interproc) < 0) {
259251875Speter        /* any failure is probably fatal, so no big deal to leave
260251875Speter         * ->curr_locked at 0. */
261251875Speter        return errno;
262251875Speter    }
263251875Speter    return APR_SUCCESS;
264251875Speter}
265251875Speter
266251875Speterstatic const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
267251875Speter{
268251875Speter#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL)
269251875Speter    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
270251875Speter#else
271251875Speter    0,
272251875Speter#endif
273251875Speter    proc_mutex_posix_create,
274251875Speter    proc_mutex_posix_acquire,
275251875Speter    proc_mutex_posix_tryacquire,
276362181Sdim#if defined(HAVE_SEM_TIMEDWAIT)
277362181Sdim    proc_mutex_posix_timedacquire,
278362181Sdim#else
279362181Sdim    proc_mutex_spinsleep_timedacquire,
280362181Sdim#endif
281251875Speter    proc_mutex_posix_release,
282251875Speter    proc_mutex_posix_cleanup,
283251875Speter    proc_mutex_no_child_init,
284362181Sdim    proc_mutex_no_perms_set,
285362181Sdim    APR_LOCK_POSIXSEM,
286251875Speter    "posixsem"
287251875Speter};
288251875Speter
289251875Speter#endif /* Posix sem implementation */
290251875Speter
291251875Speter#if APR_HAS_SYSVSEM_SERIALIZE
292251875Speter
293251875Speterstatic struct sembuf proc_mutex_op_on;
294251875Speterstatic struct sembuf proc_mutex_op_try;
295251875Speterstatic struct sembuf proc_mutex_op_off;
296251875Speter
297251875Speterstatic void proc_mutex_sysv_setup(void)
298251875Speter{
299251875Speter    proc_mutex_op_on.sem_num = 0;
300251875Speter    proc_mutex_op_on.sem_op = -1;
301251875Speter    proc_mutex_op_on.sem_flg = SEM_UNDO;
302251875Speter    proc_mutex_op_try.sem_num = 0;
303251875Speter    proc_mutex_op_try.sem_op = -1;
304251875Speter    proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT;
305251875Speter    proc_mutex_op_off.sem_num = 0;
306251875Speter    proc_mutex_op_off.sem_op = 1;
307251875Speter    proc_mutex_op_off.sem_flg = SEM_UNDO;
308251875Speter}
309251875Speter
310251875Speterstatic apr_status_t proc_mutex_sysv_cleanup(void *mutex_)
311251875Speter{
312251875Speter    apr_proc_mutex_t *mutex=mutex_;
313251875Speter    union semun ick;
314251875Speter
315362181Sdim    if (mutex->os.crossproc != -1) {
316251875Speter        ick.val = 0;
317362181Sdim        semctl(mutex->os.crossproc, 0, IPC_RMID, ick);
318251875Speter    }
319251875Speter    return APR_SUCCESS;
320251875Speter}
321251875Speter
322251875Speterstatic apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex,
323251875Speter                                           const char *fname)
324251875Speter{
325251875Speter    union semun ick;
326251875Speter    apr_status_t rv;
327251875Speter
328362181Sdim    new_mutex->os.crossproc = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
329362181Sdim    if (new_mutex->os.crossproc == -1) {
330251875Speter        rv = errno;
331251875Speter        proc_mutex_sysv_cleanup(new_mutex);
332251875Speter        return rv;
333251875Speter    }
334251875Speter    ick.val = 1;
335362181Sdim    if (semctl(new_mutex->os.crossproc, 0, SETVAL, ick) < 0) {
336251875Speter        rv = errno;
337251875Speter        proc_mutex_sysv_cleanup(new_mutex);
338362181Sdim        new_mutex->os.crossproc = -1;
339251875Speter        return rv;
340251875Speter    }
341251875Speter    new_mutex->curr_locked = 0;
342251875Speter    apr_pool_cleanup_register(new_mutex->pool,
343251875Speter                              (void *)new_mutex, apr_proc_mutex_cleanup,
344251875Speter                              apr_pool_cleanup_null);
345251875Speter    return APR_SUCCESS;
346251875Speter}
347251875Speter
348251875Speterstatic apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex)
349251875Speter{
350251875Speter    int rc;
351251875Speter
352251875Speter    do {
353362181Sdim        rc = semop(mutex->os.crossproc, &proc_mutex_op_on, 1);
354251875Speter    } while (rc < 0 && errno == EINTR);
355251875Speter    if (rc < 0) {
356251875Speter        return errno;
357251875Speter    }
358251875Speter    mutex->curr_locked = 1;
359251875Speter    return APR_SUCCESS;
360251875Speter}
361251875Speter
362251875Speterstatic apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex)
363251875Speter{
364251875Speter    int rc;
365251875Speter
366251875Speter    do {
367362181Sdim        rc = semop(mutex->os.crossproc, &proc_mutex_op_try, 1);
368251875Speter    } while (rc < 0 && errno == EINTR);
369251875Speter    if (rc < 0) {
370251875Speter        if (errno == EAGAIN) {
371251875Speter            return APR_EBUSY;
372251875Speter        }
373251875Speter        return errno;
374251875Speter    }
375251875Speter    mutex->curr_locked = 1;
376251875Speter    return APR_SUCCESS;
377251875Speter}
378251875Speter
379362181Sdim#if defined(HAVE_SEMTIMEDOP)
380362181Sdimstatic apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex,
381362181Sdim                                             apr_interval_time_t timeout)
382362181Sdim{
383362181Sdim    if (timeout <= 0) {
384362181Sdim        apr_status_t rv = proc_mutex_sysv_tryacquire(mutex);
385362181Sdim        return (rv == APR_EBUSY) ? APR_TIMEUP : rv;
386362181Sdim    }
387362181Sdim    else {
388362181Sdim        int rc;
389362181Sdim        struct timespec reltime;
390362181Sdim
391362181Sdim        reltime.tv_sec = apr_time_sec(timeout);
392362181Sdim        reltime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
393362181Sdim
394362181Sdim        do {
395362181Sdim            rc = semtimedop(mutex->os.crossproc, &proc_mutex_op_on, 1,
396362181Sdim                            &reltime);
397362181Sdim        } while (rc < 0 && errno == EINTR);
398362181Sdim        if (rc < 0) {
399362181Sdim            if (errno == EAGAIN) {
400362181Sdim                return APR_TIMEUP;
401362181Sdim            }
402362181Sdim            return errno;
403362181Sdim        }
404362181Sdim    }
405362181Sdim    mutex->curr_locked = 1;
406362181Sdim    return APR_SUCCESS;
407362181Sdim}
408362181Sdim#endif
409362181Sdim
410251875Speterstatic apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
411251875Speter{
412251875Speter    int rc;
413251875Speter
414251875Speter    mutex->curr_locked = 0;
415251875Speter    do {
416362181Sdim        rc = semop(mutex->os.crossproc, &proc_mutex_op_off, 1);
417251875Speter    } while (rc < 0 && errno == EINTR);
418251875Speter    if (rc < 0) {
419251875Speter        return errno;
420251875Speter    }
421251875Speter    return APR_SUCCESS;
422251875Speter}
423251875Speter
424362181Sdimstatic apr_status_t proc_mutex_sysv_perms_set(apr_proc_mutex_t *mutex,
425362181Sdim                                              apr_fileperms_t perms,
426362181Sdim                                              apr_uid_t uid,
427362181Sdim                                              apr_gid_t gid)
428362181Sdim{
429362181Sdim
430362181Sdim    union semun ick;
431362181Sdim    struct semid_ds buf;
432362181Sdim    buf.sem_perm.uid = uid;
433362181Sdim    buf.sem_perm.gid = gid;
434362181Sdim    buf.sem_perm.mode = apr_unix_perms2mode(perms);
435362181Sdim    ick.buf = &buf;
436362181Sdim    if (semctl(mutex->os.crossproc, 0, IPC_SET, ick) < 0) {
437362181Sdim        return errno;
438362181Sdim    }
439362181Sdim    return APR_SUCCESS;
440362181Sdim}
441362181Sdim
442251875Speterstatic const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
443251875Speter{
444251875Speter#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL)
445251875Speter    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
446251875Speter#else
447251875Speter    0,
448251875Speter#endif
449251875Speter    proc_mutex_sysv_create,
450251875Speter    proc_mutex_sysv_acquire,
451251875Speter    proc_mutex_sysv_tryacquire,
452362181Sdim#if defined(HAVE_SEMTIMEDOP)
453362181Sdim    proc_mutex_sysv_timedacquire,
454362181Sdim#else
455362181Sdim    proc_mutex_spinsleep_timedacquire,
456362181Sdim#endif
457251875Speter    proc_mutex_sysv_release,
458251875Speter    proc_mutex_sysv_cleanup,
459251875Speter    proc_mutex_no_child_init,
460362181Sdim    proc_mutex_sysv_perms_set,
461362181Sdim    APR_LOCK_SYSVSEM,
462251875Speter    "sysvsem"
463251875Speter};
464251875Speter
465251875Speter#endif /* SysV sem implementation */
466251875Speter
467251875Speter#if APR_HAS_PROC_PTHREAD_SERIALIZE
468251875Speter
469362181Sdim#ifndef APR_USE_PROC_PTHREAD_MUTEX_COND
470362181Sdim#define APR_USE_PROC_PTHREAD_MUTEX_COND \
471362181Sdim            (defined(HAVE_PTHREAD_CONDATTR_SETPSHARED) \
472362181Sdim             && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK))
473362181Sdim#endif
474362181Sdim
475362181Sdim/* The mmap()ed pthread_interproc is the native pthread_mutex_t followed
476362181Sdim * by a refcounter to track children using it.  We want to avoid calling
477362181Sdim * pthread_mutex_destroy() on the shared mutex area while it is in use by
478362181Sdim * another process, because this may mark the shared pthread_mutex_t as
479362181Sdim * invalid for everyone, including forked children (unlike "sysvsem" for
480362181Sdim * example), causing unexpected errors or deadlocks (PR 49504).  So the
481362181Sdim * last process (parent or child) referencing the mutex will effectively
482362181Sdim * destroy it.
483362181Sdim */
484362181Sdimtypedef struct {
485362181Sdim#define proc_pthread_cast(m) \
486362181Sdim    ((proc_pthread_mutex_t *)(m)->os.pthread_interproc)
487362181Sdim    pthread_mutex_t mutex;
488362181Sdim#define proc_pthread_mutex(m) \
489362181Sdim    (proc_pthread_cast(m)->mutex)
490362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
491362181Sdim    pthread_cond_t  cond;
492362181Sdim#define proc_pthread_mutex_cond(m) \
493362181Sdim    (proc_pthread_cast(m)->cond)
494362181Sdim    apr_int32_t     cond_locked;
495362181Sdim#define proc_pthread_mutex_cond_locked(m) \
496362181Sdim    (proc_pthread_cast(m)->cond_locked)
497362181Sdim    apr_uint32_t    cond_num_waiters;
498362181Sdim#define proc_pthread_mutex_cond_num_waiters(m) \
499362181Sdim    (proc_pthread_cast(m)->cond_num_waiters)
500362181Sdim#define proc_pthread_mutex_is_cond(m) \
501362181Sdim    ((m)->pthread_refcounting && proc_pthread_mutex_cond_locked(m) != -1)
502362181Sdim#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
503362181Sdim    apr_uint32_t refcount;
504362181Sdim#define proc_pthread_mutex_refcount(m) \
505362181Sdim    (proc_pthread_cast(m)->refcount)
506362181Sdim} proc_pthread_mutex_t;
507362181Sdim
508362181Sdim
509362181Sdimstatic APR_INLINE int proc_pthread_mutex_inc(apr_proc_mutex_t *mutex)
510251875Speter{
511362181Sdim    if (mutex->pthread_refcounting) {
512362181Sdim        apr_atomic_inc32(&proc_pthread_mutex_refcount(mutex));
513362181Sdim        return 1;
514362181Sdim    }
515362181Sdim    return 0;
516362181Sdim}
517362181Sdim
518362181Sdimstatic APR_INLINE int proc_pthread_mutex_dec(apr_proc_mutex_t *mutex)
519362181Sdim{
520362181Sdim    if (mutex->pthread_refcounting) {
521362181Sdim        return apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex));
522362181Sdim    }
523362181Sdim    return 0;
524362181Sdim}
525362181Sdim
526362181Sdimstatic apr_status_t proc_pthread_mutex_unref(void *mutex_)
527362181Sdim{
528251875Speter    apr_proc_mutex_t *mutex=mutex_;
529251875Speter    apr_status_t rv;
530251875Speter
531362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
532362181Sdim    if (proc_pthread_mutex_is_cond(mutex)) {
533362181Sdim        mutex->curr_locked = 0;
534362181Sdim    }
535362181Sdim    else
536362181Sdim#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
537251875Speter    if (mutex->curr_locked == 1) {
538362181Sdim        if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
539251875Speter#ifdef HAVE_ZOS_PTHREADS
540251875Speter            rv = errno;
541251875Speter#endif
542251875Speter            return rv;
543251875Speter        }
544251875Speter    }
545362181Sdim    if (!proc_pthread_mutex_dec(mutex)) {
546362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
547362181Sdim        if (proc_pthread_mutex_is_cond(mutex) &&
548362181Sdim                (rv = pthread_cond_destroy(&proc_pthread_mutex_cond(mutex)))) {
549251875Speter#ifdef HAVE_ZOS_PTHREADS
550251875Speter            rv = errno;
551251875Speter#endif
552251875Speter            return rv;
553251875Speter        }
554362181Sdim#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
555362181Sdim
556362181Sdim        if ((rv = pthread_mutex_destroy(&proc_pthread_mutex(mutex)))) {
557362181Sdim#ifdef HAVE_ZOS_PTHREADS
558362181Sdim            rv = errno;
559362181Sdim#endif
560362181Sdim            return rv;
561362181Sdim        }
562251875Speter    }
563362181Sdim    return APR_SUCCESS;
564362181Sdim}
565362181Sdim
566362181Sdimstatic apr_status_t proc_mutex_pthread_cleanup(void *mutex_)
567362181Sdim{
568362181Sdim    apr_proc_mutex_t *mutex=mutex_;
569362181Sdim    apr_status_t rv;
570362181Sdim
571362181Sdim    /* curr_locked is set to -1 until the mutex has been created */
572362181Sdim    if (mutex->curr_locked != -1) {
573362181Sdim        if ((rv = proc_pthread_mutex_unref(mutex))) {
574362181Sdim            return rv;
575362181Sdim        }
576362181Sdim    }
577362181Sdim    if (munmap(mutex->os.pthread_interproc, sizeof(proc_pthread_mutex_t))) {
578251875Speter        return errno;
579251875Speter    }
580251875Speter    return APR_SUCCESS;
581251875Speter}
582251875Speter
583362181Sdimstatic apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex,
584362181Sdim                                              const char *fname)
585251875Speter{
586251875Speter    apr_status_t rv;
587251875Speter    int fd;
588251875Speter    pthread_mutexattr_t mattr;
589251875Speter
590251875Speter    fd = open("/dev/zero", O_RDWR);
591251875Speter    if (fd < 0) {
592251875Speter        return errno;
593251875Speter    }
594251875Speter
595362181Sdim    new_mutex->os.pthread_interproc = mmap(NULL, sizeof(proc_pthread_mutex_t),
596362181Sdim                                           PROT_READ | PROT_WRITE, MAP_SHARED,
597362181Sdim                                           fd, 0);
598362181Sdim    if (new_mutex->os.pthread_interproc == MAP_FAILED) {
599362181Sdim        new_mutex->os.pthread_interproc = NULL;
600362181Sdim        rv = errno;
601251875Speter        close(fd);
602362181Sdim        return rv;
603251875Speter    }
604251875Speter    close(fd);
605251875Speter
606362181Sdim    new_mutex->pthread_refcounting = 1;
607251875Speter    new_mutex->curr_locked = -1; /* until the mutex has been created */
608362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
609362181Sdim    proc_pthread_mutex_cond_locked(new_mutex) = -1;
610362181Sdim#endif
611251875Speter
612251875Speter    if ((rv = pthread_mutexattr_init(&mattr))) {
613251875Speter#ifdef HAVE_ZOS_PTHREADS
614251875Speter        rv = errno;
615251875Speter#endif
616362181Sdim        proc_mutex_pthread_cleanup(new_mutex);
617251875Speter        return rv;
618251875Speter    }
619251875Speter    if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) {
620251875Speter#ifdef HAVE_ZOS_PTHREADS
621251875Speter        rv = errno;
622251875Speter#endif
623362181Sdim        proc_mutex_pthread_cleanup(new_mutex);
624251875Speter        pthread_mutexattr_destroy(&mattr);
625251875Speter        return rv;
626251875Speter    }
627251875Speter
628362181Sdim#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
629251875Speter#ifdef HAVE_PTHREAD_MUTEX_ROBUST
630362181Sdim    rv = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST);
631362181Sdim#else
632362181Sdim    rv = pthread_mutexattr_setrobust_np(&mattr, PTHREAD_MUTEX_ROBUST_NP);
633362181Sdim#endif
634362181Sdim    if (rv) {
635251875Speter#ifdef HAVE_ZOS_PTHREADS
636251875Speter        rv = errno;
637251875Speter#endif
638362181Sdim        proc_mutex_pthread_cleanup(new_mutex);
639251875Speter        pthread_mutexattr_destroy(&mattr);
640251875Speter        return rv;
641251875Speter    }
642251875Speter    if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) {
643251875Speter#ifdef HAVE_ZOS_PTHREADS
644251875Speter        rv = errno;
645251875Speter#endif
646362181Sdim        proc_mutex_pthread_cleanup(new_mutex);
647251875Speter        pthread_mutexattr_destroy(&mattr);
648251875Speter        return rv;
649251875Speter    }
650362181Sdim#endif /* HAVE_PTHREAD_MUTEX_ROBUST[_NP] */
651251875Speter
652362181Sdim    if ((rv = pthread_mutex_init(&proc_pthread_mutex(new_mutex), &mattr))) {
653251875Speter#ifdef HAVE_ZOS_PTHREADS
654251875Speter        rv = errno;
655251875Speter#endif
656362181Sdim        proc_mutex_pthread_cleanup(new_mutex);
657251875Speter        pthread_mutexattr_destroy(&mattr);
658251875Speter        return rv;
659251875Speter    }
660251875Speter
661362181Sdim    proc_pthread_mutex_refcount(new_mutex) = 1; /* first/parent reference */
662251875Speter    new_mutex->curr_locked = 0; /* mutex created now */
663251875Speter
664251875Speter    if ((rv = pthread_mutexattr_destroy(&mattr))) {
665251875Speter#ifdef HAVE_ZOS_PTHREADS
666251875Speter        rv = errno;
667251875Speter#endif
668362181Sdim        proc_mutex_pthread_cleanup(new_mutex);
669251875Speter        return rv;
670251875Speter    }
671251875Speter
672251875Speter    apr_pool_cleanup_register(new_mutex->pool,
673251875Speter                              (void *)new_mutex,
674251875Speter                              apr_proc_mutex_cleanup,
675251875Speter                              apr_pool_cleanup_null);
676251875Speter    return APR_SUCCESS;
677251875Speter}
678251875Speter
679362181Sdimstatic apr_status_t proc_mutex_pthread_child_init(apr_proc_mutex_t **mutex,
680362181Sdim                                                  apr_pool_t *pool,
681362181Sdim                                                  const char *fname)
682251875Speter{
683362181Sdim    (*mutex)->curr_locked = 0;
684362181Sdim    if (proc_pthread_mutex_inc(*mutex)) {
685362181Sdim        apr_pool_cleanup_register(pool, *mutex, proc_pthread_mutex_unref,
686362181Sdim                                  apr_pool_cleanup_null);
687362181Sdim    }
688362181Sdim    return APR_SUCCESS;
689362181Sdim}
690362181Sdim
691362181Sdimstatic apr_status_t proc_mutex_pthread_acquire_ex(apr_proc_mutex_t *mutex,
692362181Sdim                                                  apr_interval_time_t timeout)
693362181Sdim{
694251875Speter    apr_status_t rv;
695251875Speter
696362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
697362181Sdim    if (proc_pthread_mutex_is_cond(mutex)) {
698362181Sdim        if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) {
699362181Sdim#ifdef HAVE_ZOS_PTHREADS
700362181Sdim            rv = errno;
701251875Speter#endif
702362181Sdim#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
703362181Sdim            /* Okay, our owner died.  Let's try to make it consistent again. */
704362181Sdim            if (rv == EOWNERDEAD) {
705362181Sdim                proc_pthread_mutex_dec(mutex);
706251875Speter#ifdef HAVE_PTHREAD_MUTEX_ROBUST
707362181Sdim                pthread_mutex_consistent(&proc_pthread_mutex(mutex));
708362181Sdim#else
709362181Sdim                pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
710362181Sdim#endif
711362181Sdim            }
712362181Sdim            else
713362181Sdim#endif
714362181Sdim            return rv;
715251875Speter        }
716362181Sdim
717362181Sdim        if (!proc_pthread_mutex_cond_locked(mutex)) {
718362181Sdim            rv = APR_SUCCESS;
719362181Sdim        }
720362181Sdim        else if (!timeout) {
721362181Sdim            rv = APR_TIMEUP;
722362181Sdim        }
723362181Sdim        else {
724362181Sdim            struct timespec abstime;
725362181Sdim
726362181Sdim            if (timeout > 0) {
727362181Sdim                timeout += apr_time_now();
728362181Sdim                abstime.tv_sec = apr_time_sec(timeout);
729362181Sdim                abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
730362181Sdim            }
731362181Sdim
732362181Sdim            proc_pthread_mutex_cond_num_waiters(mutex)++;
733362181Sdim            do {
734362181Sdim                if (timeout < 0) {
735362181Sdim                    rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex),
736362181Sdim                                           &proc_pthread_mutex(mutex));
737362181Sdim                    if (rv) {
738362181Sdim#ifdef HAVE_ZOS_PTHREADS
739362181Sdim                        rv = errno;
740362181Sdim#endif
741362181Sdim                        break;
742362181Sdim                    }
743362181Sdim                }
744362181Sdim                else {
745362181Sdim                    rv = pthread_cond_timedwait(&proc_pthread_mutex_cond(mutex),
746362181Sdim                                                &proc_pthread_mutex(mutex),
747362181Sdim                                                &abstime);
748362181Sdim                    if (rv) {
749362181Sdim#ifdef HAVE_ZOS_PTHREADS
750362181Sdim                        rv = errno;
751362181Sdim#endif
752362181Sdim                        if (rv == ETIMEDOUT) {
753362181Sdim                            rv = APR_TIMEUP;
754362181Sdim                        }
755362181Sdim                        break;
756362181Sdim                    }
757362181Sdim                }
758362181Sdim            } while (proc_pthread_mutex_cond_locked(mutex));
759362181Sdim            proc_pthread_mutex_cond_num_waiters(mutex)--;
760362181Sdim        }
761362181Sdim        if (rv != APR_SUCCESS) {
762362181Sdim            pthread_mutex_unlock(&proc_pthread_mutex(mutex));
763362181Sdim            return rv;
764362181Sdim        }
765362181Sdim
766362181Sdim        proc_pthread_mutex_cond_locked(mutex) = 1;
767362181Sdim
768362181Sdim        rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex));
769362181Sdim        if (rv) {
770362181Sdim#ifdef HAVE_ZOS_PTHREADS
771362181Sdim            rv = errno;
772362181Sdim#endif
773362181Sdim            return rv;
774362181Sdim        }
775362181Sdim    }
776362181Sdim    else
777362181Sdim#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
778362181Sdim    {
779362181Sdim        if (timeout < 0) {
780362181Sdim            rv = pthread_mutex_lock(&proc_pthread_mutex(mutex));
781362181Sdim            if (rv) {
782362181Sdim#ifdef HAVE_ZOS_PTHREADS
783362181Sdim                rv = errno;
784362181Sdim#endif
785362181Sdim            }
786362181Sdim        }
787362181Sdim        else if (!timeout) {
788362181Sdim            rv = pthread_mutex_trylock(&proc_pthread_mutex(mutex));
789362181Sdim            if (rv) {
790362181Sdim#ifdef HAVE_ZOS_PTHREADS
791362181Sdim                rv = errno;
792362181Sdim#endif
793362181Sdim                if (rv == EBUSY) {
794362181Sdim                    return APR_TIMEUP;
795362181Sdim                }
796362181Sdim            }
797362181Sdim        }
798251875Speter        else
799362181Sdim#if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
800362181Sdim        {
801362181Sdim            struct timespec abstime;
802362181Sdim
803362181Sdim            timeout += apr_time_now();
804362181Sdim            abstime.tv_sec = apr_time_sec(timeout);
805362181Sdim            abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
806362181Sdim
807362181Sdim            rv = pthread_mutex_timedlock(&proc_pthread_mutex(mutex), &abstime);
808362181Sdim            if (rv) {
809362181Sdim#ifdef HAVE_ZOS_PTHREADS
810362181Sdim                rv = errno;
811362181Sdim#endif
812362181Sdim                if (rv == ETIMEDOUT) {
813362181Sdim                    return APR_TIMEUP;
814362181Sdim                }
815362181Sdim            }
816362181Sdim        }
817362181Sdim        if (rv) {
818362181Sdim#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
819362181Sdim            /* Okay, our owner died.  Let's try to make it consistent again. */
820362181Sdim            if (rv == EOWNERDEAD) {
821362181Sdim                proc_pthread_mutex_dec(mutex);
822362181Sdim#ifdef HAVE_PTHREAD_MUTEX_ROBUST
823362181Sdim                pthread_mutex_consistent(&proc_pthread_mutex(mutex));
824251875Speter#else
825362181Sdim                pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
826251875Speter#endif
827362181Sdim            }
828362181Sdim            else
829362181Sdim#endif
830362181Sdim            return rv;
831362181Sdim        }
832362181Sdim#else /* !HAVE_PTHREAD_MUTEX_TIMEDLOCK */
833362181Sdim        return proc_mutex_spinsleep_timedacquire(mutex, timeout);
834362181Sdim#endif
835251875Speter    }
836362181Sdim
837251875Speter    mutex->curr_locked = 1;
838251875Speter    return APR_SUCCESS;
839251875Speter}
840251875Speter
841362181Sdimstatic apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex)
842251875Speter{
843362181Sdim    return proc_mutex_pthread_acquire_ex(mutex, -1);
844362181Sdim}
845362181Sdim
846362181Sdimstatic apr_status_t proc_mutex_pthread_tryacquire(apr_proc_mutex_t *mutex)
847362181Sdim{
848362181Sdim    apr_status_t rv = proc_mutex_pthread_acquire_ex(mutex, 0);
849362181Sdim    return (rv == APR_TIMEUP) ? APR_EBUSY : rv;
850362181Sdim}
851362181Sdim
852362181Sdimstatic apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex,
853362181Sdim                                                apr_interval_time_t timeout)
854362181Sdim{
855362181Sdim    return proc_mutex_pthread_acquire_ex(mutex, (timeout <= 0) ? 0 : timeout);
856362181Sdim}
857362181Sdim
858362181Sdimstatic apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex)
859362181Sdim{
860251875Speter    apr_status_t rv;
861362181Sdim
862362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
863362181Sdim    if (proc_pthread_mutex_is_cond(mutex)) {
864362181Sdim        if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) {
865251875Speter#ifdef HAVE_ZOS_PTHREADS
866362181Sdim            rv = errno;
867251875Speter#endif
868362181Sdim#if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
869362181Sdim            /* Okay, our owner died.  Let's try to make it consistent again. */
870362181Sdim            if (rv == EOWNERDEAD) {
871362181Sdim                proc_pthread_mutex_dec(mutex);
872362181Sdim#ifdef HAVE_PTHREAD_MUTEX_ROBUST
873362181Sdim                pthread_mutex_consistent(&proc_pthread_mutex(mutex));
874362181Sdim#else
875362181Sdim                pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
876362181Sdim#endif
877362181Sdim            }
878362181Sdim            else
879362181Sdim#endif
880362181Sdim            return rv;
881251875Speter        }
882362181Sdim
883362181Sdim        if (!proc_pthread_mutex_cond_locked(mutex)) {
884362181Sdim            rv = APR_EINVAL;
885362181Sdim        }
886362181Sdim        else if (!proc_pthread_mutex_cond_num_waiters(mutex)) {
887251875Speter            rv = APR_SUCCESS;
888251875Speter        }
889362181Sdim        else {
890362181Sdim            rv = pthread_cond_signal(&proc_pthread_mutex_cond(mutex));
891362181Sdim#ifdef HAVE_ZOS_PTHREADS
892362181Sdim            if (rv) {
893362181Sdim                rv = errno;
894362181Sdim            }
895362181Sdim#endif
896362181Sdim        }
897362181Sdim        if (rv != APR_SUCCESS) {
898362181Sdim            pthread_mutex_unlock(&proc_pthread_mutex(mutex));
899251875Speter            return rv;
900362181Sdim        }
901362181Sdim
902362181Sdim        proc_pthread_mutex_cond_locked(mutex) = 0;
903362181Sdim    }
904362181Sdim#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
905362181Sdim
906362181Sdim    mutex->curr_locked = 0;
907362181Sdim    if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
908362181Sdim#ifdef HAVE_ZOS_PTHREADS
909362181Sdim        rv = errno;
910362181Sdim#endif
911251875Speter        return rv;
912251875Speter    }
913362181Sdim
914362181Sdim    return APR_SUCCESS;
915251875Speter}
916251875Speter
917362181Sdimstatic const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
918251875Speter{
919362181Sdim    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
920362181Sdim    proc_mutex_pthread_create,
921362181Sdim    proc_mutex_pthread_acquire,
922362181Sdim    proc_mutex_pthread_tryacquire,
923362181Sdim    proc_mutex_pthread_timedacquire,
924362181Sdim    proc_mutex_pthread_release,
925362181Sdim    proc_mutex_pthread_cleanup,
926362181Sdim    proc_mutex_pthread_child_init,
927362181Sdim    proc_mutex_no_perms_set,
928362181Sdim    APR_LOCK_PROC_PTHREAD,
929362181Sdim    "pthread"
930362181Sdim};
931362181Sdim
932362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
933362181Sdimstatic apr_status_t proc_mutex_pthread_cond_create(apr_proc_mutex_t *new_mutex,
934362181Sdim                                                   const char *fname)
935362181Sdim{
936251875Speter    apr_status_t rv;
937362181Sdim    pthread_condattr_t cattr;
938251875Speter
939362181Sdim    rv = proc_mutex_pthread_create(new_mutex, fname);
940362181Sdim    if (rv != APR_SUCCESS) {
941362181Sdim        return rv;
942362181Sdim    }
943362181Sdim
944362181Sdim    if ((rv = pthread_condattr_init(&cattr))) {
945251875Speter#ifdef HAVE_ZOS_PTHREADS
946251875Speter        rv = errno;
947251875Speter#endif
948362181Sdim        apr_pool_cleanup_run(new_mutex->pool, new_mutex,
949362181Sdim                             apr_proc_mutex_cleanup);
950251875Speter        return rv;
951251875Speter    }
952362181Sdim    if ((rv = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))) {
953362181Sdim#ifdef HAVE_ZOS_PTHREADS
954362181Sdim        rv = errno;
955362181Sdim#endif
956362181Sdim        pthread_condattr_destroy(&cattr);
957362181Sdim        apr_pool_cleanup_run(new_mutex->pool, new_mutex,
958362181Sdim                             apr_proc_mutex_cleanup);
959362181Sdim        return rv;
960362181Sdim    }
961362181Sdim    if ((rv = pthread_cond_init(&proc_pthread_mutex_cond(new_mutex),
962362181Sdim                                &cattr))) {
963362181Sdim#ifdef HAVE_ZOS_PTHREADS
964362181Sdim        rv = errno;
965362181Sdim#endif
966362181Sdim        pthread_condattr_destroy(&cattr);
967362181Sdim        apr_pool_cleanup_run(new_mutex->pool, new_mutex,
968362181Sdim                             apr_proc_mutex_cleanup);
969362181Sdim        return rv;
970362181Sdim    }
971362181Sdim    pthread_condattr_destroy(&cattr);
972362181Sdim
973362181Sdim    proc_pthread_mutex_cond_locked(new_mutex) = 0;
974362181Sdim    proc_pthread_mutex_cond_num_waiters(new_mutex) = 0;
975362181Sdim
976251875Speter    return APR_SUCCESS;
977251875Speter}
978251875Speter
979362181Sdimstatic const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_cond_methods =
980251875Speter{
981251875Speter    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
982362181Sdim    proc_mutex_pthread_cond_create,
983362181Sdim    proc_mutex_pthread_acquire,
984362181Sdim    proc_mutex_pthread_tryacquire,
985362181Sdim    proc_mutex_pthread_timedacquire,
986362181Sdim    proc_mutex_pthread_release,
987362181Sdim    proc_mutex_pthread_cleanup,
988362181Sdim    proc_mutex_pthread_child_init,
989362181Sdim    proc_mutex_no_perms_set,
990362181Sdim    APR_LOCK_PROC_PTHREAD,
991251875Speter    "pthread"
992251875Speter};
993362181Sdim#endif
994251875Speter
995251875Speter#endif
996251875Speter
997251875Speter#if APR_HAS_FCNTL_SERIALIZE
998251875Speter
999251875Speterstatic struct flock proc_mutex_lock_it;
1000251875Speterstatic struct flock proc_mutex_unlock_it;
1001251875Speter
1002251875Speterstatic apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
1003251875Speter
1004251875Speterstatic void proc_mutex_fcntl_setup(void)
1005251875Speter{
1006251875Speter    proc_mutex_lock_it.l_whence = SEEK_SET;   /* from current point */
1007251875Speter    proc_mutex_lock_it.l_start = 0;           /* -"- */
1008251875Speter    proc_mutex_lock_it.l_len = 0;             /* until end of file */
1009251875Speter    proc_mutex_lock_it.l_type = F_WRLCK;      /* set exclusive/write lock */
1010251875Speter    proc_mutex_lock_it.l_pid = 0;             /* pid not actually interesting */
1011251875Speter    proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */
1012251875Speter    proc_mutex_unlock_it.l_start = 0;         /* -"- */
1013251875Speter    proc_mutex_unlock_it.l_len = 0;           /* until end of file */
1014251875Speter    proc_mutex_unlock_it.l_type = F_UNLCK;    /* set exclusive/write lock */
1015251875Speter    proc_mutex_unlock_it.l_pid = 0;           /* pid not actually interesting */
1016251875Speter}
1017251875Speter
1018251875Speterstatic apr_status_t proc_mutex_fcntl_cleanup(void *mutex_)
1019251875Speter{
1020362181Sdim    apr_status_t status = APR_SUCCESS;
1021251875Speter    apr_proc_mutex_t *mutex=mutex_;
1022251875Speter
1023251875Speter    if (mutex->curr_locked == 1) {
1024251875Speter        status = proc_mutex_fcntl_release(mutex);
1025251875Speter        if (status != APR_SUCCESS)
1026251875Speter            return status;
1027251875Speter    }
1028251875Speter
1029362181Sdim    if (mutex->interproc) {
1030362181Sdim        status = apr_file_close(mutex->interproc);
1031362181Sdim    }
1032362181Sdim    if (!mutex->interproc_closing
1033362181Sdim            && mutex->os.crossproc != -1
1034362181Sdim            && close(mutex->os.crossproc) == -1
1035362181Sdim            && status == APR_SUCCESS) {
1036362181Sdim        status = errno;
1037362181Sdim    }
1038362181Sdim    return status;
1039251875Speter}
1040251875Speter
1041251875Speterstatic apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex,
1042251875Speter                                            const char *fname)
1043251875Speter{
1044251875Speter    int rv;
1045251875Speter
1046251875Speter    if (fname) {
1047251875Speter        new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
1048251875Speter        rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
1049251875Speter                           APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
1050251875Speter                           APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD,
1051251875Speter                           new_mutex->pool);
1052251875Speter    }
1053251875Speter    else {
1054251875Speter        new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
1055251875Speter        rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
1056251875Speter                             APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
1057251875Speter                             new_mutex->pool);
1058251875Speter    }
1059251875Speter
1060251875Speter    if (rv != APR_SUCCESS) {
1061251875Speter        return rv;
1062251875Speter    }
1063251875Speter
1064362181Sdim    new_mutex->os.crossproc = new_mutex->interproc->filedes;
1065362181Sdim    new_mutex->interproc_closing = 1;
1066251875Speter    new_mutex->curr_locked = 0;
1067251875Speter    unlink(new_mutex->fname);
1068251875Speter    apr_pool_cleanup_register(new_mutex->pool,
1069251875Speter                              (void*)new_mutex,
1070251875Speter                              apr_proc_mutex_cleanup,
1071251875Speter                              apr_pool_cleanup_null);
1072251875Speter    return APR_SUCCESS;
1073251875Speter}
1074251875Speter
1075251875Speterstatic apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex)
1076251875Speter{
1077251875Speter    int rc;
1078251875Speter
1079251875Speter    do {
1080362181Sdim        rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_lock_it);
1081251875Speter    } while (rc < 0 && errno == EINTR);
1082251875Speter    if (rc < 0) {
1083251875Speter        return errno;
1084251875Speter    }
1085251875Speter    mutex->curr_locked=1;
1086251875Speter    return APR_SUCCESS;
1087251875Speter}
1088251875Speter
1089251875Speterstatic apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex)
1090251875Speter{
1091251875Speter    int rc;
1092251875Speter
1093251875Speter    do {
1094362181Sdim        rc = fcntl(mutex->os.crossproc, F_SETLK, &proc_mutex_lock_it);
1095251875Speter    } while (rc < 0 && errno == EINTR);
1096251875Speter    if (rc < 0) {
1097251875Speter#if FCNTL_TRYACQUIRE_EACCES
1098251875Speter        if (errno == EACCES) {
1099251875Speter#else
1100251875Speter        if (errno == EAGAIN) {
1101251875Speter#endif
1102251875Speter            return APR_EBUSY;
1103251875Speter        }
1104251875Speter        return errno;
1105251875Speter    }
1106251875Speter    mutex->curr_locked = 1;
1107251875Speter    return APR_SUCCESS;
1108251875Speter}
1109251875Speter
1110251875Speterstatic apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
1111251875Speter{
1112251875Speter    int rc;
1113251875Speter
1114251875Speter    mutex->curr_locked=0;
1115251875Speter    do {
1116362181Sdim        rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_unlock_it);
1117251875Speter    } while (rc < 0 && errno == EINTR);
1118251875Speter    if (rc < 0) {
1119251875Speter        return errno;
1120251875Speter    }
1121251875Speter    return APR_SUCCESS;
1122251875Speter}
1123251875Speter
1124362181Sdimstatic apr_status_t proc_mutex_fcntl_perms_set(apr_proc_mutex_t *mutex,
1125362181Sdim                                               apr_fileperms_t perms,
1126362181Sdim                                               apr_uid_t uid,
1127362181Sdim                                               apr_gid_t gid)
1128362181Sdim{
1129362181Sdim
1130362181Sdim    if (mutex->fname) {
1131362181Sdim        if (!(perms & APR_FPROT_GSETID))
1132362181Sdim            gid = -1;
1133362181Sdim        if (fchown(mutex->os.crossproc, uid, gid) < 0) {
1134362181Sdim            return errno;
1135362181Sdim        }
1136362181Sdim    }
1137362181Sdim    return APR_SUCCESS;
1138362181Sdim}
1139362181Sdim
1140251875Speterstatic const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
1141251875Speter{
1142251875Speter#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL)
1143251875Speter    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
1144251875Speter#else
1145251875Speter    0,
1146251875Speter#endif
1147251875Speter    proc_mutex_fcntl_create,
1148251875Speter    proc_mutex_fcntl_acquire,
1149251875Speter    proc_mutex_fcntl_tryacquire,
1150362181Sdim    proc_mutex_spinsleep_timedacquire,
1151251875Speter    proc_mutex_fcntl_release,
1152251875Speter    proc_mutex_fcntl_cleanup,
1153251875Speter    proc_mutex_no_child_init,
1154362181Sdim    proc_mutex_fcntl_perms_set,
1155362181Sdim    APR_LOCK_FCNTL,
1156251875Speter    "fcntl"
1157251875Speter};
1158251875Speter
1159251875Speter#endif /* fcntl implementation */
1160251875Speter
1161251875Speter#if APR_HAS_FLOCK_SERIALIZE
1162251875Speter
1163251875Speterstatic apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
1164251875Speter
1165251875Speterstatic apr_status_t proc_mutex_flock_cleanup(void *mutex_)
1166251875Speter{
1167362181Sdim    apr_status_t status = APR_SUCCESS;
1168251875Speter    apr_proc_mutex_t *mutex=mutex_;
1169251875Speter
1170251875Speter    if (mutex->curr_locked == 1) {
1171251875Speter        status = proc_mutex_flock_release(mutex);
1172251875Speter        if (status != APR_SUCCESS)
1173251875Speter            return status;
1174251875Speter    }
1175251875Speter    if (mutex->interproc) { /* if it was opened properly */
1176362181Sdim        status = apr_file_close(mutex->interproc);
1177251875Speter    }
1178362181Sdim    if (!mutex->interproc_closing
1179362181Sdim            && mutex->os.crossproc != -1
1180362181Sdim            && close(mutex->os.crossproc) == -1
1181362181Sdim            && status == APR_SUCCESS) {
1182362181Sdim        status = errno;
1183362181Sdim    }
1184362181Sdim    if (mutex->fname) {
1185362181Sdim        unlink(mutex->fname);
1186362181Sdim    }
1187362181Sdim    return status;
1188251875Speter}
1189251875Speter
1190251875Speterstatic apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex,
1191251875Speter                                            const char *fname)
1192251875Speter{
1193251875Speter    int rv;
1194251875Speter
1195251875Speter    if (fname) {
1196251875Speter        new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
1197251875Speter        rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
1198251875Speter                           APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
1199251875Speter                           APR_UREAD | APR_UWRITE,
1200251875Speter                           new_mutex->pool);
1201251875Speter    }
1202251875Speter    else {
1203251875Speter        new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
1204251875Speter        rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
1205251875Speter                             APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
1206251875Speter                             new_mutex->pool);
1207251875Speter    }
1208251875Speter
1209251875Speter    if (rv != APR_SUCCESS) {
1210251875Speter        proc_mutex_flock_cleanup(new_mutex);
1211362181Sdim        return rv;
1212251875Speter    }
1213362181Sdim
1214362181Sdim    new_mutex->os.crossproc = new_mutex->interproc->filedes;
1215362181Sdim    new_mutex->interproc_closing = 1;
1216251875Speter    new_mutex->curr_locked = 0;
1217251875Speter    apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
1218251875Speter                              apr_proc_mutex_cleanup,
1219251875Speter                              apr_pool_cleanup_null);
1220251875Speter    return APR_SUCCESS;
1221251875Speter}
1222251875Speter
1223251875Speterstatic apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex)
1224251875Speter{
1225251875Speter    int rc;
1226251875Speter
1227251875Speter    do {
1228362181Sdim        rc = flock(mutex->os.crossproc, LOCK_EX);
1229251875Speter    } while (rc < 0 && errno == EINTR);
1230251875Speter    if (rc < 0) {
1231251875Speter        return errno;
1232251875Speter    }
1233251875Speter    mutex->curr_locked = 1;
1234251875Speter    return APR_SUCCESS;
1235251875Speter}
1236251875Speter
1237251875Speterstatic apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex)
1238251875Speter{
1239251875Speter    int rc;
1240251875Speter
1241251875Speter    do {
1242362181Sdim        rc = flock(mutex->os.crossproc, LOCK_EX | LOCK_NB);
1243251875Speter    } while (rc < 0 && errno == EINTR);
1244251875Speter    if (rc < 0) {
1245251875Speter        if (errno == EWOULDBLOCK || errno == EAGAIN) {
1246251875Speter            return APR_EBUSY;
1247251875Speter        }
1248251875Speter        return errno;
1249251875Speter    }
1250251875Speter    mutex->curr_locked = 1;
1251251875Speter    return APR_SUCCESS;
1252251875Speter}
1253251875Speter
1254251875Speterstatic apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
1255251875Speter{
1256251875Speter    int rc;
1257251875Speter
1258251875Speter    mutex->curr_locked = 0;
1259251875Speter    do {
1260362181Sdim        rc = flock(mutex->os.crossproc, LOCK_UN);
1261251875Speter    } while (rc < 0 && errno == EINTR);
1262251875Speter    if (rc < 0) {
1263251875Speter        return errno;
1264251875Speter    }
1265251875Speter    return APR_SUCCESS;
1266251875Speter}
1267251875Speter
1268251875Speterstatic apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex,
1269251875Speter                                                apr_pool_t *pool,
1270251875Speter                                                const char *fname)
1271251875Speter{
1272251875Speter    apr_proc_mutex_t *new_mutex;
1273251875Speter    int rv;
1274251875Speter
1275251875Speter    if (!fname) {
1276251875Speter        fname = (*mutex)->fname;
1277362181Sdim        if (!fname) {
1278362181Sdim            return APR_SUCCESS;
1279362181Sdim        }
1280251875Speter    }
1281362181Sdim
1282362181Sdim    new_mutex = (apr_proc_mutex_t *)apr_pmemdup(pool, *mutex,
1283362181Sdim                                                sizeof(apr_proc_mutex_t));
1284362181Sdim    new_mutex->pool = pool;
1285251875Speter    new_mutex->fname = apr_pstrdup(pool, fname);
1286251875Speter    rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
1287251875Speter                       APR_FOPEN_WRITE, 0, new_mutex->pool);
1288251875Speter    if (rv != APR_SUCCESS) {
1289251875Speter        return rv;
1290251875Speter    }
1291362181Sdim    new_mutex->os.crossproc = new_mutex->interproc->filedes;
1292362181Sdim    new_mutex->interproc_closing = 1;
1293362181Sdim
1294251875Speter    *mutex = new_mutex;
1295251875Speter    return APR_SUCCESS;
1296251875Speter}
1297251875Speter
1298362181Sdimstatic apr_status_t proc_mutex_flock_perms_set(apr_proc_mutex_t *mutex,
1299362181Sdim                                               apr_fileperms_t perms,
1300362181Sdim                                               apr_uid_t uid,
1301362181Sdim                                               apr_gid_t gid)
1302362181Sdim{
1303362181Sdim
1304362181Sdim    if (mutex->fname) {
1305362181Sdim        if (!(perms & APR_FPROT_GSETID))
1306362181Sdim            gid = -1;
1307362181Sdim        if (fchown(mutex->os.crossproc, uid, gid) < 0) {
1308362181Sdim            return errno;
1309362181Sdim        }
1310362181Sdim    }
1311362181Sdim    return APR_SUCCESS;
1312362181Sdim}
1313362181Sdim
1314251875Speterstatic const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
1315251875Speter{
1316251875Speter#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL)
1317251875Speter    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
1318251875Speter#else
1319251875Speter    0,
1320251875Speter#endif
1321251875Speter    proc_mutex_flock_create,
1322251875Speter    proc_mutex_flock_acquire,
1323251875Speter    proc_mutex_flock_tryacquire,
1324362181Sdim    proc_mutex_spinsleep_timedacquire,
1325251875Speter    proc_mutex_flock_release,
1326251875Speter    proc_mutex_flock_cleanup,
1327251875Speter    proc_mutex_flock_child_init,
1328362181Sdim    proc_mutex_flock_perms_set,
1329362181Sdim    APR_LOCK_FLOCK,
1330251875Speter    "flock"
1331251875Speter};
1332251875Speter
1333251875Speter#endif /* flock implementation */
1334251875Speter
1335251875Spetervoid apr_proc_mutex_unix_setup_lock(void)
1336251875Speter{
1337251875Speter    /* setup only needed for sysvsem and fnctl */
1338251875Speter#if APR_HAS_SYSVSEM_SERIALIZE
1339251875Speter    proc_mutex_sysv_setup();
1340251875Speter#endif
1341251875Speter#if APR_HAS_FCNTL_SERIALIZE
1342251875Speter    proc_mutex_fcntl_setup();
1343251875Speter#endif
1344251875Speter}
1345251875Speter
1346362181Sdimstatic apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex,
1347362181Sdim                                             apr_lockmech_e mech,
1348362181Sdim                                             apr_os_proc_mutex_t *ospmutex)
1349251875Speter{
1350362181Sdim#if APR_HAS_PROC_PTHREAD_SERIALIZE
1351362181Sdim    new_mutex->os.pthread_interproc = NULL;
1352362181Sdim#endif
1353362181Sdim#if APR_HAS_POSIXSEM_SERIALIZE
1354362181Sdim    new_mutex->os.psem_interproc = NULL;
1355362181Sdim#endif
1356362181Sdim#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
1357362181Sdim    new_mutex->os.crossproc = -1;
1358362181Sdim
1359362181Sdim#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
1360362181Sdim    new_mutex->interproc = NULL;
1361362181Sdim    new_mutex->interproc_closing = 0;
1362362181Sdim#endif
1363362181Sdim#endif
1364362181Sdim
1365251875Speter    switch (mech) {
1366251875Speter    case APR_LOCK_FCNTL:
1367251875Speter#if APR_HAS_FCNTL_SERIALIZE
1368362181Sdim        new_mutex->meth = &mutex_fcntl_methods;
1369362181Sdim        if (ospmutex) {
1370362181Sdim            if (ospmutex->crossproc == -1) {
1371362181Sdim                return APR_EINVAL;
1372362181Sdim            }
1373362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1374362181Sdim        }
1375251875Speter#else
1376251875Speter        return APR_ENOTIMPL;
1377251875Speter#endif
1378251875Speter        break;
1379251875Speter    case APR_LOCK_FLOCK:
1380251875Speter#if APR_HAS_FLOCK_SERIALIZE
1381362181Sdim        new_mutex->meth = &mutex_flock_methods;
1382362181Sdim        if (ospmutex) {
1383362181Sdim            if (ospmutex->crossproc == -1) {
1384362181Sdim                return APR_EINVAL;
1385362181Sdim            }
1386362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1387362181Sdim        }
1388251875Speter#else
1389251875Speter        return APR_ENOTIMPL;
1390251875Speter#endif
1391251875Speter        break;
1392251875Speter    case APR_LOCK_SYSVSEM:
1393251875Speter#if APR_HAS_SYSVSEM_SERIALIZE
1394362181Sdim        new_mutex->meth = &mutex_sysv_methods;
1395362181Sdim        if (ospmutex) {
1396362181Sdim            if (ospmutex->crossproc == -1) {
1397362181Sdim                return APR_EINVAL;
1398362181Sdim            }
1399362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1400362181Sdim        }
1401251875Speter#else
1402251875Speter        return APR_ENOTIMPL;
1403251875Speter#endif
1404251875Speter        break;
1405251875Speter    case APR_LOCK_POSIXSEM:
1406251875Speter#if APR_HAS_POSIXSEM_SERIALIZE
1407362181Sdim        new_mutex->meth = &mutex_posixsem_methods;
1408362181Sdim        if (ospmutex) {
1409362181Sdim            if (ospmutex->psem_interproc == NULL) {
1410362181Sdim                return APR_EINVAL;
1411362181Sdim            }
1412362181Sdim            new_mutex->os.psem_interproc = ospmutex->psem_interproc;
1413362181Sdim        }
1414251875Speter#else
1415251875Speter        return APR_ENOTIMPL;
1416251875Speter#endif
1417251875Speter        break;
1418251875Speter    case APR_LOCK_PROC_PTHREAD:
1419251875Speter#if APR_HAS_PROC_PTHREAD_SERIALIZE
1420362181Sdim        new_mutex->meth = &mutex_proc_pthread_methods;
1421362181Sdim        if (ospmutex) {
1422362181Sdim            if (ospmutex->pthread_interproc == NULL) {
1423362181Sdim                return APR_EINVAL;
1424362181Sdim            }
1425362181Sdim            new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
1426362181Sdim        }
1427251875Speter#else
1428251875Speter        return APR_ENOTIMPL;
1429251875Speter#endif
1430251875Speter        break;
1431362181Sdim    case APR_LOCK_DEFAULT_TIMED:
1432362181Sdim#if APR_HAS_PROC_PTHREAD_SERIALIZE \
1433362181Sdim        && (APR_USE_PROC_PTHREAD_MUTEX_COND \
1434362181Sdim            || defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) \
1435362181Sdim        && defined(HAVE_PTHREAD_MUTEX_ROBUST)
1436362181Sdim#if APR_USE_PROC_PTHREAD_MUTEX_COND
1437362181Sdim        new_mutex->meth = &mutex_proc_pthread_cond_methods;
1438362181Sdim#else
1439362181Sdim        new_mutex->meth = &mutex_proc_pthread_methods;
1440362181Sdim#endif
1441362181Sdim        if (ospmutex) {
1442362181Sdim            if (ospmutex->pthread_interproc == NULL) {
1443362181Sdim                return APR_EINVAL;
1444362181Sdim            }
1445362181Sdim            new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
1446362181Sdim        }
1447362181Sdim        break;
1448362181Sdim#elif APR_HAS_SYSVSEM_SERIALIZE && defined(HAVE_SEMTIMEDOP)
1449362181Sdim        new_mutex->meth = &mutex_sysv_methods;
1450362181Sdim        if (ospmutex) {
1451362181Sdim            if (ospmutex->crossproc == -1) {
1452362181Sdim                return APR_EINVAL;
1453362181Sdim            }
1454362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1455362181Sdim        }
1456362181Sdim        break;
1457362181Sdim#elif APR_HAS_POSIXSEM_SERIALIZE && defined(HAVE_SEM_TIMEDWAIT)
1458362181Sdim        new_mutex->meth = &mutex_posixsem_methods;
1459362181Sdim        if (ospmutex) {
1460362181Sdim            if (ospmutex->psem_interproc == NULL) {
1461362181Sdim                return APR_EINVAL;
1462362181Sdim            }
1463362181Sdim            new_mutex->os.psem_interproc = ospmutex->psem_interproc;
1464362181Sdim        }
1465362181Sdim        break;
1466362181Sdim#endif
1467362181Sdim        /* fall trough */
1468251875Speter    case APR_LOCK_DEFAULT:
1469251875Speter#if APR_USE_FLOCK_SERIALIZE
1470362181Sdim        new_mutex->meth = &mutex_flock_methods;
1471362181Sdim        if (ospmutex) {
1472362181Sdim            if (ospmutex->crossproc == -1) {
1473362181Sdim                return APR_EINVAL;
1474362181Sdim            }
1475362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1476362181Sdim        }
1477251875Speter#elif APR_USE_SYSVSEM_SERIALIZE
1478362181Sdim        new_mutex->meth = &mutex_sysv_methods;
1479362181Sdim        if (ospmutex) {
1480362181Sdim            if (ospmutex->crossproc == -1) {
1481362181Sdim                return APR_EINVAL;
1482362181Sdim            }
1483362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1484362181Sdim        }
1485251875Speter#elif APR_USE_FCNTL_SERIALIZE
1486362181Sdim        new_mutex->meth = &mutex_fcntl_methods;
1487362181Sdim        if (ospmutex) {
1488362181Sdim            if (ospmutex->crossproc == -1) {
1489362181Sdim                return APR_EINVAL;
1490362181Sdim            }
1491362181Sdim            new_mutex->os.crossproc = ospmutex->crossproc;
1492362181Sdim        }
1493251875Speter#elif APR_USE_PROC_PTHREAD_SERIALIZE
1494362181Sdim        new_mutex->meth = &mutex_proc_pthread_methods;
1495362181Sdim        if (ospmutex) {
1496362181Sdim            if (ospmutex->pthread_interproc == NULL) {
1497362181Sdim                return APR_EINVAL;
1498362181Sdim            }
1499362181Sdim            new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
1500362181Sdim        }
1501251875Speter#elif APR_USE_POSIXSEM_SERIALIZE
1502362181Sdim        new_mutex->meth = &mutex_posixsem_methods;
1503362181Sdim        if (ospmutex) {
1504362181Sdim            if (ospmutex->psem_interproc == NULL) {
1505362181Sdim                return APR_EINVAL;
1506362181Sdim            }
1507362181Sdim            new_mutex->os.psem_interproc = ospmutex->psem_interproc;
1508362181Sdim        }
1509251875Speter#else
1510251875Speter        return APR_ENOTIMPL;
1511251875Speter#endif
1512251875Speter        break;
1513251875Speter    default:
1514251875Speter        return APR_ENOTIMPL;
1515251875Speter    }
1516251875Speter    return APR_SUCCESS;
1517251875Speter}
1518251875Speter
1519251875SpeterAPR_DECLARE(const char *) apr_proc_mutex_defname(void)
1520251875Speter{
1521251875Speter    apr_status_t rv;
1522251875Speter    apr_proc_mutex_t mutex;
1523251875Speter
1524362181Sdim    if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT,
1525362181Sdim                                       NULL)) != APR_SUCCESS) {
1526251875Speter        return "unknown";
1527251875Speter    }
1528251875Speter
1529251875Speter    return apr_proc_mutex_name(&mutex);
1530251875Speter}
1531251875Speter
1532251875Speterstatic apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname)
1533251875Speter{
1534251875Speter    apr_status_t rv;
1535251875Speter
1536362181Sdim    if ((rv = proc_mutex_choose_method(new_mutex, mech,
1537362181Sdim                                       NULL)) != APR_SUCCESS) {
1538251875Speter        return rv;
1539251875Speter    }
1540251875Speter
1541251875Speter    if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) {
1542251875Speter        return rv;
1543251875Speter    }
1544251875Speter
1545251875Speter    return APR_SUCCESS;
1546251875Speter}
1547251875Speter
1548251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
1549251875Speter                                                const char *fname,
1550251875Speter                                                apr_lockmech_e mech,
1551251875Speter                                                apr_pool_t *pool)
1552251875Speter{
1553251875Speter    apr_proc_mutex_t *new_mutex;
1554251875Speter    apr_status_t rv;
1555251875Speter
1556251875Speter    new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
1557251875Speter    new_mutex->pool = pool;
1558251875Speter
1559251875Speter    if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS)
1560251875Speter        return rv;
1561251875Speter
1562251875Speter    *mutex = new_mutex;
1563251875Speter    return APR_SUCCESS;
1564251875Speter}
1565251875Speter
1566251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
1567251875Speter                                                    const char *fname,
1568251875Speter                                                    apr_pool_t *pool)
1569251875Speter{
1570251875Speter    return (*mutex)->meth->child_init(mutex, pool, fname);
1571251875Speter}
1572251875Speter
1573251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
1574251875Speter{
1575251875Speter    return mutex->meth->acquire(mutex);
1576251875Speter}
1577251875Speter
1578251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
1579251875Speter{
1580251875Speter    return mutex->meth->tryacquire(mutex);
1581251875Speter}
1582251875Speter
1583362181SdimAPR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex,
1584362181Sdim                                               apr_interval_time_t timeout)
1585362181Sdim{
1586362181Sdim#if APR_HAS_TIMEDLOCKS
1587362181Sdim    return mutex->meth->timedacquire(mutex, timeout);
1588362181Sdim#else
1589362181Sdim    return APR_ENOTIMPL;
1590362181Sdim#endif
1591362181Sdim}
1592362181Sdim
1593251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
1594251875Speter{
1595251875Speter    return mutex->meth->release(mutex);
1596251875Speter}
1597251875Speter
1598251875SpeterAPR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
1599251875Speter{
1600251875Speter    return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
1601251875Speter}
1602251875Speter
1603362181SdimAPR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex)
1604362181Sdim{
1605362181Sdim    return mutex->meth->mech;
1606362181Sdim}
1607362181Sdim
1608251875SpeterAPR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
1609251875Speter{
1610251875Speter    return mutex->meth->name;
1611251875Speter}
1612251875Speter
1613251875SpeterAPR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
1614251875Speter{
1615251875Speter    /* POSIX sems use the fname field but don't use a file,
1616251875Speter     * so be careful. */
1617251875Speter#if APR_HAS_FLOCK_SERIALIZE
1618251875Speter    if (mutex->meth == &mutex_flock_methods) {
1619251875Speter        return mutex->fname;
1620251875Speter    }
1621251875Speter#endif
1622251875Speter#if APR_HAS_FCNTL_SERIALIZE
1623251875Speter    if (mutex->meth == &mutex_fcntl_methods) {
1624251875Speter        return mutex->fname;
1625251875Speter    }
1626251875Speter#endif
1627251875Speter    return NULL;
1628251875Speter}
1629251875Speter
1630362181SdimAPR_PERMS_SET_IMPLEMENT(proc_mutex)
1631362181Sdim{
1632362181Sdim    apr_proc_mutex_t *mutex = (apr_proc_mutex_t *)theproc_mutex;
1633362181Sdim    return mutex->meth->perms_set(mutex, perms, uid, gid);
1634362181Sdim}
1635362181Sdim
1636251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
1637251875Speter
1638251875Speter/* Implement OS-specific accessors defined in apr_portable.h */
1639251875Speter
1640362181SdimAPR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex,
1641362181Sdim                                                   apr_proc_mutex_t *pmutex,
1642362181Sdim                                                   apr_lockmech_e *mech)
1643251875Speter{
1644362181Sdim    *ospmutex = pmutex->os;
1645362181Sdim    if (mech) {
1646362181Sdim        *mech = pmutex->meth->mech;
1647266735Speter    }
1648251875Speter    return APR_SUCCESS;
1649251875Speter}
1650251875Speter
1651362181SdimAPR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
1652362181Sdim                                                apr_proc_mutex_t *pmutex)
1653362181Sdim{
1654362181Sdim    return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL);
1655362181Sdim}
1656362181Sdim
1657362181SdimAPR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex,
1658251875Speter                                                apr_os_proc_mutex_t *ospmutex,
1659362181Sdim                                                apr_lockmech_e mech,
1660362181Sdim                                                int register_cleanup,
1661251875Speter                                                apr_pool_t *pool)
1662251875Speter{
1663362181Sdim    apr_status_t rv;
1664251875Speter    if (pool == NULL) {
1665251875Speter        return APR_ENOPOOL;
1666251875Speter    }
1667362181Sdim
1668251875Speter    if ((*pmutex) == NULL) {
1669251875Speter        (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool,
1670251875Speter                                                    sizeof(apr_proc_mutex_t));
1671251875Speter        (*pmutex)->pool = pool;
1672251875Speter    }
1673362181Sdim    rv = proc_mutex_choose_method(*pmutex, mech, ospmutex);
1674362181Sdim#if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
1675362181Sdim    if (rv == APR_SUCCESS) {
1676362181Sdim        rv = apr_os_file_put(&(*pmutex)->interproc, &(*pmutex)->os.crossproc,
1677362181Sdim                             0, pool);
1678362181Sdim    }
1679251875Speter#endif
1680362181Sdim
1681362181Sdim    if (rv == APR_SUCCESS && register_cleanup) {
1682362181Sdim        apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup,
1683362181Sdim                                  apr_pool_cleanup_null);
1684362181Sdim    }
1685362181Sdim    return rv;
1686251875Speter}
1687251875Speter
1688362181SdimAPR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
1689362181Sdim                                                apr_os_proc_mutex_t *ospmutex,
1690362181Sdim                                                apr_pool_t *pool)
1691362181Sdim{
1692362181Sdim    return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT,
1693362181Sdim                                    0, pool);
1694362181Sdim}
1695362181Sdim
1696