diff --git a/common/stats.c b/common/stats.c index fa86aac961..c5f1e50590 100644 --- a/common/stats.c +++ b/common/stats.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/input/input.c b/input/input.c index 67e2249e17..b8d12aae13 100644 --- a/input/input.c +++ b/input/input.c @@ -17,7 +17,6 @@ #include "config.h" -#include #include #include #include diff --git a/meson.build b/meson.build index 19fc2532b3..d23914475e 100644 --- a/meson.build +++ b/meson.build @@ -248,7 +248,6 @@ sources = files( 'osdep/io.c', 'osdep/semaphore_osx.c', 'osdep/subprocess.c', - 'osdep/threads.c', 'osdep/timer.c', ## tree_allocator @@ -354,31 +353,18 @@ if features['cplugins'] and not win32 link_flags += '-rdynamic' endif -# Note: this include is only used for windows pthreads and -# must be accompanied immediately by the following flags. -# This currently works because these are the last flags set -# in the build for windows. Adding any new flags after this -# will probably break something. -includedir = [] -win32_pthreads = get_option('win32-internal-pthreads').require( - win32 and not posix, - error_message: 'the os is not win32!', -) -features += {'win32-internal-pthreads': win32_pthreads.allowed()} -if features['win32-internal-pthreads'] - flags += ['-isystem', '-I', '-DIN_WINPTHREAD'] - includedir += include_directories('osdep/win32/include') - sources += files('osdep/win32/pthread.c') -else - # pthreads is intentionally left undefined in win32 branch to find incorrect - # uses of it immediately +win32_threads = get_option('win32-threads').require(win32) + +features += {'win32-threads': win32_threads.allowed()} +if not features['win32-threads'] pthreads = dependency('threads') + sources += files('osdep/threads.c') dependencies += pthreads endif pthread_debug = get_option('pthread-debug').require( - win32_pthreads.disabled(), - error_message: 'win32-internal-pthreads was found!', + win32_threads.disabled(), + error_message: 'win32-threads was found!', ) features += {'pthread-debug': pthread_debug.allowed()} if features['pthread-debug'] @@ -1721,8 +1707,8 @@ client_api_version = major + '.' + minor + '.0' libmpv = library('mpv', sources, dependencies: dependencies, gnu_symbol_visibility: 'hidden', link_args: cc.get_supported_link_arguments(['-Wl,-Bsymbolic']), - version: client_api_version, include_directories: includedir, - install: get_option('libmpv'), build_by_default: get_option('libmpv')) + version: client_api_version, install: get_option('libmpv'), + build_by_default: get_option('libmpv')) if get_option('libmpv') @@ -1768,7 +1754,7 @@ if get_option('cplayer') install_data('etc/mpv-symbolic.svg', install_dir: join_paths(hicolor_dir, 'symbolic', 'apps')) mpv = executable('mpv', objects: libmpv.extract_all_objects(recursive: true), dependencies: dependencies, - win_subsystem: 'windows,6.0', include_directories: includedir, install: true) + win_subsystem: 'windows,6.0', install: true) endif if get_option('tests') diff --git a/meson_options.txt b/meson_options.txt index 8a7e4af4f9..f50c55e738 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -34,7 +34,7 @@ option('uchardet', type: 'feature', value: 'auto', description: 'uchardet suppor option('uwp', type: 'feature', value: 'disabled', description: 'Universal Windows Platform') option('vapoursynth', type: 'feature', value: 'auto', description: 'VapourSynth filter bridge') option('vector', type: 'feature', value: 'auto', description: 'GCC vector instructions') -option('win32-internal-pthreads', type: 'feature', value: 'auto', description: 'internal pthread wrapper for win32 (Vista+)') +option('win32-threads', type: 'feature', value: 'auto', description: 'win32 threads') option('zimg', type: 'feature', value: 'auto', description: 'libzimg support (high quality software scaler)') option('zlib', type: 'feature', value: 'auto', description: 'zlib') diff --git a/osdep/threads-win32.h b/osdep/threads-win32.h new file mode 100644 index 0000000000..ef661aa53a --- /dev/null +++ b/osdep/threads-win32.h @@ -0,0 +1,222 @@ +/* + * This file is part of mpv. + * + * mpv 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. + * + * mpv 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 mpv. If not, see . + */ + +#pragma once + +#include +#include +#include + +#include "common/common.h" +#include "timer.h" + +typedef struct { + char use_cs; + union { + CRITICAL_SECTION cs; + SRWLOCK srw; + }; +} mp_mutex; + +typedef CONDITION_VARIABLE mp_cond; +typedef INIT_ONCE mp_once; +typedef mp_mutex mp_static_mutex; +typedef HANDLE mp_thread; +typedef DWORD mp_thread_id; + +#define MP_STATIC_COND_INITIALIZER CONDITION_VARIABLE_INIT +#define MP_STATIC_MUTEX_INITIALIZER (mp_mutex){ .srw = SRWLOCK_INIT } +#define MP_STATIC_ONCE_INITIALIZER INIT_ONCE_STATIC_INIT + +static inline int mp_mutex_init_type_internal(mp_mutex *mutex, enum mp_mutex_type mtype) +{ + mutex->use_cs = mtype == MP_MUTEX_RECURSIVE; + if (mutex->use_cs) + return !InitializeCriticalSectionEx(&mutex->cs, 0, 0); + InitializeSRWLock(&mutex->srw); + return 0; +} + +#define mp_mutex_init_type(mutex, mtype) \ + assert(!mp_mutex_init_type_internal(mutex, mtype)) + +static inline int mp_mutex_destroy(mp_mutex *mutex) +{ + if (mutex->use_cs) + DeleteCriticalSection(&mutex->cs); + return 0; +} + +static inline int mp_mutex_lock(mp_mutex *mutex) +{ + if (mutex->use_cs) { + EnterCriticalSection(&mutex->cs); + } else { + AcquireSRWLockExclusive(&mutex->srw); + } + return 0; +} + +static inline int mp_mutex_trylock(mp_mutex *mutex) +{ + if (mutex->use_cs) + return !TryEnterCriticalSection(&mutex->cs); + return !TryAcquireSRWLockExclusive(&mutex->srw); +} + +static inline int mp_mutex_unlock(mp_mutex *mutex) +{ + if (mutex->use_cs) { + LeaveCriticalSection(&mutex->cs); + } else { + ReleaseSRWLockExclusive(&mutex->srw); + } + return 0; +} + +static inline int mp_cond_init(mp_cond *cond) +{ + InitializeConditionVariable(cond); + return 0; +} + +static inline int mp_cond_destroy(mp_cond *cond) +{ + // condition variables are not destroyed + (void) cond; + return 0; +} + +static inline int mp_cond_broadcast(mp_cond *cond) +{ + WakeAllConditionVariable(cond); + return 0; +} + +static inline int mp_cond_signal(mp_cond *cond) +{ + WakeConditionVariable(cond); + return 0; +} + +static inline int mp_cond_timedwait(mp_cond *cond, mp_mutex *mutex, int64_t timeout) +{ + timeout = MPCLAMP(timeout, 0, MP_TIME_MS_TO_NS(INFINITE)) / MP_TIME_MS_TO_NS(1); + + int ret = 0; + int hrt = mp_start_hires_timers(timeout); + BOOL bRet; + + if (mutex->use_cs) { + bRet = SleepConditionVariableCS(cond, &mutex->cs, timeout); + } else { + bRet = SleepConditionVariableSRW(cond, &mutex->srw, timeout, 0); + } + if (bRet == FALSE) + ret = GetLastError() == ERROR_TIMEOUT ? ETIMEDOUT : EINVAL; + + mp_end_hires_timers(hrt); + return ret; +} + +static inline int mp_cond_wait(mp_cond *cond, mp_mutex *mutex) +{ + return mp_cond_timedwait(cond, mutex, MP_TIME_MS_TO_NS(INFINITE)); +} + +static inline int mp_cond_timedwait_until(mp_cond *cond, mp_mutex *mutex, int64_t until) +{ + return mp_cond_timedwait(cond, mutex, until - mp_time_ns()); +} + +static inline int mp_exec_once(mp_once *once, void (*init_routine)(void)) +{ + BOOL pending; + + if (!InitOnceBeginInitialize(once, 0, &pending, NULL)) + abort(); + + if (pending) { + init_routine(); + InitOnceComplete(once, 0, NULL); + } + + return 0; +} + +#define MP_THREAD_VOID unsigned __stdcall +#define MP_THREAD_RETURN() return 0 + +static inline int mp_thread_create(mp_thread *thread, + MP_THREAD_VOID (*fun)(void *), + void *__restrict arg) +{ + *thread = (HANDLE) _beginthreadex(NULL, 0, fun, arg, 0, NULL); + return *thread ? 0 : -1; +} + +static inline int mp_thread_join(mp_thread thread) +{ + DWORD ret = WaitForSingleObject(thread, INFINITE); + if (ret != WAIT_OBJECT_0) + return ret == WAIT_ABANDONED ? EINVAL : EDEADLK; + CloseHandle(thread); + return 0; +} + +static inline int mp_thread_join_id(mp_thread_id id) +{ + mp_thread thread = OpenThread(SYNCHRONIZE, FALSE, id); + if (!thread) + return ESRCH; + int ret = mp_thread_join(thread); + if (ret) + CloseHandle(thread); + return ret; +} + +static inline int mp_thread_detach(mp_thread thread) +{ + return CloseHandle(thread) ? 0 : EINVAL; +} + +#define mp_thread_current_id GetCurrentThreadId +#define mp_thread_id_equal(a, b) ((a) == (b)) +#define mp_thread_get_id(thread) GetThreadId(thread) + +wchar_t *mp_from_utf8(void *talloc_ctx, const char *s); +static inline void mp_thread_set_name(const char *name) +{ +#if !HAVE_UWP + HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (!kernel32) + return; + HRESULT (WINAPI *pSetThreadDescription)(HANDLE, PCWSTR) = + (void *) GetProcAddress(kernel32, "SetThreadDescription"); + if (!pSetThreadDescription) + return; + wchar_t *wname = mp_from_utf8(NULL, name); + pSetThreadDescription(GetCurrentThread(), wname); + talloc_free(wname); +#endif +} + +static inline int64_t mp_thread_cpu_time_ns(mp_thread_id thread) +{ + (void) thread; + return 0; +} diff --git a/osdep/threads.c b/osdep/threads.c index 1802fea3ce..b9ead75723 100644 --- a/osdep/threads.c +++ b/osdep/threads.c @@ -17,7 +17,6 @@ #include #include -#include #include "common/common.h" #include "config.h" @@ -46,7 +45,7 @@ void mpthread_set_name(const char *name) strncpy(tname, name, sizeof(tname) - 1); pthread_setname_np(pthread_self(), tname); } -#elif HAVE_WIN32_INTERNAL_PTHREADS || HAVE_BSD_THREAD_NAME +#elif HAVE_BSD_THREAD_NAME pthread_set_name_np(pthread_self(), name); #elif HAVE_OSX_THREAD_NAME pthread_setname_np(name); diff --git a/osdep/threads.h b/osdep/threads.h index 26188e8e7f..8bb00ba507 100644 --- a/osdep/threads.h +++ b/osdep/threads.h @@ -4,6 +4,8 @@ #include #include +#include "config.h" + // Helper to reduce boiler plate. int mpthread_mutex_init_recursive(pthread_mutex_t *mutex); @@ -81,6 +83,10 @@ enum mp_mutex_type { #define mp_mutex_init_type(mutex, mtype) \ assert(!mp_mutex_init_type_internal(mutex, mtype)) +#if HAVE_WIN32_THREADS +#include "threads-win32.h" +#else #include "threads-posix.h" +#endif #endif diff --git a/osdep/timer.c b/osdep/timer.c index 8a58c4bc17..17921c1665 100644 --- a/osdep/timer.c +++ b/osdep/timer.c @@ -67,6 +67,8 @@ int64_t mp_time_ns_add(int64_t time_ns, double timeout_sec) return time_ns + ti; } +#if !HAVE_WIN32_THREADS + struct timespec mp_time_ns_to_realtime(int64_t time_ns) { struct timespec ts = {0}; @@ -91,3 +93,5 @@ struct timespec mp_rel_time_to_timespec(double timeout_sec) { return mp_time_ns_to_realtime(mp_time_ns_add(mp_time_ns(), timeout_sec)); } + +#endif diff --git a/player/command.c b/player/command.c index 9757b185f3..437faf7928 100644 --- a/player/command.c +++ b/player/command.c @@ -15,7 +15,6 @@ * License along with mpv. If not, see . */ -#include #include #include #include diff --git a/player/screenshot.c b/player/screenshot.c index 1d151a5475..e4d0912679 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -15,7 +15,6 @@ * License along with mpv. If not, see . */ -#include #include #include #include diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c index cfc1f2f96f..61c95cc349 100644 --- a/stream/stream_libarchive.c +++ b/stream/stream_libarchive.c @@ -15,7 +15,6 @@ * License along with mpv. If not, see . */ -#include #include #include diff --git a/test/meson.build b/test/meson.build index 0a40bb03e7..f65110967f 100644 --- a/test/meson.build +++ b/test/meson.build @@ -40,11 +40,12 @@ if win32 test_utils_files += 'osdep/windows_utils.c' endif +if features['pthread-debug'] + test_utils_files += 'osdep/threads.c' +endif + # The zimg code requires using threads. -if features['win32-internal-pthreads'] - test_utils_args += '-DWIN32_TESTS' - test_utils_files += ['osdep/win32/pthread.c'] -else +if not features['win32-threads'] test_utils_deps += pthreads endif @@ -59,7 +60,6 @@ test_utils = static_library('test-utils', 'test_utils.c', include_directories: i # For getting imgfmts and stuff. img_utils_files = [ 'misc/thread_pool.c', - 'osdep/threads.c', 'video/csputils.c', 'video/fmt-conversion.c', 'video/img_format.c', diff --git a/test/timer.c b/test/timer.c index 6fe7770c2e..f89fd7e310 100644 --- a/test/timer.c +++ b/test/timer.c @@ -1,6 +1,7 @@ #include "common/common.h" #include "osdep/timer.h" #include "test_utils.h" +#include "config.h" #include #include @@ -37,6 +38,7 @@ int main(void) assert_int_equal(mp_time_ns_add(test2, 20.44), INT64_MAX); } +#if !HAVE_WIN32_THREADS /* conversion */ { struct timeval tv; @@ -49,6 +51,7 @@ int main(void) ts = mp_rel_time_to_timespec(0.0); assert_true(llabs(tv.tv_sec - ts.tv_sec) <= 1); } +#endif return 0; }