diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 374678310c..f3844e9d47 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -159,7 +159,12 @@ bool AppInit(int argc, char* argv[]) return false; #endif // HAVE_DECL_DAEMON } - + // Lock data directory after daemonization + if (!AppInitLockDataDirectory()) + { + // If locking the data directory failed, exit immediately + exit(EXIT_FAILURE); + } fRet = AppInitMain(threadGroup, scheduler); } catch (const std::exception& e) { diff --git a/src/init.cpp b/src/init.cpp index 1e85642019..d9b98be739 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1170,13 +1170,13 @@ bool AppInitSanityChecks() 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 + // We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened, + // and a fork will cause weird behavior to it. return LockDataDirectory(true); } -bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) +bool AppInitLockDataDirectory() { - 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. @@ -1184,7 +1184,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Detailed error printed inside LockDataDirectory return false; } + return true; +} +bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + const CChainParams& chainparams = Params(); + // ********************************************************* Step 4a: application initialization #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif diff --git a/src/init.h b/src/init.h index 8222794374..a0a824738c 100644 --- a/src/init.h +++ b/src/init.h @@ -27,27 +27,33 @@ void InitLogging(); void InitParameterInteraction(); /** Initialize bitcoin core: Basic context setup. - * @note This can be done before daemonization. + * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read. */ bool AppInitBasicSetup(); /** * Initialization: parameter interaction. - * @note This can be done before daemonization. + * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @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. + * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @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. + * Lock bitcoin core data directory. + * @note This should only be done after daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read, AppInitSanityChecks should have been called. */ +bool AppInitLockDataDirectory(); +/** + * Bitcoin core main initialization. + * @note This should only be done after daemonization. Call Shutdown() if this function fails. + * @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called. + */ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler); /** The help message mode determines what help message to show */ diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 8a745cadce..4a4116c670 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -178,6 +178,10 @@ class BitcoinCore: public QObject Q_OBJECT public: explicit BitcoinCore(); + /** Basic initialization, before starting initialization/shutdown thread. + * Return true on success. + */ + static bool baseInitialize(); public Q_SLOTS: void initialize(); @@ -270,26 +274,32 @@ void BitcoinCore::handleRunawayException(const std::exception *e) Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui"))); } +bool BitcoinCore::baseInitialize() +{ + if (!AppInitBasicSetup()) + { + return false; + } + if (!AppInitParameterInteraction()) + { + return false; + } + if (!AppInitSanityChecks()) + { + return false; + } + if (!AppInitLockDataDirectory()) + { + return false; + } + return true; +} + void BitcoinCore::initialize() { try { qDebug() << __func__ << ": Running initialization in thread"; - if (!AppInitBasicSetup()) - { - Q_EMIT initializeResult(false); - return; - } - if (!AppInitParameterInteraction()) - { - Q_EMIT initializeResult(false); - return; - } - if (!AppInitSanityChecks()) - { - Q_EMIT initializeResult(false); - return; - } bool rv = AppInitMain(threadGroup, scheduler); Q_EMIT initializeResult(rv); } catch (const std::exception& e) { @@ -689,16 +699,26 @@ int main(int argc, char *argv[]) if (GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !GetBoolArg("-min", false)) app.createSplashScreen(networkStyle.data()); + int rv = EXIT_SUCCESS; try { app.createWindow(networkStyle.data()); - app.requestInitialize(); + // Perform base initialization before spinning up initialization/shutdown thread + // This is acceptable because this function only contains steps that are quick to execute, + // so the GUI thread won't be held up. + if (BitcoinCore::baseInitialize()) { + app.requestInitialize(); #if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 - WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId()); + WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId()); #endif - app.exec(); - app.requestShutdown(); - app.exec(); + app.exec(); + app.requestShutdown(); + app.exec(); + rv = app.getReturnValue(); + } else { + // A dialog with detailed error will have been shown by InitError() + rv = EXIT_FAILURE; + } } catch (const std::exception& e) { PrintExceptionContinue(&e, "Runaway exception"); app.handleRunawayException(QString::fromStdString(GetWarnings("gui"))); @@ -706,6 +726,6 @@ int main(int argc, char *argv[]) PrintExceptionContinue(NULL, "Runaway exception"); app.handleRunawayException(QString::fromStdString(GetWarnings("gui"))); } - return app.getReturnValue(); + return rv; } #endif // BITCOIN_QT_TEST