Merge pull request #7317

8a7f000 [RPC] remove the option of having multiple timer interfaces (Jonas Schnelli)
db198d5 Fix RPCTimerInterface ordering issue Dispatching a QThread from a non Qt thread is not allowed. Always use the HTTPRPCTimerInterface (non QT) to dispatch RPCRunLater threads. (Jonas Schnelli)
This commit is contained in:
Wladimir J. van der Laan 2016-01-08 17:34:41 +01:00
commit 3b57e9cff0
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
4 changed files with 25 additions and 17 deletions

View File

@ -226,7 +226,7 @@ bool StartHTTPRPC()
assert(EventBase()); assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase()); httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
RPCRegisterTimerInterface(httpRPCTimerInterface); RPCSetTimerInterface(httpRPCTimerInterface);
return true; return true;
} }
@ -240,7 +240,7 @@ void StopHTTPRPC()
LogPrint("rpc", "Stopping HTTP RPC server\n"); LogPrint("rpc", "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true); UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) { if (httpRPCTimerInterface) {
RPCUnregisterTimerInterface(httpRPCTimerInterface); RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface; delete httpRPCTimerInterface;
httpRPCTimerInterface = 0; httpRPCTimerInterface = 0;
} }

View File

@ -278,7 +278,9 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
#endif #endif
// Register RPC timer interface // Register RPC timer interface
rpcTimerInterface = new QtRPCTimerInterface(); rpcTimerInterface = new QtRPCTimerInterface();
RPCRegisterTimerInterface(rpcTimerInterface); // avoid accidentally overwriting an existing, non QTThread
// based timer interface
RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
startExecutor(); startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS); setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
@ -293,7 +295,7 @@ RPCConsole::~RPCConsole()
{ {
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
Q_EMIT stopExecutor(); Q_EMIT stopExecutor();
RPCUnregisterTimerInterface(rpcTimerInterface); RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface; delete rpcTimerInterface;
delete ui; delete ui;
} }

View File

@ -33,7 +33,7 @@ static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started"); static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup; static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */ /* Timer-creating functions */
static std::vector<RPCTimerInterface*> timerInterfaces; static RPCTimerInterface* timerInterface = NULL;
/* Map of name to timer. /* Map of name to timer.
* @note Can be changed to std::unique_ptr when C++11 */ * @note Can be changed to std::unique_ptr when C++11 */
static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers; static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
@ -546,24 +546,28 @@ std::string HelpExampleRpc(const std::string& methodname, const std::string& arg
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n"; "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
} }
void RPCRegisterTimerInterface(RPCTimerInterface *iface) void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
{ {
timerInterfaces.push_back(iface); if (!timerInterface)
timerInterface = iface;
} }
void RPCUnregisterTimerInterface(RPCTimerInterface *iface) void RPCSetTimerInterface(RPCTimerInterface *iface)
{ {
std::vector<RPCTimerInterface*>::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface); timerInterface = iface;
assert(i != timerInterfaces.end()); }
timerInterfaces.erase(i);
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
{
if (timerInterface == iface)
timerInterface = NULL;
} }
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds) void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
{ {
if (timerInterfaces.empty()) if (!timerInterface)
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
deadlineTimers.erase(name); deadlineTimers.erase(name);
RPCTimerInterface* timerInterface = timerInterfaces[0];
LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000)))); deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
} }

View File

@ -100,10 +100,12 @@ public:
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0; virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
}; };
/** Register factory function for timers */ /** Set the factory function for timers */
void RPCRegisterTimerInterface(RPCTimerInterface *iface); void RPCSetTimerInterface(RPCTimerInterface *iface);
/** Unregister factory function for timers */ /** Set the factory function for timer, but only, if unset */
void RPCUnregisterTimerInterface(RPCTimerInterface *iface); void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface);
/** Unset factory function for timers */
void RPCUnsetTimerInterface(RPCTimerInterface *iface);
/** /**
* Run func nSeconds from now. * Run func nSeconds from now.