Skip to content

Commit 89bb036

Browse files
committed
Merge #10832: init: Factor out AppInitLockDataDirectory and fix startup core dump issue
dba485d init: Factor out AppInitLockDataDirectory (Wladimir J. van der Laan) Pull request description: Alternative to #10818, alternative solution to #10815. After this change: All the AppInit steps before and inclusive AppInitLockDataDirectory must not have Shutdown() called in case of failure. Only when AppInitMain fails, Shutdown should be called. Changes the GUI and bitcoind code to consistently do this. Tree-SHA512: 393e1a0ae05eb8e791025069e3ac4f6f3cdeb459ec63feda85d01cf6696ab3fed7632b6a0ac3641b8c7015af51d46756b5bba77f5e5f0c446f0c2dea58bbc92e
2 parents 2b0179d + dba485d commit 89bb036

File tree

4 files changed

+67
-30
lines changed

4 files changed

+67
-30
lines changed

src/bitcoind.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,12 @@ bool AppInit(int argc, char* argv[])
159159
return false;
160160
#endif // HAVE_DECL_DAEMON
161161
}
162-
162+
// Lock data directory after daemonization
163+
if (!AppInitLockDataDirectory())
164+
{
165+
// If locking the data directory failed, exit immediately
166+
exit(EXIT_FAILURE);
167+
}
163168
fRet = AppInitMain(threadGroup, scheduler);
164169
}
165170
catch (const std::exception& e) {

src/init.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,21 +1170,27 @@ bool AppInitSanityChecks()
11701170
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
11711171

11721172
// Probe the data directory lock to give an early error message, if possible
1173+
// We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened,
1174+
// and a fork will cause weird behavior to it.
11731175
return LockDataDirectory(true);
11741176
}
11751177

1176-
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
1178+
bool AppInitLockDataDirectory()
11771179
{
1178-
const CChainParams& chainparams = Params();
1179-
// ********************************************************* Step 4a: application initialization
11801180
// After daemonization get the data directory lock again and hold on to it until exit
11811181
// This creates a slight window for a race condition to happen, however this condition is harmless: it
11821182
// will at most make us exit without printing a message to console.
11831183
if (!LockDataDirectory(false)) {
11841184
// Detailed error printed inside LockDataDirectory
11851185
return false;
11861186
}
1187+
return true;
1188+
}
11871189

1190+
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
1191+
{
1192+
const CChainParams& chainparams = Params();
1193+
// ********************************************************* Step 4a: application initialization
11881194
#ifndef WIN32
11891195
CreatePidFile(GetPidFile(), getpid());
11901196
#endif

src/init.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,33 @@ void InitLogging();
2727
void InitParameterInteraction();
2828

2929
/** Initialize bitcoin core: Basic context setup.
30-
* @note This can be done before daemonization.
30+
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
3131
* @pre Parameters should be parsed and config file should be read.
3232
*/
3333
bool AppInitBasicSetup();
3434
/**
3535
* Initialization: parameter interaction.
36-
* @note This can be done before daemonization.
36+
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
3737
* @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.
3838
*/
3939
bool AppInitParameterInteraction();
4040
/**
4141
* Initialization sanity checks: ecc init, sanity checks, dir lock.
42-
* @note This can be done before daemonization.
42+
* @note This can be done before daemonization. Do not call Shutdown() if this function fails.
4343
* @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called.
4444
*/
4545
bool AppInitSanityChecks();
4646
/**
47-
* Bitcoin core main initialization.
48-
* @note This should only be done after daemonization.
47+
* Lock bitcoin core data directory.
48+
* @note This should only be done after daemonization. Do not call Shutdown() if this function fails.
4949
* @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called.
5050
*/
51+
bool AppInitLockDataDirectory();
52+
/**
53+
* Bitcoin core main initialization.
54+
* @note This should only be done after daemonization. Call Shutdown() if this function fails.
55+
* @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called.
56+
*/
5157
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler);
5258

5359
/** The help message mode determines what help message to show */

src/qt/bitcoin.cpp

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ class BitcoinCore: public QObject
178178
Q_OBJECT
179179
public:
180180
explicit BitcoinCore();
181+
/** Basic initialization, before starting initialization/shutdown thread.
182+
* Return true on success.
183+
*/
184+
static bool baseInitialize();
181185

182186
public Q_SLOTS:
183187
void initialize();
@@ -270,26 +274,32 @@ void BitcoinCore::handleRunawayException(const std::exception *e)
270274
Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui")));
271275
}
272276

277+
bool BitcoinCore::baseInitialize()
278+
{
279+
if (!AppInitBasicSetup())
280+
{
281+
return false;
282+
}
283+
if (!AppInitParameterInteraction())
284+
{
285+
return false;
286+
}
287+
if (!AppInitSanityChecks())
288+
{
289+
return false;
290+
}
291+
if (!AppInitLockDataDirectory())
292+
{
293+
return false;
294+
}
295+
return true;
296+
}
297+
273298
void BitcoinCore::initialize()
274299
{
275300
try
276301
{
277302
qDebug() << __func__ << ": Running initialization in thread";
278-
if (!AppInitBasicSetup())
279-
{
280-
Q_EMIT initializeResult(false);
281-
return;
282-
}
283-
if (!AppInitParameterInteraction())
284-
{
285-
Q_EMIT initializeResult(false);
286-
return;
287-
}
288-
if (!AppInitSanityChecks())
289-
{
290-
Q_EMIT initializeResult(false);
291-
return;
292-
}
293303
bool rv = AppInitMain(threadGroup, scheduler);
294304
Q_EMIT initializeResult(rv);
295305
} catch (const std::exception& e) {
@@ -689,23 +699,33 @@ int main(int argc, char *argv[])
689699
if (GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !GetBoolArg("-min", false))
690700
app.createSplashScreen(networkStyle.data());
691701

702+
int rv = EXIT_SUCCESS;
692703
try
693704
{
694705
app.createWindow(networkStyle.data());
695-
app.requestInitialize();
706+
// Perform base initialization before spinning up initialization/shutdown thread
707+
// This is acceptable because this function only contains steps that are quick to execute,
708+
// so the GUI thread won't be held up.
709+
if (BitcoinCore::baseInitialize()) {
710+
app.requestInitialize();
696711
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
697-
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
712+
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
698713
#endif
699-
app.exec();
700-
app.requestShutdown();
701-
app.exec();
714+
app.exec();
715+
app.requestShutdown();
716+
app.exec();
717+
rv = app.getReturnValue();
718+
} else {
719+
// A dialog with detailed error will have been shown by InitError()
720+
rv = EXIT_FAILURE;
721+
}
702722
} catch (const std::exception& e) {
703723
PrintExceptionContinue(&e, "Runaway exception");
704724
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
705725
} catch (...) {
706726
PrintExceptionContinue(NULL, "Runaway exception");
707727
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
708728
}
709-
return app.getReturnValue();
729+
return rv;
710730
}
711731
#endif // BITCOIN_QT_TEST

0 commit comments

Comments
 (0)