HTTPDownloader: Use release-acquire ordering for request state

This commit is contained in:
Stenzek
2025-11-29 15:23:21 +10:00
parent a171c25fb2
commit d6f7084309
2 changed files with 18 additions and 16 deletions

View File

@@ -98,20 +98,21 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
for (size_t index = 0; index < m_pending_http_requests.size();) for (size_t index = 0; index < m_pending_http_requests.size();)
{ {
Request* req = m_pending_http_requests[index]; Request* req = m_pending_http_requests[index];
if (req->state == Request::State::Pending) const Request::State req_state = req->state.load(std::memory_order_acquire);
if (req_state == Request::State::Pending)
{ {
unstarted_requests++; unstarted_requests++;
index++; index++;
continue; continue;
} }
if ((req->state == Request::State::Started || req->state == Request::State::Receiving) && if ((req_state == Request::State::Started || req_state == Request::State::Receiving) &&
current_time >= req->start_time && Timer::ConvertValueToSeconds(current_time - req->start_time) >= m_timeout) current_time >= req->start_time && Timer::ConvertValueToSeconds(current_time - req->start_time) >= m_timeout)
{ {
// request timed out // request timed out
ERROR_LOG("Request for '{}' timed out", req->url); ERROR_LOG("Request for '{}' timed out", req->url);
req->state.store(Request::State::Cancelled); req->state.store(Request::State::Cancelled, std::memory_order_release);
m_pending_http_requests.erase(m_pending_http_requests.begin() + index); m_pending_http_requests.erase(m_pending_http_requests.begin() + index);
lock.unlock(); lock.unlock();
@@ -123,13 +124,13 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
lock.lock(); lock.lock();
continue; continue;
} }
else if ((req->state == Request::State::Started || req->state == Request::State::Receiving) && req->progress && else if ((req_state == Request::State::Started || req_state == Request::State::Receiving) && req->progress &&
req->progress->IsCancelled()) req->progress->IsCancelled())
{ {
// request timed out // request timed out
ERROR_LOG("Request for '{}' cancelled", req->url); ERROR_LOG("Request for '{}' cancelled", req->url);
req->state.store(Request::State::Cancelled); req->state.store(Request::State::Cancelled, std::memory_order_release);
m_pending_http_requests.erase(m_pending_http_requests.begin() + index); m_pending_http_requests.erase(m_pending_http_requests.begin() + index);
lock.unlock(); lock.unlock();
@@ -142,7 +143,7 @@ void HTTPDownloader::LockedPollRequests(std::unique_lock<std::mutex>& lock)
continue; continue;
} }
if (req->state != Request::State::Complete) if (req_state != Request::State::Complete)
{ {
if (req->progress) if (req->progress)
{ {
@@ -245,9 +246,10 @@ void HTTPDownloader::LockedAddRequest(Request* request)
u32 HTTPDownloader::LockedGetActiveRequestCount() u32 HTTPDownloader::LockedGetActiveRequestCount()
{ {
u32 count = 0; u32 count = 0;
for (Request* req : m_pending_http_requests) for (const Request* const req : m_pending_http_requests)
{ {
if (req->state == Request::State::Started || req->state == Request::State::Receiving) const Request::State req_state = req->state.load(std::memory_order_acquire);
if (req_state == Request::State::Started || req_state == Request::State::Receiving)
count++; count++;
} }
return count; return count;

View File

@@ -127,7 +127,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
ERROR_LOG("WinHttp async function {} returned error {}", res->dwResult, res->dwError); ERROR_LOG("WinHttp async function {} returned error {}", res->dwResult, res->dwError);
req->status_code = HTTP_STATUS_ERROR; req->status_code = HTTP_STATUS_ERROR;
req->error.SetStringFmt("WinHttp async function {} returned error {}", res->dwResult, res->dwError); req->error.SetStringFmt("WinHttp async function {} returned error {}", res->dwResult, res->dwError);
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
return; return;
} }
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
@@ -139,7 +139,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
ERROR_LOG("WinHttpReceiveResponse() failed: {}", err); ERROR_LOG("WinHttpReceiveResponse() failed: {}", err);
req->status_code = HTTP_STATUS_ERROR; req->status_code = HTTP_STATUS_ERROR;
req->error.SetWin32("WinHttpReceiveResponse() failed: ", err); req->error.SetWin32("WinHttpReceiveResponse() failed: ", err);
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
} }
return; return;
@@ -156,7 +156,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
ERROR_LOG("WinHttpQueryHeaders() for status code failed: {}", err); ERROR_LOG("WinHttpQueryHeaders() for status code failed: {}", err);
req->status_code = HTTP_STATUS_ERROR; req->status_code = HTTP_STATUS_ERROR;
req->error.SetWin32("WinHttpQueryHeaders() failed: ", err); req->error.SetWin32("WinHttpQueryHeaders() failed: ", err);
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
return; return;
} }
@@ -188,7 +188,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
DEV_LOG("Status code {}, content-length is {}", req->status_code, req->content_length); DEV_LOG("Status code {}, content-length is {}", req->status_code, req->content_length);
req->data.reserve(req->content_length); req->data.reserve(req->content_length);
req->state = Request::State::Receiving; req->state.store(Request::State::Receiving, std::memory_order_release);
// start reading // start reading
if (!WinHttpQueryDataAvailable(hRequest, nullptr) && GetLastError() != ERROR_IO_PENDING) if (!WinHttpQueryDataAvailable(hRequest, nullptr) && GetLastError() != ERROR_IO_PENDING)
@@ -197,7 +197,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", err); ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", err);
req->status_code = HTTP_STATUS_ERROR; req->status_code = HTTP_STATUS_ERROR;
req->error.SetWin32("WinHttpQueryDataAvailable() failed: ", err); req->error.SetWin32("WinHttpQueryDataAvailable() failed: ", err);
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
} }
return; return;
@@ -210,7 +210,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
{ {
// end of request // end of request
DEV_LOG("End of request '{}', {} bytes received", req->url, req->data.size()); DEV_LOG("End of request '{}', {} bytes received", req->url, req->data.size());
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
return; return;
} }
@@ -225,7 +225,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
ERROR_LOG("WinHttpReadData() failed: {}", err); ERROR_LOG("WinHttpReadData() failed: {}", err);
req->status_code = HTTP_STATUS_ERROR; req->status_code = HTTP_STATUS_ERROR;
req->error.SetWin32("WinHttpReadData() failed: ", err); req->error.SetWin32("WinHttpReadData() failed: ", err);
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
} }
return; return;
@@ -245,7 +245,7 @@ void CALLBACK HTTPDownloaderWinHttp::HTTPStatusCallback(HINTERNET hRequest, DWOR
ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", err); ERROR_LOG("WinHttpQueryDataAvailable() failed: {}", err);
req->status_code = HTTP_STATUS_ERROR; req->status_code = HTTP_STATUS_ERROR;
req->error.SetWin32("WinHttpQueryDataAvailable() failed: ", err); req->error.SetWin32("WinHttpQueryDataAvailable() failed: ", err);
req->state.store(Request::State::Complete); req->state.store(Request::State::Complete, std::memory_order_release);
} }
return; return;