Bitcoin Core  21.99.0
P2P Digital Currency
shutdown.cpp
Go to the documentation of this file.
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 
9 
10 #include <assert.h>
11 #include <atomic>
12 #ifdef WIN32
13 #include <condition_variable>
14 #else
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #endif
19 
20 static std::atomic<bool> fRequestShutdown(false);
21 #ifdef WIN32
22 
23 std::mutex g_shutdown_mutex;
24 std::condition_variable g_shutdown_cv;
25 #else
26 
29 static int g_shutdown_pipe[2] = {-1, -1};
30 #endif
31 
33 {
34 #ifndef WIN32
35 #if HAVE_O_CLOEXEC
36  // If we can, make sure that the file descriptors are closed on exec()
37  // to prevent interference.
38  if (pipe2(g_shutdown_pipe, O_CLOEXEC) != 0) {
39  return false;
40  }
41 #else
42  if (pipe(g_shutdown_pipe) != 0) {
43  return false;
44  }
45 #endif
46 #endif
47  return true;
48 }
49 
51 {
52 #ifdef WIN32
53  std::unique_lock<std::mutex> lk(g_shutdown_mutex);
54  fRequestShutdown = true;
55  g_shutdown_cv.notify_one();
56 #else
57  // This must be reentrant and safe for calling in a signal handler, so using a condition variable is not safe.
58  // Make sure that the token is only written once even if multiple threads call this concurrently or in
59  // case of a reentrant signal.
60  if (!fRequestShutdown.exchange(true)) {
61  // Write an arbitrary byte to the write end of the shutdown pipe.
62  const char token = 'x';
63  while (true) {
64  int result = write(g_shutdown_pipe[1], &token, 1);
65  if (result < 0) {
66  // Failure. It's possible that the write was interrupted by another signal.
67  // Other errors are unexpected here.
68  assert(errno == EINTR);
69  } else {
70  assert(result == 1);
71  break;
72  }
73  }
74  }
75 #endif
76 }
77 
79 {
80  if (fRequestShutdown) {
81  // Cancel existing shutdown by waiting for it, this will reset condition flags and remove
82  // the shutdown token from the pipe.
84  }
85  fRequestShutdown = false;
86 }
87 
89 {
90  return fRequestShutdown;
91 }
92 
94 {
95 #ifdef WIN32
96  std::unique_lock<std::mutex> lk(g_shutdown_mutex);
97  g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); });
98 #else
99  char token;
100  while (true) {
101  int result = read(g_shutdown_pipe[0], &token, 1);
102  if (result < 0) {
103  // Failure. Check if the read was interrupted by a signal.
104  // Other errors are unexpected here.
105  assert(errno == EINTR);
106  } else {
107  assert(result == 1);
108  break;
109  }
110  }
111 #endif
112 }
bool ShutdownRequested()
Returns true if a shutdown is requested, false otherwise.
Definition: shutdown.cpp:88
static int g_shutdown_pipe[2]
On UNIX-like operating systems use the self-pipe trick.
Definition: shutdown.cpp:29
assert(!tx.IsCoinBase())
bool InitShutdownState()
Initialize shutdown state.
Definition: shutdown.cpp:32
static std::atomic< bool > fRequestShutdown(false)
void WaitForShutdown()
Wait for StartShutdown to be called in any thread.
Definition: shutdown.cpp:93
void AbortShutdown()
Clear shutdown flag.
Definition: shutdown.cpp:78
void StartShutdown()
Request shutdown of the application.
Definition: shutdown.cpp:50