1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-31 18:39:10 +00:00

Fix: libcurl HTTP thread race at uninit preventing thread exit

This commit is contained in:
Jonathan G Rennison
2024-01-04 01:02:22 +00:00
committed by Patric Stout
parent c6dafb0865
commit 51ef416b49
2 changed files with 28 additions and 5 deletions

View File

@@ -230,8 +230,10 @@ void HttpThread()
request->callback.OnFailure(); request->callback.OnFailure();
} }
/* Wait till the callback tells us all data is dequeued. */ /* Wait till the callback tells us all data is dequeued, or _http_thread_exit has been set. */
request->callback.WaitTillEmpty(); request->callback.WaitTillEmptyOrCondition([]() -> bool {
return _http_thread_exit;
});
} }
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
@@ -278,6 +280,11 @@ void NetworkHTTPUninitialize()
_http_thread_exit = true; _http_thread_exit = true;
/* Queues must be cleared (and the queue CV signalled) after _http_thread_exit is set to ensure that the HTTP thread can exit */
for (auto &callback : _http_callbacks) {
callback->ClearQueue();
}
{ {
std::lock_guard<std::mutex> lock(_http_mutex); std::lock_guard<std::mutex> lock(_http_mutex);
_http_cv.notify_one(); _http_cv.notify_one();

View File

@@ -75,13 +75,15 @@ public:
} }
/** /**
* Wait till the queue is dequeued. * Wait till the queue is dequeued, or a condition is met.
* @param condition Condition functor.
*/ */
void WaitTillEmpty() template <typename T>
void WaitTillEmptyOrCondition(T condition)
{ {
std::unique_lock<std::mutex> lock(this->mutex); std::unique_lock<std::mutex> lock(this->mutex);
while (!queue.empty()) { while (!(queue.empty() || condition())) {
this->queue_cv.wait(lock); this->queue_cv.wait(lock);
} }
} }
@@ -95,6 +97,20 @@ public:
return this->queue.empty(); return this->queue.empty();
} }
/**
* Clear everything in the queue.
*
* Should be called from the Game Thread.
*/
void ClearQueue()
{
std::lock_guard<std::mutex> lock(this->mutex);
this->queue.clear();
this->queue_cv.notify_all();
}
HTTPThreadSafeCallback(HTTPCallback *callback) : callback(callback) {} HTTPThreadSafeCallback(HTTPCallback *callback) : callback(callback) {}
~HTTPThreadSafeCallback() ~HTTPThreadSafeCallback()