diff --git a/include/silk/fibers/sequencer.h b/include/silk/fibers/sequencer.h index 39f8278..bc77f2c 100644 --- a/include/silk/fibers/sequencer.h +++ b/include/silk/fibers/sequencer.h @@ -126,6 +126,12 @@ class FiberSequencer return true; } + /** + * Rebase the counter to @p value, up or down. The caller guarantees quiescence: no registered waiter + * and no concurrent increment / advance / wait. + */ + void reset(uint64_t value) noexcept; + /** * Transition into the stopped state and wake every unreached waiter with * ECANCELED. After this, every unreached wait completes with ECANCELED diff --git a/src/fibers/sequencer.cpp b/src/fibers/sequencer.cpp index 0e11e3c..5f2a92d 100644 --- a/src/fibers/sequencer.cpp +++ b/src/fibers/sequencer.cpp @@ -7,6 +7,12 @@ namespace silk { +void FiberSequencer::reset(uint64_t value) noexcept +{ + SILK_ASSERT(waiters.empty()); + counter.store(value, std::memory_order_release); +} + void FiberSequencer::registerWaiter(uint64_t token, Future * future) noexcept { // Slow path: register future in the request queue for the next combiner to process. diff --git a/src/fibers/tests/sequencer-test.cpp b/src/fibers/tests/sequencer-test.cpp index 80ca756..29116df 100644 --- a/src/fibers/tests/sequencer-test.cpp +++ b/src/fibers/tests/sequencer-test.cpp @@ -47,6 +47,31 @@ TEST(FiberSequencer, waitAlreadySatisfied) EXPECT_EQ(sequencer.wait(1), 0); } +TEST(FiberSequencer, resetRebasesBelowCounter) +{ + FiberSequencer sequencer; + bool advanced = sequencer.advance(10); + ASSERT_TRUE(advanced); + + sequencer.reset(3); + ASSERT_EQ(sequencer.get(), 3u); + + // A wait at or below the rebased counter completes immediately. + int r = sequencer.wait(3); + ASSERT_EQ(r, 0); + + // A wait above it parks until advance reaches the token again. + FiberSequencer::Future future; + sequencer.wait(4, &future); + int err; + ASSERT_FALSE(future.isSet(&err)); + + advanced = sequencer.advance(4); + ASSERT_TRUE(advanced); + ASSERT_TRUE(future.isSet(&err)); + ASSERT_EQ(err, 0); +} + TEST(FiberSequencer, stopCancelsUnreachedWaiters) { FiberSequencer sequencer;