On Wed, Jul 23, 2025, at 09:42, Joel Jacobson wrote: > Great work in this thread. I'll try to help, definitively benchmarking, > but will also try to load the new design into my brain, to get the > correct mental model of it, so I can hopefully help with code review as > well.
First, my apologies for joining this long-running discussion late. Following up on my email in the "Optimize LISTEN/NOTIFY" thread [1], I wanted to elaborate on the architectural pattern my patches demonstrate, as I believe it's highly complementary to the work being done here. The fundamental distinction is between decoupled vs. combined state management. The v7 patch set creates a new Interrupt system where the wakeup mechanism and the 'pending' state for all subsystems are combined into a single, centralized atomic bitmask. My work explores an alternative: decoupling the two. The insight is that many of our legacy subsystems were designed to be stateless because they lacked the atomics and WaitEventSet abstractions we have today. The signal was a workaround for this state management limitation. This suggests a powerful, three-step migration pattern: Step 1: Decouple state management with a lock-free atomic FSM. Each subsystem should be empowered to manage its own state. My first patch for async.c [1] demonstrates this by introducing a lock-free, atomic finite state machine (FSM). Using a subsystem-specific atomic integer and CAS operations, async.c now robustly manages its own IDLE, SIGNALLED, PROCESSING states without any locks. This solves the state synchronization problem directly and eliminates the vast majority of redundant wakeups. Step 2: Trivialize the wake-up with a generic poke. Once state is managed reliably, the expensive kill(pid, SIGUSR1) syscall can be trivially replaced with a direct SetLatch, as shown in my second patch [1]. This is a simple and effective intermediate step that leverages the existing WaitEventSet infrastructure to make the wakeup much cheaper. Step 3: Decouple event dispatch with specific interrupts. The final goal is to replace the generic poke with SendInterrupt using a specific reason (e.g., INTERRUPT_ASYNC_NOTIFY). This lets the event loop wait on a bitmask of interrupt reasons and, on wakeup, dispatch only to the relevant subsystem handler—fully decoupling event handling from subsystem details. This three-step, vertical migration strategy (subsystem by subsystem) seems to offer a powerful alternative to a horizontal, layer-by-layer replacement. It allows each subsystem's logic to be self-contained and avoids constraints on a single global interrupt mask. The core WaitEventSet is kept simple: its only job is to provide the efficient, multiplexed wait. I believe the ideal architecture uses your unified Interrupt system as the low-level primitive, while encouraging key subsystems to adopt these decoupled FSMs to determine *when* to call SendInterrupt. I'm happy to help with this effort in any way I can. /Joel [1] https://www.postgresql.org/message-id/0b4d402a-9ac2-4aa8-acf8-8231dbe579ea%40app.fastmail.com