From 76d52250fd5d7a84d9ae535fd7725d3a466bbb36 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 14 Apr 2013 19:53:48 +0200 Subject: [PATCH] Signal thread stop through a pipe; fixes issues where the statistics thread would wait one round on shutdown. --- stats.cpp | 26 ++++++++++++++++++++++---- thread.cpp | 39 +++++++++++++++++++++++++++++++++++++++ thread.h | 6 ++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/stats.cpp b/stats.cpp index c9af688..f5916ed 100644 --- a/stats.cpp +++ b/stats.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include "client.h" @@ -71,9 +73,25 @@ void StatsThread::do_work() } sleep: - int left_to_sleep = stats_interval; - do { - left_to_sleep = sleep(left_to_sleep); - } while (left_to_sleep > 0 && !should_stop); + // Wait until the stop_fd pipe is closed, stats_interval timeout, + // or a spurious signal. (The latter will cause us to write stats + // too often, but that's okay.) + pollfd pfd; + pfd.fd = stop_fd_read; + pfd.events = POLLIN | POLLRDHUP; + + int nfds = poll(&pfd, 1, stats_interval * 1000); + if (nfds == 0 || (nfds == -1 && errno == EINTR)) { + continue; + } + if (nfds == 1) { + // Should stop. + break; + } + if (nfds == -1) { + perror("poll"); + usleep(100000); + continue; + } } } diff --git a/thread.cpp b/thread.cpp index 7aded3b..b263be6 100644 --- a/thread.cpp +++ b/thread.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include #include +#include #include "thread.h" @@ -9,17 +12,53 @@ Thread::~Thread() {} void Thread::run() { should_stop = false; + int pipefd[2]; + if (pipe2(pipefd, O_CLOEXEC) == -1) { + 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() { should_stop = true; + char ch = 0; + int err; + do { + err = write(stop_fd_write, &ch, 1); + } while (err == -1 && errno == EINTR); + + if (err == -1) { + perror("write"); + exit(1); + } + + do { + err = close(stop_fd_write); + } while (err == -1 && errno == EINTR); + + if (err == -1) { + perror("close"); + // Can continue (we have close-on-exec). + } + pthread_kill(worker_thread, SIGHUP); if (pthread_join(worker_thread, NULL) == -1) { perror("pthread_join"); exit(1); } + + do { + err = close(stop_fd_read); + } while (err == -1 && errno == EINTR); + + if (err == -1) { + perror("close"); + // Can continue (we have close-on-exec). + } } void *Thread::do_work_thunk(void *arg) diff --git a/thread.h b/thread.h index 9c9bdc6..26e648e 100644 --- a/thread.h +++ b/thread.h @@ -22,8 +22,14 @@ protected: volatile bool should_stop; + // A pipe that you can poll on if you want to see when should_stop + // has been set to true; stop() will write a single byte to the pipe + // and then close the other end. + int stop_fd_read; + private: pthread_t worker_thread; + int stop_fd_write; }; #endif // !defined(_THREAD_H) -- 2.39.2