aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2015-09-25 13:49:08 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2015-09-28 15:06:20 +0200
commitde9de2de361ab1355b976f17371d73e36fe3bf56 (patch)
treed7e9a1c8c8b0cf6ecb5e789d85235e0a1304f161
parent5e0c22135600fe36811da3b78216efc61ba765fb (diff)
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".
-rw-r--r--src/httpserver.cpp40
1 files changed, 37 insertions, 3 deletions
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index e967d3a4a8..9f079aedfe 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -72,13 +72,35 @@ private:
std::deque<WorkItem*> queue;
bool running;
size_t maxDepth;
+ int numThreads;
+
+ /** RAII object to keep track of number of running worker threads */
+ class ThreadCounter
+ {
+ public:
+ WorkQueue &wq;
+ ThreadCounter(WorkQueue &w): wq(w)
+ {
+ boost::lock_guard<boost::mutex> lock(wq.cs);
+ wq.numThreads += 1;
+ }
+ ~ThreadCounter()
+ {
+ boost::lock_guard<boost::mutex> lock(wq.cs);
+ wq.numThreads -= 1;
+ wq.cond.notify_all();
+ }
+ };
public:
WorkQueue(size_t maxDepth) : running(true),
- maxDepth(maxDepth)
+ maxDepth(maxDepth),
+ numThreads(0)
{
}
- /* Precondition: worker threads have all stopped */
+ /*( Precondition: worker threads have all stopped
+ * (call WaitExit)
+ */
~WorkQueue()
{
while (!queue.empty()) {
@@ -100,6 +122,7 @@ public:
/** Thread function */
void Run()
{
+ ThreadCounter count(*this);
while (running) {
WorkItem* i = 0;
{
@@ -122,6 +145,13 @@ public:
running = false;
cond.notify_all();
}
+ /** Wait for worker threads to exit */
+ void WaitExit()
+ {
+ boost::unique_lock<boost::mutex> lock(cs);
+ while (numThreads > 0)
+ cond.wait(lock);
+ }
/** Return current depth of queue */
size_t Depth()
@@ -434,7 +464,11 @@ void InterruptHTTPServer()
void StopHTTPServer()
{
LogPrint("http", "Stopping HTTP server\n");
- delete workQueue;
+ if (workQueue) {
+ LogPrint("http", "Waiting for HTTP worker threads to exit\n");
+ workQueue->WaitExit();
+ delete workQueue;
+ }
if (eventHTTP) {
evhttp_free(eventHTTP);
eventHTTP = 0;