diff --git a/contrib/worker_spi/worker_spi--1.0.sql b/contrib/worker_spi/worker_spi--1.0.sql index 09b7799..ae29213 100644 --- a/contrib/worker_spi/worker_spi--1.0.sql +++ b/contrib/worker_spi/worker_spi--1.0.sql @@ -7,3 +7,8 @@ CREATE FUNCTION worker_spi_launch(pg_catalog.int4) RETURNS pg_catalog.int4 STRICT AS 'MODULE_PATHNAME' LANGUAGE C; + +CREATE FUNCTION worker_spi_terminate(pg_catalog.int4) +RETURNS pg_catalog.int4 STRICT +AS 'MODULE_PATHNAME' +LANGUAGE C; diff --git a/contrib/worker_spi/worker_spi.c b/contrib/worker_spi/worker_spi.c index 23ace7a..a28ed14 100644 --- a/contrib/worker_spi/worker_spi.c +++ b/contrib/worker_spi/worker_spi.c @@ -43,10 +43,12 @@ PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(worker_spi_launch); +PG_FUNCTION_INFO_V1(worker_spi_terminate); void _PG_init(void); void worker_spi_main(Datum); Datum worker_spi_launch(PG_FUNCTION_ARGS); +Datum worker_spi_terminate(PG_FUNCTION_ARGS); /* flags set by signal handlers */ static volatile sig_atomic_t got_sighup = false; @@ -400,3 +402,17 @@ worker_spi_launch(PG_FUNCTION_ARGS) PG_RETURN_INT32(pid); } + + +/* + * Dynamically terminate a background worker. + */ +Datum +worker_spi_terminate(PG_FUNCTION_ARGS) +{ + pid_t pid = PG_GETARG_INT32(0); + + /* Call dedicated API */ + TerminateBackgroundWorkerByPid(pid); + PG_RETURN_NULL(); +} diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index f0540de..d5fa501 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -877,7 +877,7 @@ GetBackgroundWorkerPid(BackgroundWorkerHandle *handle, pid_t *pidp) /* * Wait for a background worker to start up. - * + * * This is like GetBackgroundWorkerPid(), except that if the worker has not * yet started, we wait for it to do so; thus, BGWH_NOT_YET_STARTED is never * returned. However, if the postmaster has died, we give up and return @@ -960,3 +960,38 @@ TerminateBackgroundWorker(BackgroundWorkerHandle *handle) if (signal_postmaster) SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE); } + +/* + * Instruct the postmaster to terminate a background worker by Pid. + */ +void +TerminateBackgroundWorkerByPid(pid_t pid) +{ + BackgroundWorkerHandle *handle = NULL; + int slotno; + + LWLockAcquire(BackgroundWorkerLock, LW_SHARED); + + /* Look at all the slots and find the wanted worker */ + for (slotno = 0; slotno < BackgroundWorkerData->total_slots; slotno++) + { + BackgroundWorkerSlot *slot = &BackgroundWorkerData->slot[slotno]; + + if (slot->pid == pid) + { + /* Worker has been found, build a result handle */ + handle = palloc(sizeof(BackgroundWorkerHandle)); + handle->slot = slotno; + handle->generation = slot->generation; + } + } + + LWLockRelease(BackgroundWorkerLock); + + /* Nothing to do if no bgworker found */ + if (!handle) + return; + + /* Now terminate it */ + TerminateBackgroundWorker(handle); +} diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index c27b08b..f66a6c0 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -115,6 +115,9 @@ extern BgwHandleStatus WaitForBackgroundWorkerStartup(BackgroundWorkerHandle * /* Terminate a bgworker */ extern void TerminateBackgroundWorker(BackgroundWorkerHandle *handle); +/* Get a background worker handle using its Pid */ +extern void TerminateBackgroundWorkerByPid(pid_t pid); + /* This is valid in a running worker */ extern BackgroundWorker *MyBgworkerEntry;