]> git.sesse.net Git - cubemap/blob - thread.cpp
Merge branch 'master' of /srv/git.sesse.net/www/cubemap
[cubemap] / thread.cpp
1 #include <assert.h>
2 #include <errno.h>
3 #include <poll.h>
4 #include <signal.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8
9 #include "log.h"
10 #include "mutexlock.h"
11 #include "thread.h"
12
13 Thread::~Thread() {}
14
15 void Thread::run()
16 {
17         pthread_mutex_init(&should_stop_mutex, NULL);
18         should_stop_status = false;
19         pthread_create(&worker_thread, NULL, &Thread::do_work_thunk, this);
20 }
21
22 void Thread::stop()
23 {
24         {
25                 MutexLock lock(&should_stop_mutex);
26                 should_stop_status = true;
27         }
28         wakeup();
29         if (pthread_join(worker_thread, NULL) == -1) {
30                 log_perror("pthread_join");
31                 exit(1);
32         }
33 }
34
35 void *Thread::do_work_thunk(void *arg)
36 {
37         Thread *thread = reinterpret_cast<Thread *>(arg);
38
39         // Block SIGHUP; only the main thread should see that.
40         // (This isn't strictly required, but it makes it easier to debug that indeed
41         // SIGUSR1 was what woke us up.)
42         sigset_t set;
43         sigaddset(&set, SIGHUP);
44         int err = pthread_sigmask(SIG_BLOCK, &set, NULL);
45         if (err != 0) {
46                 errno = err;
47                 log_perror("pthread_sigmask");
48                 exit(1);
49         }
50
51         // Block SIGUSR1, and store the old signal mask.
52         sigemptyset(&set);
53         sigaddset(&set, SIGUSR1);
54         err = pthread_sigmask(SIG_BLOCK, &set, &thread->sigset_without_usr1_block);
55         if (err != 0) {
56                 errno = err;
57                 log_perror("pthread_sigmask");
58                 exit(1);
59         }
60
61         // Call the right thunk.
62         thread->do_work();
63         return NULL;
64 }
65
66 bool Thread::wait_for_activity(int fd, short events, const struct timespec *timeout_ts)
67 {
68         pollfd pfd;
69         pfd.fd = fd;
70         pfd.events = events;
71
72         for ( ;; ) {
73                 int nfds = ppoll(&pfd, (fd == -1) ? 0 : 1, timeout_ts, &sigset_without_usr1_block);
74                 if (nfds == -1 && errno == EINTR) {
75                         return false;
76                 }
77                 if (nfds == -1) {
78                         log_perror("poll");
79                         usleep(100000);
80                         continue;
81                 }
82                 assert(nfds <= 1);
83                 return (nfds == 1);
84         }
85 }
86
87 void Thread::wakeup()
88 {
89         pthread_kill(worker_thread, SIGUSR1);
90 }
91
92 bool Thread::should_stop()
93 {
94         MutexLock lock(&should_stop_mutex);
95         return should_stop_status;
96 }