summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKacper Michajłow <kasper93@gmail.com>2023-10-22 02:43:15 +0200
committerDudemanguy <random342@airmail.cc>2023-11-05 17:36:17 +0000
commit56d35da180879ef86a15f89f1f870dcc1cb11e5f (patch)
tree4293ad8854541fc08fda8024e789144ae69ccca1
parent55ed50ba901e70adda09f1cf8c0de7cf80cabeb3 (diff)
downloadmpv-56d35da180879ef86a15f89f1f870dcc1cb11e5f.tar.bz2
mpv-56d35da180879ef86a15f89f1f870dcc1cb11e5f.tar.xz
mp_thread: add win32 implementation
-rw-r--r--common/stats.c1
-rw-r--r--input/input.c1
-rw-r--r--meson.build34
-rw-r--r--meson_options.txt2
-rw-r--r--osdep/threads-win32.h222
-rw-r--r--osdep/threads.c3
-rw-r--r--osdep/threads.h6
-rw-r--r--osdep/timer.c4
-rw-r--r--player/command.c1
-rw-r--r--player/screenshot.c1
-rw-r--r--stream/stream_libarchive.c1
-rw-r--r--test/meson.build10
-rw-r--r--test/timer.c3
13 files changed, 252 insertions, 37 deletions
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 <pthread.h>
#include <stdatomic.h>
#include <time.h>
#include <unistd.h>
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 <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <errno.h>
+#include <process.h>
+#include <windows.h>
+
+#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 <stdio.h>
#include <errno.h>
-#include <pthread.h>
#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 <pthread.h>
#include <inttypes.h>
+#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 <http://www.gnu.org/licenses/>.
*/
-#include <pthread.h>
#include <float.h>
#include <stdlib.h>
#include <inttypes.h>
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 <http://www.gnu.org/licenses/>.
*/
-#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
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 <http://www.gnu.org/licenses/>.
*/
-#include <pthread.h>
#include <archive.h>
#include <archive_entry.h>
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 <time.h>
#include <sys/time.h>
@@ -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;
}