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
This commit is contained in:
commit
89bb0365b9
4 changed files with 67 additions and 30 deletions
|
@ -159,7 +159,12 @@ bool AppInit(int argc, char* argv[])
|
||||||
return false;
|
return false;
|
||||||
#endif // HAVE_DECL_DAEMON
|
#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);
|
fRet = AppInitMain(threadGroup, scheduler);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
|
|
12
src/init.cpp
12
src/init.cpp
|
@ -1170,13 +1170,13 @@ bool AppInitSanityChecks()
|
||||||
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
|
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
|
// 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);
|
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
|
// 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
|
// 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.
|
// 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
|
// Detailed error printed inside LockDataDirectory
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||||
|
{
|
||||||
|
const CChainParams& chainparams = Params();
|
||||||
|
// ********************************************************* Step 4a: application initialization
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
CreatePidFile(GetPidFile(), getpid());
|
CreatePidFile(GetPidFile(), getpid());
|
||||||
#endif
|
#endif
|
||||||
|
|
16
src/init.h
16
src/init.h
|
@ -27,27 +27,33 @@ void InitLogging();
|
||||||
void InitParameterInteraction();
|
void InitParameterInteraction();
|
||||||
|
|
||||||
/** Initialize bitcoin core: Basic context setup.
|
/** 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.
|
* @pre Parameters should be parsed and config file should be read.
|
||||||
*/
|
*/
|
||||||
bool AppInitBasicSetup();
|
bool AppInitBasicSetup();
|
||||||
/**
|
/**
|
||||||
* Initialization: parameter interaction.
|
* 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.
|
* @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called.
|
||||||
*/
|
*/
|
||||||
bool AppInitParameterInteraction();
|
bool AppInitParameterInteraction();
|
||||||
/**
|
/**
|
||||||
* Initialization sanity checks: ecc init, sanity checks, dir lock.
|
* 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.
|
* @pre Parameters should be parsed and config file should be read, AppInitParameterInteraction should have been called.
|
||||||
*/
|
*/
|
||||||
bool AppInitSanityChecks();
|
bool AppInitSanityChecks();
|
||||||
/**
|
/**
|
||||||
* Bitcoin core main initialization.
|
* Lock bitcoin core data directory.
|
||||||
* @note This should only be done after daemonization.
|
* @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.
|
* @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);
|
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 */
|
||||||
|
|
|
@ -178,6 +178,10 @@ class BitcoinCore: public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit BitcoinCore();
|
explicit BitcoinCore();
|
||||||
|
/** Basic initialization, before starting initialization/shutdown thread.
|
||||||
|
* Return true on success.
|
||||||
|
*/
|
||||||
|
static bool baseInitialize();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void initialize();
|
void initialize();
|
||||||
|
@ -270,26 +274,32 @@ void BitcoinCore::handleRunawayException(const std::exception *e)
|
||||||
Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui")));
|
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()
|
void BitcoinCore::initialize()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
qDebug() << __func__ << ": Running initialization in thread";
|
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);
|
bool rv = AppInitMain(threadGroup, scheduler);
|
||||||
Q_EMIT initializeResult(rv);
|
Q_EMIT initializeResult(rv);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -689,9 +699,14 @@ int main(int argc, char *argv[])
|
||||||
if (GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !GetBoolArg("-min", false))
|
if (GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !GetBoolArg("-min", false))
|
||||||
app.createSplashScreen(networkStyle.data());
|
app.createSplashScreen(networkStyle.data());
|
||||||
|
|
||||||
|
int rv = EXIT_SUCCESS;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
app.createWindow(networkStyle.data());
|
app.createWindow(networkStyle.data());
|
||||||
|
// 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();
|
app.requestInitialize();
|
||||||
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
|
#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());
|
||||||
|
@ -699,6 +714,11 @@ int main(int argc, char *argv[])
|
||||||
app.exec();
|
app.exec();
|
||||||
app.requestShutdown();
|
app.requestShutdown();
|
||||||
app.exec();
|
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) {
|
} catch (const std::exception& e) {
|
||||||
PrintExceptionContinue(&e, "Runaway exception");
|
PrintExceptionContinue(&e, "Runaway exception");
|
||||||
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
|
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
|
||||||
|
@ -706,6 +726,6 @@ int main(int argc, char *argv[])
|
||||||
PrintExceptionContinue(NULL, "Runaway exception");
|
PrintExceptionContinue(NULL, "Runaway exception");
|
||||||
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
|
app.handleRunawayException(QString::fromStdString(GetWarnings("gui")));
|
||||||
}
|
}
|
||||||
return app.getReturnValue();
|
return rv;
|
||||||
}
|
}
|
||||||
#endif // BITCOIN_QT_TEST
|
#endif // BITCOIN_QT_TEST
|
||||||
|
|
Loading…
Reference in a new issue