mirror of
https://github.com/XRPLF/rippled.git
synced 2026-03-21 12:12:34 +00:00
Compare commits
1 Commits
develop
...
pratik/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331b4739ae |
@@ -76,7 +76,22 @@ JobQueue::Coro::resume()
|
||||
auto saved = detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(&lvs_);
|
||||
std::lock_guard lock(mutex_);
|
||||
XRPL_ASSERT(static_cast<bool>(coro_), "xrpl::JobQueue::Coro::resume : is runnable");
|
||||
// A late resume() can arrive after the coroutine has already completed.
|
||||
// This is an expected (if rare) outcome of the race condition documented
|
||||
// in JobQueue.h:354-377 where post() schedules a resume job before the
|
||||
// coroutine yields — the mutex serializes access, but by the time this
|
||||
// resume() acquires the lock the coroutine may have already run to
|
||||
// completion. Calling operator() on a completed boost::coroutine2 is
|
||||
// undefined behavior, so we must check and return early.
|
||||
if (!coro_)
|
||||
{
|
||||
detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(saved);
|
||||
std::lock_guard lk(mutex_run_);
|
||||
running_ = false;
|
||||
cv_.notify_all();
|
||||
return;
|
||||
}
|
||||
coro_();
|
||||
detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(saved);
|
||||
|
||||
@@ -99,8 +99,8 @@ public:
|
||||
Effects:
|
||||
The coroutine continues execution from where it last left off
|
||||
using this same thread.
|
||||
Undefined behavior if called after the coroutine has completed
|
||||
with a return (as opposed to a yield()).
|
||||
If the coroutine has already completed, returns immediately
|
||||
(handles the documented post-before-yield race condition).
|
||||
Undefined behavior if resume() or post() called consecutively
|
||||
without a corresponding yield.
|
||||
*/
|
||||
@@ -357,8 +357,9 @@ private:
|
||||
If the post() job were to be executed before yield(), undefined behavior
|
||||
would occur. The lock ensures that coro_ is not called again until we exit
|
||||
the coroutine. At which point a scheduled resume() job waiting on the lock
|
||||
would gain entry, harmlessly call coro_ and immediately return as we have
|
||||
already completed the coroutine.
|
||||
would gain entry. resume() checks if the coroutine has already completed
|
||||
(coro_ converts to false) and returns early if so, since calling operator()
|
||||
on a completed boost::coroutine2 pull_type is undefined behavior.
|
||||
|
||||
The race condition occurs as follows:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user