Merge branch 'pratik/std-coro/cleanup-boost-coroutine' into pratik/std-coro/tsan-fixes

# Conflicts:
#	include/xrpl/core/JobQueue.h
This commit is contained in:
Pratik Mankawde
2026-07-27 11:31:31 +01:00
5 changed files with 63 additions and 28 deletions

View File

@@ -152,6 +152,10 @@ template <>
class CoroTask<void>
{
public:
// The C++ coroutine protocol mandates these names (promise_type,
// initial_suspend, await_ready, ...) and instance-callable awaiter
// methods, which conflict with the project naming/static conventions.
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
struct promise_type;
using Handle = std::coroutine_handle<promise_type>;
@@ -260,6 +264,7 @@ public:
exception_ = std::current_exception();
}
};
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
/**
* Default constructor. Creates an empty (null handle) task.
@@ -313,7 +318,7 @@ public:
/**
* @return The underlying coroutine_handle
*/
Handle
[[nodiscard]] Handle
handle() const
{
return handle_;
@@ -322,7 +327,7 @@ public:
/**
* @return true if the coroutine has run to completion (or thrown)
*/
bool
[[nodiscard]] bool
done() const
{
return handle_ && handle_.done();
@@ -334,7 +339,8 @@ public:
* Always false. This task is lazy, so co_await always suspends
* the caller to set up the continuation link.
*/
bool
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
[[nodiscard]] bool
await_ready() const noexcept
{
return false;
@@ -368,6 +374,7 @@ public:
if (auto& ep = handle_.promise().exception_)
std::rethrow_exception(ep);
}
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
private:
// Exclusively-owned coroutine handle. Null after move or default
@@ -477,6 +484,10 @@ class CoroTask
"CoroTask<T> requires T to be move-constructible");
public:
// The C++ coroutine protocol mandates these names (promise_type,
// initial_suspend, await_ready, ...) and instance-callable awaiter
// methods, which conflict with the project naming/static conventions.
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
struct promise_type;
using Handle = std::coroutine_handle<promise_type>;
@@ -578,6 +589,7 @@ public:
result_.template emplace<2>(std::current_exception());
}
};
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
/**
* Default constructor. Creates an empty (null handle) task.
@@ -631,7 +643,7 @@ public:
/**
* @return The underlying coroutine_handle
*/
Handle
[[nodiscard]] Handle
handle() const
{
return handle_;
@@ -640,7 +652,7 @@ public:
/**
* @return true if the coroutine has run to completion (or thrown)
*/
bool
[[nodiscard]] bool
done() const
{
return handle_ && handle_.done();
@@ -651,7 +663,8 @@ public:
/**
* Always false. co_await always suspends to set up continuation.
*/
bool
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
[[nodiscard]] bool
await_ready() const noexcept
{
return false;
@@ -689,6 +702,7 @@ public:
std::rethrow_exception(*ep);
return std::get<1>(std::move(result));
}
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
private:
// Exclusively-owned coroutine handle. Null after move or default

View File

@@ -93,8 +93,8 @@ inline JobQueue::CoroTaskRunner::CoroTaskRunner(
CreateT,
JobQueue& jq,
JobType type,
std::string const& name)
: jq_(jq), type_(type), name_(name), runCount_(0)
std::string name)
: jq_(jq), type_(type), name_(std::move(name))
{
}
@@ -147,7 +147,7 @@ inline JobQueue::CoroTaskRunner::~CoroTaskRunner()
inline void
JobQueue::CoroTaskRunner::onSuspend()
{
std::lock_guard lock(jq_.mutex_);
std::scoped_lock const lock(jq_.mutex_);
++jq_.nSuspend_;
}
@@ -157,7 +157,7 @@ JobQueue::CoroTaskRunner::onSuspend()
inline void
JobQueue::CoroTaskRunner::onUndoSuspend()
{
std::lock_guard lock(jq_.mutex_);
std::scoped_lock const lock(jq_.mutex_);
--jq_.nSuspend_;
}
@@ -175,6 +175,10 @@ JobQueue::CoroTaskRunner::suspend()
* Custom awaiter for suspend(). Always suspends (await_ready
* returns false) and increments nSuspend_ in await_suspend().
*/
// The C++ coroutine protocol mandates these awaiter names and
// instance-callable methods, which conflict with the project
// naming/static conventions.
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
struct SuspendAwaiter
{
CoroTaskRunner& runner_; // The runner that owns this coroutine.
@@ -182,7 +186,7 @@ JobQueue::CoroTaskRunner::suspend()
/**
* Always returns false so the coroutine suspends.
*/
bool
[[nodiscard]] bool
await_ready() const noexcept
{
return false;
@@ -203,6 +207,7 @@ JobQueue::CoroTaskRunner::suspend()
{
}
};
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
return SuspendAwaiter{*this};
}
@@ -220,11 +225,15 @@ JobQueue::CoroTaskRunner::suspend()
inline auto
JobQueue::CoroTaskRunner::yieldAndPost()
{
// The C++ coroutine protocol mandates these awaiter names and
// instance-callable methods, which conflict with the project
// naming/static conventions.
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
struct YieldPostAwaiter
{
CoroTaskRunner& runner_;
bool
[[nodiscard]] bool
await_ready() const noexcept
{
return false;
@@ -266,6 +275,7 @@ JobQueue::CoroTaskRunner::yieldAndPost()
{
}
};
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
return YieldPostAwaiter{*this};
}
@@ -280,7 +290,7 @@ inline bool
JobQueue::CoroTaskRunner::post()
{
{
std::lock_guard lk(mutexRun_);
std::scoped_lock const lk(mutexRun_);
++runCount_;
}
@@ -291,7 +301,7 @@ JobQueue::CoroTaskRunner::post()
}
// The coroutine will not run. Undo the runCount_ increment.
std::lock_guard lk(mutexRun_);
std::scoped_lock const lk(mutexRun_);
--runCount_;
cv_.notify_all();
return false;
@@ -316,12 +326,12 @@ inline void
JobQueue::CoroTaskRunner::resume()
{
{
std::lock_guard lock(jq_.mutex_);
std::scoped_lock const lock(jq_.mutex_);
--jq_.nSuspend_;
}
auto saved = detail::getLocalValues().release();
detail::getLocalValues().reset(&lvs_);
std::lock_guard lock(mutex_);
std::scoped_lock const lock(mutex_);
XRPL_ASSERT(
task_.handle() && !task_.done(),
"xrpl::JobQueue::CoroTaskRunner::resume : task handle is valid and not done");
@@ -374,7 +384,7 @@ JobQueue::CoroTaskRunner::resume()
// frame destruction triggers runner cleanup.
[[maybe_unused]] auto completed = std::move(task_);
}
std::lock_guard lk(mutexRun_);
std::scoped_lock const lk(mutexRun_);
--runCount_;
cv_.notify_all();
}
@@ -402,7 +412,7 @@ JobQueue::CoroTaskRunner::expectEarlyExit()
{
if (!finished_.load(std::memory_order_acquire))
{
std::lock_guard lock(jq_.mutex_);
std::scoped_lock const lock(jq_.mutex_);
--jq_.nSuspend_;
finished_.store(true, std::memory_order_release);
}

View File

@@ -16,7 +16,6 @@
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <coroutine>
#include <cstdint>
#include <functional>
#include <map>
@@ -266,7 +265,7 @@ public:
// enqueuing a second resume while the first is still running.
// A bool would be clobbered: R2.post() sets true, then R1's
// cleanup sets false — losing the fact that R2 is still pending.
int runCount_;
int runCount_ = 0;
// Serializes all coroutine resume() calls, preventing concurrent
// execution of the coroutine body on multiple threads. Handles the
@@ -346,7 +345,7 @@ public:
* @param type Job type for scheduling priority
* @param name Human-readable name for logging
*/
CoroTaskRunner(CreateT, JobQueue&, JobType, std::string const&);
CoroTaskRunner(CreateT, JobQueue&, JobType, std::string);
CoroTaskRunner(CoroTaskRunner const&) = delete;
CoroTaskRunner&
@@ -744,7 +743,7 @@ JobQueue::postCoroTask(JobType t, std::string const& name, F&& f)
// true between the check and the increment, leaving an orphan nSuspend_
// that causes stop() to hang.
{
std::lock_guard lock(mutex_);
std::scoped_lock const lock(mutex_);
if (stopping_)
return nullptr;
++nSuspend_;

View File

@@ -1,5 +1,6 @@
#pragma once
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/JobQueue.h>
#include <coroutine>
@@ -154,7 +155,11 @@ struct JobQueueAwaiter
/**
* Always returns false so the coroutine suspends.
*/
bool
// The C++ coroutine protocol mandates these awaiter names and
// instance-callable methods, which conflict with the project
// naming/static conventions.
// NOLINTBEGIN(readability-identifier-naming, readability-convert-member-functions-to-static)
[[nodiscard]] bool
await_ready() const noexcept
{
return false;
@@ -201,6 +206,7 @@ struct JobQueueAwaiter
await_resume() const noexcept
{
}
// NOLINTEND(readability-identifier-naming, readability-convert-member-functions-to-static)
};
} // namespace xrpl