diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index 3a646a55f..6ad83fcae 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -96,7 +96,7 @@ namespace winrt::impl { resume_background(handle); } - else if ((context.m_context_type == 2 /* APTTYPE_NTA */) && is_sta_thread()) + else if (is_sta_thread()) { resume_apartment_on_threadpool(context.m_context, handle); } diff --git a/test/old_tests/UnitTests/apartment_context.cpp b/test/old_tests/UnitTests/apartment_context.cpp index ae3511698..7aa2f2efc 100644 --- a/test/old_tests/UnitTests/apartment_context.cpp +++ b/test/old_tests/UnitTests/apartment_context.cpp @@ -56,6 +56,64 @@ namespace REQUIRE(is_nta_on_mta()); } + + IAsyncAction TestStaToStaApartmentContext() + { + bool pass = false; + + apartment_context original; + + // Create an STA thread and switch to it. + auto controller1 = DispatcherQueueController::CreateOnDedicatedThread(); + co_await resume_foreground(controller1.DispatcherQueue()); + + // Save the COM context for the first STA thread. + apartment_context context1; + + // Create another STA thread and switch to it. + auto controller2 = DispatcherQueueController::CreateOnDedicatedThread(); + co_await resume_foreground(controller2.DispatcherQueue()); + + // The first STA thread remains hung as long as this is true. + bool hang_sta_1 = true; + + // Hang the first STA thread. + controller1.DispatcherQueue().TryEnqueue([&] { + bool hang = true; + while (hang_sta_1) + { + if (!WaitOnAddress(&hang_sta_1, &hang, sizeof(hang), 1000)) + { + return; // failed - timed out + } + } + pass = true; + }); + + // Queue work to the second STA thread to unstick the first thread. + // This requires that the second STA thread be available to dispatch work + // after the "co_await context1" below. + controller2.DispatcherQueue().TryEnqueue([&] { + hang_sta_1 = false; + WakeByAddressAll(&hang_sta_1); + }); + + // Try to switch to the first STA thread via COM context. + // The first STA thread is hung, but once this thread (the second STA thread) + // processes work, it will unstick the first STA thread. + // This test verifies that the second STA thread does become available + // to do work and is not hung waiting for the first STA thread. + co_await context1; + + REQUIRE(pass); + + // Clean up. + co_await original; + + co_await controller1.ShutdownQueueAsync(); + co_await controller2.ShutdownQueueAsync(); + } + } TEST_CASE("apartment_context coverage") @@ -67,3 +125,8 @@ TEST_CASE("apartment_context nta") { TestNeutralApartmentContext().get(); } + +TEST_CASE("apartment_context sta") +{ + TestStaToStaApartmentContext().get(); +}