You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modules-dev@httpd.apache.org by Micha Lenk <mi...@lenk.info> on 2014/09/29 15:18:39 UTC

How to wait on a global lock with timeout

Hi,

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?

Any suggestions are highly appreciated.

Best regards,
Micha

Re: How to wait on a global lock with timeout

Posted by Massimo Manghi <mx...@apache.org>.
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" <yl...@gmail.com> ha scritto:

> On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic <yl...@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

Posted by Micha Lenk <mi...@lenk.info>.
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

Posted by Yann Ylavic <yl...@gmail.com>.
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

Posted by Micha Lenk <mi...@lenk.info>.
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


Re: How to wait on a global lock with timeout

Posted by Yann Ylavic <yl...@gmail.com>.
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

Posted by Micha Lenk <mi...@lenk.info>.
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

Posted by Yann Ylavic <yl...@gmail.com>.
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 <yl...@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

Posted by Micha Lenk <mi...@lenk.info>.
Hi Yann,

On 30.09.2014 18:16, Yann Ylavic wrote:
> On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic <yl...@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

Posted by Yann Ylavic <yl...@gmail.com>.
On Tue, Sep 30, 2014 at 5:30 PM, Yann Ylavic <yl...@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

Posted by Yann Ylavic <yl...@gmail.com>.
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.