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