diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 3cf7e53c0..9b0b1d6e4 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -21,6 +21,7 @@ #include "init.h" #include "main.h" +#include "rpcserver.h" #include "ui_interface.h" #include "util.h" #include "wallet.h" @@ -227,6 +228,13 @@ void BitcoinCore::initialize() { LogPrintf("Running AppInit2 in thread\n"); int rv = AppInit2(threadGroup); + if(rv) + { + /* Start a dummy RPC thread if no RPC thread is active yet + * to handle timeouts. + */ + StartDummyRPCThread(); + } emit initializeResult(rv); } catch (std::exception& e) { handleRunawayException(&e); diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index 6bf371e75..d3ed48525 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -49,7 +49,6 @@ enum RPCErrorCode RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter RPC_DATABASE_ERROR = -20, // Database error RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format - RPC_SERVER_NOT_STARTED = -18, // RPC server was not started (StartRPCThreads() not called) // P2P client errors RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 9d34a900f..0d9e95402 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -38,6 +38,7 @@ static asio::io_service* rpc_io_service = NULL; static map > deadlineTimers; static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; +static boost::asio::io_service::work *rpc_dummy_work = NULL; void RPCTypeCheck(const Array& params, const list& typesExpected, @@ -607,6 +608,19 @@ void StartRPCThreads() rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); } +void StartDummyRPCThread() +{ + if(rpc_io_service == NULL) + { + rpc_io_service = new asio::io_service(); + /* Create dummy "work" to keep the thread from exiting when no timeouts active, + * see http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service.html#boost_asio.reference.io_service.stopping_the_io_service_from_running_out_of_work */ + rpc_dummy_work = new asio::io_service::work(*rpc_io_service); + rpc_worker_group = new boost::thread_group(); + rpc_worker_group->create_thread(boost::bind(&asio::io_service::run, rpc_io_service)); + } +} + void StopRPCThreads() { if (rpc_io_service == NULL) return; @@ -615,6 +629,7 @@ void StopRPCThreads() rpc_io_service->stop(); if (rpc_worker_group != NULL) rpc_worker_group->join_all(); + delete rpc_dummy_work; rpc_dummy_work = NULL; delete rpc_worker_group; rpc_worker_group = NULL; delete rpc_ssl_context; rpc_ssl_context = NULL; delete rpc_io_service; rpc_io_service = NULL; diff --git a/src/rpcserver.h b/src/rpcserver.h index 9087be9e8..9008c3281 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -20,7 +20,14 @@ class CBlockIndex; +/* Start RPC threads */ void StartRPCThreads(); +/* Alternative to StartRPCThreads for the GUI, when no server is + * used. The RPC thread in this case is only used to handle timeouts. + * If real RPC threads have already been started this is a no-op. + */ +void StartDummyRPCThread(); +/* Stop RPC threads */ void StopRPCThreads(); /* diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 8ad5c9c51..68f5fe525 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1562,8 +1562,6 @@ Value walletpassphrase(const Array& params, bool fHelp) if (fHelp) return true; - if (!fServer) - throw JSONRPCError(RPC_SERVER_NOT_STARTED, "Error: RPC server was not started, use server=1 to change this."); if (!pwalletMain->IsCrypted()) throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");