"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/locks/unix/proc_mutex.c" (22 Mar 2019, 49820 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "proc_mutex.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    1 /* Licensed to the Apache Software Foundation (ASF) under one or more
    2  * contributor license agreements.  See the NOTICE file distributed with
    3  * this work for additional information regarding copyright ownership.
    4  * The ASF licenses this file to You under the Apache License, Version 2.0
    5  * (the "License"); you may not use this file except in compliance with
    6  * the License.  You may obtain a copy of the License at
    7  *
    8  *     http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 
   17 #include "apr.h"
   18 #include "apr_strings.h"
   19 #include "apr_arch_proc_mutex.h"
   20 #include "apr_arch_file_io.h" /* for apr_mkstemp() */
   21 #include "apr_hash.h"
   22 #include "apr_atomic.h"
   23 
   24 APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
   25 {
   26     return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup);
   27 }
   28 
   29 #if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \
   30     APR_HAS_SYSVSEM_SERIALIZE
   31 static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex,
   32                                              apr_pool_t *cont,
   33                                              const char *fname)
   34 {
   35     return APR_SUCCESS;
   36 }
   37 #endif    
   38 
   39 #if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_PROC_PTHREAD_SERIALIZE
   40 static apr_status_t proc_mutex_no_perms_set(apr_proc_mutex_t *mutex,
   41                                             apr_fileperms_t perms,
   42                                             apr_uid_t uid,
   43                                             apr_gid_t gid)
   44 {
   45     return APR_ENOTIMPL;
   46 }
   47 #endif    
   48 
   49 #if APR_HAS_FCNTL_SERIALIZE \
   50     || APR_HAS_FLOCK_SERIALIZE \
   51     || (APR_HAS_SYSVSEM_SERIALIZE \
   52         && !defined(HAVE_SEMTIMEDOP)) \
   53     || (APR_HAS_POSIXSEM_SERIALIZE \
   54         && !defined(HAVE_SEM_TIMEDWAIT)) \
   55     || (APR_HAS_PROC_PTHREAD_SERIALIZE \
   56         && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) \
   57         && !defined(HAVE_PTHREAD_CONDATTR_SETPSHARED))
   58 static apr_status_t proc_mutex_spinsleep_timedacquire(apr_proc_mutex_t *mutex,
   59                                                   apr_interval_time_t timeout)
   60 {
   61 #define SLEEP_TIME apr_time_from_msec(10)
   62     apr_status_t rv;
   63     for (;;) {
   64         rv = apr_proc_mutex_trylock(mutex);
   65         if (!APR_STATUS_IS_EBUSY(rv)) {
   66             if (rv == APR_SUCCESS) {
   67                 mutex->curr_locked = 1;
   68             }
   69             break;
   70         }
   71         if (timeout <= 0) {
   72             rv = APR_TIMEUP;
   73             break;
   74         }
   75         if (timeout > SLEEP_TIME) {
   76             apr_sleep(SLEEP_TIME);
   77             timeout -= SLEEP_TIME;
   78         }
   79         else {
   80             apr_sleep(timeout);
   81             timeout = 0;
   82         }
   83     }
   84     return rv;
   85 }
   86 #endif
   87 
   88 #if APR_HAS_POSIXSEM_SERIALIZE
   89 
   90 #ifndef SEM_FAILED
   91 #define SEM_FAILED (-1)
   92 #endif
   93 
   94 static apr_status_t proc_mutex_posix_cleanup(void *mutex_)
   95 {
   96     apr_proc_mutex_t *mutex = mutex_;
   97     
   98     if (sem_close(mutex->os.psem_interproc) < 0) {
   99         return errno;
  100     }
  101 
  102     return APR_SUCCESS;
  103 }    
  104 
  105 static unsigned int rshash (char *p) {
  106     /* hash function from Robert Sedgwicks 'Algorithms in C' book */
  107    unsigned int b    = 378551;
  108    unsigned int a    = 63689;
  109    unsigned int retval = 0;
  110 
  111    for( ; *p; p++)
  112    {
  113       retval = retval * a + (*p);
  114       a *= b;
  115    }
  116 
  117    return retval;
  118 }
  119 
  120 static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex,
  121                                             const char *fname)
  122 {
  123     #define APR_POSIXSEM_NAME_MIN 13
  124     sem_t *psem;
  125     char semname[32];
  126     
  127     /*
  128      * This bogusness is to follow what appears to be the
  129      * lowest common denominator in Posix semaphore naming:
  130      *   - start with '/'
  131      *   - be at most 14 chars
  132      *   - be unique and not match anything on the filesystem
  133      *
  134      * Because of this, we use fname to generate a (unique) hash
  135      * and use that as the name of the semaphore. If no filename was
  136      * given, we create one based on the time. We tuck the name
  137      * away, since it might be useful for debugging. We use 2 hashing
  138      * functions to try to avoid collisions.
  139      *
  140      * To  make this as robust as possible, we initially try something
  141      * larger (and hopefully more unique) and gracefully fail down to the
  142      * LCD above.
  143      *
  144      * NOTE: Darwin (Mac OS X) seems to be the most restrictive
  145      * implementation. Versions previous to Darwin 6.2 had the 14
  146      * char limit, but later rev's allow up to 31 characters.
  147      *
  148      */
  149     if (fname) {
  150         apr_ssize_t flen = strlen(fname);
  151         char *p = apr_pstrndup(new_mutex->pool, fname, strlen(fname));
  152         unsigned int h1, h2;
  153         h1 = (apr_hashfunc_default((const char *)p, &flen) & 0xffffffff);
  154         h2 = (rshash(p) & 0xffffffff);
  155         apr_snprintf(semname, sizeof(semname), "/ApR.%xH%x", h1, h2);
  156     } else {
  157         apr_time_t now;
  158         unsigned long sec;
  159         unsigned long usec;
  160         now = apr_time_now();
  161         sec = apr_time_sec(now);
  162         usec = apr_time_usec(now);
  163         apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec);
  164     }
  165     do {
  166         psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
  167     } while (psem == (sem_t *)SEM_FAILED && errno == EINTR);
  168     if (psem == (sem_t *)SEM_FAILED) {
  169         if (errno == ENAMETOOLONG) {
  170             /* Oh well, good try */
  171             semname[APR_POSIXSEM_NAME_MIN] = '\0';
  172         } else {
  173             return errno;
  174         }
  175         do {
  176             psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
  177         } while (psem == (sem_t *)SEM_FAILED && errno == EINTR);
  178     }
  179 
  180     if (psem == (sem_t *)SEM_FAILED) {
  181         return errno;
  182     }
  183     /* Ahhh. The joys of Posix sems. Predelete it... */
  184     sem_unlink(semname);
  185     new_mutex->os.psem_interproc = psem;
  186     new_mutex->fname = apr_pstrdup(new_mutex->pool, semname);
  187     apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
  188                               apr_proc_mutex_cleanup, 
  189                               apr_pool_cleanup_null);
  190     return APR_SUCCESS;
  191 }
  192 
  193 static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex)
  194 {
  195     int rc;
  196 
  197     do {
  198         rc = sem_wait(mutex->os.psem_interproc);
  199     } while (rc < 0 && errno == EINTR);
  200     if (rc < 0) {
  201         return errno;
  202     }
  203     mutex->curr_locked = 1;
  204     return APR_SUCCESS;
  205 }
  206 
  207 static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex)
  208 {
  209     int rc;
  210 
  211     do {
  212         rc = sem_trywait(mutex->os.psem_interproc);
  213     } while (rc < 0 && errno == EINTR);
  214     if (rc < 0) {
  215         if (errno == EAGAIN) {
  216             return APR_EBUSY;
  217         }
  218         return errno;
  219     }
  220     mutex->curr_locked = 1;
  221     return APR_SUCCESS;
  222 }
  223 
  224 #if defined(HAVE_SEM_TIMEDWAIT)
  225 static apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex,
  226                                               apr_interval_time_t timeout)
  227 {
  228     if (timeout <= 0) {
  229         apr_status_t rv = proc_mutex_posix_tryacquire(mutex);
  230         return (rv == APR_EBUSY) ? APR_TIMEUP : rv;
  231     }
  232     else {
  233         int rc;
  234         struct timespec abstime;
  235 
  236         timeout += apr_time_now();
  237         abstime.tv_sec = apr_time_sec(timeout);
  238         abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
  239         
  240         do {
  241             rc = sem_timedwait(mutex->os.psem_interproc, &abstime);
  242         } while (rc < 0 && errno == EINTR);
  243         if (rc < 0) {
  244             if (errno == ETIMEDOUT) {
  245                 return APR_TIMEUP;
  246             }
  247             return errno;
  248         }
  249     }
  250     mutex->curr_locked = 1;
  251     return APR_SUCCESS;
  252 }
  253 #endif
  254 
  255 static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
  256 {
  257     mutex->curr_locked = 0;
  258     if (sem_post(mutex->os.psem_interproc) < 0) {
  259         /* any failure is probably fatal, so no big deal to leave
  260          * ->curr_locked at 0. */
  261         return errno;
  262     }
  263     return APR_SUCCESS;
  264 }
  265 
  266 static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
  267 {
  268 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL)
  269     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  270 #else
  271     0,
  272 #endif
  273     proc_mutex_posix_create,
  274     proc_mutex_posix_acquire,
  275     proc_mutex_posix_tryacquire,
  276 #if defined(HAVE_SEM_TIMEDWAIT)
  277     proc_mutex_posix_timedacquire,
  278 #else
  279     proc_mutex_spinsleep_timedacquire,
  280 #endif
  281     proc_mutex_posix_release,
  282     proc_mutex_posix_cleanup,
  283     proc_mutex_no_child_init,
  284     proc_mutex_no_perms_set,
  285     APR_LOCK_POSIXSEM,
  286     "posixsem"
  287 };
  288 
  289 #endif /* Posix sem implementation */
  290 
  291 #if APR_HAS_SYSVSEM_SERIALIZE
  292 
  293 static struct sembuf proc_mutex_op_on;
  294 static struct sembuf proc_mutex_op_try;
  295 static struct sembuf proc_mutex_op_off;
  296 
  297 static void proc_mutex_sysv_setup(void)
  298 {
  299     proc_mutex_op_on.sem_num = 0;
  300     proc_mutex_op_on.sem_op = -1;
  301     proc_mutex_op_on.sem_flg = SEM_UNDO;
  302     proc_mutex_op_try.sem_num = 0;
  303     proc_mutex_op_try.sem_op = -1;
  304     proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT;
  305     proc_mutex_op_off.sem_num = 0;
  306     proc_mutex_op_off.sem_op = 1;
  307     proc_mutex_op_off.sem_flg = SEM_UNDO;
  308 }
  309 
  310 static apr_status_t proc_mutex_sysv_cleanup(void *mutex_)
  311 {
  312     apr_proc_mutex_t *mutex=mutex_;
  313     union semun ick;
  314     
  315     if (mutex->os.crossproc != -1) {
  316         ick.val = 0;
  317         semctl(mutex->os.crossproc, 0, IPC_RMID, ick);
  318     }
  319     return APR_SUCCESS;
  320 }    
  321 
  322 static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex,
  323                                            const char *fname)
  324 {
  325     union semun ick;
  326     apr_status_t rv;
  327     
  328     new_mutex->os.crossproc = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
  329     if (new_mutex->os.crossproc == -1) {
  330         rv = errno;
  331         proc_mutex_sysv_cleanup(new_mutex);
  332         return rv;
  333     }
  334     ick.val = 1;
  335     if (semctl(new_mutex->os.crossproc, 0, SETVAL, ick) < 0) {
  336         rv = errno;
  337         proc_mutex_sysv_cleanup(new_mutex);
  338         new_mutex->os.crossproc = -1;
  339         return rv;
  340     }
  341     new_mutex->curr_locked = 0;
  342     apr_pool_cleanup_register(new_mutex->pool,
  343                               (void *)new_mutex, apr_proc_mutex_cleanup, 
  344                               apr_pool_cleanup_null);
  345     return APR_SUCCESS;
  346 }
  347 
  348 static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex)
  349 {
  350     int rc;
  351 
  352     do {
  353         rc = semop(mutex->os.crossproc, &proc_mutex_op_on, 1);
  354     } while (rc < 0 && errno == EINTR);
  355     if (rc < 0) {
  356         return errno;
  357     }
  358     mutex->curr_locked = 1;
  359     return APR_SUCCESS;
  360 }
  361 
  362 static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex)
  363 {
  364     int rc;
  365 
  366     do {
  367         rc = semop(mutex->os.crossproc, &proc_mutex_op_try, 1);
  368     } while (rc < 0 && errno == EINTR);
  369     if (rc < 0) {
  370         if (errno == EAGAIN) {
  371             return APR_EBUSY;
  372         }
  373         return errno;
  374     }
  375     mutex->curr_locked = 1;
  376     return APR_SUCCESS;
  377 }
  378 
  379 #if defined(HAVE_SEMTIMEDOP)
  380 static apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex,
  381                                              apr_interval_time_t timeout)
  382 {
  383     if (timeout <= 0) {
  384         apr_status_t rv = proc_mutex_sysv_tryacquire(mutex);
  385         return (rv == APR_EBUSY) ? APR_TIMEUP : rv;
  386     }
  387     else {
  388         int rc;
  389         struct timespec reltime;
  390 
  391         reltime.tv_sec = apr_time_sec(timeout);
  392         reltime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
  393 
  394         do {
  395             rc = semtimedop(mutex->os.crossproc, &proc_mutex_op_on, 1,
  396                             &reltime);
  397         } while (rc < 0 && errno == EINTR);
  398         if (rc < 0) {
  399             if (errno == EAGAIN) {
  400                 return APR_TIMEUP;
  401             }
  402             return errno;
  403         }
  404     }
  405     mutex->curr_locked = 1;
  406     return APR_SUCCESS;
  407 }
  408 #endif
  409 
  410 static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
  411 {
  412     int rc;
  413 
  414     mutex->curr_locked = 0;
  415     do {
  416         rc = semop(mutex->os.crossproc, &proc_mutex_op_off, 1);
  417     } while (rc < 0 && errno == EINTR);
  418     if (rc < 0) {
  419         return errno;
  420     }
  421     return APR_SUCCESS;
  422 }
  423 
  424 static apr_status_t proc_mutex_sysv_perms_set(apr_proc_mutex_t *mutex,
  425                                               apr_fileperms_t perms,
  426                                               apr_uid_t uid,
  427                                               apr_gid_t gid)
  428 {
  429 
  430     union semun ick;
  431     struct semid_ds buf;
  432     buf.sem_perm.uid = uid;
  433     buf.sem_perm.gid = gid;
  434     buf.sem_perm.mode = apr_unix_perms2mode(perms);
  435     ick.buf = &buf;
  436     if (semctl(mutex->os.crossproc, 0, IPC_SET, ick) < 0) {
  437         return errno;
  438     }
  439     return APR_SUCCESS;
  440 }
  441 
  442 static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
  443 {
  444 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL)
  445     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  446 #else
  447     0,
  448 #endif
  449     proc_mutex_sysv_create,
  450     proc_mutex_sysv_acquire,
  451     proc_mutex_sysv_tryacquire,
  452 #if defined(HAVE_SEMTIMEDOP)
  453     proc_mutex_sysv_timedacquire,
  454 #else
  455     proc_mutex_spinsleep_timedacquire,
  456 #endif
  457     proc_mutex_sysv_release,
  458     proc_mutex_sysv_cleanup,
  459     proc_mutex_no_child_init,
  460     proc_mutex_sysv_perms_set,
  461     APR_LOCK_SYSVSEM,
  462     "sysvsem"
  463 };
  464 
  465 #endif /* SysV sem implementation */
  466 
  467 #if APR_HAS_PROC_PTHREAD_SERIALIZE
  468 
  469 #ifndef APR_USE_PROC_PTHREAD_MUTEX_COND
  470 #define APR_USE_PROC_PTHREAD_MUTEX_COND \
  471             (defined(HAVE_PTHREAD_CONDATTR_SETPSHARED) \
  472              && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK))
  473 #endif
  474 
  475 /* The mmap()ed pthread_interproc is the native pthread_mutex_t followed
  476  * by a refcounter to track children using it.  We want to avoid calling
  477  * pthread_mutex_destroy() on the shared mutex area while it is in use by
  478  * another process, because this may mark the shared pthread_mutex_t as
  479  * invalid for everyone, including forked children (unlike "sysvsem" for
  480  * example), causing unexpected errors or deadlocks (PR 49504).  So the
  481  * last process (parent or child) referencing the mutex will effectively
  482  * destroy it.
  483  */
  484 typedef struct {
  485 #define proc_pthread_cast(m) \
  486     ((proc_pthread_mutex_t *)(m)->os.pthread_interproc)
  487     pthread_mutex_t mutex;
  488 #define proc_pthread_mutex(m) \
  489     (proc_pthread_cast(m)->mutex)
  490 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  491     pthread_cond_t  cond;
  492 #define proc_pthread_mutex_cond(m) \
  493     (proc_pthread_cast(m)->cond)
  494     apr_int32_t     cond_locked;
  495 #define proc_pthread_mutex_cond_locked(m) \
  496     (proc_pthread_cast(m)->cond_locked)
  497     apr_uint32_t    cond_num_waiters;
  498 #define proc_pthread_mutex_cond_num_waiters(m) \
  499     (proc_pthread_cast(m)->cond_num_waiters)
  500 #define proc_pthread_mutex_is_cond(m) \
  501     ((m)->pthread_refcounting && proc_pthread_mutex_cond_locked(m) != -1)
  502 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
  503     apr_uint32_t refcount;
  504 #define proc_pthread_mutex_refcount(m) \
  505     (proc_pthread_cast(m)->refcount)
  506 } proc_pthread_mutex_t;
  507 
  508 
  509 static APR_INLINE int proc_pthread_mutex_inc(apr_proc_mutex_t *mutex)
  510 {
  511     if (mutex->pthread_refcounting) {
  512         apr_atomic_inc32(&proc_pthread_mutex_refcount(mutex));
  513         return 1;
  514     }
  515     return 0;
  516 }
  517 
  518 static APR_INLINE int proc_pthread_mutex_dec(apr_proc_mutex_t *mutex)
  519 {
  520     if (mutex->pthread_refcounting) {
  521         return apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex));
  522     }
  523     return 0;
  524 }
  525 
  526 static apr_status_t proc_pthread_mutex_unref(void *mutex_)
  527 {
  528     apr_proc_mutex_t *mutex=mutex_;
  529     apr_status_t rv;
  530 
  531 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  532     if (proc_pthread_mutex_is_cond(mutex)) {
  533         mutex->curr_locked = 0;
  534     }
  535     else
  536 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
  537     if (mutex->curr_locked == 1) {
  538         if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
  539 #ifdef HAVE_ZOS_PTHREADS
  540             rv = errno;
  541 #endif
  542             return rv;
  543         }
  544     }
  545     if (!proc_pthread_mutex_dec(mutex)) {
  546 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  547         if (proc_pthread_mutex_is_cond(mutex) &&
  548                 (rv = pthread_cond_destroy(&proc_pthread_mutex_cond(mutex)))) {
  549 #ifdef HAVE_ZOS_PTHREADS
  550             rv = errno;
  551 #endif
  552             return rv;
  553         }
  554 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
  555 
  556         if ((rv = pthread_mutex_destroy(&proc_pthread_mutex(mutex)))) {
  557 #ifdef HAVE_ZOS_PTHREADS
  558             rv = errno;
  559 #endif
  560             return rv;
  561         }
  562     }
  563     return APR_SUCCESS;
  564 }
  565 
  566 static apr_status_t proc_mutex_pthread_cleanup(void *mutex_)
  567 {
  568     apr_proc_mutex_t *mutex=mutex_;
  569     apr_status_t rv;
  570 
  571     /* curr_locked is set to -1 until the mutex has been created */
  572     if (mutex->curr_locked != -1) {
  573         if ((rv = proc_pthread_mutex_unref(mutex))) {
  574             return rv;
  575         }
  576     }
  577     if (munmap(mutex->os.pthread_interproc, sizeof(proc_pthread_mutex_t))) {
  578         return errno;
  579     }
  580     return APR_SUCCESS;
  581 }
  582 
  583 static apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex,
  584                                               const char *fname)
  585 {
  586     apr_status_t rv;
  587     int fd;
  588     pthread_mutexattr_t mattr;
  589 
  590     fd = open("/dev/zero", O_RDWR);
  591     if (fd < 0) {
  592         return errno;
  593     }
  594 
  595     new_mutex->os.pthread_interproc = mmap(NULL, sizeof(proc_pthread_mutex_t),
  596                                            PROT_READ | PROT_WRITE, MAP_SHARED,
  597                                            fd, 0); 
  598     if (new_mutex->os.pthread_interproc == MAP_FAILED) {
  599         new_mutex->os.pthread_interproc = NULL;
  600         rv = errno;
  601         close(fd);
  602         return rv;
  603     }
  604     close(fd);
  605 
  606     new_mutex->pthread_refcounting = 1;
  607     new_mutex->curr_locked = -1; /* until the mutex has been created */
  608 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  609     proc_pthread_mutex_cond_locked(new_mutex) = -1;
  610 #endif
  611 
  612     if ((rv = pthread_mutexattr_init(&mattr))) {
  613 #ifdef HAVE_ZOS_PTHREADS
  614         rv = errno;
  615 #endif
  616         proc_mutex_pthread_cleanup(new_mutex);
  617         return rv;
  618     }
  619     if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) {
  620 #ifdef HAVE_ZOS_PTHREADS
  621         rv = errno;
  622 #endif
  623         proc_mutex_pthread_cleanup(new_mutex);
  624         pthread_mutexattr_destroy(&mattr);
  625         return rv;
  626     }
  627 
  628 #if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
  629 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  630     rv = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST);
  631 #else
  632     rv = pthread_mutexattr_setrobust_np(&mattr, PTHREAD_MUTEX_ROBUST_NP);
  633 #endif
  634     if (rv) {
  635 #ifdef HAVE_ZOS_PTHREADS
  636         rv = errno;
  637 #endif
  638         proc_mutex_pthread_cleanup(new_mutex);
  639         pthread_mutexattr_destroy(&mattr);
  640         return rv;
  641     }
  642     if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) {
  643 #ifdef HAVE_ZOS_PTHREADS
  644         rv = errno;
  645 #endif
  646         proc_mutex_pthread_cleanup(new_mutex);
  647         pthread_mutexattr_destroy(&mattr);
  648         return rv;
  649     }
  650 #endif /* HAVE_PTHREAD_MUTEX_ROBUST[_NP] */
  651 
  652     if ((rv = pthread_mutex_init(&proc_pthread_mutex(new_mutex), &mattr))) {
  653 #ifdef HAVE_ZOS_PTHREADS
  654         rv = errno;
  655 #endif
  656         proc_mutex_pthread_cleanup(new_mutex);
  657         pthread_mutexattr_destroy(&mattr);
  658         return rv;
  659     }
  660 
  661     proc_pthread_mutex_refcount(new_mutex) = 1; /* first/parent reference */
  662     new_mutex->curr_locked = 0; /* mutex created now */
  663 
  664     if ((rv = pthread_mutexattr_destroy(&mattr))) {
  665 #ifdef HAVE_ZOS_PTHREADS
  666         rv = errno;
  667 #endif
  668         proc_mutex_pthread_cleanup(new_mutex);
  669         return rv;
  670     }
  671 
  672     apr_pool_cleanup_register(new_mutex->pool,
  673                               (void *)new_mutex,
  674                               apr_proc_mutex_cleanup, 
  675                               apr_pool_cleanup_null);
  676     return APR_SUCCESS;
  677 }
  678 
  679 static apr_status_t proc_mutex_pthread_child_init(apr_proc_mutex_t **mutex,
  680                                                   apr_pool_t *pool, 
  681                                                   const char *fname)
  682 {
  683     (*mutex)->curr_locked = 0;
  684     if (proc_pthread_mutex_inc(*mutex)) {
  685         apr_pool_cleanup_register(pool, *mutex, proc_pthread_mutex_unref, 
  686                                   apr_pool_cleanup_null);
  687     }
  688     return APR_SUCCESS;
  689 }
  690 
  691 static apr_status_t proc_mutex_pthread_acquire_ex(apr_proc_mutex_t *mutex,
  692                                                   apr_interval_time_t timeout)
  693 {
  694     apr_status_t rv;
  695 
  696 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  697     if (proc_pthread_mutex_is_cond(mutex)) {
  698         if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) {
  699 #ifdef HAVE_ZOS_PTHREADS 
  700             rv = errno;
  701 #endif
  702 #if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
  703             /* Okay, our owner died.  Let's try to make it consistent again. */
  704             if (rv == EOWNERDEAD) {
  705                 proc_pthread_mutex_dec(mutex);
  706 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  707                 pthread_mutex_consistent(&proc_pthread_mutex(mutex));
  708 #else
  709                 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
  710 #endif
  711             }
  712             else
  713 #endif
  714             return rv;
  715         }
  716 
  717         if (!proc_pthread_mutex_cond_locked(mutex)) {
  718             rv = APR_SUCCESS;
  719         }
  720         else if (!timeout) {
  721             rv = APR_TIMEUP;
  722         }
  723         else {
  724             struct timespec abstime;
  725 
  726             if (timeout > 0) {
  727                 timeout += apr_time_now();
  728                 abstime.tv_sec = apr_time_sec(timeout);
  729                 abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
  730             }
  731 
  732             proc_pthread_mutex_cond_num_waiters(mutex)++;
  733             do {
  734                 if (timeout < 0) {
  735                     rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex),
  736                                            &proc_pthread_mutex(mutex));
  737                     if (rv) {
  738 #ifdef HAVE_ZOS_PTHREADS
  739                         rv = errno;
  740 #endif
  741                         break;
  742                     }
  743                 }
  744                 else {
  745                     rv = pthread_cond_timedwait(&proc_pthread_mutex_cond(mutex),
  746                                                 &proc_pthread_mutex(mutex),
  747                                                 &abstime);
  748                     if (rv) {
  749 #ifdef HAVE_ZOS_PTHREADS
  750                         rv = errno;
  751 #endif
  752                         if (rv == ETIMEDOUT) {
  753                             rv = APR_TIMEUP;
  754                         }
  755                         break;
  756                     }
  757                 }
  758             } while (proc_pthread_mutex_cond_locked(mutex));
  759             proc_pthread_mutex_cond_num_waiters(mutex)--;
  760         }
  761         if (rv != APR_SUCCESS) {
  762             pthread_mutex_unlock(&proc_pthread_mutex(mutex));
  763             return rv;
  764         }
  765 
  766         proc_pthread_mutex_cond_locked(mutex) = 1;
  767 
  768         rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex));
  769         if (rv) {
  770 #ifdef HAVE_ZOS_PTHREADS
  771             rv = errno;
  772 #endif
  773             return rv;
  774         }
  775     }
  776     else
  777 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
  778     {
  779         if (timeout < 0) {
  780             rv = pthread_mutex_lock(&proc_pthread_mutex(mutex));
  781             if (rv) {
  782 #ifdef HAVE_ZOS_PTHREADS
  783                 rv = errno;
  784 #endif
  785             }
  786         }
  787         else if (!timeout) {
  788             rv = pthread_mutex_trylock(&proc_pthread_mutex(mutex));
  789             if (rv) {
  790 #ifdef HAVE_ZOS_PTHREADS
  791                 rv = errno;
  792 #endif
  793                 if (rv == EBUSY) {
  794                     return APR_TIMEUP;
  795                 }
  796             }
  797         }
  798         else
  799 #if defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
  800         {
  801             struct timespec abstime;
  802 
  803             timeout += apr_time_now();
  804             abstime.tv_sec = apr_time_sec(timeout);
  805             abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
  806 
  807             rv = pthread_mutex_timedlock(&proc_pthread_mutex(mutex), &abstime);
  808             if (rv) {
  809 #ifdef HAVE_ZOS_PTHREADS 
  810                 rv = errno;
  811 #endif
  812                 if (rv == ETIMEDOUT) {
  813                     return APR_TIMEUP;
  814                 }
  815             }
  816         }
  817         if (rv) {
  818 #if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
  819             /* Okay, our owner died.  Let's try to make it consistent again. */
  820             if (rv == EOWNERDEAD) {
  821                 proc_pthread_mutex_dec(mutex);
  822 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  823                 pthread_mutex_consistent(&proc_pthread_mutex(mutex));
  824 #else
  825                 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
  826 #endif
  827             }
  828             else
  829 #endif
  830             return rv;
  831         }
  832 #else /* !HAVE_PTHREAD_MUTEX_TIMEDLOCK */
  833         return proc_mutex_spinsleep_timedacquire(mutex, timeout);
  834 #endif
  835     }
  836 
  837     mutex->curr_locked = 1;
  838     return APR_SUCCESS;
  839 }
  840 
  841 static apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex)
  842 {
  843     return proc_mutex_pthread_acquire_ex(mutex, -1);
  844 }
  845 
  846 static apr_status_t proc_mutex_pthread_tryacquire(apr_proc_mutex_t *mutex)
  847 {
  848     apr_status_t rv = proc_mutex_pthread_acquire_ex(mutex, 0);
  849     return (rv == APR_TIMEUP) ? APR_EBUSY : rv;
  850 }
  851 
  852 static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex,
  853                                                 apr_interval_time_t timeout)
  854 {
  855     return proc_mutex_pthread_acquire_ex(mutex, (timeout <= 0) ? 0 : timeout);
  856 }
  857 
  858 static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex)
  859 {
  860     apr_status_t rv;
  861 
  862 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  863     if (proc_pthread_mutex_is_cond(mutex)) {
  864         if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) {
  865 #ifdef HAVE_ZOS_PTHREADS 
  866             rv = errno;
  867 #endif
  868 #if defined(HAVE_PTHREAD_MUTEX_ROBUST) || defined(HAVE_PTHREAD_MUTEX_ROBUST_NP)
  869             /* Okay, our owner died.  Let's try to make it consistent again. */
  870             if (rv == EOWNERDEAD) {
  871                 proc_pthread_mutex_dec(mutex);
  872 #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  873                 pthread_mutex_consistent(&proc_pthread_mutex(mutex));
  874 #else
  875                 pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
  876 #endif
  877             }
  878             else
  879 #endif
  880             return rv;
  881         }
  882 
  883         if (!proc_pthread_mutex_cond_locked(mutex)) {
  884             rv = APR_EINVAL;
  885         }
  886         else if (!proc_pthread_mutex_cond_num_waiters(mutex)) {
  887             rv = APR_SUCCESS;
  888         }
  889         else {
  890             rv = pthread_cond_signal(&proc_pthread_mutex_cond(mutex));
  891 #ifdef HAVE_ZOS_PTHREADS
  892             if (rv) {
  893                 rv = errno;
  894             }
  895 #endif
  896         }
  897         if (rv != APR_SUCCESS) {
  898             pthread_mutex_unlock(&proc_pthread_mutex(mutex));
  899             return rv;
  900         }
  901 
  902         proc_pthread_mutex_cond_locked(mutex) = 0;
  903     }
  904 #endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
  905 
  906     mutex->curr_locked = 0;
  907     if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
  908 #ifdef HAVE_ZOS_PTHREADS
  909         rv = errno;
  910 #endif
  911         return rv;
  912     }
  913 
  914     return APR_SUCCESS;
  915 }
  916 
  917 static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
  918 {
  919     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  920     proc_mutex_pthread_create,
  921     proc_mutex_pthread_acquire,
  922     proc_mutex_pthread_tryacquire,
  923     proc_mutex_pthread_timedacquire,
  924     proc_mutex_pthread_release,
  925     proc_mutex_pthread_cleanup,
  926     proc_mutex_pthread_child_init,
  927     proc_mutex_no_perms_set,
  928     APR_LOCK_PROC_PTHREAD,
  929     "pthread"
  930 };
  931 
  932 #if APR_USE_PROC_PTHREAD_MUTEX_COND
  933 static apr_status_t proc_mutex_pthread_cond_create(apr_proc_mutex_t *new_mutex,
  934                                                    const char *fname)
  935 {
  936     apr_status_t rv;
  937     pthread_condattr_t cattr;
  938 
  939     rv = proc_mutex_pthread_create(new_mutex, fname);
  940     if (rv != APR_SUCCESS) {
  941         return rv;
  942     }
  943 
  944     if ((rv = pthread_condattr_init(&cattr))) {
  945 #ifdef HAVE_ZOS_PTHREADS
  946         rv = errno;
  947 #endif
  948         apr_pool_cleanup_run(new_mutex->pool, new_mutex,
  949                              apr_proc_mutex_cleanup); 
  950         return rv;
  951     }
  952     if ((rv = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))) {
  953 #ifdef HAVE_ZOS_PTHREADS
  954         rv = errno;
  955 #endif
  956         pthread_condattr_destroy(&cattr);
  957         apr_pool_cleanup_run(new_mutex->pool, new_mutex,
  958                              apr_proc_mutex_cleanup); 
  959         return rv;
  960     }
  961     if ((rv = pthread_cond_init(&proc_pthread_mutex_cond(new_mutex),
  962                                 &cattr))) {
  963 #ifdef HAVE_ZOS_PTHREADS
  964         rv = errno;
  965 #endif
  966         pthread_condattr_destroy(&cattr);
  967         apr_pool_cleanup_run(new_mutex->pool, new_mutex,
  968                              apr_proc_mutex_cleanup); 
  969         return rv;
  970     }
  971     pthread_condattr_destroy(&cattr);
  972 
  973     proc_pthread_mutex_cond_locked(new_mutex) = 0;
  974     proc_pthread_mutex_cond_num_waiters(new_mutex) = 0;
  975 
  976     return APR_SUCCESS;
  977 }
  978 
  979 static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_cond_methods =
  980 {
  981     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  982     proc_mutex_pthread_cond_create,
  983     proc_mutex_pthread_acquire,
  984     proc_mutex_pthread_tryacquire,
  985     proc_mutex_pthread_timedacquire,
  986     proc_mutex_pthread_release,
  987     proc_mutex_pthread_cleanup,
  988     proc_mutex_pthread_child_init,
  989     proc_mutex_no_perms_set,
  990     APR_LOCK_PROC_PTHREAD,
  991     "pthread"
  992 };
  993 #endif
  994 
  995 #endif
  996 
  997 #if APR_HAS_FCNTL_SERIALIZE
  998 
  999 static struct flock proc_mutex_lock_it;
 1000 static struct flock proc_mutex_unlock_it;
 1001 
 1002 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
 1003 
 1004 static void proc_mutex_fcntl_setup(void)
 1005 {
 1006     proc_mutex_lock_it.l_whence = SEEK_SET;   /* from current point */
 1007     proc_mutex_lock_it.l_start = 0;           /* -"- */
 1008     proc_mutex_lock_it.l_len = 0;             /* until end of file */
 1009     proc_mutex_lock_it.l_type = F_WRLCK;      /* set exclusive/write lock */
 1010     proc_mutex_lock_it.l_pid = 0;             /* pid not actually interesting */
 1011     proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */
 1012     proc_mutex_unlock_it.l_start = 0;         /* -"- */
 1013     proc_mutex_unlock_it.l_len = 0;           /* until end of file */
 1014     proc_mutex_unlock_it.l_type = F_UNLCK;    /* set exclusive/write lock */
 1015     proc_mutex_unlock_it.l_pid = 0;           /* pid not actually interesting */
 1016 }
 1017 
 1018 static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_)
 1019 {
 1020     apr_status_t status = APR_SUCCESS;
 1021     apr_proc_mutex_t *mutex=mutex_;
 1022 
 1023     if (mutex->curr_locked == 1) {
 1024         status = proc_mutex_fcntl_release(mutex);
 1025         if (status != APR_SUCCESS)
 1026             return status;
 1027     }
 1028         
 1029     if (mutex->interproc) {
 1030         status = apr_file_close(mutex->interproc);
 1031     }
 1032     if (!mutex->interproc_closing
 1033             && mutex->os.crossproc != -1
 1034             && close(mutex->os.crossproc) == -1
 1035             && status == APR_SUCCESS) {
 1036         status = errno;
 1037     }
 1038     return status;
 1039 }    
 1040 
 1041 static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex,
 1042                                             const char *fname)
 1043 {
 1044     int rv;
 1045  
 1046     if (fname) {
 1047         new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
 1048         rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
 1049                            APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
 1050                            APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD,
 1051                            new_mutex->pool);
 1052     }
 1053     else {
 1054         new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
 1055         rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
 1056                              APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
 1057                              new_mutex->pool);
 1058     }
 1059  
 1060     if (rv != APR_SUCCESS) {
 1061         return rv;
 1062     }
 1063 
 1064     new_mutex->os.crossproc = new_mutex->interproc->filedes;
 1065     new_mutex->interproc_closing = 1;
 1066     new_mutex->curr_locked = 0;
 1067     unlink(new_mutex->fname);
 1068     apr_pool_cleanup_register(new_mutex->pool,
 1069                               (void*)new_mutex,
 1070                               apr_proc_mutex_cleanup, 
 1071                               apr_pool_cleanup_null);
 1072     return APR_SUCCESS; 
 1073 }
 1074 
 1075 static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex)
 1076 {
 1077     int rc;
 1078 
 1079     do {
 1080         rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_lock_it);
 1081     } while (rc < 0 && errno == EINTR);
 1082     if (rc < 0) {
 1083         return errno;
 1084     }
 1085     mutex->curr_locked=1;
 1086     return APR_SUCCESS;
 1087 }
 1088 
 1089 static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex)
 1090 {
 1091     int rc;
 1092 
 1093     do {
 1094         rc = fcntl(mutex->os.crossproc, F_SETLK, &proc_mutex_lock_it);
 1095     } while (rc < 0 && errno == EINTR);
 1096     if (rc < 0) {
 1097 #if FCNTL_TRYACQUIRE_EACCES
 1098         if (errno == EACCES) {
 1099 #else
 1100         if (errno == EAGAIN) {
 1101 #endif
 1102             return APR_EBUSY;
 1103         }
 1104         return errno;
 1105     }
 1106     mutex->curr_locked = 1;
 1107     return APR_SUCCESS;
 1108 }
 1109 
 1110 static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
 1111 {
 1112     int rc;
 1113 
 1114     mutex->curr_locked=0;
 1115     do {
 1116         rc = fcntl(mutex->os.crossproc, F_SETLKW, &proc_mutex_unlock_it);
 1117     } while (rc < 0 && errno == EINTR);
 1118     if (rc < 0) {
 1119         return errno;
 1120     }
 1121     return APR_SUCCESS;
 1122 }
 1123 
 1124 static apr_status_t proc_mutex_fcntl_perms_set(apr_proc_mutex_t *mutex,
 1125                                                apr_fileperms_t perms,
 1126                                                apr_uid_t uid,
 1127                                                apr_gid_t gid)
 1128 {
 1129 
 1130     if (mutex->fname) {
 1131         if (!(perms & APR_FPROT_GSETID))
 1132             gid = -1;
 1133         if (fchown(mutex->os.crossproc, uid, gid) < 0) {
 1134             return errno;
 1135         }
 1136     }
 1137     return APR_SUCCESS;
 1138 }
 1139 
 1140 static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
 1141 {
 1142 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL)
 1143     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 1144 #else
 1145     0,
 1146 #endif
 1147     proc_mutex_fcntl_create,
 1148     proc_mutex_fcntl_acquire,
 1149     proc_mutex_fcntl_tryacquire,
 1150     proc_mutex_spinsleep_timedacquire,
 1151     proc_mutex_fcntl_release,
 1152     proc_mutex_fcntl_cleanup,
 1153     proc_mutex_no_child_init,
 1154     proc_mutex_fcntl_perms_set,
 1155     APR_LOCK_FCNTL,
 1156     "fcntl"
 1157 };
 1158 
 1159 #endif /* fcntl implementation */
 1160 
 1161 #if APR_HAS_FLOCK_SERIALIZE
 1162 
 1163 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
 1164 
 1165 static apr_status_t proc_mutex_flock_cleanup(void *mutex_)
 1166 {
 1167     apr_status_t status = APR_SUCCESS;
 1168     apr_proc_mutex_t *mutex=mutex_;
 1169 
 1170     if (mutex->curr_locked == 1) {
 1171         status = proc_mutex_flock_release(mutex);
 1172         if (status != APR_SUCCESS)
 1173             return status;
 1174     }
 1175     if (mutex->interproc) { /* if it was opened properly */
 1176         status = apr_file_close(mutex->interproc);
 1177     }
 1178     if (!mutex->interproc_closing
 1179             && mutex->os.crossproc != -1
 1180             && close(mutex->os.crossproc) == -1
 1181             && status == APR_SUCCESS) {
 1182         status = errno;
 1183     }
 1184     if (mutex->fname) {
 1185         unlink(mutex->fname);
 1186     }
 1187     return status;
 1188 }    
 1189 
 1190 static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex,
 1191                                             const char *fname)
 1192 {
 1193     int rv;
 1194  
 1195     if (fname) {
 1196         new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
 1197         rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
 1198                            APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
 1199                            APR_UREAD | APR_UWRITE,
 1200                            new_mutex->pool);
 1201     }
 1202     else {
 1203         new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
 1204         rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
 1205                              APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
 1206                              new_mutex->pool);
 1207     }
 1208  
 1209     if (rv != APR_SUCCESS) {
 1210         proc_mutex_flock_cleanup(new_mutex);
 1211         return rv;
 1212     }
 1213 
 1214     new_mutex->os.crossproc = new_mutex->interproc->filedes;
 1215     new_mutex->interproc_closing = 1;
 1216     new_mutex->curr_locked = 0;
 1217     apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
 1218                               apr_proc_mutex_cleanup,
 1219                               apr_pool_cleanup_null);
 1220     return APR_SUCCESS;
 1221 }
 1222 
 1223 static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex)
 1224 {
 1225     int rc;
 1226 
 1227     do {
 1228         rc = flock(mutex->os.crossproc, LOCK_EX);
 1229     } while (rc < 0 && errno == EINTR);
 1230     if (rc < 0) {
 1231         return errno;
 1232     }
 1233     mutex->curr_locked = 1;
 1234     return APR_SUCCESS;
 1235 }
 1236 
 1237 static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex)
 1238 {
 1239     int rc;
 1240 
 1241     do {
 1242         rc = flock(mutex->os.crossproc, LOCK_EX | LOCK_NB);
 1243     } while (rc < 0 && errno == EINTR);
 1244     if (rc < 0) {
 1245         if (errno == EWOULDBLOCK || errno == EAGAIN) {
 1246             return APR_EBUSY;
 1247         }
 1248         return errno;
 1249     }
 1250     mutex->curr_locked = 1;
 1251     return APR_SUCCESS;
 1252 }
 1253 
 1254 static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
 1255 {
 1256     int rc;
 1257 
 1258     mutex->curr_locked = 0;
 1259     do {
 1260         rc = flock(mutex->os.crossproc, LOCK_UN);
 1261     } while (rc < 0 && errno == EINTR);
 1262     if (rc < 0) {
 1263         return errno;
 1264     }
 1265     return APR_SUCCESS;
 1266 }
 1267 
 1268 static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex,
 1269                                                 apr_pool_t *pool, 
 1270                                                 const char *fname)
 1271 {
 1272     apr_proc_mutex_t *new_mutex;
 1273     int rv;
 1274 
 1275     if (!fname) {
 1276         fname = (*mutex)->fname;
 1277         if (!fname) {
 1278             return APR_SUCCESS;
 1279         }
 1280     }
 1281 
 1282     new_mutex = (apr_proc_mutex_t *)apr_pmemdup(pool, *mutex,
 1283                                                 sizeof(apr_proc_mutex_t));
 1284     new_mutex->pool = pool;
 1285     new_mutex->fname = apr_pstrdup(pool, fname);
 1286     rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
 1287                        APR_FOPEN_WRITE, 0, new_mutex->pool);
 1288     if (rv != APR_SUCCESS) {
 1289         return rv;
 1290     }
 1291     new_mutex->os.crossproc = new_mutex->interproc->filedes;
 1292     new_mutex->interproc_closing = 1;
 1293 
 1294     *mutex = new_mutex;
 1295     return APR_SUCCESS;
 1296 }
 1297 
 1298 static apr_status_t proc_mutex_flock_perms_set(apr_proc_mutex_t *mutex,
 1299                                                apr_fileperms_t perms,
 1300                                                apr_uid_t uid,
 1301                                                apr_gid_t gid)
 1302 {
 1303 
 1304     if (mutex->fname) {
 1305         if (!(perms & APR_FPROT_GSETID))
 1306             gid = -1;
 1307         if (fchown(mutex->os.crossproc, uid, gid) < 0) {
 1308             return errno;
 1309         }
 1310     }
 1311     return APR_SUCCESS;
 1312 }
 1313 
 1314 static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
 1315 {
 1316 #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL)
 1317     APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 1318 #else
 1319     0,
 1320 #endif
 1321     proc_mutex_flock_create,
 1322     proc_mutex_flock_acquire,
 1323     proc_mutex_flock_tryacquire,
 1324     proc_mutex_spinsleep_timedacquire,
 1325     proc_mutex_flock_release,
 1326     proc_mutex_flock_cleanup,
 1327     proc_mutex_flock_child_init,
 1328     proc_mutex_flock_perms_set,
 1329     APR_LOCK_FLOCK,
 1330     "flock"
 1331 };
 1332 
 1333 #endif /* flock implementation */
 1334 
 1335 void apr_proc_mutex_unix_setup_lock(void)
 1336 {
 1337     /* setup only needed for sysvsem and fnctl */
 1338 #if APR_HAS_SYSVSEM_SERIALIZE
 1339     proc_mutex_sysv_setup();
 1340 #endif
 1341 #if APR_HAS_FCNTL_SERIALIZE
 1342     proc_mutex_fcntl_setup();
 1343 #endif
 1344 }
 1345 
 1346 static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex,
 1347                                              apr_lockmech_e mech,
 1348                                              apr_os_proc_mutex_t *ospmutex)
 1349 {
 1350 #if APR_HAS_PROC_PTHREAD_SERIALIZE
 1351     new_mutex->os.pthread_interproc = NULL;
 1352 #endif
 1353 #if APR_HAS_POSIXSEM_SERIALIZE
 1354     new_mutex->os.psem_interproc = NULL;
 1355 #endif
 1356 #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
 1357     new_mutex->os.crossproc = -1;
 1358 
 1359 #if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
 1360     new_mutex->interproc = NULL;
 1361     new_mutex->interproc_closing = 0;
 1362 #endif
 1363 #endif
 1364 
 1365     switch (mech) {
 1366     case APR_LOCK_FCNTL:
 1367 #if APR_HAS_FCNTL_SERIALIZE
 1368         new_mutex->meth = &mutex_fcntl_methods;
 1369         if (ospmutex) {
 1370             if (ospmutex->crossproc == -1) {
 1371                 return APR_EINVAL;
 1372             }
 1373             new_mutex->os.crossproc = ospmutex->crossproc;
 1374         }
 1375 #else
 1376         return APR_ENOTIMPL;
 1377 #endif
 1378         break;
 1379     case APR_LOCK_FLOCK:
 1380 #if APR_HAS_FLOCK_SERIALIZE
 1381         new_mutex->meth = &mutex_flock_methods;
 1382         if (ospmutex) {
 1383             if (ospmutex->crossproc == -1) {
 1384                 return APR_EINVAL;
 1385             }
 1386             new_mutex->os.crossproc = ospmutex->crossproc;
 1387         }
 1388 #else
 1389         return APR_ENOTIMPL;
 1390 #endif
 1391         break;
 1392     case APR_LOCK_SYSVSEM:
 1393 #if APR_HAS_SYSVSEM_SERIALIZE
 1394         new_mutex->meth = &mutex_sysv_methods;
 1395         if (ospmutex) {
 1396             if (ospmutex->crossproc == -1) {
 1397                 return APR_EINVAL;
 1398             }
 1399             new_mutex->os.crossproc = ospmutex->crossproc;
 1400         }
 1401 #else
 1402         return APR_ENOTIMPL;
 1403 #endif
 1404         break;
 1405     case APR_LOCK_POSIXSEM:
 1406 #if APR_HAS_POSIXSEM_SERIALIZE
 1407         new_mutex->meth = &mutex_posixsem_methods;
 1408         if (ospmutex) {
 1409             if (ospmutex->psem_interproc == NULL) {
 1410                 return APR_EINVAL;
 1411             }
 1412             new_mutex->os.psem_interproc = ospmutex->psem_interproc;
 1413         }
 1414 #else
 1415         return APR_ENOTIMPL;
 1416 #endif
 1417         break;
 1418     case APR_LOCK_PROC_PTHREAD:
 1419 #if APR_HAS_PROC_PTHREAD_SERIALIZE
 1420         new_mutex->meth = &mutex_proc_pthread_methods;
 1421         if (ospmutex) {
 1422             if (ospmutex->pthread_interproc == NULL) {
 1423                 return APR_EINVAL;
 1424             }
 1425             new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
 1426         }
 1427 #else
 1428         return APR_ENOTIMPL;
 1429 #endif
 1430         break;
 1431     case APR_LOCK_DEFAULT_TIMED:
 1432 #if APR_HAS_PROC_PTHREAD_SERIALIZE \
 1433         && (APR_USE_PROC_PTHREAD_MUTEX_COND \
 1434             || defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) \
 1435         && defined(HAVE_PTHREAD_MUTEX_ROBUST)
 1436 #if APR_USE_PROC_PTHREAD_MUTEX_COND
 1437         new_mutex->meth = &mutex_proc_pthread_cond_methods;
 1438 #else
 1439         new_mutex->meth = &mutex_proc_pthread_methods;
 1440 #endif
 1441         if (ospmutex) {
 1442             if (ospmutex->pthread_interproc == NULL) {
 1443                 return APR_EINVAL;
 1444             }
 1445             new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
 1446         }
 1447         break;
 1448 #elif APR_HAS_SYSVSEM_SERIALIZE && defined(HAVE_SEMTIMEDOP)
 1449         new_mutex->meth = &mutex_sysv_methods;
 1450         if (ospmutex) {
 1451             if (ospmutex->crossproc == -1) {
 1452                 return APR_EINVAL;
 1453             }
 1454             new_mutex->os.crossproc = ospmutex->crossproc;
 1455         }
 1456         break;
 1457 #elif APR_HAS_POSIXSEM_SERIALIZE && defined(HAVE_SEM_TIMEDWAIT)
 1458         new_mutex->meth = &mutex_posixsem_methods;
 1459         if (ospmutex) {
 1460             if (ospmutex->psem_interproc == NULL) {
 1461                 return APR_EINVAL;
 1462             }
 1463             new_mutex->os.psem_interproc = ospmutex->psem_interproc;
 1464         }
 1465         break;
 1466 #endif
 1467         /* fall trough */
 1468     case APR_LOCK_DEFAULT:
 1469 #if APR_USE_FLOCK_SERIALIZE
 1470         new_mutex->meth = &mutex_flock_methods;
 1471         if (ospmutex) {
 1472             if (ospmutex->crossproc == -1) {
 1473                 return APR_EINVAL;
 1474             }
 1475             new_mutex->os.crossproc = ospmutex->crossproc;
 1476         }
 1477 #elif APR_USE_SYSVSEM_SERIALIZE
 1478         new_mutex->meth = &mutex_sysv_methods;
 1479         if (ospmutex) {
 1480             if (ospmutex->crossproc == -1) {
 1481                 return APR_EINVAL;
 1482             }
 1483             new_mutex->os.crossproc = ospmutex->crossproc;
 1484         }
 1485 #elif APR_USE_FCNTL_SERIALIZE
 1486         new_mutex->meth = &mutex_fcntl_methods;
 1487         if (ospmutex) {
 1488             if (ospmutex->crossproc == -1) {
 1489                 return APR_EINVAL;
 1490             }
 1491             new_mutex->os.crossproc = ospmutex->crossproc;
 1492         }
 1493 #elif APR_USE_PROC_PTHREAD_SERIALIZE
 1494         new_mutex->meth = &mutex_proc_pthread_methods;
 1495         if (ospmutex) {
 1496             if (ospmutex->pthread_interproc == NULL) {
 1497                 return APR_EINVAL;
 1498             }
 1499             new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
 1500         }
 1501 #elif APR_USE_POSIXSEM_SERIALIZE
 1502         new_mutex->meth = &mutex_posixsem_methods;
 1503         if (ospmutex) {
 1504             if (ospmutex->psem_interproc == NULL) {
 1505                 return APR_EINVAL;
 1506             }
 1507             new_mutex->os.psem_interproc = ospmutex->psem_interproc;
 1508         }
 1509 #else
 1510         return APR_ENOTIMPL;
 1511 #endif
 1512         break;
 1513     default:
 1514         return APR_ENOTIMPL;
 1515     }
 1516     return APR_SUCCESS;
 1517 }
 1518 
 1519 APR_DECLARE(const char *) apr_proc_mutex_defname(void)
 1520 {
 1521     apr_status_t rv;
 1522     apr_proc_mutex_t mutex;
 1523 
 1524     if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT,
 1525                                        NULL)) != APR_SUCCESS) {
 1526         return "unknown";
 1527     }
 1528 
 1529     return apr_proc_mutex_name(&mutex);
 1530 }
 1531    
 1532 static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname)
 1533 {
 1534     apr_status_t rv;
 1535 
 1536     if ((rv = proc_mutex_choose_method(new_mutex, mech,
 1537                                        NULL)) != APR_SUCCESS) {
 1538         return rv;
 1539     }
 1540 
 1541     if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) {
 1542         return rv;
 1543     }
 1544 
 1545     return APR_SUCCESS;
 1546 }
 1547 
 1548 APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
 1549                                                 const char *fname,
 1550                                                 apr_lockmech_e mech,
 1551                                                 apr_pool_t *pool)
 1552 {
 1553     apr_proc_mutex_t *new_mutex;
 1554     apr_status_t rv;
 1555 
 1556     new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
 1557     new_mutex->pool = pool;
 1558 
 1559     if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS)
 1560         return rv;
 1561 
 1562     *mutex = new_mutex;
 1563     return APR_SUCCESS;
 1564 }
 1565 
 1566 APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
 1567                                                     const char *fname,
 1568                                                     apr_pool_t *pool)
 1569 {
 1570     return (*mutex)->meth->child_init(mutex, pool, fname);
 1571 }
 1572 
 1573 APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
 1574 {
 1575     return mutex->meth->acquire(mutex);
 1576 }
 1577 
 1578 APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
 1579 {
 1580     return mutex->meth->tryacquire(mutex);
 1581 }
 1582 
 1583 APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex,
 1584                                                apr_interval_time_t timeout)
 1585 {
 1586 #if APR_HAS_TIMEDLOCKS
 1587     return mutex->meth->timedacquire(mutex, timeout);
 1588 #else
 1589     return APR_ENOTIMPL;
 1590 #endif
 1591 }
 1592 
 1593 APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
 1594 {
 1595     return mutex->meth->release(mutex);
 1596 }
 1597 
 1598 APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
 1599 {
 1600     return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
 1601 }
 1602 
 1603 APR_DECLARE(apr_lockmech_e) apr_proc_mutex_mech(apr_proc_mutex_t *mutex)
 1604 {
 1605     return mutex->meth->mech;
 1606 }
 1607 
 1608 APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
 1609 {
 1610     return mutex->meth->name;
 1611 }
 1612 
 1613 APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
 1614 {
 1615     /* POSIX sems use the fname field but don't use a file,
 1616      * so be careful. */
 1617 #if APR_HAS_FLOCK_SERIALIZE
 1618     if (mutex->meth == &mutex_flock_methods) {
 1619         return mutex->fname;
 1620     }
 1621 #endif
 1622 #if APR_HAS_FCNTL_SERIALIZE
 1623     if (mutex->meth == &mutex_fcntl_methods) {
 1624         return mutex->fname;
 1625     }
 1626 #endif
 1627     return NULL;
 1628 }
 1629 
 1630 APR_PERMS_SET_IMPLEMENT(proc_mutex)
 1631 {
 1632     apr_proc_mutex_t *mutex = (apr_proc_mutex_t *)theproc_mutex;
 1633     return mutex->meth->perms_set(mutex, perms, uid, gid);
 1634 }
 1635 
 1636 APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
 1637 
 1638 /* Implement OS-specific accessors defined in apr_portable.h */
 1639 
 1640 APR_DECLARE(apr_status_t) apr_os_proc_mutex_get_ex(apr_os_proc_mutex_t *ospmutex, 
 1641                                                    apr_proc_mutex_t *pmutex,
 1642                                                    apr_lockmech_e *mech)
 1643 {
 1644     *ospmutex = pmutex->os;
 1645     if (mech) {
 1646         *mech = pmutex->meth->mech;
 1647     }
 1648     return APR_SUCCESS;
 1649 }
 1650 
 1651 APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
 1652                                                 apr_proc_mutex_t *pmutex)
 1653 {
 1654     return apr_os_proc_mutex_get_ex(ospmutex, pmutex, NULL);
 1655 }
 1656 
 1657 APR_DECLARE(apr_status_t) apr_os_proc_mutex_put_ex(apr_proc_mutex_t **pmutex,
 1658                                                 apr_os_proc_mutex_t *ospmutex,
 1659                                                 apr_lockmech_e mech,
 1660                                                 int register_cleanup,
 1661                                                 apr_pool_t *pool)
 1662 {
 1663     apr_status_t rv;
 1664     if (pool == NULL) {
 1665         return APR_ENOPOOL;
 1666     }
 1667 
 1668     if ((*pmutex) == NULL) {
 1669         (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool,
 1670                                                     sizeof(apr_proc_mutex_t));
 1671         (*pmutex)->pool = pool;
 1672     }
 1673     rv = proc_mutex_choose_method(*pmutex, mech, ospmutex);
 1674 #if APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE
 1675     if (rv == APR_SUCCESS) {
 1676         rv = apr_os_file_put(&(*pmutex)->interproc, &(*pmutex)->os.crossproc,
 1677                              0, pool);
 1678     }
 1679 #endif
 1680 
 1681     if (rv == APR_SUCCESS && register_cleanup) {
 1682         apr_pool_cleanup_register(pool, *pmutex, apr_proc_mutex_cleanup, 
 1683                                   apr_pool_cleanup_null);
 1684     }
 1685     return rv;
 1686 }
 1687 
 1688 APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
 1689                                                 apr_os_proc_mutex_t *ospmutex,
 1690                                                 apr_pool_t *pool)
 1691 {
 1692     return apr_os_proc_mutex_put_ex(pmutex, ospmutex, APR_LOCK_DEFAULT,
 1693                                     0, pool);
 1694 }
 1695