Re: How to wait on a global lock with timeout

2015-05-16 Thread Micha Lenk
Hi Yann,

thanks for your explanation.

Am 16.05.2015 um 19:05 schrieb Yann Ylavic:
 Trying to get locked mutex... timed out after 1 second (expected)
 Child trying to unlock the mutex got 1 (unexpected)
 Trying to get locked mutex... timed out after 2 seconds (unexpected)

 Did I do anything wrong?
 
 A mutex must be unlocked by the thread which locked it (error 1 is EPERM).

Ok, makes sense to me.

Regards,
Micha


Re: How to wait on a global lock with timeout

2015-05-16 Thread Yann Ylavic
Hi Micha,

On Sat, May 16, 2015 at 5:22 PM, Micha Lenk mi...@lenk.info wrote:

 Sorry, took me a while to give your patch a try. As the patch didn't
 apply cleanly to trunk (ie. SVN rev. 1676013), I assume that it is
 already applied in trunk. So I went ahead without applying your patch.
 Is this correct?

Yes, links point to svn commits in trunk.



 I wrote a small test program that should prove me that timed global
 locks work across process boundaries (see attached source). But for some
 reason apr_global_mutex_unlock() return 1 if called in the child
 process. This is the output that I get from the compiled test program:

 Trying to get locked mutex... timed out after 1 second (expected)
 Child trying to unlock the mutex got 1 (unexpected)
 Trying to get locked mutex... timed out after 2 seconds (unexpected)

 Did I do anything wrong?

A mutex must be unlocked by the thread which locked it (error 1 is EPERM).

Thus you can:
lock()
if fork() == 0:
lock()
else:
unlock()

but not:
lock()
if fork() == 0:
unlock()
else:
lock()

Regards,
Yann.


Re: How to wait on a global lock with timeout

2015-05-16 Thread Micha Lenk
Hi Yann,

Am 25.03.2015 um 09:56 schrieb Yann Ylavic:
 To mitigate that design flaw I would provide the timeout by reference
 and update it by the functions using it. This has also the nice benefit
 that the caller is able to retrieve the time it needed to wait.
 
 By doing so, you have to get the current time (call apr_time_now())
 each time, and I wanted to avoid it when the native functions don't
 need it.
 The remaining time is not important if you can pass an absolute time (IMHO).

Ok, understood. You're right.

Sorry, took me a while to give your patch a try. As the patch didn't
apply cleanly to trunk (ie. SVN rev. 1676013), I assume that it is
already applied in trunk. So I went ahead without applying your patch.
Is this correct?

I wrote a small test program that should prove me that timed global
locks work across process boundaries (see attached source). But for some
reason apr_global_mutex_unlock() return 1 if called in the child
process. This is the output that I get from the compiled test program:

Trying to get locked mutex... timed out after 1 second (expected)
Child trying to unlock the mutex got 1 (unexpected)
Trying to get locked mutex... timed out after 2 seconds (unexpected)

Did I do anything wrong?


Best regards,
Micha

#include assert.h
#include stdio.h
#include unistd.h
#include apr.h
#include apr_pools.h
#include apr_global_mutex.h


#define LOCKFILE /tmp/apr-synctest-lockfile


int main(int argc, const char *argv[]) {
apr_pool_t *pool = NULL;
apr_global_mutex_t *mutex = NULL;
apr_time_t timeout;
apr_status_t rv;
pid_t child;
int child_rc;
int rc = 0;

assert(apr_initialize() == APR_SUCCESS);
assert(apr_pool_create(pool, NULL) == APR_SUCCESS);

apr_global_mutex_create(mutex, LOCKFILE, APR_LOCK_DEFAULT_TIMED, pool);
/*
 * LOCK
 */
apr_global_mutex_lock(mutex);
timeout = apr_time_from_sec(1);
printf(Trying to get locked mutex...);
rv = apr_global_mutex_timedlock(mutex, timeout, 0);
if (rv == APR_TIMEUP) {
printf( timed out after 1 second (expected)\n);
} else {
printf( FAILED: %d (unexpected)\n, rv);
rc = 1;
	goto cleanup;
}

child = fork();
if (child == 0) { // child process
assert(apr_global_mutex_child_init(mutex, LOCKFILE, pool) == APR_SUCCESS);
	(void)sleep(1);
/*
 * UNLOCK in forked child
 */
	rv = apr_global_mutex_unlock(mutex);
if (rv != APR_SUCCESS) {
rc = 1;
	printf(Child trying to unlock the mutex got %d (unexpected)\n, rv);
}
} else if (child  0) { // parent process
timeout = apr_time_from_sec(2);
	printf(Trying to get locked mutex...);
rv = apr_global_mutex_timedlock(mutex, timeout, 0);
	if (rv == APR_SUCCESS) {
	printf( OK (expected)\n);
} else if (rv == APR_TIMEUP) {
printf( timed out after 2 seconds (unexpected)\n);
rc = 1;
	} else {
	printf( FAILED: %d (unexpected)\n, rv);
	rc = 1;
	}
	wait(child_rc);
	if (rc == 0)
	rc = child_rc;
} else { // fork() failed
printf(failed to fork(): %m);
	rc = 1;
	goto cleanup;
}


cleanup:
apr_pool_destroy(pool);
apr_terminate();
return rc;
}


Re: How to wait on a global lock with timeout

2015-03-25 Thread Micha Lenk
Hi Yann,

Am 20.03.2015 um 02:59 schrieb Yann Ylavic:
 a few times later, commited in [1] and [2] :)

Wow, thanks for coming back to that issue.

 Can you please check if it works for you?

I only had time to review the code changes. I looked at the
implementation of apr_global_mutex_timedlock(). There I noticed that, if
APR_HAS_THREADS, you are doing 3 timed operations without checking the
remaining time. If all operations take almost the given timeout, this
can in the end result in almost 3 times the allowed value.

To mitigate that design flaw I would provide the timeout by reference
and update it by the functions using it. This has also the nice benefit
that the caller is able to retrieve the time it needed to wait.

I hope to have some time to check out the new functions in my code soon.

 I also attached the patch against 1.6.x, if that can help...
 It should also apply to 1.5.x, though it will never be backported
 there (due to API changes).

Backports are not needed. Thanks for offering.

Regards,
Micha


Re: How to wait on a global lock with timeout

2015-03-25 Thread Yann Ylavic
Hi Micha,

thanks for the review.

On Wed, Mar 25, 2015 at 7:19 AM, Micha Lenk mi...@lenk.info wrote:

 I only had time to review the code changes. I looked at the
 implementation of apr_global_mutex_timedlock(). There I noticed that, if
 APR_HAS_THREADS, you are doing 3 timed operations without checking the
 remaining time. If all operations take almost the given timeout, this
 can in the end result in almost 3 times the allowed value.

The new _timedlocked() functions all take a third parameter (called
absolute) which tells whether the given timeout is absolute (1) or
relative (0).
This is because some native implementations use an absolute time, and
others a relative one, hence we do the conversion in the
implementations when needed only.
In apr_global_mutex_timedlock(), if the given timeout is relative, we
force it to an absolute one and call apr_thread_mutex_timedlock() (if
needed) and apr_proc_mutex_timedlock() accordingly, hence the timeout
is assured globally.


 To mitigate that design flaw I would provide the timeout by reference
 and update it by the functions using it. This has also the nice benefit
 that the caller is able to retrieve the time it needed to wait.

By doing so, you have to get the current time (call apr_time_now())
each time, and I wanted to avoid it when the native functions don't
need it.
The remaining time is not important if you can pass an absolute time (IMHO).

Regards,
Yann.


Re: How to wait on a global lock with timeout

2015-03-19 Thread Yann Ylavic
Hi Micha,

a few times later, commited in [1] and [2] :)

Can you please check if it works for you?

I also attached the patch against 1.6.x, if that can help...
It should also apply to 1.5.x, though it will never be backported
there (due to API changes).

Thanks for your interest,
Yann.

[1] http://svn.apache.org/r1667900
[2] http://svn.apache.org/r1667901

On Tue, Sep 30, 2014 at 8:22 PM, Micha Lenk mi...@lenk.info wrote:
 Hi Yann,

 On 30.09.2014 18:16, Yann Ylavic wrote:

 On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic ylavic@gmail.com wrote:

 I have been working on a patch to provide
 apr_[thread/proc]_mutex_timedlock() in APR, [...]


 I think that is exactly what I was looking for...

 Your idea to use the native mutex functions is probably better than nothing.
 It provides the needed functionality at least for some platforms.

 I think I'll give my patch a new chance, at least for proc-mutexes
 (and hence global-mutexes), but this is not a today's solution in any
 case since I would be at best an APR-1.6 feature (if accepted)...


 That would be great. I am looking forward to test that, as soon as
 available... ;)

 Regards,
 Micha
Index: configure.in
===
--- configure.in	(revision 1667923)
+++ configure.in	(working copy)
@@ -2137,11 +2137,18 @@ AC_SUBST(struct_rlimit)
 dnl - Checking for Locking Characteristics 
 echo ${nl}Checking for Locking...
 
-AC_CHECK_FUNCS(semget semctl flock)
-AC_CHECK_HEADERS(semaphore.h OS.h)
+AC_CHECK_FUNCS(semget semctl semop semtimedop flock)
+APR_IFALLYES(func:semtimedop, have_semtimedop=1, have_semtimedop=0)
+
+AC_CHECK_HEADERS(semaphore.h)
 AC_SEARCH_LIBS(sem_open, rt)
-AC_CHECK_FUNCS(sem_close sem_unlink sem_post sem_wait create_sem)
+AC_CHECK_FUNCS(sem_close sem_unlink sem_post sem_wait sem_timedwait)
+APR_IFALLYES(func:sem_timedwait, have_sem_timedwait=1, have_sem_timedwait=0)
 
+AC_CHECK_HEADERS(OS.h)
+AC_CHECK_FUNCS(create_sem acquire_sem acquire_sem_etc)
+APR_IFALLYES(header:OS.h func:acquire_sem_etc, have_acquire_sem_etc=1, have_acquire_sem_etc=0)
+
 # Some systems return ENOSYS from sem_open.
 AC_CACHE_CHECK(for working sem_open,ac_cv_func_sem_open,[
 AC_TRY_RUN([
@@ -2199,7 +2206,10 @@ APR_CHECK_DEFINE_FILES(POLLIN, poll.h sys/poll.h)
 
 if test $threads = 1; then
 APR_CHECK_DEFINE(PTHREAD_PROCESS_SHARED, pthread.h)
-AC_CHECK_FUNCS(pthread_mutexattr_setpshared)
+AC_CHECK_FUNCS(pthread_mutex_timedlock pthread_mutexattr_setpshared)
+APR_IFALLYES(header:pthread.h func:pthread_mutex_timedlock,
+ have_pthread_mutex_timedlock=1, have_pthread_mutex_timedlock=0)
+AC_SUBST(have_pthread_mutex_timedlock)
 # Some systems have setpshared and define PROCESS_SHARED, but don't 
 # really support PROCESS_SHARED locks.  So, we must validate that we 
 # can go through the steps without receiving some sort of system error.
@@ -2237,8 +2247,8 @@ fi
 APR_IFALLYES(header:semaphore.h func:sem_open func:sem_close dnl
  func:sem_unlink func:sem_post func:sem_wait,
  hasposixser=1, hasposixser=0)
-APR_IFALLYES(func:semget func:semctl define:SEM_UNDO, hassysvser=1, 
- hassysvser=0)
+APR_IFALLYES(func:semget func:semctl func:semop define:SEM_UNDO,
+ hassysvser=1, hassysvser=0)
 APR_IFALLYES(func:flock define:LOCK_EX, hasflockser=1, hasflockser=0)
 APR_IFALLYES(header:fcntl.h define:F_SETLK, hasfcntlser=1, hasfcntlser=0)
 # note: the current APR use of shared mutex requires /dev/zero
@@ -2263,9 +2273,9 @@ APR_IFALLYES(func:flock define:LOCK_EX,
 APR_DECIDE(USE_FLOCK_SERIALIZE, [4.2BSD-style flock()]))
 APR_IFALLYES(header:fcntl.h define:F_SETLK,
 APR_DECIDE(USE_FCNTL_SERIALIZE, [SVR4-style fcntl()]))
-APR_IFALLYES(func:semget func:semctl define:SEM_UNDO,
+APR_IFALLYES(func:semget func:semctl func:semop define:SEM_UNDO,
 APR_DECIDE(USE_SYSVSEM_SERIALIZE, [SysV IPC semget()]))
-APR_IFALLYES(header:OS.h func:create_sem, 
+APR_IFALLYES(header:OS.h func:create_sem func:acquire_sem func:acquire_sem_etc, 
 APR_DECIDE(USE_BEOSSEM, [BeOS Semaphores])) 
 if test x$apr_lock_method != x; then
 APR_DECISION_FORCE($apr_lock_method)
Index: include/apr_global_mutex.h
===
--- include/apr_global_mutex.h	(revision 1667923)
+++ include/apr_global_mutex.h	(working copy)
@@ -29,6 +29,7 @@
 #if APR_PROC_MUTEX_IS_GLOBAL
 #include apr_proc_mutex.h
 #endif
+#include apr_time.h
 
 #ifdef __cplusplus
 extern C {
@@ -66,6 +67,7 @@ typedef struct apr_global_mutex_t apr_global_mutex
  *APR_LOCK_POSIXSEM
  *APR_LOCK_PROC_PTHREAD
  *APR_LOCK_DEFAULT pick the default mechanism for the platform
+ *APR_LOCK_DEFAULT_TIMED pick the default timed mechanism
  * /PRE
  * @param pool the pool from which to allocate the mutex.
  * @warning Check APR_HAS_foo_SERIALIZE 

Re: How to wait on a global lock with timeout

2014-09-30 Thread Yann Ylavic
Hi Micha,

On Mon, Sep 29, 2014 at 3:18 PM, Micha Lenk mi...@lenk.info wrote:
 in an Apache module I am in the need to wait for a global lock (e.g. an
 apr_global_mutex_t), but in theory the lock might not get released by the
 other process in a timely manner, so I would like to limit the time to wait
 for the lock. What do you suggest me to do?

I have been working on a patch to provide
apr_[thread/proc]_mutex_timedlock() in APR, but did not finish the
work mostly because of APR_ENOTIMPL on some mutex mechanisms (mainly
Windows CRITICAL_SECTIONs which lack the functionality, making the APR
abstraction quite useless IMO, or at least unix specific). Maybe I'll
have a new look at it these days if I have the time to.

For now you may have the possibility to use native mutex functions
(eg. pthread_mutex_timedlock or WaitForSingleObject) with the native
object retrieved by ap_os_[thread/proc]_mutex_get(), but this requires
either to create the mutex with a mechanism supporting the timeout, or
the existing mutex to have such a mechanism.

Hence this may be non-portable code, or with many APR_HAS_*_SERIALIZE,
and still the problem with platforms that don't support it...

Regards,
Yann.


Re: How to wait on a global lock with timeout

2014-09-30 Thread Yann Ylavic
On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic ylavic@gmail.com wrote:
 I have been working on a patch to provide
 apr_[thread/proc]_mutex_timedlock() in APR, but did not finish the
 work mostly because of APR_ENOTIMPL on some mutex mechanisms (mainly
 Windows CRITICAL_SECTIONs which lack the functionality, making the APR
 abstraction quite useless IMO, or at least unix specific). Maybe I'll
 have a new look at it these days if I have the time to.

Hmm, this remark about Windows only concerns thread-mutexes,
proc-mutexes don't use a CRITICAL_SECTION but a HANDLE (which is then
usable with WaitForSingleObject() that accepts a timeout).

I think I'll give my patch a new chance, at least for proc-mutexes
(and hence global-mutexes), but this is not a today's solution in any
case since I would be at best an APR-1.6 feature (if accepted)...


Re: How to wait on a global lock with timeout

2014-09-30 Thread Micha Lenk

Hi Yann,

On 30.09.2014 18:16, Yann Ylavic wrote:

On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic ylavic@gmail.com wrote:

I have been working on a patch to provide
apr_[thread/proc]_mutex_timedlock() in APR, [...]


I think that is exactly what I was looking for...

Your idea to use the native mutex functions is probably better than 
nothing. It provides the needed functionality at least for some platforms.



I think I'll give my patch a new chance, at least for proc-mutexes
(and hence global-mutexes), but this is not a today's solution in any
case since I would be at best an APR-1.6 feature (if accepted)...


That would be great. I am looking forward to test that, as soon as 
available... ;)


Regards,
Micha


Re: How to wait on a global lock with timeout

2014-09-30 Thread Massimo Manghi
I join the line of those waiting for this feature in APR. I really would
like to have it available

-- Massimo
Il 30/Set/2014 18:16 Yann Ylavic ylavic@gmail.com ha scritto:

 On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic ylavic@gmail.com wrote:
  I have been working on a patch to provide
  apr_[thread/proc]_mutex_timedlock() in APR, but did not finish the
  work mostly because of APR_ENOTIMPL on some mutex mechanisms (mainly
  Windows CRITICAL_SECTIONs which lack the functionality, making the APR
  abstraction quite useless IMO, or at least unix specific). Maybe I'll
  have a new look at it these days if I have the time to.

 Hmm, this remark about Windows only concerns thread-mutexes,
 proc-mutexes don't use a CRITICAL_SECTION but a HANDLE (which is then
 usable with WaitForSingleObject() that accepts a timeout).

 I think I'll give my patch a new chance, at least for proc-mutexes
 (and hence global-mutexes), but this is not a today's solution in any
 case since I would be at best an APR-1.6 feature (if accepted)...