I assume you cloned the FTL git repo in a similar way as described on the docs.
I recommend you create a new branch first:
git switch master
git branch --copy v6.7.1-patched
git switch v6.7.1-patched
Due to the history being based on eb0aa5e, a simple git revert eb0aa5e does not suffice.
I created a patchfile that properly un-does the commit and removes the static_assert():
0001-Don-t-require-ATOMIC_BOOL_LOCK_FREE.txt (4.2 KB)
From 09921676e944a9afc3abb3ce9f372cdcba2467f5 Mon Sep 17 00:00:00 2001
From: darkexplosiveqwx <101737077+darkexplosiveqwx@users.noreply.github.com>
Date: Mon, 21 Sep 2026 07:16:40 +0200: [PATCH] Don't require ATOMIC_BOOL_LOCK_FREE
This reverts commit eb0aa5eaa3abedeba61328b0ab7f3600548bc81f.
---
src/events.c | 43 +++++++++++++++++++++++++++++--------------
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/src/events.c b/src/events.c
index 72a7e495..9d8fcf0e 100644
--- a/src/events.c
+++ b/src/events.c
@@ -12,7 +12,7 @@
#include "FTL.h"
// public prototypes
#include "events.h"
-// atomic_exchange()
+// atomic_flag_test_and_set()
#include <stdatomic.h>
// struct config
#include "config/config.h"
@@ -23,11 +23,7 @@
static const char *eventtext(const enum events event);
// Queue containing all possible events
-// An atomic_bool rather than an atomic_flag: a flag cannot be read without
-// setting it. RELOAD_GRAVITY is raised from the SIGRTMIN handler, so the type
-// has to be lock-free for the exchange to be async-signal-safe
-static _Atomic bool eventqueue[EVENTS_MAX];
-static_assert(ATOMIC_BOOL_LOCK_FREE == 2, "Event queue must be lock-free, it is used from a signal handler");
+static volatile atomic_flag eventqueue[EVENTS_MAX] = { ATOMIC_FLAG_INIT };
// Set/Request event
// We set the events atomically to ensure no race collisions can happen. If an
@@ -35,8 +31,10 @@ static_assert(ATOMIC_BOOL_LOCK_FREE == 2, "Event queue must be lock-free, it is
// added multiple times
void _set_event(const enum events event, int line, const char *function, const char *file)
{
- // Set eventqueue bit, learning what it was in the same operation
- const bool is_set = atomic_exchange(&eventqueue[event], true);
+ bool is_set = false;
+ // Set eventqueue bit
+ if(atomic_flag_test_and_set(&eventqueue[event]))
+ is_set = true;
// Possible debug logging
if(config.debug.events.v.b)
@@ -56,17 +54,30 @@ void _set_event(const enum events event, int line, const char *function, const c
// exchange on its own: the event is logged where it is processed anyway
void set_event_from_signal(const enum events event)
{
- atomic_exchange(&eventqueue[event], true);
+ // Set eventqueue bit
+ atomic_flag_test_and_set(&eventqueue[event]);
}
// Get and clear event
-// Read and clear in one exchange, so there is no window in which a producer
-// sees a value the consumer has already taken. Compiles to XCHG on x86_64 and
-// i686, and to the LDAXRB/STLXRB pair on ARM64
+// Unfortunately, we cannot read the value of an atomic_flag without setting it
+// either to true or false. This is by design. Hence, we implement testing by
+// first trying to set the the flag to true. If this "fails", we know the flag
+// has already been set.
+// On x86_64 and i686 CPUs, these atomic instrictions are implemented using the
+// XCHG asm instruction, which simply exchanges the content of two registers or,
+// in this case, a register and a memory location (the respective eventqueue
+// pointer). This is guaranteed to happen atomically by automatically
+// implementing the processor's locking protocol during the operation.
+// On other architecture, similar instructions are used to reassemble the same
+// effect (but typically with a few more instructions). ARM64, for instance,
+// uses LDAXRB (Load-aquire exclusive register byte) and STAXRB (Store-release
+// exclusive register byte) to implement the same thing with a few more
+// instructions.
bool _get_and_clear_event(const enum events event, int line, const char *function, const char *file)
{
- // Read the bit and clear it in the same operation
- const bool is_set = atomic_exchange(&eventqueue[event], false);
+ bool is_set = false;
+ if(atomic_flag_test_and_set(&eventqueue[event]))
+ is_set = true;
// Possible debug logging only for SET status, to avoid log file flooding with NOT SET messages
if(is_set && config.debug.events.v.b)
@@ -75,6 +86,10 @@ bool _get_and_clear_event(const enum events event, int line, const char *functio
eventtext(event), function, file, line);
}
+ // Clear eventqueue bit (we set it above) ...
+ atomic_flag_clear(&eventqueue[event]);
+
+ // ... and return status
return is_set;
}
--
2.53.0
You may try copy and pasting the patch, but you need to be careful with tabs (they may get copied as spaces and then the diff will fail) into 0001-Don-t-require-ATOMIC_BOOL_LOCK_FREE.patch.
Alternatively you can download the file liked above and copy it as 0001-Don-t-require-ATOMIC_BOOL_LOCK_FREE.patch to your Pogoplug.
Then apply the patch:
git am 0001-Don-t-require-ATOMIC_BOOL_LOCK_FREE.patch
For FTL v7 there is another feature planned to require lock-free C11 atomics, but that will be an integral part of the new logger, so reverting it will be difficult.
I’d be interested in the output of the following test program to see what values your system has for the other lock-free test macros:
cat > /tmp/lock-free-c11-test.c <<'EOF'
#include <stdio.h>
#include <stdatomic.h>
int main(void)
{
printf("ATOMIC_BOOL_LOCK_FREE = %d\n", ATOMIC_BOOL_LOCK_FREE);
printf("ATOMIC_CHAR_LOCK_FREE = %d\n", ATOMIC_CHAR_LOCK_FREE);
printf("ATOMIC_CHAR16_T_LOCK_FREE = %d\n", ATOMIC_CHAR16_T_LOCK_FREE);
printf("ATOMIC_CHAR32_T_LOCK_FREE = %d\n", ATOMIC_CHAR32_T_LOCK_FREE);
printf("ATOMIC_WCHAR_T_LOCK_FREE = %d\n", ATOMIC_WCHAR_T_LOCK_FREE);
printf("ATOMIC_SHORT_LOCK_FREE = %d\n", ATOMIC_SHORT_LOCK_FREE);
printf("ATOMIC_INT_LOCK_FREE = %d\n", ATOMIC_INT_LOCK_FREE);
printf("ATOMIC_LONG_LOCK_FREE = %d\n", ATOMIC_LONG_LOCK_FREE);
printf("ATOMIC_LLONG_LOCK_FREE = %d\n", ATOMIC_LLONG_LOCK_FREE);
printf("ATOMIC_POINTER_LOCK_FREE = %d\n", ATOMIC_POINTER_LOCK_FREE);
return 0;
}
EOF
cc -std=c11 -O2 /tmp/lock-free-c11-test.c -o /tmp/lock-free-c11-test
cc -std=c11 -O2 -march=native -mcpu=native /tmp/lock-free-c11-test.c -o /tmp/lock-free-c11-test-native
/tmp/lock-free-c11-test
/tmp/lock-free-c11-test-native
rm -rf /tmp/lock-free-c11-test*