[FFmpeg-devel] [PATCH] w32pthreads: add pthread_once emulation
Matt Oliver
protogonoi at gmail.com
Wed Oct 7 19:06:51 CEST 2015
On 8 October 2015 at 03:29, 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 looks better.
So by win32thread_init mess im assuming your referring to a need to have
called it before hand. Given that youve added it to the only 2 functions
that need it then doesnt that mean that win32thread_init be completely
removed from all other code and only used locally in w32pthread.h and only
when WIN32_WINNT<0x600.
More information about the ffmpeg-devel
mailing list