[FFmpeg-devel] [PATCH] w32pthreads: add pthread_once emulation
Hendrik Leppkes
h.leppkes at gmail.com
Wed Oct 7 18:29:30 CEST 2015
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
- Hendrik
More information about the ffmpeg-devel
mailing list