You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Chris Darroch <ch...@pearsoncmg.com> on 2002/09/16 23:57:10 UTC

Re: [PATCH] trial implementation of proc_pthread trylock

Aaron Bannert wrote:

> On Thu, Aug 22, 2002 at 03:59:24PM -0400, Chris Darroch wrote:


[snip]


>>   The proc_mutex_proc_pthread_acquire() function seems to
>>suck up the EOWNERDEAD return value, setting the curr_locked flag
>>to 1 and returning APR_SUCCESS, so that's what I made the tryacquire
>>case do also.
>>
>>   However, it seems to me that this behaviour, for both functions,
>>might not be too helpful for callers, since any data they
>>are protecting with our lock might be in an inconsistent state,
>>but they'd have no way of determining that from our return value.
>>Maybe we should invent an APR_EOWNERDEAD value and return that?
>>
> 
> You are correct, but we can't invent an APR_EOWNERDEAD unless that
> semantic is portable, which I don't believe it is. What happens to
> a mutex right now when the owner dies, on platforms that don't have
> pthread_mutex_consistent_np()?
> 
> I'm all for implementing trylock where possible, but I'm not comfortable
> introducing non-posix/non-portable pthread calls.


    Sorry to take so long testing this out ... had a deadline
in the meantime.  On my Solaris 8 box -- only type I have access to --
the behaviour seems to be as follows.  I'm using the Sun WorkShop 6,
update 2, C 5.3 cc compiler.

    The code I used for testing is appeneded below.  It tries the
four (of five) process lock types that have apr.h defines as valid
on my platform -- APR_USE_FLOCK_SERIALIZE is 0, so I can't test that
one (easily, anyway).

    The little process below creates a process lock using standard
apr_proc_mutex_create(), forks a child, and then both parent and
child try to acquire a lock with apr_proc_mutex_lock().  The parent
waits a bit so the child always goes first.  (Note that I'm just
testing the standard lock behaviour, not any kind of experimental
trylock implementation.)

    I can then let the process run, or kill the child with good ole
"kill -9", and see what happens.  The results are as follows:


1) APR_LOCK_PROC_PTHREAD (default on Solaris 8):
    OK in both cases.  Killing the child results in immediate lock
    by the parent, with no status report.  As expected.

2) APR_LOCK_FCNTL:
    OK in both cases, as above for APR_LOCK_PROC_PTHREAD.

3) APR_LOCK_SYSVSEM:
    Letting the process run normally results in error reports from
    the parent:

unable to lock lock: 36, Identifier removed
unable to unlock lock: 22, Invalid argument

    Interestingly, killing the child causes the parent to run normally
    without reporting any errors.

4) APR_LOCK_POSIXSEM:

    OK in the normal case.  Parent hangs when the child process is
    killed.


    So (3) and (4) have sort-of reversed behaviour, and neither seems
consistent with (1) or (2).

    My sense, then, is that things might not be quite as portable
as could be desired -- leaving aside entirely the question of
whether or not to implement apr_proc_mutex_trylock().  If others could
try this on different platforms, especially using the
default APR lock type, that would be enlightening.

    I'm not sure what a good solution is, because I'm not sure if
all these lock types -- on different platforms -- can be made to
detect, or not detect, the death of the process that holds the lock.

Chris.

====================================
#include <stdio.h>
#include <stdlib.h>
#include "apr_general.h"
#include "apr_pools.h"
#include "apr_proc_mutex.h"

int main(int argc, const char * const *argv)
{
     apr_status_t s;
     apr_pool_t *p;
     apr_proc_mutex_t *l;
     char buf[100];
     int pid;
     int i;

     apr_app_initialize(&argc, &argv, NULL);
     atexit(apr_terminate);

     apr_pool_create(&p, NULL);

     /**** DEBUG: try one of APR_LOCK_FLOCK, APR_LOCK_FCNTL,
      **** APR_LOCK_POSIXSEM, APR_LOCK_SYSVSEM, APR_LOCK_PROC_PTHREAD
      ****/

     s = apr_proc_mutex_create(&l, "/path/to/non/NFS/volume",
         APR_LOCK_SYSVSEM, p);
     if(s)
     {
         fprintf(stderr, "unable to create lock: %d, %s", (int) s,
             apr_strerror(s, buf, 100));
     }

     printf("lock name: %s\n", apr_proc_mutex_name(l));

     if((pid = fork()) == -1)
     {
         fprintf(stderr, "unable to fork");
         exit(1);
     }

     if(pid)
         sleep(1);

     s = apr_proc_mutex_lock(l);
     if(s)
     {
         fprintf(stderr, "unable to lock lock: %d, %s", (int) s,
             apr_strerror(s, buf, 100));
     }

     if(pid)
         printf("parent (child: %d)\n", pid);
     else
         printf("child\n");

     for(i = 0; i < 20; ++i)
     {
         printf("%d\n", i);
         sleep(1);
     }

     s = apr_proc_mutex_unlock(l);
     if(s)
     {
         fprintf(stderr, "unable to unlock lock: %d, %s", (int) s,
             apr_strerror(s, buf, 100));
     }

     if(!pid)
         exit(0);

     s = apr_proc_mutex_destroy(l);
     if(s)
     {
         fprintf(stderr, "unable to destroy lock: %d, %s", (int) s,
             apr_strerror(s, buf, 100));
     }

     exit(0);
}