This prevents a potential race condition if control flow ends up in
ShutdownHTTPServer before the thread gets to queue->Run(),
deleting the work queue while workers are still going to use it.
Meant to fix #12362.
448 | @@ -449,6 +449,7 @@ bool UpdateHTTPServerLogging(bool enable) { 449 | 450 | std::thread threadHTTP; 451 | std::future<bool> threadResult; 452 | +static std::vector<std::thread> threadHTTPWorkers;
Could follow g_thread_http_workers naming convention.
Can we please first make sure that this fixes the issue before jumping on naming issues
utACK 2fefa3077e69dfdbccbd010cda5627787ec92bb8. Untested, but change makes sense. Detached threads are always a little suspicious.
460 | @@ -460,8 +461,7 @@ bool StartHTTPServer() 461 | threadHTTP = std::thread(std::move(task), eventBase, eventHTTP); 462 | 463 | for (int i = 0; i < rpcThreads; i++) { 464 | - std::thread rpc_worker(HTTPWorkQueueRun, workQueue); 465 | - rpc_worker.detach(); 466 | + threadHTTPWorkers.emplace_back(std::thread(HTTPWorkQueueRun, workQueue));
No need to create the temporary just to move it into a new std::thread constructor.
Right
Tested ACK 2fefa3077e69dfdbccbd010cda5627787ec92bb8 - my previous sleeps and valgrind are no longer able to find any issue here.
Would love to see @jnewbery confirm he cannot reproduce anymore as well.
This prevents a potential race condition if control flow ends up in
`ShutdownHTTPServer` before the thread gets to `queue->Run()`,
deleting the work queue while workers are still going to use it.
Meant to fix #12362.
Signed-off-by: Wladimir J. van der Laan <laanwj@gmail.com>
This function, which waits for all threads to exit, is no longer needed
now that threads are joined instead.
Signed-off-by: Wladimir J. van der Laan <laanwj@gmail.com>
486 | @@ -487,6 +487,10 @@ void StopHTTPServer()
487 | if (workQueue) {
488 | LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");
489 | workQueue->WaitExit();
I think we don't need WaitExit() anymore with this?
It would seem not, indeed. Testing shows no difference with it removed.
Ok, will remove it in a separate commit.
ok, renamed the variable and added a commit to remove WaitExit()
I can confirm that I'm not able to reproduce the error when running with commit f94665466ed50e868c98b1a1c708ad5767727bb6.
139 | @@ -141,13 +140,6 @@ class WorkQueue 140 | running = false; 141 | cond.notify_all(); 142 | } 143 | - /** Wait for worker threads to exit */ 144 | - void WaitExit() 145 | - { 146 | - std::unique_lock<std::mutex> lock(cs); 147 | - while (numThreads > 0)
In commit "http: Remove WaitExit from WorkQueue"
It looks like the numThreads variable is unused now, so it might be worth removing as well.
Thanks, I removed those in a new commit.
utACK f94665466ed50e868c98b1a1c708ad5767727bb6. Only changes were variable rename and temp std::thread / WaitExit remove suggestions above.
477 | @@ -486,7 +478,10 @@ void StopHTTPServer() 478 | LogPrint(BCLog::HTTP, "Stopping HTTP server\n"); 479 | if (workQueue) { 480 | LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n"); 481 | - workQueue->WaitExit(); 482 | + for (auto& thread: g_thread_http_workers) { 483 | + thread.join();
From the documentation, I don't think this is needed, clear() below is enough.
No, if you delete a thread without either calling detach() or join(), terminate() is called. join() is not automatically called for you.
utACK.
utACK f94665466ed50e868c98b1a1c708ad5767727bb6. This is easier to read as well.
utACK
The HTTP worker thread counter, as well as the RAII object that was used
to maintain it, is unused now, so can be removed.
Signed-off-by: Wladimir J. van der Laan <laanwj@gmail.com>
95 | 96 | public: 97 | explicit WorkQueue(size_t _maxDepth) : running(true), 98 | - maxDepth(_maxDepth), 99 | - numThreads(0) 100 | + maxDepth(_maxDepth)
Nit, dunno about correct indentation here..
456 | @@ -486,7 +457,10 @@ void StopHTTPServer() 457 | LogPrint(BCLog::HTTP, "Stopping HTTP server\n"); 458 | if (workQueue) { 459 | LogPrint(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n"); 460 | - workQueue->WaitExit(); 461 | + for (auto& thread: g_thread_http_workers) {
Nit, space before :.
419 | @@ -449,6 +420,7 @@ bool UpdateHTTPServerLogging(bool enable) {
420 |
421 | std::thread threadHTTP;
422 | std::future<bool> threadResult;
Nit, this and the above could be static too.
Yes, but out of scope of this PR to change that.
utACK 11e0151.
Nice cleanup!
FWIW I wrote HTTPWorkQueue with the idea that it could likely be replaced with a 1-liner after c++11, I think there's scope for more code removal. Out of scope for a 0.16.0 fix ofc.