-
Notifications
You must be signed in to change notification settings - Fork 184
/
Copy pathasync_scope.cpp
122 lines (103 loc) · 3.61 KB
/
async_scope.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "../../relacy/relacy_std.hpp"
#include "../../relacy/relacy_cli.hpp"
#include <stdexec/execution.hpp>
#include <exec/async_scope.hpp>
#include <exec/static_thread_pool.hpp>
#include <exec/single_thread_context.hpp>
#include <optional>
#include <stdexcept>
using rl::nvar;
using rl::nvolatile;
using rl::mutex;
namespace ex = stdexec;
using exec::async_scope;
struct drop_async_scope_future : rl::test_suite<drop_async_scope_future, 1> {
static size_t const dynamic_thread_count = 1;
void thread(unsigned) {
exec::single_thread_context ctx;
ex::scheduler auto sch = ctx.get_scheduler();
exec::async_scope scope;
std::atomic_bool produced{false};
ex::sender auto begin = ex::schedule(sch);
{
ex::sender auto ftr =
scope.spawn_future(begin | stdexec::then([&]() { produced.store(true); }));
(void) ftr;
}
stdexec::sync_wait(scope.on_empty() | stdexec::then([&]() { RL_ASSERT(produced.load()); }));
}
};
struct attach_async_scope_future : rl::test_suite<attach_async_scope_future, 1> {
static size_t const dynamic_thread_count = 1;
void thread(unsigned) {
exec::single_thread_context ctx;
ex::scheduler auto sch = ctx.get_scheduler();
exec::async_scope scope;
std::atomic_bool produced{false};
ex::sender auto begin = ex::schedule(sch);
ex::sender auto ftr =
scope.spawn_future(begin | stdexec::then([&]() { produced.store(true); }));
ex::sender auto ftr_then = std::move(ftr) | stdexec::then([&] { RL_ASSERT(produced.load()); });
stdexec::sync_wait(stdexec::when_all(scope.on_empty(), std::move(ftr_then)));
}
};
struct async_scope_future_set_result : rl::test_suite<async_scope_future_set_result, 1> {
static size_t const dynamic_thread_count = 1;
void thread(unsigned) {
struct throwing_copy {
throwing_copy() = default;
throwing_copy(const throwing_copy&) {
throw std::logic_error("");
}
};
exec::single_thread_context ctx;
ex::scheduler auto sch = ctx.get_scheduler();
exec::async_scope scope;
ex::sender auto begin = ex::schedule(sch);
ex::sender auto ftr = scope.spawn_future(begin | stdexec::then([] { return throwing_copy(); }));
bool threw = false;
try {
stdexec::sync_wait(std::move(ftr));
RL_ASSERT(false);
} catch (const std::logic_error&) {
threw = true;
}
RL_ASSERT(threw);
stdexec::sync_wait(scope.on_empty());
}
};
template <int test_case>
struct async_scope_request_stop : rl::test_suite<async_scope_request_stop<test_case>, 1> {
static size_t const dynamic_thread_count = 1;
void thread(unsigned) {
exec::single_thread_context ctx;
ex::scheduler auto sch = ctx.get_scheduler();
if constexpr (test_case == 0) {
exec::async_scope scope;
ex::sender auto begin = ex::schedule(sch);
ex::sender auto ftr = scope.spawn_future(scope.spawn_future(begin));
scope.request_stop();
stdexec::sync_wait(ex::when_all(scope.on_empty(), std::move(ftr)));
} else {
exec::async_scope scope;
ex::sender auto begin = ex::schedule(sch);
{
// Drop the future on the floor
ex::sender auto ftr = scope.spawn_future(scope.spawn_future(begin));
}
scope.request_stop();
stdexec::sync_wait(scope.on_empty());
}
}
};
auto main() -> int {
rl::test_params p;
p.iteration_count = 100000;
p.execution_depth_limit = 10000;
rl::simulate<drop_async_scope_future>(p);
rl::simulate<attach_async_scope_future>(p);
rl::simulate<async_scope_future_set_result>(p);
rl::simulate<async_scope_request_stop<0>>(p);
rl::simulate<async_scope_request_stop<1>>(p);
return 0;
}