X-Git-Url: https://git.sesse.net/?p=cubemap;a=blobdiff_plain;f=thread.h;h=728df27cd38002881f5270315344c1616307fc42;hp=9c9bdc6d3ba79b49728c0398521382d6d33bb9f0;hb=845934ca50eee40884e8cc85ea81eb310efa5ca3;hpb=94561762b1294b76508eb5554aedbb56fcaececc;ds=sidebyside diff --git a/thread.h b/thread.h index 9c9bdc6..728df27 100644 --- a/thread.h +++ b/thread.h @@ -1,12 +1,19 @@ #ifndef _THREAD_H #define _THREAD_H +#include #include -// A rather generic thread class with start/stop functionality. -// NOTE: stop is somewhat racy (there's no guaranteed breakout from syscalls), -// since signals don't stick. We'll need to figure out something more -// intelligent later, probably based on sending a signal to an fd. +struct timespec; + +// A thread class with start/stop and signal functionality. +// +// SIGUSR1 is blocked during execution of do_work(), so that you are guaranteed +// to receive it when doing wait_for_activity(), and never elsewhere. This means +// that you can test whatever status flags you'd want before calling +// wait_for_activity(), and then be sure that it actually returns immediately +// if a SIGUSR1 (ie., wakeup()) happened, even if it were sent between your test +// and the wait_for_activity() call. class Thread { public: @@ -15,15 +22,39 @@ public: void stop(); protected: - // Recovers the this pointer, and calls do_work(). + // Recovers the this pointer, blocks SIGUSR1, and calls do_work(). static void *do_work_thunk(void *arg); virtual void do_work() = 0; - volatile bool should_stop; + // Waits until there is activity of the given type on (or an error), + // or until a wakeup. Returns true if there was actually activity on + // the file descriptor. + // + // If fd is -1, wait until a wakeup or timeout. + // if timeout_ts is NULL, there is no timeout. + bool wait_for_activity(int fd, short events, const timespec *timeout_ts); + + // Wait until a wakeup. + void wait_for_wakeup(const timespec *timeout_ts) { wait_for_activity(-1, 0, timeout_ts); } + + // Make wait_for_activity() return. Note that this is a relatively expensive + // operation. + void wakeup(); + + bool should_stop(); + + // The signal set as it were before we blocked SIGUSR1. + sigset_t sigset_without_usr1_block; private: pthread_t worker_thread; + + // Protects should_stop_status. + pthread_mutex_t should_stop_mutex; + + // If this is set, the thread should return as soon as possible from do_work(). + bool should_stop_status; }; #endif // !defined(_THREAD_H)