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