summaryrefslogtreecommitdiffstats
path: root/misc/thread_tools.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc/thread_tools.c')
-rw-r--r--misc/thread_tools.c130
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