From 74575f2e67938e8f41022b897e9da1f43e400812 Mon Sep 17 00:00:00 2001 From: Vadim Skipin Date: Fri, 24 Jul 2026 18:43:29 +0000 Subject: [PATCH] Add FiberSequencer::reset Rebase the counter to an arbitrary value, up or down, under a caller- guaranteed quiescence contract: no registered waiter (asserted against the waiter tree) and no concurrent operation. advance stays monotone; reset serves callers that re-derive a baseline, like a storage recovery attempt whose durable prefix legitimately regresses. --- include/silk/fibers/sequencer.h | 6 ++++++ src/fibers/sequencer.cpp | 6 ++++++ src/fibers/tests/sequencer-test.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+) 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;