Browse Source

Merge #9010: Split up AppInit2 into multiple phases, daemonize after datadir lock errors

deec83f init: Get rid of fServer flag (Wladimir J. van der Laan)
16ca0bf init: Try to aquire datadir lock before and after daemonization (Wladimir J. van der Laan)
0cc8b6b init: Split up AppInit2 into multiple phases (Wladimir J. van der Laan)
0.14
Pieter Wuille 8 years ago
parent
commit
a143b88dbd
No known key found for this signature in database
GPG Key ID: DBA1A67379A1A931
  1. 26
      src/bitcoind.cpp
  2. 86
      src/init.cpp
  3. 25
      src/init.h
  4. 17
      src/qt/bitcoin.cpp
  5. 1
      src/util.cpp
  6. 1
      src/util.h

26
src/bitcoind.cpp

@ -128,6 +128,26 @@ bool AppInit(int argc, char* argv[])
fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n"); fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// -server defaults to true for bitcoind but not for the GUI so do this here
SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
InitLogging();
InitParameterInteraction();
if (!AppInitBasicSetup())
{
// InitError will have been called with detailed error, which ends up on console
exit(1);
}
if (!AppInitParameterInteraction())
{
// InitError will have been called with detailed error, which ends up on console
exit(1);
}
if (!AppInitSanityChecks())
{
// InitError will have been called with detailed error, which ends up on console
exit(1);
}
if (GetBoolArg("-daemon", false)) if (GetBoolArg("-daemon", false))
{ {
#if HAVE_DECL_DAEMON #if HAVE_DECL_DAEMON
@ -143,12 +163,8 @@ bool AppInit(int argc, char* argv[])
return false; return false;
#endif // HAVE_DECL_DAEMON #endif // HAVE_DECL_DAEMON
} }
SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console fRet = AppInitMain(threadGroup, scheduler);
InitLogging();
InitParameterInteraction();
fRet = AppInit2(threadGroup, scheduler);
} }
catch (const std::exception& e) { catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInit()"); PrintExceptionContinue(&e, "AppInit()");

86
src/init.cpp

@ -780,10 +780,17 @@ void InitLogging()
LogPrintf("Bitcoin version %s\n", FormatFullVersion()); LogPrintf("Bitcoin version %s\n", FormatFullVersion());
} }
/** Initialize bitcoin. namespace { // Variables internal to initialization process only
* @pre Parameters should be parsed and config file should be read.
*/ ServiceFlags nRelevantServices = NODE_NETWORK;
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) int nMaxConnections;
int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = NODE_NETWORK;
}
bool AppInitBasicSetup()
{ {
// ********************************************************* Step 1: setup // ********************************************************* Step 1: setup
#ifdef _MSC_VER #ifdef _MSC_VER
@ -835,9 +842,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
#endif #endif
return true;
}
// ********************************************************* Step 2: parameter interactions bool AppInitParameterInteraction()
{
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
// ********************************************************* Step 2: parameter interactions
// also see: InitParameterInteraction() // also see: InitParameterInteraction()
@ -849,12 +860,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Make sure enough file descriptors are available // Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
int nMaxConnections = std::max(nUserMaxConnections, 0); nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations // Trim requested connection counts, to fit into system limitations
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
if (nFD < MIN_CORE_FILEDESCRIPTORS) if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available.")); return InitError(_("Not enough file descriptors available."));
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections); nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
@ -912,8 +923,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
fServer = GetBoolArg("-server", false);
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files // block pruning; get the amount of disk space (in MiB) to allot for block & undo files
int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024; int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024;
if (nSignedPruneTarget < 0) { if (nSignedPruneTarget < 0) {
@ -969,9 +978,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Option to startup with mocktime set (used for regression testing): // Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
ServiceFlags nLocalServices = NODE_NETWORK;
ServiceFlags nRelevantServices = NODE_NETWORK;
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
@ -1020,17 +1026,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
} }
} }
} }
return true;
}
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log static bool LockDataDirectory(bool probeOnly)
{
// Initialize elliptic curve code
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
// Sanity check
if (!InitSanityCheck())
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
std::string strDataDir = GetDataDir().string(); std::string strDataDir = GetDataDir().string();
// Make sure only a single Bitcoin process is using the data directory. // Make sure only a single Bitcoin process is using the data directory.
@ -1040,11 +1040,45 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
try { try {
static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
if (!lock.try_lock()) if (!lock.try_lock()) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME))); return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME)));
}
if (probeOnly) {
lock.unlock();
}
} catch(const boost::interprocess::interprocess_exception& e) { } catch(const boost::interprocess::interprocess_exception& e) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what())); return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what()));
} }
return true;
}
bool AppInitSanityChecks()
{
// ********************************************************* Step 4: sanity checks
// Initialize elliptic curve code
ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle());
// Sanity check
if (!InitSanityCheck())
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
// Probe the data directory lock to give an early error message, if possible
return LockDataDirectory(true);
}
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
{
const CChainParams& chainparams = Params();
// ********************************************************* Step 4a: application initialization
// After daemonization get the data directory lock again and hold on to it until exit
// This creates a slight window for a race condition to happen, however this condition is harmless: it
// will at most make us exit without printing a message to console.
if (!LockDataDirectory(false)) {
// Detailed error printed inside LockDataDirectory
return false;
}
#ifndef WIN32 #ifndef WIN32
CreatePidFile(GetPidFile(), getpid()); CreatePidFile(GetPidFile(), getpid());
@ -1058,7 +1092,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!fLogTimestamps) if (!fLogTimestamps)
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", strDataDir); LogPrintf("Using data directory %s\n", GetDataDir().string());
LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string()); LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
@ -1077,7 +1111,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
* that the server is there and will be ready later). Warmup mode will * that the server is there and will be ready later). Warmup mode will
* be disabled when initialisation is finished. * be disabled when initialisation is finished.
*/ */
if (fServer) if (GetBoolArg("-server", false))
{ {
uiInterface.InitMessage.connect(SetRPCWarmupStatus); uiInterface.InitMessage.connect(SetRPCWarmupStatus);
if (!AppInitServers(threadGroup)) if (!AppInitServers(threadGroup))

25
src/init.h

@ -25,7 +25,30 @@ void Shutdown();
void InitLogging(); void InitLogging();
//!Parameter interaction: change current parameters depending on various rules //!Parameter interaction: change current parameters depending on various rules
void InitParameterInteraction(); void InitParameterInteraction();
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler);
/** Initialize bitcoin core: Basic context setup.
* @note This can be done before daemonization.
* @pre Parameters should be parsed and config file should be read.
*/
bool AppInitBasicSetup();
/**
* Initialization: parameter interaction.
* @note This can be done before daemonization.
* @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.
*/
bool AppInitParameterInteraction();
/**
* Initialization sanity checks: ecc init, sanity checks, dir lock.
* @note This can be done before daemonization.
* @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called.
*/
bool AppInitSanityChecks();
/**
* Bitcoin core main initialization.
* @note This should only be done after daemonization.
* @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called.
*/
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler);
/** The help message mode determines what help message to show */ /** The help message mode determines what help message to show */
enum HelpMessageMode { enum HelpMessageMode {

17
src/qt/bitcoin.cpp

@ -268,7 +268,22 @@ void BitcoinCore::initialize()
try try
{ {
qDebug() << __func__ << ": Running AppInit2 in thread"; qDebug() << __func__ << ": Running AppInit2 in thread";
int rv = AppInit2(threadGroup, scheduler); if (!AppInitBasicSetup())
{
Q_EMIT initializeResult(false);
return;
}
if (!AppInitParameterInteraction())
{
Q_EMIT initializeResult(false);
return;
}
if (!AppInitSanityChecks())
{
Q_EMIT initializeResult(false);
return;
}
int rv = AppInitMain(threadGroup, scheduler);
Q_EMIT initializeResult(rv); Q_EMIT initializeResult(rv);
} catch (const std::exception& e) { } catch (const std::exception& e) {
handleRunawayException(&e); handleRunawayException(&e);

1
src/util.cpp

@ -107,7 +107,6 @@ map<string, vector<string> > mapMultiArgs;
bool fDebug = false; bool fDebug = false;
bool fPrintToConsole = false; bool fPrintToConsole = false;
bool fPrintToDebugLog = true; bool fPrintToDebugLog = true;
bool fServer = false;
string strMiscWarning; string strMiscWarning;
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;

1
src/util.h

@ -46,7 +46,6 @@ extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
extern bool fDebug; extern bool fDebug;
extern bool fPrintToConsole; extern bool fPrintToConsole;
extern bool fPrintToDebugLog; extern bool fPrintToDebugLog;
extern bool fServer;
extern std::string strMiscWarning; extern std::string strMiscWarning;
extern bool fLogTimestamps; extern bool fLogTimestamps;
extern bool fLogTimeMicros; extern bool fLogTimeMicros;

Loading…
Cancel
Save