From adc2b863db3a29068928cc2045ed12d3348803ad Mon Sep 17 00:00:00 2001 From: Dmitry Fomin Date: Wed, 9 Sep 2026 15:11:15 +0000 Subject: [PATCH v7 1/2] Add begin/end hooks for timed wait events Add guarded begin and end hooks for explicitly instrumented wait sites so an extension can measure selected waits without changing the ordinary reporting path. Discussion: https://postgr.es/m/CAPHG-0mAOn05ae6Kqx1wHXxzOk4E5W7ajjd=QBhgkR7a0uyQmw@mail.gmail.com --- src/backend/utils/activity/wait_event.c | 4 ++ src/include/utils/wait_event.h | 59 +++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c index e36a740a888..34c8dc46ef4 100644 --- a/src/backend/utils/activity/wait_event.c +++ b/src/backend/utils/activity/wait_event.c @@ -40,6 +40,10 @@ static const char *pgstat_get_wait_io(WaitEventIO w); static uint32 local_my_wait_event_info; uint32 *my_wait_event_info = &local_my_wait_event_info; +wait_event_hook_type wait_event_begin_hook = NULL; +wait_event_hook_type wait_event_end_hook = NULL; +int wait_event_hook_depth = 0; + #define WAIT_EVENT_CLASS_MASK 0xFF000000 #define WAIT_EVENT_ID_MASK 0x0000FFFF diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h index 86ee348220d..ef8b68f2019 100644 --- a/src/include/utils/wait_event.h +++ b/src/include/utils/wait_event.h @@ -17,11 +17,50 @@ extern const char *pgstat_get_wait_event(uint32 wait_event_info); extern const char *pgstat_get_wait_event_type(uint32 wait_event_info); static inline void pgstat_report_wait_start(uint32 wait_event_info); static inline void pgstat_report_wait_end(void); +static inline void pgstat_report_wait_start_timed(uint32 wait_event_info); +static inline void pgstat_report_wait_end_timed(void); extern void pgstat_set_wait_event_storage(uint32 *wait_event_info); extern void pgstat_reset_wait_event_storage(void); extern PGDLLIMPORT uint32 *my_wait_event_info; +/* + * Hooks for explicitly instrumented waits. Hook implementations may use + * only preallocated backend-local state; they must not wait, allocate memory, + * acquire locks, or report errors. The depth guard prevents re-entry. + * + * Hook users that chain callbacks must save the previous hook pointers, call + * the previous begin hook before their own begin work, and perform their own + * end work before calling the previous end hook. + */ +typedef void (*wait_event_hook_type) (uint32 wait_event_info); + +extern PGDLLIMPORT wait_event_hook_type wait_event_begin_hook; +extern PGDLLIMPORT wait_event_hook_type wait_event_end_hook; +extern PGDLLIMPORT int wait_event_hook_depth; + +static inline void +pgstat_wait_event_hook_begin(uint32 wait_event_info) +{ + if (wait_event_begin_hook != NULL && wait_event_hook_depth == 0) + { + wait_event_hook_depth++; + wait_event_begin_hook(wait_event_info); + wait_event_hook_depth--; + } +} + +static inline void +pgstat_wait_event_hook_end(uint32 wait_event_info) +{ + if (wait_event_end_hook != NULL && wait_event_hook_depth == 0) + { + wait_event_hook_depth++; + wait_event_end_hook(wait_event_info); + wait_event_hook_depth--; + } +} + /* * Wait Events - Extension, InjectionPoint @@ -86,5 +125,25 @@ pgstat_report_wait_end(void) *(volatile uint32 *) my_wait_event_info = 0; } +/* + * Explicitly instrumented variant of the ordinary wait-event reporting pair. + * The ordinary functions above remain unchanged for uninstrumented sites. + */ +static inline void +pgstat_report_wait_start_timed(uint32 wait_event_info) +{ + *(volatile uint32 *) my_wait_event_info = wait_event_info; + pgstat_wait_event_hook_begin(wait_event_info); +} + +static inline void +pgstat_report_wait_end_timed(void) +{ + uint32 wait_event_info = *(volatile uint32 *) my_wait_event_info; + + pgstat_wait_event_hook_end(wait_event_info); + *(volatile uint32 *) my_wait_event_info = 0; +} + #endif /* WAIT_EVENT_H */ -- 2.43.0