> rbb         01/09/01 00:29:07
> 
>   Modified:    threadproc/win32 thread.c
>   Log:
>   Avoid a rather nasty bug in the Windows apr_thread_once function.  We
>   basically, check the value before we increment, and after.  By checking
>   before, we take a hit of one if statement, but avoid a kernel call in
>   most cases.
>   Submitted by:       Will Rowe <[EMAIL PROTECTED]>
>   
>   Revision  Changes    Path
>   1.38      +11 -0     apr/threadproc/win32/thread.c
>   
>   Index: thread.c
>   ===================================================================
>   RCS file: /home/cvs/apr/threadproc/win32/thread.c,v
>   retrieving revision 1.37
>   retrieving revision 1.38
>   diff -u -r1.37 -r1.38
>   --- thread.c        2001/09/01 07:10:25     1.37
>   +++ thread.c        2001/09/01 07:29:07     1.38
>   @@ -231,6 +231,17 @@
>    APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control,
>                                              void (*func)(void))
>    {
>   +    /* Quick escape hatch, and bug fix.  The InterlockedIncrement
>   +     * call is just incrementing a long int, so it has the potential
>   +     * to wrap.  Very unlikely, but still, that would be an almost
>   +     * impossible bug to hunt.  With this, we might see one or two
>   +     * calls to InterlockedIncrement, but never enough to wrap the
>   +     * long int.  This also saves us a kernel call for most calls to
>   +     * this function.
>   +     */
>   +    if (control->value) {
>   +        return APR_SUCCESS;
>   +    }
>        InterlockedIncrement(&control->value);
>        if (control->value == 1) {
>            func();

This still isn't correct.  Now we have a race condition that
could result in the function never being called instead of once.
This looks better IMHO:

    APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control,
                                              void (*func)(void))
    {         
        if (!InterlockedExchange(&control->value, 1))
            func();

        return APR_SUCCESS;
    }

This way we also don't have the wrapping problem.


Sander

Reply via email to