]> git.sesse.net Git - cubemap/blob - thread.cpp
Some README updates.
[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 "thread.h"
11
12 using namespace std;
13
14 Thread::~Thread() {}
15
16 void Thread::run()
17 {
18         should_stop_status = false;
19         pthread_create(&worker_thread, nullptr, &Thread::do_work_thunk, this);
20 }
21
22 void Thread::stop()
23 {
24         {
25                 lock_guard<mutex> lock(should_stop_mutex);
26                 should_stop_status = true;
27         }
28         wakeup();
29         if (pthread_join(worker_thread, nullptr) == -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         sigemptyset(&set);
44         sigaddset(&set, SIGHUP);
45         int err = pthread_sigmask(SIG_BLOCK, &set, nullptr);
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 nullptr;
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         lock_guard<mutex> lock(should_stop_mutex);
96         return should_stop_status;
97 }