Browse Source

init: Factor out AppInitLockDataDirectory

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.
0.15
Wladimir J. van der Laan 7 years ago
parent
commit
dba485d651
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
  1. 7
      src/bitcoind.cpp
  2. 12
      src/init.cpp
  3. 16
      src/init.h
  4. 42
      src/qt/bitcoin.cpp

7
src/bitcoind.cpp

@ -159,7 +159,12 @@ bool AppInit(int argc, char* argv[]) @@ -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) {

12
src/init.cpp

@ -1170,13 +1170,13 @@ bool AppInitSanityChecks() @@ -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) @@ -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

16
src/init.h

@ -27,27 +27,33 @@ void InitLogging(); @@ -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 */

42
src/qt/bitcoin.cpp

@ -178,6 +178,10 @@ class BitcoinCore: public QObject @@ -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) @@ -270,26 +274,32 @@ void BitcoinCore::handleRunawayException(const std::exception *e)
Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui")));
}
void BitcoinCore::initialize()
bool BitcoinCore::baseInitialize()
{
try
{
qDebug() << __func__ << ": Running initialization in thread";
if (!AppInitBasicSetup())
{
Q_EMIT initializeResult(false);
return;
return false;
}
if (!AppInitParameterInteraction())
{
Q_EMIT initializeResult(false);
return;
return false;
}
if (!AppInitSanityChecks())
{
Q_EMIT initializeResult(false);
return;
return false;
}
if (!AppInitLockDataDirectory())
{
return false;
}
return true;
}
void BitcoinCore::initialize()
{
try
{
qDebug() << __func__ << ": Running initialization in thread";
bool rv = AppInitMain(threadGroup, scheduler);
Q_EMIT initializeResult(rv);
} catch (const std::exception& e) {
@ -689,9 +699,14 @@ int main(int argc, char *argv[]) @@ -689,9 +699,14 @@ 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());
// 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());
@ -699,6 +714,11 @@ int main(int argc, char *argv[]) @@ -699,6 +714,11 @@ int main(int argc, char *argv[])
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[]) @@ -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

Loading…
Cancel
Save