feat: xce_disable_hook() + _Atomic hook_fn_t + NULL-slot reuse (P1-2a)

- hook_item_t.fn changed to _Atomic hook_fn_t (C11 stdatomic)
- xce_disable_hook(): atomically stores NULL into the slot fn field;
  returns 0 on success, -ENOENT if fn not found, -EINVAL on bad args
- xce_add_hook(): scans for NULL (disabled) slots before allocating;
  uses atomic_store_explicit(release) when writing fn pointer
- xce_run_hooks(): atomic_load_explicit(acquire) + NULL guard so
  disabled slots are silently skipped without disrupting the loop
- Add src/lib/testsuite/test_hooks.c with 3 TDD tests:
  test_disable_hook_stops_invocation
  test_disable_hook_returns_enoent_if_not_found
  test_add_hook_reuses_null_slot
- Register test_hooks in meson.build and test.c runner

Required by ha_demote_to_standby() to atomically disable persistence
hooks when the controller steps down from primary, preventing unbounded
hook list growth across promote/demote cycles (resolution A6-015,
A7-004, A7-016).
This commit is contained in:
Rongsong Shen 2026-05-07 13:55:42 +00:00
parent 89c360f7b5
commit f155b1ef97
5 changed files with 169 additions and 4 deletions

View file

@ -3,6 +3,7 @@
#define __HOOK_H__ 1
#include <stdarg.h>
#include <stdatomic.h>
#include <stddef.h>
#include "xlist.h"
@ -12,8 +13,8 @@
typedef int (*hook_fn_t)(int, int, int, void*, va_list);
typedef struct {
hook_fn_t fn;
void* data;
_Atomic hook_fn_t fn;
void* data;
} hook_item_t;
typedef struct {
@ -23,6 +24,7 @@ typedef struct {
extern int xce_hook_init(hooksys_t*, int);
extern int xce_add_hook(hooksys_t*, int, hook_fn_t, void*);
extern int xce_disable_hook(hooksys_t*, int, hook_fn_t);
extern int xce_run_hooks(hooksys_t*, int, int, int, ...);
extern void xce_hook_fini(hooksys_t*);