mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-09 09:51:08 +02:00
Clean up shutdown process
This commit is contained in:
195
src/init.cpp
195
src/init.cpp
@ -40,75 +40,65 @@ enum BindFlags {
|
||||
// Shutdown
|
||||
//
|
||||
|
||||
void ExitTimeout(void* parg)
|
||||
{
|
||||
#ifdef WIN32
|
||||
MilliSleep(5000);
|
||||
ExitProcess(0);
|
||||
#endif
|
||||
}
|
||||
//
|
||||
// Thread management and startup/shutdown:
|
||||
//
|
||||
// The network-processing threads are all part of a thread group
|
||||
// created by AppInit() or the Qt main() function.
|
||||
//
|
||||
// A clean exit happens when StartShutdown() or the SIGTERM
|
||||
// signal handler sets fRequestShutdown, which triggers
|
||||
// the DetectShutdownThread(), which interrupts the main thread group.
|
||||
// DetectShutdownThread() then exits, which causes AppInit() to
|
||||
// continue (it .joins the shutdown thread).
|
||||
// Shutdown() is then
|
||||
// called to clean up database connections, and stop other
|
||||
// threads that should only be stopped after the main network-processing
|
||||
// threads have exited.
|
||||
//
|
||||
// Note that if running -daemon the parent process returns from AppInit2
|
||||
// before adding any threads to the threadGroup, so .join_all() returns
|
||||
// immediately and the parent exits from main().
|
||||
//
|
||||
// Shutdown for Qt is very similar, only it uses a QTimer to detect
|
||||
// fRequestShutdown getting set (either by RPC stop or SIGTERM)
|
||||
// and then does the normal Qt shutdown thing.
|
||||
//
|
||||
|
||||
volatile bool fRequestShutdown = false;
|
||||
|
||||
void StartShutdown()
|
||||
{
|
||||
#ifdef QT_GUI
|
||||
// ensure we leave the Qt main loop for a clean GUI exit (Shutdown() is called in bitcoin.cpp afterwards)
|
||||
uiInterface.QueueShutdown();
|
||||
#else
|
||||
// Without UI, Shutdown() can simply be started in a new thread
|
||||
NewThread(Shutdown, NULL);
|
||||
#endif
|
||||
fRequestShutdown = true;
|
||||
}
|
||||
|
||||
static CCoinsViewDB *pcoinsdbview;
|
||||
|
||||
void Shutdown(void* parg)
|
||||
void Shutdown()
|
||||
{
|
||||
static CCriticalSection cs_Shutdown;
|
||||
static bool fTaken;
|
||||
TRY_LOCK(cs_Shutdown, lockShutdown);
|
||||
if (!lockShutdown) return;
|
||||
|
||||
// Make this thread recognisable as the shutdown thread
|
||||
RenameThread("bitcoin-shutoff");
|
||||
nTransactionsUpdated++;
|
||||
StopRPCThreads();
|
||||
bitdb.Flush(false);
|
||||
StopNode();
|
||||
{
|
||||
fShutdown = true;
|
||||
fRequestShutdown = true;
|
||||
nTransactionsUpdated++;
|
||||
StopRPCThreads();
|
||||
bitdb.Flush(false);
|
||||
StopNode();
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (pblocktree)
|
||||
pblocktree->Flush();
|
||||
if (pcoinsTip)
|
||||
pcoinsTip->Flush();
|
||||
delete pcoinsTip;
|
||||
delete pcoinsdbview;
|
||||
delete pblocktree;
|
||||
}
|
||||
bitdb.Flush(true);
|
||||
boost::filesystem::remove(GetPidFile());
|
||||
UnregisterWallet(pwalletMain);
|
||||
delete pwalletMain;
|
||||
NewThread(ExitTimeout, NULL);
|
||||
MilliSleep(50);
|
||||
printf("Bitcoin exited\n\n");
|
||||
fExit = true;
|
||||
#ifndef QT_GUI
|
||||
// ensure non-UI client gets exited here, but let Bitcoin-Qt reach 'return 0;' in bitcoin.cpp
|
||||
exit(0);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!fExit)
|
||||
MilliSleep(500);
|
||||
MilliSleep(100);
|
||||
ExitThread(0);
|
||||
LOCK(cs_main);
|
||||
if (pblocktree)
|
||||
pblocktree->Flush();
|
||||
if (pcoinsTip)
|
||||
pcoinsTip->Flush();
|
||||
delete pcoinsTip; pcoinsTip = NULL;
|
||||
delete pcoinsdbview; pcoinsdbview = NULL;
|
||||
delete pblocktree; pblocktree = NULL;
|
||||
}
|
||||
bitdb.Flush(true);
|
||||
boost::filesystem::remove(GetPidFile());
|
||||
UnregisterWallet(pwalletMain);
|
||||
delete pwalletMain;
|
||||
}
|
||||
|
||||
//
|
||||
@ -116,9 +106,13 @@ void Shutdown(void* parg)
|
||||
//
|
||||
void DetectShutdownThread(boost::thread_group* threadGroup)
|
||||
{
|
||||
while (fRequestShutdown == false)
|
||||
// Tell the main threads to shutdown.
|
||||
while (!fRequestShutdown)
|
||||
{
|
||||
MilliSleep(200);
|
||||
threadGroup->interrupt_all();
|
||||
if (fRequestShutdown)
|
||||
threadGroup->interrupt_all();
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSIGTERM(int)
|
||||
@ -143,6 +137,8 @@ void HandleSIGHUP(int)
|
||||
bool AppInit(int argc, char* argv[])
|
||||
{
|
||||
boost::thread_group threadGroup;
|
||||
boost::thread* detectShutdownThread = NULL;
|
||||
|
||||
bool fRet = false;
|
||||
try
|
||||
{
|
||||
@ -154,7 +150,7 @@ bool AppInit(int argc, char* argv[])
|
||||
if (!boost::filesystem::is_directory(GetDataDir(false)))
|
||||
{
|
||||
fprintf(stderr, "Error: Specified directory does not exist\n");
|
||||
Shutdown(NULL);
|
||||
Shutdown();
|
||||
}
|
||||
ReadConfigFile(mapArgs, mapMultiArgs);
|
||||
|
||||
@ -184,7 +180,31 @@ bool AppInit(int argc, char* argv[])
|
||||
int ret = CommandLineRPC(argc, argv);
|
||||
exit(ret);
|
||||
}
|
||||
#if !defined(WIN32)
|
||||
fDaemon = GetBoolArg("-daemon");
|
||||
if (fDaemon)
|
||||
{
|
||||
// Daemonize
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
|
||||
return false;
|
||||
}
|
||||
if (pid > 0) // Parent process, pid is child process id
|
||||
{
|
||||
CreatePidFile(GetPidFile(), pid);
|
||||
return true;
|
||||
}
|
||||
// Child process falls through to rest of initialization
|
||||
|
||||
pid_t sid = setsid();
|
||||
if (sid < 0)
|
||||
fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
|
||||
fRet = AppInit2(threadGroup);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
@ -192,12 +212,20 @@ bool AppInit(int argc, char* argv[])
|
||||
} catch (...) {
|
||||
PrintExceptionContinue(NULL, "AppInit()");
|
||||
}
|
||||
if (!fRet)
|
||||
{
|
||||
Shutdown(NULL);
|
||||
threadGroup.interrupt_all();
|
||||
threadGroup.join_all();
|
||||
if (!fRet) {
|
||||
if (detectShutdownThread)
|
||||
detectShutdownThread->interrupt();
|
||||
threadGroup.interrupt_all();
|
||||
}
|
||||
|
||||
if (detectShutdownThread)
|
||||
{
|
||||
detectShutdownThread->join();
|
||||
delete detectShutdownThread;
|
||||
detectShutdownThread = NULL;
|
||||
}
|
||||
Shutdown();
|
||||
|
||||
return fRet;
|
||||
}
|
||||
|
||||
@ -214,7 +242,7 @@ int main(int argc, char* argv[])
|
||||
if (fRet && fDaemon)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return (fRet ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -302,7 +330,7 @@ std::string HelpMessage()
|
||||
" -rpcport=<port> " + _("Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)") + "\n" +
|
||||
" -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
|
||||
" -rpcconnect=<ip> " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
|
||||
" -rpcthreads=<n> " + _("Use this mean threads to service RPC calls (default: 4)") + "\n" +
|
||||
" -rpcthreads=<n> " + _("Use this many threads to service RPC calls (default: 4)") + "\n" +
|
||||
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
|
||||
" -walletnotify=<cmd> " + _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)") + "\n" +
|
||||
" -alertnotify=<cmd> " + _("Execute command when a relevant alert is received (%s in cmd is replaced by message)") + "\n" +
|
||||
@ -440,8 +468,6 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
sigaction(SIGHUP, &sa_hup, NULL);
|
||||
#endif
|
||||
|
||||
threadGroup.create_thread(boost::bind(&DetectShutdownThread, &threadGroup));
|
||||
|
||||
// ********************************************************* Step 2: parameter interactions
|
||||
|
||||
fTestNet = GetBoolArg("-testnet");
|
||||
@ -499,12 +525,6 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
else
|
||||
fDebugNet = GetBoolArg("-debugnet");
|
||||
|
||||
#if !defined(WIN32) && !defined(QT_GUI)
|
||||
fDaemon = GetBoolArg("-daemon");
|
||||
#else
|
||||
fDaemon = false;
|
||||
#endif
|
||||
|
||||
if (fDaemon)
|
||||
fServer = true;
|
||||
else
|
||||
@ -552,28 +572,6 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
if (!lock.try_lock())
|
||||
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), strDataDir.c_str()));
|
||||
|
||||
#if !defined(WIN32) && !defined(QT_GUI)
|
||||
if (fDaemon)
|
||||
{
|
||||
// Daemonize
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
|
||||
return false;
|
||||
}
|
||||
if (pid > 0)
|
||||
{
|
||||
CreatePidFile(GetPidFile(), pid);
|
||||
return true;
|
||||
}
|
||||
|
||||
pid_t sid = setsid();
|
||||
if (sid < 0)
|
||||
fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (GetBoolArg("-shrinkdebugfile", !fDebug))
|
||||
ShrinkDebugFile();
|
||||
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
@ -1011,8 +1009,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size());
|
||||
printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size());
|
||||
|
||||
if (!NewThread(StartNode, (void*)&threadGroup))
|
||||
InitError(_("Error: could not start node"));
|
||||
StartNode(threadGroup);
|
||||
|
||||
if (fServer)
|
||||
StartRPCThreads();
|
||||
@ -1030,12 +1027,8 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||
// Add wallet transactions that aren't already in a block to mapTransactions
|
||||
pwalletMain->ReacceptWalletTransactions();
|
||||
|
||||
#if !defined(QT_GUI)
|
||||
// Loop until process is exit()ed from shutdown() function,
|
||||
// called from ThreadRPCServer thread when a "stop" command is received.
|
||||
while (1)
|
||||
MilliSleep(5000);
|
||||
#endif
|
||||
// Run a thread to flush wallet periodically
|
||||
threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
|
||||
|
||||
return true;
|
||||
return !fRequestShutdown;
|
||||
}
|
||||
|
Reference in New Issue
Block a user