[FFmpeg-devel] [PATCH] w32pthreads: add pthread_once emulation
Hendrik Leppkes
h.leppkes at gmail.com
Sat Oct 10 10:11:27 CEST 2015
On Wed, Oct 7, 2015 at 6:29 PM, Hendrik Leppkes <h.leppkes at gmail.com> wrote:
> On Wed, Oct 7, 2015 at 6:23 PM, Matt Oliver <protogonoi at gmail.com> wrote:
>> On 6 October 2015 at 21:36, Hendrik Leppkes <h.leppkes at 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 deb1c53..8523976 100644
>>> --- a/compat/w32pthreads.h
>>> +++ b/compat/w32pthreads.h
>>> @@ -154,6 +154,19 @@ static inline int pthread_cond_signal(pthread_cond_t
>>> *cond)
>>> return 0;
>>> }
>>>
>>> +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 */
>>> @@ -304,6 +317,57 @@ static av_unused int
>>> pthread_cond_signal(pthread_cond_t *cond)
>>> pthread_mutex_unlock(&win32_cond->mtx_broadcast);
>>> return 0;
>>> }
>>> +
>>> +/* 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)
>>> @@ -319,6 +383,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
>>>
>>> }
>>> --
>>> 2.5.3.windows.1
>>
>>
>> LGTM
>
> There is a new version of the patch which also solves the
> w32thread_init mess, so this one isn't the final version anymore.
> Current working version is here:
> https://github.com/Nevcairiel/FFmpeg/commits/pthread_once
>
This version has been applied.
More information about the ffmpeg-devel
mailing list