1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-2020 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 AbortNode(const std::string & strMessage,bilingual_str user_message)21bool AbortNode(const std::string& strMessage, bilingual_str user_message) 22 { 23 SetMiscWarning(Untranslated(strMessage)); 24 LogPrintf("*** %s\n", strMessage); 25 if (user_message.empty()) { 26 user_message = _("A fatal internal error occurred, see debug.log for details"); 27 } 28 AbortError(user_message); 29 StartShutdown(); 30 return false; 31 } 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 InitShutdownState()45bool InitShutdownState() 46 { 47 #ifndef WIN32 48 std::optional<TokenPipe> pipe = TokenPipe::Make(); 49 if (!pipe) return false; 50 g_shutdown_r = pipe->TakeReadEnd(); 51 g_shutdown_w = pipe->TakeWriteEnd(); 52 #endif 53 return true; 54 } 55 StartShutdown()56void StartShutdown() 57 { 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 if (!fRequestShutdown.exchange(true)) { 67 // Write an arbitrary byte to the write end of the shutdown pipe. 68 int res = g_shutdown_w.TokenWrite('x'); 69 if (res != 0) { 70 LogPrintf("Sending shutdown token failed\n"); 71 assert(0); 72 } 73 } 74 #endif 75 } 76 AbortShutdown()77void AbortShutdown() 78 { 79 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 WaitForShutdown(); 83 } 84 fRequestShutdown = false; 85 } 86 ShutdownRequested()87bool ShutdownRequested() 88 { 89 return fRequestShutdown; 90 } 91 WaitForShutdown()92void WaitForShutdown() 93 { 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 int res = g_shutdown_r.TokenRead(); 99 if (res != 'x') { 100 LogPrintf("Reading shutdown token failed\n"); 101 assert(0); 102 } 103 #endif 104 } 105