shutdown: Use RAII TokenPipe in shutdown

This commit is contained in:
Wladimir J. van der Laan 2021-01-26 19:34:47 +01:00
parent 612f746a8f
commit c3e6fdee6d

View File

@ -5,16 +5,15 @@
#include <shutdown.h> #include <shutdown.h>
#include <logging.h>
#include <util/tokenpipe.h>
#include <config/bitcoin-config.h> #include <config/bitcoin-config.h>
#include <assert.h> #include <assert.h>
#include <atomic> #include <atomic>
#ifdef WIN32 #ifdef WIN32
#include <condition_variable> #include <condition_variable>
#else
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#endif #endif
static std::atomic<bool> fRequestShutdown(false); static std::atomic<bool> fRequestShutdown(false);
@ -24,25 +23,18 @@ std::mutex g_shutdown_mutex;
std::condition_variable g_shutdown_cv; std::condition_variable g_shutdown_cv;
#else #else
/** On UNIX-like operating systems use the self-pipe trick. /** On UNIX-like operating systems use the self-pipe trick.
* Index 0 will be the read end of the pipe, index 1 the write end.
*/ */
static int g_shutdown_pipe[2] = {-1, -1}; static TokenPipeEnd g_shutdown_r;
static TokenPipeEnd g_shutdown_w;
#endif #endif
bool InitShutdownState() bool InitShutdownState()
{ {
#ifndef WIN32 #ifndef WIN32
#if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2 std::optional<TokenPipe> pipe = TokenPipe::Make();
// If we can, make sure that the file descriptors are closed on exec() if (!pipe) return false;
// to prevent interference. g_shutdown_r = pipe->TakeReadEnd();
if (pipe2(g_shutdown_pipe, O_CLOEXEC) != 0) { g_shutdown_w = pipe->TakeWriteEnd();
return false;
}
#else
if (pipe(g_shutdown_pipe) != 0) {
return false;
}
#endif
#endif #endif
return true; return true;
} }
@ -59,17 +51,10 @@ void StartShutdown()
// case of a reentrant signal. // case of a reentrant signal.
if (!fRequestShutdown.exchange(true)) { if (!fRequestShutdown.exchange(true)) {
// Write an arbitrary byte to the write end of the shutdown pipe. // Write an arbitrary byte to the write end of the shutdown pipe.
const char token = 'x'; int res = g_shutdown_w.TokenWrite('x');
while (true) { if (res != 0) {
int result = write(g_shutdown_pipe[1], &token, 1); LogPrintf("Sending shutdown token failed\n");
if (result < 0) { assert(0);
// Failure. It's possible that the write was interrupted by another signal.
// Other errors are unexpected here.
assert(errno == EINTR);
} else {
assert(result == 1);
break;
}
} }
} }
#endif #endif
@ -96,17 +81,10 @@ void WaitForShutdown()
std::unique_lock<std::mutex> lk(g_shutdown_mutex); std::unique_lock<std::mutex> lk(g_shutdown_mutex);
g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); }); g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); });
#else #else
char token; int res = g_shutdown_r.TokenRead();
while (true) { if (res != 'x') {
int result = read(g_shutdown_pipe[0], &token, 1); LogPrintf("Reading shutdown token failed\n");
if (result < 0) { assert(0);
// Failure. Check if the read was interrupted by a signal.
// Other errors are unexpected here.
assert(errno == EINTR);
} else {
assert(result == 1);
break;
}
} }
#endif #endif
} }