Branch data Line data Source code
# 1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto # 2 : : // Copyright (c) 2009-2021 The Bitcoin Core developers # 3 : : // Distributed under the MIT software license, see the accompanying # 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. # 5 : : # 6 : : #include <shutdown.h> # 7 : : # 8 : : #include <logging.h> # 9 : : #include <node/ui_interface.h> # 10 : : #include <util/tokenpipe.h> # 11 : : #include <warnings.h> # 12 : : # 13 : : #include <config/bitcoin-config.h> # 14 : : # 15 : : #include <assert.h> # 16 : : #include <atomic> # 17 : : #ifdef WIN32 # 18 : : #include <condition_variable> # 19 : : #endif # 20 : : # 21 : : bool AbortNode(const std::string& strMessage, bilingual_str user_message) # 22 : 1 : { # 23 : 1 : SetMiscWarning(Untranslated(strMessage)); # 24 : 1 : LogPrintf("*** %s\n", strMessage); # 25 [ + - ]: 1 : if (user_message.empty()) { # 26 : 1 : user_message = _("A fatal internal error occurred, see debug.log for details"); # 27 : 1 : } # 28 : 1 : AbortError(user_message); # 29 : 1 : StartShutdown(); # 30 : 1 : return false; # 31 : 1 : } # 32 : : # 33 : : static std::atomic<bool> fRequestShutdown(false); # 34 : : #ifdef WIN32 # 35 : : /** On windows it is possible to simply use a condition variable. */ # 36 : : std::mutex g_shutdown_mutex; # 37 : : std::condition_variable g_shutdown_cv; # 38 : : #else # 39 : : /** On UNIX-like operating systems use the self-pipe trick. # 40 : : */ # 41 : : static TokenPipeEnd g_shutdown_r; # 42 : : static TokenPipeEnd g_shutdown_w; # 43 : : #endif # 44 : : # 45 : : bool InitShutdownState() # 46 : 802 : { # 47 : 802 : #ifndef WIN32 # 48 : 802 : std::optional<TokenPipe> pipe = TokenPipe::Make(); # 49 [ - + ]: 802 : if (!pipe) return false; # 50 : 802 : g_shutdown_r = pipe->TakeReadEnd(); # 51 : 802 : g_shutdown_w = pipe->TakeWriteEnd(); # 52 : 802 : #endif # 53 : 802 : return true; # 54 : 802 : } # 55 : : # 56 : : void StartShutdown() # 57 : 732 : { # 58 : : #ifdef WIN32 # 59 : : std::unique_lock<std::mutex> lk(g_shutdown_mutex); # 60 : : fRequestShutdown = true; # 61 : : g_shutdown_cv.notify_one(); # 62 : : #else # 63 : : // This must be reentrant and safe for calling in a signal handler, so using a condition variable is not safe. # 64 : : // Make sure that the token is only written once even if multiple threads call this concurrently or in # 65 : : // case of a reentrant signal. # 66 [ + - ]: 732 : if (!fRequestShutdown.exchange(true)) { # 67 : : // Write an arbitrary byte to the write end of the shutdown pipe. # 68 : 732 : int res = g_shutdown_w.TokenWrite('x'); # 69 [ - + ]: 732 : if (res != 0) { # 70 : 0 : LogPrintf("Sending shutdown token failed\n"); # 71 : 0 : assert(0); # 72 : 0 : } # 73 : 732 : } # 74 : 732 : #endif # 75 : 732 : } # 76 : : # 77 : : void AbortShutdown() # 78 : 1 : { # 79 [ + - ]: 1 : if (fRequestShutdown) { # 80 : : // Cancel existing shutdown by waiting for it, this will reset condition flags and remove # 81 : : // the shutdown token from the pipe. # 82 : 1 : WaitForShutdown(); # 83 : 1 : } # 84 : 1 : fRequestShutdown = false; # 85 : 1 : } # 86 : : # 87 : : bool ShutdownRequested() # 88 : 1046032 : { # 89 : 1046032 : return fRequestShutdown; # 90 : 1046032 : } # 91 : : # 92 : : void WaitForShutdown() # 93 : 719 : { # 94 : : #ifdef WIN32 # 95 : : std::unique_lock<std::mutex> lk(g_shutdown_mutex); # 96 : : g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); }); # 97 : : #else # 98 : 719 : int res = g_shutdown_r.TokenRead(); # 99 [ - + ]: 719 : if (res != 'x') { # 100 : 0 : LogPrintf("Reading shutdown token failed\n"); # 101 : 0 : assert(0); # 102 : 0 : } # 103 : 719 : #endif # 104 : 719 : }