X-Git-Url: https://git.sesse.net/?p=cubemap;a=blobdiff_plain;f=thread.cpp;h=2aaf34f11441cefe3befcba7b33cc08c6d4f6db6;hp=f719eacb95c5379a2d664f23c49c04e0b50b767b;hb=562cf44b96b5c0260d1a1ab18b2dd2408b6d1fc8;hpb=4856c49f1b63753ce86ad759ee649a1117628a8e diff --git a/thread.cpp b/thread.cpp index f719eac..2aaf34f 100644 --- a/thread.cpp +++ b/thread.cpp @@ -1,71 +1,96 @@ +#include +#include +#include +#include #include #include #include -#include -#include -#include #include "log.h" +#include "mutexlock.h" #include "thread.h" - + Thread::~Thread() {} void Thread::run() { - should_stop = false; - int pipefd[2]; - if (pipe2(pipefd, O_CLOEXEC) == -1) { - log_perror("pipe"); - exit(1); - } - stop_fd_read = pipefd[0]; - stop_fd_write = pipefd[1]; + pthread_mutex_init(&should_stop_mutex, NULL); + should_stop_status = false; pthread_create(&worker_thread, NULL, &Thread::do_work_thunk, this); } void Thread::stop() { - should_stop = true; - char ch = 0; - int err; - do { - err = write(stop_fd_write, &ch, 1); - } while (err == -1 && errno == EINTR); - - if (err == -1) { - log_perror("write"); + { + MutexLock lock(&should_stop_mutex); + should_stop_status = true; + } + wakeup(); + if (pthread_join(worker_thread, NULL) == -1) { + log_perror("pthread_join"); exit(1); } +} - do { - err = close(stop_fd_write); - } while (err == -1 && errno == EINTR); +void *Thread::do_work_thunk(void *arg) +{ + Thread *thread = reinterpret_cast(arg); - if (err == -1) { - log_perror("close"); - // Can continue (we have close-on-exec). + // Block SIGHUP; only the main thread should see that. + // (This isn't strictly required, but it makes it easier to debug that indeed + // SIGUSR1 was what woke us up.) + sigset_t set; + sigaddset(&set, SIGHUP); + int err = pthread_sigmask(SIG_BLOCK, &set, NULL); + if (err != 0) { + errno = err; + log_perror("pthread_sigmask"); + exit(1); } - pthread_kill(worker_thread, SIGHUP); - if (pthread_join(worker_thread, NULL) == -1) { - log_perror("pthread_join"); + // Block SIGUSR1, and store the old signal mask. + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + err = pthread_sigmask(SIG_BLOCK, &set, &thread->sigset_without_usr1_block); + if (err != 0) { + errno = err; + log_perror("pthread_sigmask"); exit(1); } - - do { - err = close(stop_fd_read); - } while (err == -1 && errno == EINTR); - if (err == -1) { - log_perror("close"); - // Can continue (we have close-on-exec). + // Call the right thunk. + thread->do_work(); + return NULL; +} + +bool Thread::wait_for_activity(int fd, short events, const struct timespec *timeout_ts) +{ + pollfd pfd; + pfd.fd = fd; + pfd.events = events; + + for ( ;; ) { + int nfds = ppoll(&pfd, (fd == -1) ? 0 : 1, timeout_ts, &sigset_without_usr1_block); + if (nfds == -1 && errno == EINTR) { + return false; + } + if (nfds == -1) { + log_perror("poll"); + usleep(100000); + continue; + } + assert(nfds <= 1); + return (nfds == 1); } } -void *Thread::do_work_thunk(void *arg) +void Thread::wakeup() { - Thread *thread = reinterpret_cast(arg); - thread->do_work(); - return NULL; + pthread_kill(worker_thread, SIGUSR1); } +bool Thread::should_stop() +{ + MutexLock lock(&should_stop_mutex); + return should_stop_status; +}