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