Skip to content

Commit 66886c9

Browse files
Migrate Coroutine_test and JobQueue_test from Boost.Coroutine to C++20 coroutines
Rewrite all test coroutine code to use postCoroTask() and co_await runner->suspend() instead of the old postCoro() / Coro::yield() API: - Coroutine_test: Migrate correct_order, incorrect_order, and thread_specific_storage tests. Replace shared_ptr<JobQueue::Coro> with shared_ptr<JobQueue::CoroTaskRunner>, yield() with co_await runner->suspend(). - JobQueue_test: Rename testPostCoro to testPostCoroTask. Migrate all 3 sub-tests (repeated post, repeated resume, shutdown rejection) to the new API. After this change, zero .cpp files reference postCoro() or JobQueue::Coro. The old API declarations remain in JobQueue.h and Coro.ipp for removal in the cleanup milestone. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 04fe18d commit 66886c9

File tree

2 files changed

+70
-53
lines changed

2 files changed

+70
-53
lines changed

src/test/core/Coroutine_test.cpp

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <test/jtx.h>
22

3+
#include <xrpl/core/CoroTask.h>
34
#include <xrpl/core/JobQueue.h>
45

56
#include <chrono>
@@ -54,13 +55,15 @@ class Coroutine_test : public beast::unit_test::suite
5455
}));
5556

5657
gate g1, g2;
57-
std::shared_ptr<JobQueue::Coro> c;
58-
env.app().getJobQueue().postCoro(jtCLIENT, "CoroTest", [&](auto const& cr) {
59-
c = cr;
60-
g1.signal();
61-
c->yield();
62-
g2.signal();
63-
});
58+
std::shared_ptr<JobQueue::CoroTaskRunner> c;
59+
env.app().getJobQueue().postCoroTask(
60+
jtCLIENT, "CoroTest", [&](auto runner) -> CoroTask<void> {
61+
c = runner;
62+
g1.signal();
63+
co_await runner->suspend();
64+
g2.signal();
65+
co_return;
66+
});
6467
BEAST_EXPECT(g1.wait_for(5s));
6568
c->join();
6669
c->post();
@@ -81,11 +84,17 @@ class Coroutine_test : public beast::unit_test::suite
8184
}));
8285

8386
gate g;
84-
env.app().getJobQueue().postCoro(jtCLIENT, "CoroTest", [&](auto const& c) {
85-
c->post();
86-
c->yield();
87-
g.signal();
88-
});
87+
env.app().getJobQueue().postCoroTask(
88+
jtCLIENT, "CoroTest", [&](auto runner) -> CoroTask<void> {
89+
// Schedule a resume before suspending. The posted job
90+
// cannot actually call resume() until the current resume()
91+
// releases CoroTaskRunner::mutex_, which only happens after
92+
// the coroutine suspends at co_await.
93+
runner->post();
94+
co_await runner->suspend();
95+
g.signal();
96+
co_return;
97+
});
8998
BEAST_EXPECT(g.wait_for(5s));
9099
}
91100

@@ -101,7 +110,7 @@ class Coroutine_test : public beast::unit_test::suite
101110
auto& jq = env.app().getJobQueue();
102111

103112
static int const N = 4;
104-
std::array<std::shared_ptr<JobQueue::Coro>, N> a;
113+
std::array<std::shared_ptr<JobQueue::CoroTaskRunner>, N> a;
105114

106115
LocalValue<int> lv(-1);
107116
BEAST_EXPECT(*lv == -1);
@@ -118,19 +127,21 @@ class Coroutine_test : public beast::unit_test::suite
118127

119128
for (int i = 0; i < N; ++i)
120129
{
121-
jq.postCoro(jtCLIENT, "CoroTest", [&, id = i](auto const& c) {
122-
a[id] = c;
123-
g.signal();
124-
c->yield();
125-
126-
this->BEAST_EXPECT(*lv == -1);
127-
*lv = id;
128-
this->BEAST_EXPECT(*lv == id);
129-
g.signal();
130-
c->yield();
131-
132-
this->BEAST_EXPECT(*lv == id);
133-
});
130+
jq.postCoroTask(
131+
jtCLIENT, "CoroTest", [&, id = i](auto runner) -> CoroTask<void> {
132+
a[id] = runner;
133+
g.signal();
134+
co_await runner->suspend();
135+
136+
this->BEAST_EXPECT(*lv == -1);
137+
*lv = id;
138+
this->BEAST_EXPECT(*lv == id);
139+
g.signal();
140+
co_await runner->suspend();
141+
142+
this->BEAST_EXPECT(*lv == id);
143+
co_return;
144+
});
134145
BEAST_EXPECT(g.wait_for(5s));
135146
a[i]->join();
136147
}

src/test/core/JobQueue_test.cpp

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <test/jtx/Env.h>
22

33
#include <xrpl/beast/unit_test.h>
4+
#include <xrpl/core/CoroTask.h>
45
#include <xrpl/core/JobQueue.h>
56

67
namespace xrpl {
@@ -44,86 +45,91 @@ class JobQueue_test : public beast::unit_test::suite
4445
}
4546

4647
void
47-
testPostCoro()
48+
testPostCoroTask()
4849
{
4950
jtx::Env env{*this};
5051

5152
JobQueue& jQueue = env.app().getJobQueue();
5253
{
53-
// Test repeated post()s until the Coro completes.
54+
// Test repeated post()s until the coroutine completes.
5455
std::atomic<int> yieldCount{0};
55-
auto const coro = jQueue.postCoro(
56+
auto const runner = jQueue.postCoroTask(
5657
jtCLIENT,
5758
"PostCoroTest1",
58-
[&yieldCount](std::shared_ptr<JobQueue::Coro> const& coroCopy) {
59+
[&yieldCount](auto runner) -> CoroTask<void> {
5960
while (++yieldCount < 4)
60-
coroCopy->yield();
61+
co_await runner->suspend();
62+
co_return;
6163
});
62-
BEAST_EXPECT(coro != nullptr);
64+
BEAST_EXPECT(runner != nullptr);
6365

6466
// Wait for the Job to run and yield.
6567
while (yieldCount == 0)
6668
;
6769

68-
// Now re-post until the Coro says it is done.
70+
// Now re-post until the CoroTaskRunner says it is done.
6971
int old = yieldCount;
70-
while (coro->runnable())
72+
while (runner->runnable())
7173
{
72-
BEAST_EXPECT(coro->post());
74+
BEAST_EXPECT(runner->post());
7375
while (old == yieldCount)
7476
{
7577
}
76-
coro->join();
78+
runner->join();
7779
BEAST_EXPECT(++old == yieldCount);
7880
}
7981
BEAST_EXPECT(yieldCount == 4);
8082
}
8183
{
82-
// Test repeated resume()s until the Coro completes.
84+
// Test repeated resume()s until the coroutine completes.
8385
int yieldCount{0};
84-
auto const coro = jQueue.postCoro(
86+
auto const runner = jQueue.postCoroTask(
8587
jtCLIENT,
8688
"PostCoroTest2",
87-
[&yieldCount](std::shared_ptr<JobQueue::Coro> const& coroCopy) {
89+
[&yieldCount](auto runner) -> CoroTask<void> {
8890
while (++yieldCount < 4)
89-
coroCopy->yield();
91+
co_await runner->suspend();
92+
co_return;
9093
});
91-
if (!coro)
94+
if (!runner)
9295
{
93-
// There's no good reason we should not get a Coro, but we
96+
// There's no good reason we should not get a runner, but we
9497
// can't continue without one.
9598
BEAST_EXPECT(false);
9699
return;
97100
}
98101

99102
// Wait for the Job to run and yield.
100-
coro->join();
103+
runner->join();
101104

102-
// Now resume until the Coro says it is done.
105+
// Now resume until the CoroTaskRunner says it is done.
103106
int old = yieldCount;
104-
while (coro->runnable())
107+
while (runner->runnable())
105108
{
106-
coro->resume(); // Resume runs synchronously on this thread.
109+
runner->resume(); // Resume runs synchronously on this thread.
107110
BEAST_EXPECT(++old == yieldCount);
108111
}
109112
BEAST_EXPECT(yieldCount == 4);
110113
}
111114
{
112115
// If the JobQueue is stopped, we should no
113-
// longer be able to add a Coro (and calling postCoro() should
114-
// return false).
116+
// longer be able to post a coroutine (and calling postCoroTask()
117+
// should return nullptr).
115118
using namespace std::chrono_literals;
116119
jQueue.stop();
117120

118-
// The Coro should never run, so having the Coro access this
121+
// The coroutine should never run, so having it access this
119122
// unprotected variable on the stack should be completely safe.
120123
// Not recommended for the faint of heart...
121124
bool unprotected;
122-
auto const coro = jQueue.postCoro(
123-
jtCLIENT, "PostCoroTest3", [&unprotected](std::shared_ptr<JobQueue::Coro> const&) {
125+
auto const runner = jQueue.postCoroTask(
126+
jtCLIENT,
127+
"PostCoroTest3",
128+
[&unprotected](auto) -> CoroTask<void> {
124129
unprotected = false;
130+
co_return;
125131
});
126-
BEAST_EXPECT(coro == nullptr);
132+
BEAST_EXPECT(runner == nullptr);
127133
}
128134
}
129135

@@ -132,7 +138,7 @@ class JobQueue_test : public beast::unit_test::suite
132138
run() override
133139
{
134140
testAddJob();
135-
testPostCoro();
141+
testPostCoroTask();
136142
}
137143
};
138144

0 commit comments

Comments
 (0)