diff options
author | wm4 <wm4@nowhere> | 2018-05-06 13:00:05 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2018-05-24 19:56:34 +0200 |
commit | 22c002138d8b82a021564ddab447fafd90852e75 (patch) | |
tree | 233503a74b229f24bdedfc70b18d29f6354b46ae /misc/thread_tools.c | |
parent | 383da1bfd59fa77366d5e61612da4da8d4f1cf6c (diff) | |
download | mpv-22c002138d8b82a021564ddab447fafd90852e75.tar.bz2 mpv-22c002138d8b82a021564ddab447fafd90852e75.tar.xz |
misc: add a synchronization helper
This is almost like rendezvous(), except it allows async wakeup, and
does not require global state. It will be used by a later commit.
struct mp_waiter is intended to be allocated on the stack, and uses an
initializer including PTHREAD_MUTEX_INITIALIZER. This is the first case
in mpv that it uses PTHREAD_MUTEX_INITIALIZER for stack-allocated
mutexes. It seems POSIX still does not allow this formally, but since
POSIX is worth less than used toilet paper, I don't really care. Modern
OSes use futexes, which means you can make _every_ memory location a
lock, and this code tries to make use of it, without using OS specific
code.
The name of the source file is rather generic, because I intend to dump
further small helpers there (or maybe move mp_rendezvous() to it).
Diffstat (limited to 'misc/thread_tools.c')
-rw-r--r-- | misc/thread_tools.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/misc/thread_tools.c b/misc/thread_tools.c new file mode 100644 index 0000000000..4bcb952267 --- /dev/null +++ b/misc/thread_tools.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2018 the mpv developers + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include "thread_tools.h" + +uintptr_t mp_waiter_wait(struct mp_waiter *waiter) +{ + pthread_mutex_lock(&waiter->lock); + while (!waiter->done) + pthread_cond_wait(&waiter->wakeup, &waiter->lock); + pthread_mutex_unlock(&waiter->lock); + + uintptr_t ret = waiter->value; + + // We document that after mp_waiter_wait() the waiter object becomes + // invalid. (It strictly returns only after mp_waiter_wakeup() has returned, + // and the object is "single-shot".) So destroy it here. + + // Normally, we expect that the system uses futexes, in which case the + // following functions will do nearly nothing. This is true for Windows + // and Linux. But some lesser OSes still might allocate kernel objects + // when initializing mutexes, so destroy them here. + pthread_mutex_destroy(&waiter->lock); + pthread_cond_destroy(&waiter->wakeup); + + memset(waiter, 0xCA, sizeof(*waiter)); // for debugging + + return ret; +} + +void mp_waiter_wakeup(struct mp_waiter *waiter, uintptr_t value) +{ + pthread_mutex_lock(&waiter->lock); + assert(!waiter->done); + waiter->done = true; + waiter->value = value; + pthread_cond_signal(&waiter->wakeup); + pthread_mutex_unlock(&waiter->lock); +} + +bool mp_waiter_poll(struct mp_waiter *waiter) +{ + pthread_mutex_lock(&waiter->lock); + bool r = waiter->done; + pthread_mutex_unlock(&waiter->lock); + return r; +} |