Merge commit 'b22693b06d1e5d73454a65c203b4d31c1ca5b69a'
authorHendrik Leppkes <h.leppkes@gmail.com>
Sat, 10 Oct 2015 07:45:16 +0000 (09:45 +0200)
committerHendrik Leppkes <h.leppkes@gmail.com>
Sat, 10 Oct 2015 07:45:16 +0000 (09:45 +0200)
* commit 'b22693b06d1e5d73454a65c203b4d31c1ca5b69a':
  w32pthreads: Add pthread_once emulation

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>
1  2 
compat/w32pthreads.h

diff --combined compat/w32pthreads.h
@@@ -4,20 -4,20 +4,20 @@@
   * Authors: Steven Walters <kemuri9@gmail.com>
   *          Pegasys Inc. <http://www.pegasys-inc.com>
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -26,8 -26,8 +26,8 @@@
   * w32threads to pthreads wrapper
   */
  
 -#ifndef LIBAV_COMPAT_W32PTHREADS_H
 -#define LIBAV_COMPAT_W32PTHREADS_H
 +#ifndef FFMPEG_COMPAT_W32PTHREADS_H
 +#define FFMPEG_COMPAT_W32PTHREADS_H
  
  /* Build up a pthread-like API using underlying Windows API. Have only static
   * methods so as to not conflict with a potentially linked in pthread-win32
@@@ -40,7 -40,6 +40,7 @@@
  #include <process.h>
  
  #include "libavutil/attributes.h"
 +#include "libavutil/common.h"
  #include "libavutil/internal.h"
  #include "libavutil/mem.h"
  
@@@ -87,19 -86,14 +87,19 @@@ static av_unused int pthread_create(pth
      return !thread->handle;
  }
  
 -static av_unused void pthread_join(pthread_t thread, void **value_ptr)
 +static av_unused int pthread_join(pthread_t thread, void **value_ptr)
  {
      DWORD ret = WaitForSingleObject(thread.handle, INFINITE);
 -    if (ret != WAIT_OBJECT_0)
 -        return;
 +    if (ret != WAIT_OBJECT_0) {
 +        if (ret == WAIT_ABANDONED)
 +            return EINVAL;
 +        else
 +            return EDEADLK;
 +    }
      if (value_ptr)
          *value_ptr = thread.ret;
      CloseHandle(thread.handle);
 +    return 0;
  }
  
  static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr)
@@@ -124,22 -118,34 +124,35 @@@ static inline int pthread_mutex_unlock(
  }
  
  #if _WIN32_WINNT >= 0x0600
 -
+ 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;
+ }
 -static inline void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
 +static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
  {
      InitializeConditionVariable(cond);
 +    return 0;
  }
  
  /* native condition variables do not destroy */
 -static inline void pthread_cond_destroy(pthread_cond_t *cond)
 +static inline int pthread_cond_destroy(pthread_cond_t *cond)
  {
 -    return;
 +    return 0;
  }
  
 -static inline void pthread_cond_broadcast(pthread_cond_t *cond)
 +static inline int pthread_cond_broadcast(pthread_cond_t *cond)
  {
      WakeAllConditionVariable(cond);
 +    return 0;
  }
  
  static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
      return 0;
  }
  
 -static inline void pthread_cond_signal(pthread_cond_t *cond)
 +static inline int pthread_cond_signal(pthread_cond_t *cond)
  {
      WakeConditionVariable(cond);
 +    return 0;
  }
  
  #else // _WIN32_WINNT < 0x0600
+ /* 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);
+ /* pre-Windows 6.0 compat using a spin-lock */
+ static inline void w32thread_once_fallback(LONG volatile *state, void (*init_routine)(void))
+ {
+     switch (InterlockedCompareExchange(state, 1, 0)) {
+     /* Initial run */
+     case 0:
+         init_routine();
+         InterlockedExchange(state, 2);
+         break;
+     /* Another thread is running init */
+     case 1:
+         while (1) {
+             MemoryBarrier();
+             if (*state == 2)
+                 break;
+             Sleep(0);
+         }
+         break;
+     /* Initialization complete */
+     case 2:
+         break;
+     }
+ }
+ 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;
+     }
+     w32thread_once_fallback(&once_control->state, init_routine);
+     return 0;
+ }
  /* for pre-Windows 6.0 platforms we need to define and use our own condition
   * variable and api */
  typedef struct  win32_cond_t {
      pthread_mutex_t mtx_broadcast;
      pthread_mutex_t mtx_waiter_count;
@@@ -173,37 -233,36 +241,37 @@@ static void (WINAPI *cond_signal)(pthre
  static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex,
                                  DWORD milliseconds);
  
 -static av_unused void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
 +static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
  {
      win32_cond_t *win32_cond = NULL;
      if (cond_init) {
          cond_init(cond);
 -        return;
 +        return 0;
      }
  
      /* non native condition variables */
      win32_cond = av_mallocz(sizeof(win32_cond_t));
      if (!win32_cond)
 -        return;
 +        return ENOMEM;
      cond->Ptr = win32_cond;
      win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
      if (!win32_cond->semaphore)
 -        return;
 +        return ENOMEM;
      win32_cond->waiters_done = CreateEvent(NULL, TRUE, FALSE, NULL);
      if (!win32_cond->waiters_done)
 -        return;
 +        return ENOMEM;
  
      pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL);
      pthread_mutex_init(&win32_cond->mtx_broadcast, NULL);
 +    return 0;
  }
  
 -static av_unused void pthread_cond_destroy(pthread_cond_t *cond)
 +static av_unused int pthread_cond_destroy(pthread_cond_t *cond)
  {
      win32_cond_t *win32_cond = cond->Ptr;
      /* native condition variables do not destroy */
      if (cond_init)
 -        return;
 +        return 0;
  
      /* non native condition variables */
      CloseHandle(win32_cond->semaphore);
      pthread_mutex_destroy(&win32_cond->mtx_broadcast);
      av_freep(&win32_cond);
      cond->Ptr = NULL;
 +    return 0;
  }
  
 -static av_unused void pthread_cond_broadcast(pthread_cond_t *cond)
 +static av_unused int pthread_cond_broadcast(pthread_cond_t *cond)
  {
      win32_cond_t *win32_cond = cond->Ptr;
      int have_waiter;
  
      if (cond_broadcast) {
          cond_broadcast(cond);
 -        return;
 +        return 0;
      }
  
      /* non native condition variables */
      } else
          pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
      pthread_mutex_unlock(&win32_cond->mtx_broadcast);
 +    return 0;
  }
  
  static av_unused int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
      return pthread_mutex_lock(mutex);
  }
  
 -static av_unused void pthread_cond_signal(pthread_cond_t *cond)
 +static av_unused int pthread_cond_signal(pthread_cond_t *cond)
  {
      win32_cond_t *win32_cond = cond->Ptr;
      int have_waiter;
      if (cond_signal) {
          cond_signal(cond);
 -        return;
 +        return 0;
      }
  
      pthread_mutex_lock(&win32_cond->mtx_broadcast);
      }
  
      pthread_mutex_unlock(&win32_cond->mtx_broadcast);
 +    return 0;
  }
  #endif
  
@@@ -319,8 -375,12 +387,12 @@@ static av_unused void w32thread_init(vo
          (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
  
  }
  
 -#endif /* LIBAV_COMPAT_W32PTHREADS_H */
 +#endif /* FFMPEG_COMPAT_W32PTHREADS_H */