[FFmpeg-devel] [PATCH 1/5] w32pthreads: always use Vista+ API, drop XP support

wm4 nfxjfg at googlemail.com
Fri Dec 22 00:22:20 EET 2017


This removes the XP compatibility code, and switches entirely to SWR
locks, which are available starting at Windows Vista.

This removes CRITICAL_SECTION use, which allows us to add
PTHREAD_MUTEX_INITIALIZER, which will be useful later.

Windows XP is hereby not a supported build target anymore. It was
decided in a project vote that this is OK. (Technically, it could still
be built for Windows XP using an external pthread lib as of this
commit.)

Windows Vista adds WSAPoll(), and for some reason struct pollfd. Since
we raise the Windows API level globally when enabling w32threads, we
need to move it before configure checks for struct pollfd to avoid that
the compatibility ifdef mess redefines it.
---
Not sure if there's a better way to do the things configure does.
---
 Changelog                  |   2 +
 compat/w32pthreads.h       | 269 ++-------------------------------------------
 configure                  |  93 ++++++++--------
 libavcodec/pthread_frame.c |   4 -
 libavcodec/pthread_slice.c |   4 -
 libavfilter/pthread.c      |   4 -
 libavutil/slicethread.c    |   4 -
 7 files changed, 60 insertions(+), 320 deletions(-)

diff --git a/Changelog b/Changelog
index ee48876128..decd6c712a 100644
--- a/Changelog
+++ b/Changelog
@@ -27,6 +27,8 @@ version <next>:
 - video setrange filter
 - nsp demuxer
 - support LibreSSL (via libtls)
+- Dropped support for building for Windows XP. The minimum supported Windows
+  version is Windows Vista.
 
 
 version 3.4:
diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h
index eeead6051f..9c7e0f574d 100644
--- a/compat/w32pthreads.h
+++ b/compat/w32pthreads.h
@@ -56,24 +56,12 @@ typedef struct pthread_t {
     void *ret;
 } pthread_t;
 
-/* the conditional variable api for windows 6.0+ uses critical sections and
- * not mutexes */
-typedef CRITICAL_SECTION pthread_mutex_t;
-
-/* This is the CONDITION_VARIABLE typedef for using Windows' native
- * conditional variables on kernels 6.0+. */
-#if HAVE_CONDITION_VARIABLE_PTR
+/* use light weight mutex/condition variable API for Windows Vista and later */
+typedef SRWLOCK pthread_mutex_t;
 typedef CONDITION_VARIABLE pthread_cond_t;
-#else
-typedef struct pthread_cond_t {
-    void *Ptr;
-} pthread_cond_t;
-#endif
 
-#if _WIN32_WINNT >= 0x0600
-#define InitializeCriticalSection(x) InitializeCriticalSectionEx(x, 0, 0)
-#define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE)
-#endif
+#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT
+#define PTHREAD_COND_INITIALIZER CONDITION_VARIABLE_INIT
 
 static av_unused unsigned __stdcall attribute_align_arg win32thread_worker(void *arg)
 {
@@ -114,26 +102,25 @@ static av_unused int pthread_join(pthread_t thread, void **value_ptr)
 
 static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr)
 {
-    InitializeCriticalSection(m);
+    InitializeSRWLock(m);
     return 0;
 }
 static inline int pthread_mutex_destroy(pthread_mutex_t *m)
 {
-    DeleteCriticalSection(m);
+    /* Unlocked SWR locks use no resources */
     return 0;
 }
 static inline int pthread_mutex_lock(pthread_mutex_t *m)
 {
-    EnterCriticalSection(m);
+    AcquireSRWLockExclusive(m);
     return 0;
 }
 static inline int pthread_mutex_unlock(pthread_mutex_t *m)
 {
-    LeaveCriticalSection(m);
+    ReleaseSRWLockExclusive(m);
     return 0;
 }
 
-#if _WIN32_WINNT >= 0x0600
 typedef INIT_ONCE pthread_once_t;
 #define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
 
@@ -167,7 +154,7 @@ static inline int pthread_cond_broadcast(pthread_cond_t *cond)
 
 static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
-    SleepConditionVariableCS(cond, mutex, INFINITE);
+    SleepConditionVariableSRW(cond, mutex, INFINITE, 0);
     return 0;
 }
 
@@ -177,242 +164,4 @@ static inline int pthread_cond_signal(pthread_cond_t *cond)
     return 0;
 }
 
-#else // _WIN32_WINNT < 0x0600
-
-/* atomic init state of dynamically loaded functions */
-static LONG w32thread_init_state = 0;
-static av_unused void w32thread_init(void);
-
-/* 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))
-{
-    w32thread_once_fallback(&w32thread_init_state, w32thread_init);
-
-    /* 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;
-    volatile int waiter_count;
-    HANDLE semaphore;
-    HANDLE waiters_done;
-    volatile int is_broadcast;
-} win32_cond_t;
-
-/* function pointers to conditional variable API on windows 6.0+ kernels */
-static void (WINAPI *cond_broadcast)(pthread_cond_t *cond);
-static void (WINAPI *cond_init)(pthread_cond_t *cond);
-static void (WINAPI *cond_signal)(pthread_cond_t *cond);
-static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex,
-                                DWORD milliseconds);
-
-static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
-{
-    win32_cond_t *win32_cond = NULL;
-
-    w32thread_once_fallback(&w32thread_init_state, w32thread_init);
-
-    if (cond_init) {
-        cond_init(cond);
-        return 0;
-    }
-
-    /* non native condition variables */
-    win32_cond = (win32_cond_t*)av_mallocz(sizeof(win32_cond_t));
-    if (!win32_cond)
-        return ENOMEM;
-    cond->Ptr = win32_cond;
-    win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
-    if (!win32_cond->semaphore)
-        return ENOMEM;
-    win32_cond->waiters_done = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (!win32_cond->waiters_done)
-        return ENOMEM;
-
-    pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL);
-    pthread_mutex_init(&win32_cond->mtx_broadcast, NULL);
-    return 0;
-}
-
-static av_unused int pthread_cond_destroy(pthread_cond_t *cond)
-{
-    win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr;
-    /* native condition variables do not destroy */
-    if (cond_init)
-        return 0;
-
-    /* non native condition variables */
-    CloseHandle(win32_cond->semaphore);
-    CloseHandle(win32_cond->waiters_done);
-    pthread_mutex_destroy(&win32_cond->mtx_waiter_count);
-    pthread_mutex_destroy(&win32_cond->mtx_broadcast);
-    av_freep(&win32_cond);
-    cond->Ptr = NULL;
-    return 0;
-}
-
-static av_unused int pthread_cond_broadcast(pthread_cond_t *cond)
-{
-    win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr;
-    int have_waiter;
-
-    if (cond_broadcast) {
-        cond_broadcast(cond);
-        return 0;
-    }
-
-    /* non native condition variables */
-    pthread_mutex_lock(&win32_cond->mtx_broadcast);
-    pthread_mutex_lock(&win32_cond->mtx_waiter_count);
-    have_waiter = 0;
-
-    if (win32_cond->waiter_count) {
-        win32_cond->is_broadcast = 1;
-        have_waiter = 1;
-    }
-
-    if (have_waiter) {
-        ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL);
-        pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
-        WaitForSingleObject(win32_cond->waiters_done, INFINITE);
-        ResetEvent(win32_cond->waiters_done);
-        win32_cond->is_broadcast = 0;
-    } 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)
-{
-    win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr;
-    int last_waiter;
-    if (cond_wait) {
-        cond_wait(cond, mutex, INFINITE);
-        return 0;
-    }
-
-    /* non native condition variables */
-    pthread_mutex_lock(&win32_cond->mtx_broadcast);
-    pthread_mutex_lock(&win32_cond->mtx_waiter_count);
-    win32_cond->waiter_count++;
-    pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
-    pthread_mutex_unlock(&win32_cond->mtx_broadcast);
-
-    // unlock the external mutex
-    pthread_mutex_unlock(mutex);
-    WaitForSingleObject(win32_cond->semaphore, INFINITE);
-
-    pthread_mutex_lock(&win32_cond->mtx_waiter_count);
-    win32_cond->waiter_count--;
-    last_waiter = !win32_cond->waiter_count || !win32_cond->is_broadcast;
-    pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
-
-    if (last_waiter)
-        SetEvent(win32_cond->waiters_done);
-
-    // lock the external mutex
-    return pthread_mutex_lock(mutex);
-}
-
-static av_unused int pthread_cond_signal(pthread_cond_t *cond)
-{
-    win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr;
-    int have_waiter;
-    if (cond_signal) {
-        cond_signal(cond);
-        return 0;
-    }
-
-    pthread_mutex_lock(&win32_cond->mtx_broadcast);
-
-    /* non-native condition variables */
-    pthread_mutex_lock(&win32_cond->mtx_waiter_count);
-    have_waiter = win32_cond->waiter_count;
-    pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
-
-    if (have_waiter) {
-        ReleaseSemaphore(win32_cond->semaphore, 1, NULL);
-        WaitForSingleObject(win32_cond->waiters_done, INFINITE);
-        ResetEvent(win32_cond->waiters_done);
-    }
-
-    pthread_mutex_unlock(&win32_cond->mtx_broadcast);
-    return 0;
-}
-#endif
-
-static av_unused void w32thread_init(void)
-{
-#if _WIN32_WINNT < 0x0600
-    HMODULE kernel_dll = GetModuleHandle(TEXT("kernel32.dll"));
-    /* if one is available, then they should all be available */
-    cond_init      = (void (WINAPI*)(pthread_cond_t *))
-        GetProcAddress(kernel_dll, "InitializeConditionVariable");
-    cond_broadcast = (void (WINAPI*)(pthread_cond_t *))
-        GetProcAddress(kernel_dll, "WakeAllConditionVariable");
-    cond_signal    = (void (WINAPI*)(pthread_cond_t *))
-        GetProcAddress(kernel_dll, "WakeConditionVariable");
-    cond_wait      = (BOOL (WINAPI*)(pthread_cond_t *, pthread_mutex_t *, DWORD))
-        GetProcAddress(kernel_dll, "SleepConditionVariableCS");
-    initonce_begin = (BOOL (WINAPI*)(pthread_once_t *, DWORD, BOOL *, void **))
-        GetProcAddress(kernel_dll, "InitOnceBeginInitialize");
-    initonce_complete = (BOOL (WINAPI*)(pthread_once_t *, DWORD, void *))
-        GetProcAddress(kernel_dll, "InitOnceComplete");
-#endif
-
-}
-
 #endif /* COMPAT_W32PTHREADS_H */
diff --git a/configure b/configure
index d09eec4155..f917f94f64 100755
--- a/configure
+++ b/configure
@@ -2089,7 +2089,6 @@ TOOLCHAIN_FEATURES="
 "
 
 TYPES_LIST="
-    CONDITION_VARIABLE_Ptr
     kCMVideoCodecType_HEVC
     socklen_t
     struct_addrinfo
@@ -5163,8 +5162,8 @@ probe_libc(){
         add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1
         check_${pfx}cpp_condition _mingw.h "__MSVCRT_VERSION__ < 0x0700" &&
             add_${pfx}cppflags -D__MSVCRT_VERSION__=0x0700
-        check_${pfx}cpp_condition windows.h "defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0502" &&
-            add_${pfx}cppflags -D_WIN32_WINNT=0x0502
+        check_${pfx}cpp_condition windows.h "defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600" &&
+            add_${pfx}cppflags -D_WIN32_WINNT=0x0600
         eval test \$${pfx_no_}cc_type = "gcc" &&
             add_${pfx}cppflags -D__printf__=__gnu_printf__
     elif check_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then
@@ -5184,14 +5183,14 @@ probe_libc(){
         # 0x601 by default unless something else is set by the user.
         # This can easily lead to us detecting functions only present
         # in such new versions and producing binaries requiring windows 7.0.
-        # Therefore explicitly set the default to XP unless the user has
+        # Therefore explicitly set the default to Vista unless the user has
         # set something else on the command line.
         # Don't do this if WINAPI_FAMILY is set and is set to a non-desktop
         # family. For these cases, configure is free to use any functions
         # found in the SDK headers by default. (Alternatively, we could force
         # _WIN32_WINNT to 0x0602 in that case.)
         check_${pfx}cpp_condition stdlib.h "defined(_WIN32_WINNT)" ||
-            { check_${pfx}cpp <<EOF && add_${pfx}cppflags -D_WIN32_WINNT=0x0502; }
+            { check_${pfx}cpp <<EOF && add_${pfx}cppflags -D_WIN32_WINNT=0x0600; }
 #ifdef WINAPI_FAMILY
 #include <winapifamily.h>
 #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
@@ -5564,6 +5563,51 @@ check_code cc arm_neon.h "int16x8_t test = vdupq_n_s16(0)" && enable intrinsics_
 check_ldflags -Wl,--as-needed
 check_ldflags -Wl,-z,noexecstack
 
+if ! disabled w32threads && ! enabled pthreads; then
+    check_func_headers "windows.h process.h" _beginthreadex &&
+        check_type "windows.h" CONDITION_VARIABLE &&
+        enable w32threads || disable w32threads
+    if ! enabled w32threads && enabled winrt; then
+        check_func_headers "windows.h" CreateThread &&
+            enable w32threads || disable w32threads
+    fi
+fi
+
+if enabled w32threads; then
+    if check_cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" ; then
+        add_cppflags -D_WIN32_WINNT=0x0600
+    fi
+fi
+
+# check for some common methods of building with pthread support
+# do this before the optional library checks as some of them require pthreads
+if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then
+    if check_lib pthreads pthread.h pthread_join   -pthread &&
+       check_lib pthreads pthread.h pthread_create -pthread; then
+        add_cflags -pthread
+    elif check_lib pthreads pthread.h pthread_join   -pthreads &&
+         check_lib pthreads pthread.h pthread_create -pthreads; then
+        add_cflags -pthreads
+    elif check_lib pthreads pthread.h pthread_join   -ldl -pthread &&
+         check_lib pthreads pthread.h pthread_create -ldl -pthread; then
+        add_cflags -ldl -pthread
+    elif check_lib pthreads pthread.h pthread_join   -lpthreadGC2 &&
+         check_lib pthreads pthread.h pthread_create -lpthreadGC2; then
+        :
+    elif check_lib pthreads pthread.h pthread_join   -lpthread &&
+         check_lib pthreads pthread.h pthread_create -lpthread; then
+        :
+    elif check_func pthread_join && check_func pthread_create; then
+        enable pthreads
+    fi
+    check_code cc "pthread.h" "static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER" || disable pthreads
+
+    if enabled pthreads; then
+        check_builtin sem_timedwait semaphore.h "sem_t *s; sem_init(s,0,0); sem_timedwait(s,0); sem_destroy(s)" $pthreads_extralibs
+        check_func pthread_cancel $pthreads_extralibs
+    fi
+fi
+
 if ! disabled network; then
     check_func getaddrinfo $network_extralibs
     check_func inet_aton $network_extralibs
@@ -5668,7 +5712,6 @@ check_func_headers windows.h SetConsoleTextAttribute
 check_func_headers windows.h SetConsoleCtrlHandler
 check_func_headers windows.h Sleep
 check_func_headers windows.h VirtualAlloc
-check_struct windows.h "CONDITION_VARIABLE" Ptr
 check_func_headers glob.h glob
 enabled xlib &&
     check_func_headers "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv -lX11 -lXext
@@ -5750,44 +5793,6 @@ check_type "vdpau/vdpau.h" "VdpPictureInfoHEVC"
 
 check_cpp_condition windows.h "!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)" && enable winrt || disable winrt
 
-if ! disabled w32threads && ! enabled pthreads; then
-    check_func_headers "windows.h process.h" _beginthreadex &&
-        enable w32threads || disable w32threads
-    if ! enabled w32threads && enabled winrt; then
-        check_func_headers "windows.h" CreateThread &&
-            enable w32threads || disable w32threads
-    fi
-fi
-
-# check for some common methods of building with pthread support
-# do this before the optional library checks as some of them require pthreads
-if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then
-    if check_lib pthreads pthread.h pthread_join   -pthread &&
-       check_lib pthreads pthread.h pthread_create -pthread; then
-        add_cflags -pthread
-    elif check_lib pthreads pthread.h pthread_join   -pthreads &&
-         check_lib pthreads pthread.h pthread_create -pthreads; then
-        add_cflags -pthreads
-    elif check_lib pthreads pthread.h pthread_join   -ldl -pthread &&
-         check_lib pthreads pthread.h pthread_create -ldl -pthread; then
-        add_cflags -ldl -pthread
-    elif check_lib pthreads pthread.h pthread_join   -lpthreadGC2 &&
-         check_lib pthreads pthread.h pthread_create -lpthreadGC2; then
-        :
-    elif check_lib pthreads pthread.h pthread_join   -lpthread &&
-         check_lib pthreads pthread.h pthread_create -lpthread; then
-        :
-    elif check_func pthread_join && check_func pthread_create; then
-        enable pthreads
-    fi
-    check_code cc "pthread.h" "static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER" || disable pthreads
-
-    if enabled pthreads; then
-        check_builtin sem_timedwait semaphore.h "sem_t *s; sem_init(s,0,0); sem_timedwait(s,0); sem_destroy(s)" $pthreads_extralibs
-        check_func pthread_cancel $pthreads_extralibs
-    fi
-fi
-
 enabled  zlib && check_lib zlib   zlib.h      zlibVersion    -lz
 enabled bzlib && check_lib bzlib bzlib.h BZ2_bzlibVersion    -lbz2
 enabled  lzma && check_lib lzma   lzma.h lzma_version_number -llzma
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index e6e6d1f599..25aa3e2cd2 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -728,10 +728,6 @@ int ff_frame_thread_init(AVCodecContext *avctx)
     FrameThreadContext *fctx;
     int i, err = 0;
 
-#if HAVE_W32THREADS
-    w32thread_init();
-#endif
-
     if (!thread_count) {
         int nb_cpus = av_cpu_count();
 #if FF_API_DEBUG_MV
diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c
index d659f9b0ba..77cfe3c9f6 100644
--- a/libavcodec/pthread_slice.c
+++ b/libavcodec/pthread_slice.c
@@ -132,10 +132,6 @@ int ff_slice_thread_init(AVCodecContext *avctx)
     int thread_count = avctx->thread_count;
     static void (*mainfunc)(void *);
 
-#if HAVE_W32THREADS
-    w32thread_init();
-#endif
-
     // We cannot do this in the encoder init as the threads are created before
     if (av_codec_is_encoder(avctx->codec) &&
         avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO &&
diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c
index 567dd4c178..7e37c73ca3 100644
--- a/libavfilter/pthread.c
+++ b/libavfilter/pthread.c
@@ -85,10 +85,6 @@ int ff_graph_thread_init(AVFilterGraph *graph)
 {
     int ret;
 
-#if HAVE_W32THREADS
-    w32thread_init();
-#endif
-
     if (graph->nb_threads == 1) {
         graph->thread_type = 0;
         return 0;
diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c
index c43f87a2aa..dfbe551ef2 100644
--- a/libavutil/slicethread.c
+++ b/libavutil/slicethread.c
@@ -99,10 +99,6 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
     AVSliceThread *ctx;
     int nb_workers, i;
 
-#if HAVE_W32THREADS
-    w32thread_init();
-#endif
-
     av_assert0(nb_threads >= 0);
     if (!nb_threads) {
         int nb_cpus = av_cpu_count();
-- 
2.15.1



More information about the ffmpeg-devel mailing list