diff --git a/Include/httpClient/httpClient.h b/Include/httpClient/httpClient.h
index 68937c0b..0b128a09 100644
--- a/Include/httpClient/httpClient.h
+++ b/Include/httpClient/httpClient.h
@@ -136,9 +136,19 @@ STDAPI HCInitialize(_In_opt_ HCInitArgs* args) noexcept;
/// Immediately reclaims all resources associated with the library.
/// If you called HCMemSetFunctions(), call this before shutting down your app's memory manager.
///
+///
+/// Deprecated, Use HCCleanupAsync instead which allows control of which queue is running the cleanup work and does not potentially deadlock.
+///
///
STDAPI_(void) HCCleanup() noexcept;
+///
+/// Reclaims all resources associated with the library.
+/// If you called HCMemSetFunctions(), call this before shutting down your app's memory manager.
+///
+///
+STDAPI HCCleanupAsync(XAsyncBlock* async) noexcept;
+
///
/// Returns the version of the library
///
diff --git a/Source/Global/global.cpp b/Source/Global/global.cpp
index eeaba2b6..4b6215a5 100644
--- a/Source/Global/global.cpp
+++ b/Source/Global/global.cpp
@@ -5,6 +5,7 @@
#include "../HTTP/httpcall.h"
#include "buildver.h"
#include "global.h"
+#include "../Logger/trace_internal.h"
#include "../Mock/lhc_mock.h"
#if !HC_NOWEBSOCKETS
@@ -33,6 +34,8 @@ HRESULT http_singleton::singleton_access(
// Create the singleton only for the first client calling create
if (!s_useCount)
{
+ HCTraceImplInit();
+
PerformEnv performEnv;
RETURN_IF_FAILED(Internal_InitializeHttpPlatform(createArgs, performEnv));
@@ -113,7 +116,38 @@ HRESULT http_singleton::cleanup_async(
) noexcept
{
std::shared_ptr singleton{};
- RETURN_IF_FAILED(singleton_access(singleton_access_mode::cleanup, nullptr, singleton));
+ HRESULT hr = singleton_access(singleton_access_mode::cleanup, nullptr, singleton);
+
+ // if the singleton is still in use, or already cleaned up, fail immediately
+ if (FAILED(hr))
+ {
+ intptr_t hrPtrSize = hr;
+ return XAsyncBegin(
+ async,
+ reinterpret_cast(hrPtrSize),
+ reinterpret_cast(cleanup_async),
+ __FUNCTION__,
+ [](XAsyncOp op, const XAsyncProviderData* data)
+ {
+ switch (op)
+ {
+ case XAsyncOp::Begin:
+ {
+ intptr_t hrPtrSize = reinterpret_cast(data->context);
+ return static_cast(hrPtrSize);
+ }
+ case XAsyncOp::Cleanup:
+ {
+ return S_OK;
+ }
+ default:
+ {
+ assert(false);
+ return S_OK;
+ }
+ }
+ });
+ }
return XAsyncBegin(
async,
@@ -147,6 +181,9 @@ HRESULT http_singleton::cleanup_async(
// self is the only reference at this point, the singleton will be destroyed on this thread.
self.reset();
+ // cleanup tracing now that we are done
+ HCTraceImplCleanup();
+
XAsyncComplete(data->async, S_OK, 0);
return S_OK;
}
diff --git a/Source/Global/global_publics.cpp b/Source/Global/global_publics.cpp
index b1080ad8..b30fcb8b 100644
--- a/Source/Global/global_publics.cpp
+++ b/Source/Global/global_publics.cpp
@@ -5,7 +5,6 @@
#include "../HTTP/httpcall.h"
#include "buildver.h"
#include "global.h"
-#include "../Logger/trace_internal.h"
using namespace xbox::httpclient;
@@ -27,7 +26,6 @@ STDAPI
HCInitialize(_In_opt_ HCInitArgs* args) noexcept
try
{
- HCTraceImplInit();
return http_singleton::create(args);
}
CATCH_RETURN()
@@ -36,16 +34,21 @@ STDAPI_(void) HCCleanup() noexcept
try
{
XAsyncBlock async{};
- HRESULT hr = http_singleton::cleanup_async(&async);
+ HRESULT hr = HCCleanupAsync(&async);
if (SUCCEEDED(hr))
{
XAsyncGetStatus(&async, true);
}
-
- HCTraceImplCleanup();
}
CATCH_RETURN_WITH(;)
+STDAPI HCCleanupAsync(XAsyncBlock* async) noexcept
+try
+{
+ return http_singleton::cleanup_async(async);
+}
+CATCH_RETURN()
+
STDAPI
HCSetGlobalProxy(_In_ const char* proxyUri) noexcept
try