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);
}



Reply via email to