dash/src/shutdown.cpp
MarcoFalke 673111c448
Merge #19233: Make SetMiscWarning() accept bilingual_str argument
d49612f98add29066817b7c808b76c2d728948e5 Make SetMiscWarning() accept bilingual_str argument (Hennadii Stepanov)
d1ae7c0355662481a7d181a0a458284936d53eb1 Make GetWarnings() return bilingual_str (Hennadii Stepanov)
38e33aa481cefbe12c50f344bae190c0d95fb489 refactor: Make GetWarnings() bilingual_str aware internally (Hennadii Stepanov)

Pull request description:

  This is one more step for consistent usage of `bilingual_str`.

  No new translation messages are defined.

ACKs for top commit:
  laanwj:
    Code review ACK d49612f98add29066817b7c808b76c2d728948e5
  MarcoFalke:
    ACK d49612f98add29066817b7c808b76c2d728948e5 🌂

Tree-SHA512: 7413cb94a85291209c182845f6873350bb9e9ce940647d416c462a136603832fec8a63d792341bf634f07629767c78bc206d3a318cf10c7e87241c114c2496e9
2024-01-16 15:05:05 -06:00

141 lines
3.6 KiB
C++

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <shutdown.h>
#include <logging.h>
#include <node/ui_interface.h>
#include <warnings.h>
#include <config/bitcoin-config.h>
#include <assert.h>
#include <atomic>
#ifdef WIN32
#include <condition_variable>
#else
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#endif
bool AbortNode(const std::string& strMessage, bilingual_str user_message)
{
SetMiscWarning(Untranslated(strMessage));
LogPrintf("*** %s\n", strMessage);
if (user_message.empty()) {
user_message = _("A fatal internal error occurred, see debug.log for details");
}
AbortError(user_message);
StartShutdown();
return false;
}
static std::atomic<bool> fRequestShutdown(false);
static std::atomic<bool> fRequestRestart(false);
#ifdef WIN32
/** On windows it is possible to simply use a condition variable. */
std::mutex g_shutdown_mutex;
std::condition_variable g_shutdown_cv;
#else
/** 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};
#endif
bool InitShutdownState()
{
#ifndef WIN32
#if HAVE_O_CLOEXEC && HAVE_DECL_PIPE2
// If we can, make sure that the file descriptors are closed on exec()
// to prevent interference.
if (pipe2(g_shutdown_pipe, O_CLOEXEC) != 0) {
return false;
}
#else
if (pipe(g_shutdown_pipe) != 0) {
return false;
}
#endif
#endif
return true;
}
void StartShutdown()
{
#ifdef WIN32
std::unique_lock<std::mutex> lk(g_shutdown_mutex);
fRequestShutdown = true;
g_shutdown_cv.notify_one();
#else
// This must be reentrant and safe for calling in a signal handler, so using a condition variable is not safe.
// Make sure that the token is only written once even if multiple threads call this concurrently or in
// case of a reentrant signal.
if (!fRequestShutdown.exchange(true)) {
// Write an arbitrary byte to the write end of the shutdown pipe.
const char token = 'x';
while (true) {
int result = write(g_shutdown_pipe[1], &token, 1);
if (result < 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
}
void StartRestart()
{
fRequestRestart = true;
StartShutdown();
}
void AbortShutdown()
{
if (fRequestShutdown) {
// Cancel existing shutdown by waiting for it, this will reset condition flags and remove
// the shutdown token from the pipe.
WaitForShutdown();
}
fRequestShutdown = false;
}
bool ShutdownRequested()
{
return fRequestShutdown;
}
bool RestartRequested()
{
return fRequestRestart;
}
void WaitForShutdown()
{
#ifdef WIN32
std::unique_lock<std::mutex> lk(g_shutdown_mutex);
g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); });
#else
char token;
while (true) {
int result = read(g_shutdown_pipe[0], &token, 1);
if (result < 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
}