Skip to content

Commit de9de2d

Browse files
committed
http: Wait for worker threads to exit
Add a WaitExit() call to http's WorkQueue to make it delete the work queue only when all worker threads stopped. This fixes a problem that was reproducable by pressing Ctrl-C during AppInit2: ``` /usr/include/boost/thread/pthread/condition_variable_fwd.hpp:81: boost::condition_variable::~condition_variable(): Assertion `!ret' failed. /usr/include/boost/thread/pthread/mutex.hpp:108: boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed. ``` I was assuming that `threadGroup->join_all();` would always have been called when entering the Shutdown(). However this is not the case in bitcoind's AppInit2-non-zero-exit case "was left out intentionally here".
1 parent 5e0c221 commit de9de2d

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

src/httpserver.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,35 @@ class WorkQueue
7272
std::deque<WorkItem*> queue;
7373
bool running;
7474
size_t maxDepth;
75+
int numThreads;
76+
77+
/** RAII object to keep track of number of running worker threads */
78+
class ThreadCounter
79+
{
80+
public:
81+
WorkQueue &wq;
82+
ThreadCounter(WorkQueue &w): wq(w)
83+
{
84+
boost::lock_guard<boost::mutex> lock(wq.cs);
85+
wq.numThreads += 1;
86+
}
87+
~ThreadCounter()
88+
{
89+
boost::lock_guard<boost::mutex> lock(wq.cs);
90+
wq.numThreads -= 1;
91+
wq.cond.notify_all();
92+
}
93+
};
7594

7695
public:
7796
WorkQueue(size_t maxDepth) : running(true),
78-
maxDepth(maxDepth)
97+
maxDepth(maxDepth),
98+
numThreads(0)
7999
{
80100
}
81-
/* Precondition: worker threads have all stopped */
101+
/*( Precondition: worker threads have all stopped
102+
* (call WaitExit)
103+
*/
82104
~WorkQueue()
83105
{
84106
while (!queue.empty()) {
@@ -100,6 +122,7 @@ class WorkQueue
100122
/** Thread function */
101123
void Run()
102124
{
125+
ThreadCounter count(*this);
103126
while (running) {
104127
WorkItem* i = 0;
105128
{
@@ -122,6 +145,13 @@ class WorkQueue
122145
running = false;
123146
cond.notify_all();
124147
}
148+
/** Wait for worker threads to exit */
149+
void WaitExit()
150+
{
151+
boost::unique_lock<boost::mutex> lock(cs);
152+
while (numThreads > 0)
153+
cond.wait(lock);
154+
}
125155

126156
/** Return current depth of queue */
127157
size_t Depth()
@@ -434,7 +464,11 @@ void InterruptHTTPServer()
434464
void StopHTTPServer()
435465
{
436466
LogPrint("http", "Stopping HTTP server\n");
437-
delete workQueue;
467+
if (workQueue) {
468+
LogPrint("http", "Waiting for HTTP worker threads to exit\n");
469+
workQueue->WaitExit();
470+
delete workQueue;
471+
}
438472
if (eventHTTP) {
439473
evhttp_free(eventHTTP);
440474
eventHTTP = 0;

0 commit comments

Comments
 (0)