Skip to content

Commit fe82394

Browse files
committed
fix(async): avoid double resume in when smoke test
- Replace manual coroutine resume loop with scheduler-driven sync_wait - Prevent double resume between main thread and scheduler thread - Fix segfault in async.when_smoke test
1 parent f2f0d71 commit fe82394

1 file changed

Lines changed: 39 additions & 44 deletions

File tree

tests/core/when_smoke_test.cpp

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
*/
1414
#include <cassert>
1515
#include <chrono>
16+
#include <future>
1617
#include <iostream>
18+
#include <memory>
1719
#include <optional>
1820
#include <thread>
1921
#include <tuple>
@@ -29,7 +31,7 @@ using vix::async::core::task;
2931
using vix::async::core::when_all;
3032
using vix::async::core::when_any;
3133

32-
// Helpers: drive a scheduler loop while awaiting a task
34+
// Helpers: run scheduler loop in background
3335
struct scheduler_runner
3436
{
3537
scheduler &sched;
@@ -50,57 +52,50 @@ struct scheduler_runner
5052
}
5153
};
5254

55+
// sync_wait for task<T> that is scheduler-driven (no manual resume!)
5356
template <typename T>
54-
static T sync_await(task<T> t)
57+
static T sync_wait(scheduler &sched, task<T> t)
5558
{
56-
struct runner
57-
{
58-
task<T> inner;
59-
std::optional<T> value;
59+
auto p = std::make_shared<std::promise<T>>();
60+
auto fut = p->get_future();
6061

61-
task<void> run()
62+
auto wrapper = [p, inner = std::move(t)]() mutable -> task<void>
63+
{
64+
try
6265
{
63-
value = co_await inner;
64-
co_return;
66+
if constexpr (std::is_void_v<T>)
67+
{
68+
co_await inner;
69+
p->set_value();
70+
}
71+
else
72+
{
73+
T v = co_await inner;
74+
p->set_value(std::move(v));
75+
}
6576
}
66-
};
67-
68-
runner r{std::move(t), std::nullopt};
69-
auto top = r.run();
70-
auto h = top.handle();
71-
assert(h);
72-
73-
while (!h.done())
74-
h.resume();
75-
76-
assert(r.value.has_value());
77-
return std::move(*r.value);
78-
}
79-
80-
static void sync_await(task<void> t)
81-
{
82-
struct runner
83-
{
84-
task<void> inner;
85-
86-
task<void> run()
77+
catch (...)
8778
{
88-
co_await inner;
89-
co_return;
79+
p->set_exception(std::current_exception());
9080
}
81+
co_return;
9182
};
9283

93-
runner r{std::move(t)};
94-
auto top = r.run();
95-
auto h = top.handle();
96-
assert(h);
84+
// start wrapper on the scheduler thread
85+
std::move(wrapper()).start(sched);
9786

98-
while (!h.done())
99-
h.resume();
87+
if constexpr (std::is_void_v<T>)
88+
{
89+
fut.get();
90+
return;
91+
}
92+
else
93+
{
94+
return fut.get();
95+
}
10096
}
10197

102-
// when_any compatibility helpers:
103-
// support tuple<optional<T>...> and tuple<T...>
98+
// when_any compatibility helpers
10499
template <typename X>
105100
static bool is_ready(const X &x)
106101
{
@@ -231,10 +226,10 @@ int main()
231226
scheduler sched;
232227
scheduler_runner run{sched};
233228

234-
sync_await(test_when_all_basic(sched));
235-
sync_await(test_when_all_mixed_timing(sched));
236-
sync_await(test_when_any_picks_first(sched));
237-
sync_await(test_when_any_handles_immediate(sched));
229+
sync_wait<void>(sched, test_when_all_basic(sched));
230+
sync_wait<void>(sched, test_when_all_mixed_timing(sched));
231+
sync_wait<void>(sched, test_when_any_picks_first(sched));
232+
sync_wait<void>(sched, test_when_any_handles_immediate(sched));
238233

239234
std::cout << "async_when_smoke: OK\n";
240235
return 0;

0 commit comments

Comments
 (0)