On Tue,  6 Oct 2015 12:41:13 +0200
Hendrik Leppkes <h.lepp...@gmail.com> wrote:

> The emulation uses native InitOnce* APIs on Windows Vista+, and a
> lock-free/allocation-free approach using atomics and spinning for Windows XP.
> ---
> This is in preparation to use pthread_once for global static init functions,
> and eventually removing the global lock in avcodec_open2
> 
> compat/w32pthreads.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 68 insertions(+)
> 
> diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h
> index 3748289..ef28036 100644
> --- a/compat/w32pthreads.h
> +++ b/compat/w32pthreads.h
> @@ -145,6 +145,19 @@ static inline void pthread_cond_signal(pthread_cond_t 
> *cond)
>      WakeConditionVariable(cond);
>  }
>  
> +typedef INIT_ONCE pthread_once_t;
> +#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
> +
> +static av_unused int pthread_once(pthread_once_t *once_control, void 
> (*init_routine)(void))
> +{
> +    BOOL pending = FALSE;
> +    InitOnceBeginInitialize(once_control, 0, &pending, NULL);
> +    if (pending)
> +        init_routine();
> +    InitOnceComplete(once_control, 0, NULL);
> +    return 0;
> +}
> +
>  #else // _WIN32_WINNT < 0x0600
>  /* for pre-Windows 6.0 platforms we need to define and use our own condition
>   * variable and api */
> @@ -291,6 +304,57 @@ static av_unused void pthread_cond_signal(pthread_cond_t 
> *cond)
>  
>      pthread_mutex_unlock(&win32_cond->mtx_broadcast);
>  }
> +
> +/* for pre-Windows 6.0 platforms, define INIT_ONCE struct,
> + * compatible to the one used in the native API */
> +
> +typedef union pthread_once_t  {
> +    void * Ptr;    ///< For the Windows 6.0+ native functions
> +    LONG state;    ///< For the pre-Windows 6.0 compat code
> +} pthread_once_t;
> +
> +#define PTHREAD_ONCE_INIT {0}
> +
> +/* function pointers to init once API on windows 6.0+ kernels */
> +static BOOL (WINAPI *initonce_begin)(pthread_once_t *lpInitOnce, DWORD 
> dwFlags, BOOL *fPending, void **lpContext);
> +static BOOL (WINAPI *initonce_complete)(pthread_once_t *lpInitOnce, DWORD 
> dwFlags, void *lpContext);
> +
> +static av_unused int pthread_once(pthread_once_t *once_control, void 
> (*init_routine)(void))
> +{
> +    /* Use native functions on Windows 6.0+ */
> +    if (initonce_begin && initonce_complete)
> +    {
> +        BOOL pending = FALSE;
> +        initonce_begin(once_control, 0, &pending, NULL);
> +        if (pending)
> +            init_routine();
> +        initonce_complete(once_control, 0, NULL);
> +        return 0;
> +    }
> +
> +    /* pre-Windows 6.0 compat using a spin-lock */
> +    switch (InterlockedCompareExchange(&once_control->state, 1, 0))
> +    {
> +        /* Initial run */
> +        case 0:
> +            init_routine();
> +            InterlockedExchange(&once_control->state, 2);
> +            break;
> +        /* Another thread is running init */
> +        case 1:
> +            while (1) {
> +                MemoryBarrier();
> +                if (once_control->state == 2)
> +                    break;
> +                Sleep(0);
> +            }
> +            break;
> +        /* Initialization complete */
> +        case 2:
> +            break;
> +    }
> +    return 0;
> +}
>  #endif
>  
>  static av_unused void w32thread_init(void)
> @@ -306,6 +370,10 @@ static av_unused void w32thread_init(void)
>          (void*)GetProcAddress(kernel_dll, "WakeConditionVariable");
>      cond_wait      =
>          (void*)GetProcAddress(kernel_dll, "SleepConditionVariableCS");
> +    initonce_begin =
> +        (void*)GetProcAddress(kernel_dll, "InitOnceBeginInitialize");
> +    initonce_complete =
> +        (void*)GetProcAddress(kernel_dll, "InitOnceComplete");
>  #endif
>  
>  }

Seems all fine to me. (We've essentially did some patch review
iterations on IRC already.)
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to