]> git.sesse.net Git - cubemap/blob - thread.cpp
Compile and link with -pthread, not -lpthread.
[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         sigaddset(&set, SIGHUP);
45         int err = pthread_sigmask(SIG_BLOCK, &set, NULL);
46         if (err != 0) {
47                 errno = err;
48                 log_perror("pthread_sigmask");
49                 exit(1);
50         }
51
52         // Block SIGUSR1, and store the old signal mask.
53         sigemptyset(&set);
54         sigaddset(&set, SIGUSR1);
55         err = pthread_sigmask(SIG_BLOCK, &set, &thread->sigset_without_usr1_block);
56         if (err != 0) {
57                 errno = err;
58                 log_perror("pthread_sigmask");
59                 exit(1);
60         }
61
62         // Call the right thunk.
63         thread->do_work();
64         return NULL;
65 }
66
67 bool Thread::wait_for_activity(int fd, short events, const struct timespec *timeout_ts)
68 {
69         pollfd pfd;
70         pfd.fd = fd;
71         pfd.events = events;
72
73         for ( ;; ) {
74                 int nfds = ppoll(&pfd, (fd == -1) ? 0 : 1, timeout_ts, &sigset_without_usr1_block);
75                 if (nfds == -1 && errno == EINTR) {
76                         return false;
77                 }
78                 if (nfds == -1) {
79                         log_perror("poll");
80                         usleep(100000);
81                         continue;
82                 }
83                 assert(nfds <= 1);
84                 return (nfds == 1);
85         }
86 }
87
88 void Thread::wakeup()
89 {
90         pthread_kill(worker_thread, SIGUSR1);
91 }
92
93 bool Thread::should_stop()
94 {
95         MutexLock lock(&should_stop_mutex);
96         return should_stop_status;
97 }