diff options
Diffstat (limited to 'misc/thread_tools.c')
-rw-r--r-- | misc/thread_tools.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/misc/thread_tools.c b/misc/thread_tools.c index 4bcb952267..57a4900ad6 100644 --- a/misc/thread_tools.c +++ b/misc/thread_tools.c @@ -15,6 +15,19 @@ #include <assert.h> #include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +#ifdef __MINGW32__ +#include <windows.h> +#else +#include <poll.h> +#endif + +#include "common/common.h" +#include "osdep/atomic.h" +#include "osdep/io.h" #include "thread_tools.h" @@ -60,3 +73,120 @@ bool mp_waiter_poll(struct mp_waiter *waiter) pthread_mutex_unlock(&waiter->lock); return r; } + +#ifndef __MINGW32__ +struct mp_cancel { + atomic_bool triggered; + int wakeup_pipe[2]; +}; + +static void cancel_destroy(void *p) +{ + struct mp_cancel *c = p; + if (c->wakeup_pipe[0] >= 0) { + close(c->wakeup_pipe[0]); + close(c->wakeup_pipe[1]); + } +} + +struct mp_cancel *mp_cancel_new(void *talloc_ctx) +{ + struct mp_cancel *c = talloc_ptrtype(talloc_ctx, c); + talloc_set_destructor(c, cancel_destroy); + *c = (struct mp_cancel){.triggered = ATOMIC_VAR_INIT(false)}; + mp_make_wakeup_pipe(c->wakeup_pipe); + return c; +} + +void mp_cancel_trigger(struct mp_cancel *c) +{ + atomic_store(&c->triggered, true); + (void)write(c->wakeup_pipe[1], &(char){0}, 1); +} + +void mp_cancel_reset(struct mp_cancel *c) +{ + atomic_store(&c->triggered, false); + // Flush it fully. + while (1) { + int r = read(c->wakeup_pipe[0], &(char[256]){0}, 256); + if (r < 0 && errno == EINTR) + continue; + if (r <= 0) + break; + } +} + +bool mp_cancel_test(struct mp_cancel *c) +{ + return c ? atomic_load_explicit(&c->triggered, memory_order_relaxed) : false; +} + +bool mp_cancel_wait(struct mp_cancel *c, double timeout) +{ + struct pollfd fd = { .fd = c->wakeup_pipe[0], .events = POLLIN }; + poll(&fd, 1, timeout * 1000); + return fd.revents & POLLIN; +} + +int mp_cancel_get_fd(struct mp_cancel *c) +{ + return c->wakeup_pipe[0]; +} + +#else + +struct mp_cancel { + atomic_bool triggered; + HANDLE event; +}; + +static void cancel_destroy(void *p) +{ + struct mp_cancel *c = p; + CloseHandle(c->event); +} + +struct mp_cancel *mp_cancel_new(void *talloc_ctx) +{ + struct mp_cancel *c = talloc_ptrtype(talloc_ctx, c); + talloc_set_destructor(c, cancel_destroy); + *c = (struct mp_cancel){.triggered = ATOMIC_VAR_INIT(false)}; + c->event = CreateEventW(NULL, TRUE, FALSE, NULL); + return c; +} + +void mp_cancel_trigger(struct mp_cancel *c) +{ + atomic_store(&c->triggered, true); + SetEvent(c->event); +} + +void mp_cancel_reset(struct mp_cancel *c) +{ + atomic_store(&c->triggered, false); + ResetEvent(c->event); +} + +bool mp_cancel_test(struct mp_cancel *c) +{ + return c ? atomic_load_explicit(&c->triggered, memory_order_relaxed) : false; +} + +bool mp_cancel_wait(struct mp_cancel *c, double timeout) +{ + return WaitForSingleObject(c->event, timeout < 0 ? INFINITE : timeout * 1000) + == WAIT_OBJECT_0; +} + +void *mp_cancel_get_event(struct mp_cancel *c) +{ + return c->event; +} + +int mp_cancel_get_fd(struct mp_cancel *c) +{ + return -1; +} + +#endif |