Skip to content

Commit a143b88

Browse files
committed
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)
2 parents 56bee49 + deec83f commit a143b88

File tree

6 files changed

+121
-35
lines changed

6 files changed

+121
-35
lines changed

src/bitcoind.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,26 @@ bool AppInit(int argc, char* argv[])
128128
fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n");
129129
exit(EXIT_FAILURE);
130130
}
131+
// -server defaults to true for bitcoind but not for the GUI so do this here
132+
SoftSetBoolArg("-server", true);
133+
// Set this early so that parameter interactions go to console
134+
InitLogging();
135+
InitParameterInteraction();
136+
if (!AppInitBasicSetup())
137+
{
138+
// InitError will have been called with detailed error, which ends up on console
139+
exit(1);
140+
}
141+
if (!AppInitParameterInteraction())
142+
{
143+
// InitError will have been called with detailed error, which ends up on console
144+
exit(1);
145+
}
146+
if (!AppInitSanityChecks())
147+
{
148+
// InitError will have been called with detailed error, which ends up on console
149+
exit(1);
150+
}
131151
if (GetBoolArg("-daemon", false))
132152
{
133153
#if HAVE_DECL_DAEMON
@@ -143,12 +163,8 @@ bool AppInit(int argc, char* argv[])
143163
return false;
144164
#endif // HAVE_DECL_DAEMON
145165
}
146-
SoftSetBoolArg("-server", true);
147166

148-
// Set this early so that parameter interactions go to console
149-
InitLogging();
150-
InitParameterInteraction();
151-
fRet = AppInit2(threadGroup, scheduler);
167+
fRet = AppInitMain(threadGroup, scheduler);
152168
}
153169
catch (const std::exception& e) {
154170
PrintExceptionContinue(&e, "AppInit()");

src/init.cpp

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -780,10 +780,17 @@ void InitLogging()
780780
LogPrintf("Bitcoin version %s\n", FormatFullVersion());
781781
}
782782

783-
/** Initialize bitcoin.
784-
* @pre Parameters should be parsed and config file should be read.
785-
*/
786-
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
783+
namespace { // Variables internal to initialization process only
784+
785+
ServiceFlags nRelevantServices = NODE_NETWORK;
786+
int nMaxConnections;
787+
int nUserMaxConnections;
788+
int nFD;
789+
ServiceFlags nLocalServices = NODE_NETWORK;
790+
791+
}
792+
793+
bool AppInitBasicSetup()
787794
{
788795
// ********************************************************* Step 1: setup
789796
#ifdef _MSC_VER
@@ -835,9 +842,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
835842
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
836843
signal(SIGPIPE, SIG_IGN);
837844
#endif
845+
return true;
846+
}
838847

839-
// ********************************************************* Step 2: parameter interactions
848+
bool AppInitParameterInteraction()
849+
{
840850
const CChainParams& chainparams = Params();
851+
// ********************************************************* Step 2: parameter interactions
841852

842853
// also see: InitParameterInteraction()
843854

@@ -849,12 +860,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
849860

850861
// Make sure enough file descriptors are available
851862
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
852-
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
853-
int nMaxConnections = std::max(nUserMaxConnections, 0);
863+
nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
864+
nMaxConnections = std::max(nUserMaxConnections, 0);
854865

855866
// Trim requested connection counts, to fit into system limitations
856867
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
857-
int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
868+
nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
858869
if (nFD < MIN_CORE_FILEDESCRIPTORS)
859870
return InitError(_("Not enough file descriptors available."));
860871
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
@@ -912,8 +923,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
912923
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
913924
nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS;
914925

915-
fServer = GetBoolArg("-server", false);
916-
917926
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
918927
int64_t nSignedPruneTarget = GetArg("-prune", 0) * 1024 * 1024;
919928
if (nSignedPruneTarget < 0) {
@@ -969,9 +978,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
969978
// Option to startup with mocktime set (used for regression testing):
970979
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
971980

972-
ServiceFlags nLocalServices = NODE_NETWORK;
973-
ServiceFlags nRelevantServices = NODE_NETWORK;
974-
975981
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
976982
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
977983

@@ -1020,17 +1026,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
10201026
}
10211027
}
10221028
}
1029+
return true;
1030+
}
10231031

1024-
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
1025-
1026-
// Initialize elliptic curve code
1027-
ECC_Start();
1028-
globalVerifyHandle.reset(new ECCVerifyHandle());
1029-
1030-
// Sanity check
1031-
if (!InitSanityCheck())
1032-
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
1033-
1032+
static bool LockDataDirectory(bool probeOnly)
1033+
{
10341034
std::string strDataDir = GetDataDir().string();
10351035

10361036
// Make sure only a single Bitcoin process is using the data directory.
@@ -1040,11 +1040,45 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
10401040

10411041
try {
10421042
static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
1043-
if (!lock.try_lock())
1043+
if (!lock.try_lock()) {
10441044
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME)));
1045+
}
1046+
if (probeOnly) {
1047+
lock.unlock();
1048+
}
10451049
} catch(const boost::interprocess::interprocess_exception& e) {
10461050
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what()));
10471051
}
1052+
return true;
1053+
}
1054+
1055+
bool AppInitSanityChecks()
1056+
{
1057+
// ********************************************************* Step 4: sanity checks
1058+
1059+
// Initialize elliptic curve code
1060+
ECC_Start();
1061+
globalVerifyHandle.reset(new ECCVerifyHandle());
1062+
1063+
// Sanity check
1064+
if (!InitSanityCheck())
1065+
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
1066+
1067+
// Probe the data directory lock to give an early error message, if possible
1068+
return LockDataDirectory(true);
1069+
}
1070+
1071+
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
1072+
{
1073+
const CChainParams& chainparams = Params();
1074+
// ********************************************************* Step 4a: application initialization
1075+
// After daemonization get the data directory lock again and hold on to it until exit
1076+
// This creates a slight window for a race condition to happen, however this condition is harmless: it
1077+
// will at most make us exit without printing a message to console.
1078+
if (!LockDataDirectory(false)) {
1079+
// Detailed error printed inside LockDataDirectory
1080+
return false;
1081+
}
10481082

10491083
#ifndef WIN32
10501084
CreatePidFile(GetPidFile(), getpid());
@@ -1058,7 +1092,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
10581092
if (!fLogTimestamps)
10591093
LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()));
10601094
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
1061-
LogPrintf("Using data directory %s\n", strDataDir);
1095+
LogPrintf("Using data directory %s\n", GetDataDir().string());
10621096
LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string());
10631097
LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD);
10641098

@@ -1077,7 +1111,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
10771111
* that the server is there and will be ready later). Warmup mode will
10781112
* be disabled when initialisation is finished.
10791113
*/
1080-
if (fServer)
1114+
if (GetBoolArg("-server", false))
10811115
{
10821116
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
10831117
if (!AppInitServers(threadGroup))

src/init.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,30 @@ void Shutdown();
2525
void InitLogging();
2626
//!Parameter interaction: change current parameters depending on various rules
2727
void InitParameterInteraction();
28-
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler);
28+
29+
/** Initialize bitcoin core: Basic context setup.
30+
* @note This can be done before daemonization.
31+
* @pre Parameters should be parsed and config file should be read.
32+
*/
33+
bool AppInitBasicSetup();
34+
/**
35+
* Initialization: parameter interaction.
36+
* @note This can be done before daemonization.
37+
* @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.
38+
*/
39+
bool AppInitParameterInteraction();
40+
/**
41+
* Initialization sanity checks: ecc init, sanity checks, dir lock.
42+
* @note This can be done before daemonization.
43+
* @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called.
44+
*/
45+
bool AppInitSanityChecks();
46+
/**
47+
* Bitcoin core main initialization.
48+
* @note This should only be done after daemonization.
49+
* @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called.
50+
*/
51+
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler);
2952

3053
/** The help message mode determines what help message to show */
3154
enum HelpMessageMode {

src/qt/bitcoin.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,22 @@ void BitcoinCore::initialize()
268268
try
269269
{
270270
qDebug() << __func__ << ": Running AppInit2 in thread";
271-
int rv = AppInit2(threadGroup, scheduler);
271+
if (!AppInitBasicSetup())
272+
{
273+
Q_EMIT initializeResult(false);
274+
return;
275+
}
276+
if (!AppInitParameterInteraction())
277+
{
278+
Q_EMIT initializeResult(false);
279+
return;
280+
}
281+
if (!AppInitSanityChecks())
282+
{
283+
Q_EMIT initializeResult(false);
284+
return;
285+
}
286+
int rv = AppInitMain(threadGroup, scheduler);
272287
Q_EMIT initializeResult(rv);
273288
} catch (const std::exception& e) {
274289
handleRunawayException(&e);

src/util.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ map<string, vector<string> > mapMultiArgs;
107107
bool fDebug = false;
108108
bool fPrintToConsole = false;
109109
bool fPrintToDebugLog = true;
110-
bool fServer = false;
111110
string strMiscWarning;
112111
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
113112
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;

src/util.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
4646
extern bool fDebug;
4747
extern bool fPrintToConsole;
4848
extern bool fPrintToDebugLog;
49-
extern bool fServer;
5049
extern std::string strMiscWarning;
5150
extern bool fLogTimestamps;
5251
extern bool fLogTimeMicros;

0 commit comments

Comments
 (0)