-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
#include "log.h"
-#include "mutexlock.h"
#include "thread.h"
-
+
Thread::~Thread() {}
void Thread::run()
{
- pthread_mutex_init(&should_stop_mutex, NULL);
- should_stop_status = false;
+ 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_create(&worker_thread, NULL, &Thread::do_work_thunk, this);
}
void Thread::stop()
{
- {
- MutexLock lock(&should_stop_mutex);
- should_stop_status = true;
- }
- wakeup();
- if (pthread_join(worker_thread, NULL) == -1) {
- log_perror("pthread_join");
+ 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");
exit(1);
}
-}
-void *Thread::do_work_thunk(void *arg)
-{
- Thread *thread = reinterpret_cast<Thread *>(arg);
+ do {
+ err = close(stop_fd_write);
+ } while (err == -1 && errno == EINTR);
- // 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);
+ if (err == -1) {
+ log_perror("close");
+ // Can continue (we have close-on-exec).
}
- // 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");
+ pthread_kill(worker_thread, SIGHUP);
+ if (pthread_join(worker_thread, NULL) == -1) {
+ log_perror("pthread_join");
exit(1);
}
+
+ do {
+ err = close(stop_fd_read);
+ } while (err == -1 && errno == EINTR);
- // 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);
+ if (err == -1) {
+ log_perror("close");
+ // Can continue (we have close-on-exec).
}
}
-void Thread::wakeup()
+void *Thread::do_work_thunk(void *arg)
{
- pthread_kill(worker_thread, SIGUSR1);
+ Thread *thread = reinterpret_cast<Thread *>(arg);
+ thread->do_work();
+ return NULL;
}
-bool Thread::should_stop()
-{
- MutexLock lock(&should_stop_mutex);
- return should_stop_status;
-}