diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index a3d6ac5..07270a9 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -59,12 +59,17 @@ typedef struct */ #define NumProcSignalSlots (MaxBackends + NUM_AUXPROCTYPES) +static bool CustomSignalPendings[NUM_CUSTOM_PROCSIGNALS]; +static ProcSignalHandler_type CustomHandlers[NUM_CUSTOM_PROCSIGNALS]; + static ProcSignalSlot *ProcSignalSlots = NULL; static volatile ProcSignalSlot *MyProcSignalSlot = NULL; static bool CheckProcSignal(ProcSignalReason reason); static void CleanupProcSignalState(int status, Datum arg); +static void CustomSignalInterrupt(ProcSignalReason reason); + /* * ProcSignalShmemSize * Compute space needed for procsignal's shared memory @@ -165,6 +170,57 @@ CleanupProcSignalState(int status, Datum arg) } /* + * RegisterCustomProcSignalHandler + * Assign specific handler of custom process signal with new ProcSignalReason key. + * Return INVALID_PROCSIGNAL if all custom signals have been assigned. + */ +ProcSignalReason +RegisterCustomProcSignalHandler(ProcSignalHandler_type handler) +{ + ProcSignalReason reason; + + /* iterate through custom signal keys to find free spot */ + for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++) + if (!CustomHandlers[reason - PROCSIG_CUSTOM_1]) + { + CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler; + return reason; + } + return INVALID_PROCSIGNAL; +} + +/* + * AssignCustomProcSignalHandler + * Assign handler of custom process signal with specific ProcSignalReason key. + * Return old ProcSignal handler. + * Assume incoming reason is one of custom ProcSignals. + */ +ProcSignalHandler_type +AssignCustomProcSignalHandler(ProcSignalReason reason, ProcSignalHandler_type handler) +{ + ProcSignalHandler_type old; + + Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); + + old = CustomHandlers[reason - PROCSIG_CUSTOM_1]; + CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler; + return old; +} + +/* + * GetCustomProcSignalHandler + * Get handler of custom process signal. + * Assume incoming reason is one of custom ProcSignals. + */ +ProcSignalHandler_type +GetCustomProcSignalHandler(ProcSignalReason reason) +{ + Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); + + return CustomHandlers[reason - PROCSIG_CUSTOM_1]; +} + +/* * SendProcSignal * Send a signal to a Postgres process * @@ -259,7 +315,8 @@ CheckProcSignal(ProcSignalReason reason) void procsignal_sigusr1_handler(SIGNAL_ARGS) { - int save_errno = errno; + int save_errno = errno; + ProcSignalReason reason; if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT)) HandleCatchupInterrupt(); @@ -288,9 +345,55 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN)) RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); + for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++) + if (CheckProcSignal(reason)) + CustomSignalInterrupt(reason); + SetLatch(MyLatch); latch_sigusr1_handler(); errno = save_errno; } + +/* + * Handle receipt of an interrupt indicating a custom process signal. + */ +static void +CustomSignalInterrupt(ProcSignalReason reason) +{ + int save_errno = errno; + + Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); + + /* set interrupt flags */ + InterruptPending = true; + CustomSignalPendings[reason - PROCSIG_CUSTOM_1] = true; + + /* make sure the event is processed in due course */ + SetLatch(MyLatch); + + errno = save_errno; +} + +/* + * CheckAndHandleCustomSignals + * Check custom signal flags and call handler assigned to that signal if it is not NULL. + * This function is called within CHECK_FOR_INTERRUPTS if interrupt have been occurred. + */ +void +CheckAndHandleCustomSignals(void) +{ + int i; + + for (i = 0; i < NUM_CUSTOM_PROCSIGNALS; i++) + if (CustomSignalPendings[i]) + { + ProcSignalHandler_type handler; + + CustomSignalPendings[i] = false; + handler = CustomHandlers[i]; + if (handler) + handler(); + } +} diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 98ccbbb..c5d649c 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3005,6 +3005,8 @@ ProcessInterrupts(void) if (ParallelMessagePending) HandleParallelMessages(); + + CheckAndHandleCustomSignals(); } diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index f67b982..e941dcb 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -17,6 +17,8 @@ #include "storage/backendid.h" +#define NUM_CUSTOM_PROCSIGNALS 64 + /* * Reasons for signalling a Postgres child process (a backend or an auxiliary * process, like checkpointer). We can cope with concurrent signals for different @@ -29,6 +31,8 @@ */ typedef enum { + INVALID_PROCSIGNAL = -1, /* Must be first */ + PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */ @@ -41,9 +45,20 @@ typedef enum PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + PROCSIG_CUSTOM_1, + /* + * PROCSIG_CUSTOM_2, + * ..., + * PROCSIG_CUSTOM_N-1, + */ + PROCSIG_CUSTOM_N = PROCSIG_CUSTOM_1 + NUM_CUSTOM_PROCSIGNALS - 1, + NUM_PROCSIGNALS /* Must be last! */ } ProcSignalReason; +/* Handler of custom process signal */ +typedef void (*ProcSignalHandler_type) (void); + /* * prototypes for functions in procsignal.c */ @@ -51,9 +66,15 @@ extern Size ProcSignalShmemSize(void); extern void ProcSignalShmemInit(void); extern void ProcSignalInit(int pss_idx); +extern ProcSignalReason RegisterCustomProcSignalHandler(ProcSignalHandler_type handler); +extern ProcSignalHandler_type AssignCustomProcSignalHandler(ProcSignalReason reason, + ProcSignalHandler_type handler); +extern ProcSignalHandler_type GetCustomProcSignalHandler(ProcSignalReason reason); extern int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId); +extern void CheckAndHandleCustomSignals(void); + extern void procsignal_sigusr1_handler(SIGNAL_ARGS); #endif /* PROCSIGNAL_H */