winrt::Windows::Foundation::IAsyncAction clear_all_apartments_async()

in include/wil/com_apartment_variable.h [282:343]


            winrt::Windows::Foundation::IAsyncAction clear_all_apartments_async()
            {
                // gather all the apartments that hold objects we need to destruct
                // (do not gather the objects themselves, because the apartment might
                // destruct before we get around to it, and we should let the apartment
                // destruct the object while it still can).

                std::vector<winrt::apartment_context> contexts;
                { // scope for lock
                    auto lock = winrt::slim_lock_guard(s_lock);
                    for (auto& [id, storage] : s_apartmentStorage)
                    {
                        auto variable = storage.variables.find(this);
                        if (variable != storage.variables.end())
                        {
                            contexts.push_back(storage.context);
                        }
                    }
                }

                if (contexts.empty())
                {
                    co_return;
                }

                wil::unique_mta_usage_cookie mta_reference; // need to extend the MTA due to async cleanup
                FAIL_FAST_IF_FAILED(CoIncrementMTAUsage(mta_reference.put()));

                // From a background thread hop into each apartment to run down the object
                // if it's still there.
                co_await winrt::resume_background();

                // This hook enables testing the case where execution of this method loses the race with
                // apartment rundown by other means.
                if constexpr (test_hook::AsyncRundownDelayForTestingRaces != INFINITE)
                {
                    Sleep(test_hook::AsyncRundownDelayForTestingRaces);
                }

                for (auto&& context : contexts)
                {
                    try
                    {
                        co_await context;
                        clear();
                    }
                    catch (winrt::hresult_error const& e)
                    {
                        // Ignore failure if apartment ran down before we could clean it up.
                        // The object already ran down as part of apartment cleanup.
                        if ((e.code() != RPC_E_SERVER_DIED_DNE) &&
                            (e.code() != RPC_E_DISCONNECTED))
                        {
                            throw;
                        }
                    }
                    catch (...)
                    {
                        FAIL_FAST();
                    }
                }
            }