Skip to content

Commit c34c31a

Browse files
committed
Try making async_propagate_cancel test more debuggable
1 parent 4b8b455 commit c34c31a

File tree

1 file changed

+44
-19
lines changed

1 file changed

+44
-19
lines changed

test/test/async_propagate_cancel.cpp

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace
99
// Checks that cancellation propagation works.
1010
//
1111

12-
IAsyncAction Action()
12+
IAsyncAction Action(handle* wait)
1313
{
1414
// Do an extra co_await before the resume_on_signal
1515
// so that there is a race window where we can try to cancel
@@ -18,11 +18,12 @@ namespace
1818

1919
auto cancel = co_await get_cancellation_token();
2020
cancel.enable_propagation();
21+
SetEvent(wait->get());
2122
co_await resume_on_signal(GetCurrentProcess()); // never wakes
2223
REQUIRE(false);
2324
}
2425

25-
IAsyncActionWithProgress<int> ActionWithProgress()
26+
IAsyncActionWithProgress<int> ActionWithProgress(handle* wait)
2627
{
2728
// Do an extra co_await before the resume_on_signal
2829
// so that there is a race window where we can try to cancel
@@ -31,11 +32,12 @@ namespace
3132

3233
auto cancel = co_await get_cancellation_token();
3334
cancel.enable_propagation();
35+
SetEvent(wait->get());
3436
co_await resume_on_signal(GetCurrentProcess()); // never wakes
3537
REQUIRE(false);
3638
}
3739

38-
IAsyncOperation<int> Operation()
40+
IAsyncOperation<int> Operation(handle* wait)
3941
{
4042
// Do an extra co_await before the resume_on_signal
4143
// so that there is a race window where we can try to cancel
@@ -44,12 +46,13 @@ namespace
4446

4547
auto cancel = co_await get_cancellation_token();
4648
cancel.enable_propagation();
49+
SetEvent(wait->get());
4750
co_await resume_on_signal(GetCurrentProcess()); // never wakes
4851
REQUIRE(false);
4952
co_return 1;
5053
}
5154

52-
IAsyncOperationWithProgress<int, int> OperationWithProgress()
55+
IAsyncOperationWithProgress<int, int> OperationWithProgress(handle* wait)
5356
{
5457
// Do an extra co_await before the resume_on_signal
5558
// so that there is a race window where we can try to cancel
@@ -58,13 +61,14 @@ namespace
5861

5962
auto cancel = co_await get_cancellation_token();
6063
cancel.enable_propagation();
64+
SetEvent(wait->get());
6165
co_await resume_on_signal(GetCurrentProcess()); // never wakes
6266
REQUIRE(false);
6367
co_return 1;
6468
}
6569

6670
// Checking cancellation propagation for resume_after.
67-
IAsyncAction DelayAction()
71+
IAsyncAction DelayAction(handle* wait)
6872
{
6973
// Do an extra co_await before the resume_on_signal
7074
// so that there is a race window where we can try to cancel
@@ -73,6 +77,7 @@ namespace
7377

7478
auto cancel = co_await get_cancellation_token();
7579
cancel.enable_propagation();
80+
SetEvent(wait->get());
7681
co_await resume_after(std::chrono::hours(1)); // effectively sleep forever
7782
REQUIRE(false);
7883
}
@@ -83,7 +88,7 @@ namespace
8388
// carried all the way down, and also lets us verify (via
8489
// manual debugging) the deep cancellation doesn't cause us to
8590
// blow up the stack on deeply nested cancellation.
86-
IAsyncAction ActionAction(int depth)
91+
IAsyncAction ActionAction(handle* wait, int depth)
8792
{
8893
// Do an extra co_await before the resume_on_signal
8994
// so that there is a race window where we can try to cancel
@@ -94,20 +99,21 @@ namespace
9499
cancel.enable_propagation();
95100
if (depth > 0)
96101
{
97-
co_await ActionAction(depth - 1);
102+
co_await ActionAction(wait, depth - 1);
98103
}
99104
else
100105
{
101-
co_await Action();
106+
co_await Action(wait);
102107
}
103108
REQUIRE(false);
104109
}
105110

106111
template <typename F>
107-
void Check(F make)
112+
void Check(F make, bool should_wait)
108113
{
109114
handle completed{ CreateEvent(nullptr, true, false, nullptr) };
110-
auto async = make();
115+
handle wait{ CreateEvent(nullptr, true, false, nullptr) };
116+
auto async = make(&wait);
111117
REQUIRE(async.Status() == AsyncStatus::Started);
112118

113119
async.Completed([&](auto&& sender, AsyncStatus status)
@@ -117,28 +123,47 @@ namespace
117123
SetEvent(completed.get());
118124
});
119125

126+
if (should_wait)
127+
{
128+
REQUIRE(WaitForSingleObject(wait.get(), IsDebuggerPresent() ? INFINITE : 2000) == WAIT_OBJECT_0);
129+
}
120130
async.Cancel();
121131

122132
// Wait indefinitely if a debugger is present, to make it easier to debug this test.
123-
REQUIRE(WaitForSingleObject(completed.get(), IsDebuggerPresent() ? INFINITE : 1000) == WAIT_OBJECT_0);
133+
REQUIRE(WaitForSingleObject(completed.get(), IsDebuggerPresent() ? INFINITE : 2000) == WAIT_OBJECT_0);
124134

125135
REQUIRE(async.Status() == AsyncStatus::Canceled);
126136
REQUIRE(async.ErrorCode() == HRESULT_FROM_WIN32(ERROR_CANCELLED));
127137
REQUIRE_THROWS_AS(async.GetResults(), hresult_canceled);
128138
}
139+
140+
struct wait_t
141+
{
142+
static constexpr bool value = true;
143+
};
144+
145+
struct no_wait_t
146+
{
147+
static constexpr bool value = false;
148+
};
129149
}
130150

131151
#if defined(__clang__) && defined(_MSC_VER)
132152
// FIXME: Test is known to segfault when built with Clang.
133-
TEST_CASE("async_propagate_cancel", "[.clang-crash]")
153+
TEMPLATE_TEST_CASE("async_propagate_cancel", "[.clang-crash]", wait_t, no_wait_t)
134154
#else
135-
TEST_CASE("async_propagate_cancel")
155+
TEMPLATE_TEST_CASE("async_propagate_cancel", "", wait_t, no_wait_t)
136156
#endif
137157
{
138-
Check(Action);
139-
Check(ActionWithProgress);
140-
Check(Operation);
141-
Check(OperationWithProgress);
142-
Check(DelayAction);
143-
Check([] { return ActionAction(10); });
158+
#define CHECK_CASE(a) \
159+
SECTION("CHECK_CASE(" #a ")") { \
160+
Check(a, TestType::value); \
161+
}
162+
163+
CHECK_CASE(Action);
164+
CHECK_CASE(ActionWithProgress);
165+
CHECK_CASE(Operation);
166+
CHECK_CASE(OperationWithProgress);
167+
CHECK_CASE(DelayAction);
168+
CHECK_CASE([](handle* wait) { return ActionAction(wait, 10); });
144169
}

0 commit comments

Comments
 (0)