Skip to content

Commit 0835afb

Browse files
authored
Always bounce through the threadpool when switching from STA (#856)
1 parent fbf0543 commit 0835afb

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

strings/base_coroutine_threadpool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ namespace winrt::impl
9696
{
9797
resume_background(handle);
9898
}
99-
else if ((context.m_context_type == 2 /* APTTYPE_NTA */) && is_sta_thread())
99+
else if (is_sta_thread())
100100
{
101101
resume_apartment_on_threadpool(context.m_context, handle);
102102
}

test/old_tests/UnitTests/apartment_context.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,64 @@ namespace
5656

5757
REQUIRE(is_nta_on_mta());
5858
}
59+
60+
IAsyncAction TestStaToStaApartmentContext()
61+
{
62+
bool pass = false;
63+
64+
apartment_context original;
65+
66+
// Create an STA thread and switch to it.
67+
auto controller1 = DispatcherQueueController::CreateOnDedicatedThread();
68+
co_await resume_foreground(controller1.DispatcherQueue());
69+
70+
// Save the COM context for the first STA thread.
71+
apartment_context context1;
72+
73+
// Create another STA thread and switch to it.
74+
auto controller2 = DispatcherQueueController::CreateOnDedicatedThread();
75+
co_await resume_foreground(controller2.DispatcherQueue());
76+
77+
// The first STA thread remains hung as long as this is true.
78+
bool hang_sta_1 = true;
79+
80+
// Hang the first STA thread.
81+
controller1.DispatcherQueue().TryEnqueue([&] {
82+
bool hang = true;
83+
while (hang_sta_1)
84+
{
85+
if (!WaitOnAddress(&hang_sta_1, &hang, sizeof(hang), 1000))
86+
{
87+
return; // failed - timed out
88+
}
89+
}
90+
pass = true;
91+
});
92+
93+
// Queue work to the second STA thread to unstick the first thread.
94+
// This requires that the second STA thread be available to dispatch work
95+
// after the "co_await context1" below.
96+
controller2.DispatcherQueue().TryEnqueue([&] {
97+
hang_sta_1 = false;
98+
WakeByAddressAll(&hang_sta_1);
99+
});
100+
101+
// Try to switch to the first STA thread via COM context.
102+
// The first STA thread is hung, but once this thread (the second STA thread)
103+
// processes work, it will unstick the first STA thread.
104+
// This test verifies that the second STA thread does become available
105+
// to do work and is not hung waiting for the first STA thread.
106+
co_await context1;
107+
108+
REQUIRE(pass);
109+
110+
// Clean up.
111+
co_await original;
112+
113+
co_await controller1.ShutdownQueueAsync();
114+
co_await controller2.ShutdownQueueAsync();
115+
}
116+
59117
}
60118

61119
TEST_CASE("apartment_context coverage")
@@ -67,3 +125,8 @@ TEST_CASE("apartment_context nta")
67125
{
68126
TestNeutralApartmentContext().get();
69127
}
128+
129+
TEST_CASE("apartment_context sta")
130+
{
131+
TestStaToStaApartmentContext().get();
132+
}

0 commit comments

Comments
 (0)