Subject: [RFC] Lock-free atomic handler dispatch for runtime reconfiguration To: linux-rt@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- Hello, I am writing to share a pattern I discovered while building single-producer/single-consumer (SPSC) ring buffers for low-latency systems. Over the past 18 months of learning C, I have developed a lock-free mechanism for hot-swapping function pointers at runtime using atomic operations with C11 acquire-release semantics. **Background:** I have approximately 1.5 years of hands-on C experience and about 15,000 lines of production code. The first 10,000 lines focused heavily on understanding pointers. This atomic dispatch pattern emerged over 8 months of iterative development. I recognize the kernel community brings deep expertise, and I approach this with appropriate humility. **Note on presentation:** I am dyslexic and ambidextrous and I use Ai assistive tools for grammar and clarity, but all technical content and pattern discovery are entirely my own work. --- ## My Problem In real-time systems with strict latency budgets, it is common to need runtime reconfiguration without stopping the world or coordinating threads. Examples include: - Toggling audit/metrics export on and off - Swapping diagnostic callbacks without restart - Hot-swapping print functions for different output formats - Changing processing strategies at runtime based on control-plane signals Existing approaches have trade-offs: - **Locks** introduce coordination overhead and potential contention - **Callback tables** require index management and potentially CAS loops - **Jump labels** provide compile-time flexibility only - **Full restart** requires stopping the system I needed a pattern that was lock-free, runtime-reconfigurable, and required zero coordination overhead. --- ## My Solution: Atomic Function Dispatch The core idea is simple: store a function pointer in shared memory and update it atomically using C11 acquire-release semantics. The producer publishes a new handler; the consumer loads it with the guarantee that all prior writes are visible. ```c /* Producer: hot-swap a new handler */ void Control_room_CheckOff_Switch(void (*fn)(const StringRegistry *)) { atomic_store_explicit( (_Atomic(void (**)(const StringRegistry *))) &CR.size, fn, memory_order_release ); } /* Consumer: load and invoke safely */ void (*current_handler)(const StringRegistry *) = atomic_load_explicit( (_Atomic(void (*)(const StringRegistry *))) &CR.size, memory_order_acquire ); if (current_handler) { current_handler(®istry); } ``` The acquire-release pair ensures: - Producer releases: "All prior writes are complete and visible." - Consumer acquires: "I see all prior writes and the new handler safely." --- ## Performance Characteristics | Attribute | Measurement | |-----------|------------| | **Latency** | ~8-12 CPU cycles (~15-20 ns on x86-64) | | **Jitter** | Zero — fixed, deterministic latency | | **Lock-Free** | Yes — single atomic store/load, no loops or coordination | | **Coordination Overhead** | None — no locks, CAS loops, or kernel interaction | This pattern occupies a middle ground: - Near jump_label speed (3-5 cycles, but compile-time only) - Full runtime flexibility (any function, any time) - Zero stop-the-world pauses - Predictable, bounded latency --- ## Real-World Usage In production SPSC ring buffers, this enables control-plane hot-swaps: ```c void ControlRoom_swap_audit(struct ControlRoom *cr, void (*new_fn)(const struct ControlRoom *)) { atomic_store_explicit(&cr->audit_fn, new_fn, memory_order_release); } void ControlRoom_swap_metrics(struct ControlRoom *cr, void (*new_fn)(const struct ControlRoom *)) { atomic_store_explicit(&cr->push_metrics_fn, new_fn, memory_order_release); } ``` Each swap is instantaneous and visible to all consumers with no coordination. This is essential for real-time control in low-latency systems. --- ## Why Share This I studied the Linux kernel extensively while learning systems programming. The kernel's latency discipline and careful use of memory ordering were my primary teachers. Similar structures exist in `kernel/jump_label.c` and `kernel/events/ring_buffer.c`, and I wanted to validate my approach against existing kernel patterns. I do not claim this pattern is novel in the kernel context. But I discovered it independently through first-principles thinking about atomic operations, and it has proven invaluable in practice. I hope this submission demonstrates that careful study of kernel patterns, combined with first-principles reasoning about memory ordering, can lead to useful code even for newcomers to C. --- ## Limitations 1. **Specific to atomic function pointers** — not for larger structures 2. **Not a replacement for callback tables** — if I need index-based dispatch, a callback table may be more appropriate 3. **Still testing latency measurements** — I am validating the 8-12 cycle estimate with hardware performance counters --- ## Questions for the Community I welcome feedback on: - Memory ordering correctness across architectures - Whether this pattern solves a problem the kernel cares about - Suggestions for production-grade validation - Any gotchas or limitations I may have missed --- ## Conclusion The Atomic Function Dispatch pattern is a lock-free, zero-overhead mechanism for hot-swapping function pointers at runtime. I am grateful for the opportunity to share this work and welcome corrections or questions from the community. Best regards, David --- **Appendix: RFC Document** For detailed technical breakdown, wire diagrams, and integration examples, please refer to the attached RFC document. David dseda1@aol.com ### Appendix: Wire Diagram ``` ┌──────────────────────────────────────────────────┐ │ CALLER │ │ void new_handler(const StringRegistry *r) {...} │ │ Control_room_CheckOff_Switch(new_handler); │ │ │ │ │ ▼ │ │ (*fn) = signal │ │ │ │ └───────────────────┼──────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────┐ │ ATOMIC STORE (The Wire) │ │ atomic_store_explicit( │ │ &cr->handler_fn, │ │ fn, │ │ memory_order_release) │ │ │ │ └───────────────────┼──────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────┐ │ SHARED MEMORY (The Terminal) │ │ cr->handler_fn now points to: new_handler │ │ │ │ All prior writes are visible to consumers │ │ │ │ └───────────────────┼──────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────┐ │ CONSUMER │ │ void (*h)(...) = atomic_load_explicit( │ │ &cr->handler_fn, memory_order_acquire) │ │ │ │ Safe to invoke; all prior writes visible │ │ h(®istry); │ └──────────────────────────────────────────────────┘ ```