aboutsummaryrefslogtreecommitdiff
path: root/src/init.cpp
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2013-03-09 12:02:57 -0500
committerGavin Andresen <gavinandresen@gmail.com>2013-04-03 19:57:53 -0400
commitb31499ec72edd1554d4612d1b54808fce0360e14 (patch)
treea2d03852b9fd6e9595470210479f212ccf4313f1 /src/init.cpp
parent21eb5adadbe3110a8708f2570185566e1f137a49 (diff)
downloadbitcoin-b31499ec72edd1554d4612d1b54808fce0360e14.tar.xz
Clean up shutdown process
Diffstat (limited to 'src/init.cpp')
-rw-r--r--src/init.cpp193
1 files changed, 93 insertions, 100 deletions
diff --git a/src/init.cpp b/src/init.cpp
index a2e85f2ef2..3ccd01e3bc 100644
--- a/src/init.cpp
+++ b/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)
+ if (!fRet) {
+ if (detectShutdownThread)
+ detectShutdownThread->interrupt();
+ threadGroup.interrupt_all();
+ }
+
+ if (detectShutdownThread)
{
- Shutdown(NULL);
- threadGroup.interrupt_all();
- threadGroup.join_all();
+ 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;
}