From 3ac76c00207c2d9fca46e067c1d11a6a8af4b849 Mon Sep 17 00:00:00 2001
From: Florian Fischer <florian.fischer@muhq.space>
Date: Sun, 4 Sep 2022 17:06:20 +0200
Subject: [PATCH] AbstractIoSleepStrategy: remove erroneous assertion

In my master's thesis, I described in listing 4.4 an io_uring-based
suspension and notification algorithm, which is slightly different from
what emper does.

The described algorithm does not reset the sleep state if a worker
skips sleeping because of a global sleeper count of less than 0 (line 21).

Emper does always reset the sleep state to SleeperState::Running if
the sleep method returned early (either the worker was specifically
notified or the global sleep count indicated to skip the sleep attempt).

Both variants are sound, but invariably resetting the sleeper count to
running minimizes the windows of useless specific notifications.

However, the assertion in onNewWorkNotification assumes the sleep state
is always SleeperState::Notified if a specific notification is received
through the worker's io_uring.

Emper, resetting the sleep state, introduces a race between the notifier
observing the state as sleeping, setting it to notified, and posting a
notification to the potential sleeper's io_uring.
But the sleeper skips the sleep attempt because the global sleeper count
righteously resetting its state to running while invalidating the
assertion.

Therefore we remove the assertion because it is not invariant.
---
 emper/sleep_strategy/AbstractIoSleepStrategy.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/emper/sleep_strategy/AbstractIoSleepStrategy.cpp b/emper/sleep_strategy/AbstractIoSleepStrategy.cpp
index 188fb696..6eae8bdc 100644
--- a/emper/sleep_strategy/AbstractIoSleepStrategy.cpp
+++ b/emper/sleep_strategy/AbstractIoSleepStrategy.cpp
@@ -123,16 +123,13 @@ void AbstractIoSleepStrategy::onNewWorkNotification(IoContext& io,
 
 	if (data.isMarked()) {
 		LOGD("Got specific notification");
-
-		ATTR_UNUSED auto oldState =
-				sleepState.exchange(SleeperState::Running, std::memory_order_release);
-		assert(oldState == SleeperState::Notified);
 	} else {
 		LOGD("Got new work notification");
-		sleepState.store(SleeperState::Running, std::memory_order_release);
 		// Reset global flag to indicate that a new sleep cqe must be prepared
 		readingGlobal = false;
 	}
+
+	sleepState.store(SleeperState::Running, std::memory_order_release);
 }
 
 template void AbstractIoSleepStrategy::onNewWorkNotification<CallerEnvironment::OWNER>(
-- 
GitLab