summaryrefslogtreecommitdiffstats
path: root/osdep
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-07-27 22:59:38 +0200
committerwm4 <wm4@nowhere>2015-07-27 22:59:38 +0200
commitb3468d53c71594f7e29e0ac736dc3b82b92446a3 (patch)
tree4dc80ca167b1414fce22fb6901a4fc45330a09bd /osdep
parent3452f9aeac75a2134780b5bb4a1112d44de25d50 (diff)
downloadmpv-b3468d53c71594f7e29e0ac736dc3b82b92446a3.tar.bz2
mpv-b3468d53c71594f7e29e0ac736dc3b82b92446a3.tar.xz
win32: pthread: don't play dirty tricks for mutex init
We used double-checked locking on pthread_mutex_t.requires_init in order to lazily initialize static mutexes (since CRITICAL_SECTION has no native way to do this). This was kind of unclean: we relied on MSVC semantics for volatile (which apparently means all accesses are weakly atomic), which is not such a good idea since mpv can't even be compiled with MSVC. Since it's too much of a pain to get weak atomics, just use INIT_ONCE for initializing the CRITICAL_SECTION. Microsoft most likely implemented this in an extremely efficient way. Essentially, it provides a mechanism for correct double-checked locking without having to deal with the tricky details. We still use an extra flag to avoid calling it at all for normal locks. (To get weak atomics, we could have used stdatomic.h, which modern MinGW provides just fine. But I don't want this wrapper depend on MinGW specifics if possible.)
Diffstat (limited to 'osdep')
-rw-r--r--osdep/win32/include/pthread.h5
-rw-r--r--osdep/win32/pthread.c33
2 files changed, 10 insertions, 28 deletions
diff --git a/osdep/win32/include/pthread.h b/osdep/win32/include/pthread.h
index 2e9436d80b..7b82eb2651 100644
--- a/osdep/win32/include/pthread.h
+++ b/osdep/win32/include/pthread.h
@@ -25,11 +25,12 @@
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
typedef struct {
- volatile LONG requires_init;
+ char static_mutex;
+ INIT_ONCE static_init;
CRITICAL_SECTION cs;
} pthread_mutex_t;
-#define PTHREAD_MUTEX_INITIALIZER {1}
+#define PTHREAD_MUTEX_INITIALIZER {1, INIT_ONCE_STATIC_INIT}
#define pthread_mutexattr_t int
#define pthread_mutexattr_destroy(attr) (void)0
diff --git a/osdep/win32/pthread.c b/osdep/win32/pthread.c
index ee4b5a158d..4838df48b7 100644
--- a/osdep/win32/pthread.c
+++ b/osdep/win32/pthread.c
@@ -18,27 +18,6 @@
#include <errno.h>
#include <sys/time.h>
-// We keep this around to avoid active waiting while handling static
-// initializers.
-static pthread_once_t init_cs_once = PTHREAD_ONCE_INIT;
-static CRITICAL_SECTION init_cs;
-
-static void init_init_cs(void)
-{
- InitializeCriticalSection(&init_cs);
-}
-
-static void init_lock(void)
-{
- pthread_once(&init_cs_once, init_init_cs);
- EnterCriticalSection(&init_cs);
-}
-
-static void init_unlock(void)
-{
- LeaveCriticalSection(&init_cs);
-}
-
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
{
BOOL pending;
@@ -66,12 +45,14 @@ int pthread_mutex_init(pthread_mutex_t *restrict mutex,
int pthread_mutex_lock(pthread_mutex_t *mutex)
{
- if (mutex->requires_init) {
- init_lock();
- if (mutex->requires_init)
+ if (mutex->static_mutex) {
+ BOOL pending;
+ if (!InitOnceBeginInitialize(&mutex->static_init, 0, &pending, NULL))
+ abort();
+ if (pending) {
InitializeCriticalSection(&mutex->cs);
- _InterlockedAnd(&mutex->requires_init, 0);
- init_unlock();
+ InitOnceComplete(&mutex->static_init, 0, NULL);
+ }
}
EnterCriticalSection(&mutex->cs);
return 0;