Skip to content

Commit

Permalink
[RPC]: Fix RPCTimerInterface ordering issue (bitcoin#7317)
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed Oct 3, 2018
1 parent 056b4d5 commit 0053876
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/httprpc.cpp
Expand Up @@ -177,7 +177,7 @@ bool StartHTTPRPC()

assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
RPCRegisterTimerInterface(httpRPCTimerInterface);
RPCSetTimerInterface(httpRPCTimerInterface);
return true;
}

Expand All @@ -191,7 +191,7 @@ void StopHTTPRPC()
LogPrint("rpc", "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
RPCUnregisterTimerInterface(httpRPCTimerInterface);
RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface;
httpRPCTimerInterface = 0;
}
Expand Down
6 changes: 4 additions & 2 deletions src/qt/rpcconsole.cpp
Expand Up @@ -319,7 +319,9 @@ RPCConsole::RPCConsole(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHi
#endif
// Register RPC timer interface
rpcTimerInterface = new QtRPCTimerInterface();
RPCRegisterTimerInterface(rpcTimerInterface);
// avoid accidentally overwriting an existing, non QTThread
// based timer interface
RPCSetTimerInterfaceIfUnset(rpcTimerInterface);

startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
Expand All @@ -333,7 +335,7 @@ RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
emit stopExecutor();
RPCUnregisterTimerInterface(rpcTimerInterface);
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
}
Expand Down
22 changes: 13 additions & 9 deletions src/rpc/server.cpp
Expand Up @@ -37,7 +37,7 @@ static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;

/* Timer-creating functions */
static std::vector<RPCTimerInterface*> timerInterfaces;
static RPCTimerInterface* timerInterface = NULL;
/* Map of name to timer.
* @note Can be changed to std::unique_ptr when C++11 */
static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
Expand Down Expand Up @@ -624,24 +624,28 @@ std::string HelpExampleRpc(string methodname, string args)
methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:51473/\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);
assert(i != timerInterfaces.end());
timerInterfaces.erase(i);
timerInterface = iface;
}

void RPCUnsetTimerInterface(RPCTimerInterface *iface)
{
if (timerInterface == iface)
timerInterface = NULL;
}

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");
deadlineTimers.erase(name);
RPCTimerInterface* timerInterface = timerInterfaces[0];
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))));
}
Expand Down
10 changes: 6 additions & 4 deletions src/rpc/server.h
Expand Up @@ -101,10 +101,12 @@ class RPCTimerInterface
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
};

/** Register factory function for timers */
void RPCRegisterTimerInterface(RPCTimerInterface *iface);
/** Unregister factory function for timers */
void RPCUnregisterTimerInterface(RPCTimerInterface *iface);
/** Set factory function for timers */
void RPCSetTimerInterface(RPCTimerInterface *iface);
/** Set factory function for timers, but only if unset */
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface);
/** Unset factory function for timers */
void RPCUnsetTimerInterface(RPCTimerInterface *iface);

/**
* Run func nSeconds from now.
Expand Down

0 comments on commit 0053876

Please sign in to comment.