Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vWtEo-00BzWf-02 for pgsql-hackers@arkaria.postgresql.org; Sat, 20 Dec 2025 09:26:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vWtEm-00A2Ft-2k for pgsql-hackers@arkaria.postgresql.org; Sat, 20 Dec 2025 09:26:57 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vWtEm-00A2Fl-18 for pgsql-hackers@lists.postgresql.org; Sat, 20 Dec 2025 09:26:57 +0000 Received: from forwardcorp1d.mail.yandex.net ([2a02:6b8:c41:1300:1:45:d181:df01]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vWtEk-001jtK-0j for pgsql-hackers@lists.postgresql.org; Sat, 20 Dec 2025 09:26:56 +0000 Received: from mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net [IPv6:2a02:6b8:c42:65a0:0:640:e1de:0]) by forwardcorp1d.mail.yandex.net (Yandex) with ESMTPS id 5EF8280816; Sat, 20 Dec 2025 12:26:51 +0300 (MSK) Received: from smtpclient.apple (unknown [2a02:6bf:803e:e00:7d77:6f4:c9a1:d73b]) by mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net (smtpcorp/Yandex) with ESMTPSA id oQUH4d0AqiE0-AIaSAVKJ; Sat, 20 Dec 2025 12:26:51 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex-team.ru; s=default; t=1766222811; bh=Os3opjPpnLaKG2AEVth1wEBzu46hsh0J3gRU6PeGkrw=; h=References:To:Cc:In-Reply-To:Date:From:Message-Id:Subject; b=Ns4sIWex925zf1/ZmY+2FyDD9JyqvOSoVaJU9ozPc/iTVh6Mbq7nqIrcQLCzQ8zyb +Fnr5WvJ1LaHphctjtM2+Zoh2ExG+/vHejLdwVAQTvmb512/t7Ta26QsRK9/VTF9g6 Lml4+IZmBo7sj2WO4fAcWE5mnmnoQuuptmLs5Jj8= Authentication-Results: mail-nwsmtp-smtp-corp-main-56.klg.yp-c.yandex.net; dkim=pass header.i=@yandex-team.ru From: Roman Khapov Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_43E0BEC6-50D6-4CC2-8CAD-D6E97D725D0B" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81\)) Subject: Re: Additional message in pg_terminate_backend Date: Sat, 20 Dec 2025 14:26:40 +0500 In-Reply-To: Cc: pgsql-hackers@lists.postgresql.org To: Daniel Gustafsson References: <064E214D-D86F-4917-A0B6-67EAD6BCB24A@yandex-team.ru> X-Mailer: Apple Mail (2.3826.700.81) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_43E0BEC6-50D6-4CC2-8CAD-D6E97D725D0B Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii > On 17 Dec 2025, at 21:02, Daniel Gustafsson wrote: >=20 > Greenplum already has support for passing a message in the terminate = command > doesnt it? Or at least it used to have but perhaps it was ripped out, = my > memory is getting a bit fuzzy. >=20 > = https://github.com/greenplum-db/gpdb-archive/commit/fa6c2d43d675aa05e2d9f7= 97e3008f6fe075ee2c >=20 Well, seems like I missed that patch.. Anyway, now I need same functionality in PostgreSQL, and your patch = seems interesting, especially in part where you keep messages in separated shmem region. So I adopted your patch, maybe in that form it can be useful for = PostgreSQL? --Apple-Mail=_43E0BEC6-50D6-4CC2-8CAD-D6E97D725D0B Content-Disposition: attachment; filename=v2-0001-pg_terminate_backend_msg-and-pg_cancel_backend_ms.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0001-pg_terminate_backend_msg-and-pg_cancel_backend_ms.patch" Content-Transfer-Encoding: quoted-printable =46rom=20e85dae5f0ebfce8612c615aa8c9505672e08bed2=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20roman=20khapov=20=0ADate:=20= Sat,=2020=20Dec=202025=2008:03:01=20+0000=0ASubject:=20[PATCH=20v2]=20= pg_terminate_backend_msg=20and=20pg_cancel_backend_msg=0A=0ASometimes=20= it=20is=20useful=20to=20terminate=20some=20backend=0Aprocess=20with=20= additional=20message=20from=20admin.=0A=0AThis=20patch=20introduces=20= two=20new=20functions:=0A=20-=20pg_terminate_backend_msg(pid,=20timeout,=20= msg)=0A=20-=20pg_cancel_backend_msg(pid,=20msg)=0A=0AThe=20functions=20= are=20similar=20with=20pg_terminate_backend/pg_cancel_backend,=0Abut=20= adds=20additional=20argument:=20the=20message,=20that=20will=20be=20= passed=20into=0AFATAL/ERROR=20packet=20when=20terminating/canceling=20= backend.=0A=0ATo=20do=20that,=20the=20patch=20introduces=20new=20module:=20= BackendMsg=20-=20shared=20memory=0Aregion=20that=20holds=20pairs=20of=20= (message,=20pid)=20which=20are=20checked=20in=20ProcessInterrupts()=0A=0A= Ex.=20of=20usage:=0Apostgres=3D#=20select=20= pg_terminate_backend_msg(pg_backend_pid(),=200,=20'Some=20message');=0A= FATAL:=20=20terminating=20connection=20due=20to=20administrator=20= command:=20Some=20message=0A=0AAuthor:=20Daniel=20Gustafsson=20= =0AAuthor:=20Roman=20Khapov=20=0A= Reviewed-by:=0ADiscussion:=0A---=0A=20= src/backend/catalog/system_functions.sql=20=20=20=20=20=20|=20=20=205=20= +=0A=20src/backend/storage/ipc/ipci.c=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20|=20=20=203=20+=0A=20src/backend/storage/ipc/signalfuncs.c=20= =20=20=20=20=20=20=20=20|=20=2078=20+++++++--=0A=20= src/backend/tcop/postgres.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20|=20=2032=20+++-=0A=20src/backend/utils/init/postinit.c=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=20=202=20+=0A=20= src/backend/utils/misc/Makefile=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=203=20+-=0A=20src/backend/utils/misc/backend_msg.c=20=20=20=20= =20=20=20=20=20=20|=20155=20++++++++++++++++++=0A=20= src/include/catalog/pg_proc.dat=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=207=20+=0A=20src/include/utils/backend_msg.h=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20|=20=2030=20++++=0A=20= .../modules/test_misc/t/010_backend_msg.pl=20=20=20=20|=20=2031=20++++=0A= =2010=20files=20changed,=20330=20insertions(+),=2016=20deletions(-)=0A=20= create=20mode=20100644=20src/backend/utils/misc/backend_msg.c=0A=20= create=20mode=20100644=20src/include/utils/backend_msg.h=0A=20create=20= mode=20100644=20src/test/modules/test_misc/t/010_backend_msg.pl=0A=0A= diff=20--git=20a/src/backend/catalog/system_functions.sql=20= b/src/backend/catalog/system_functions.sql=0Aindex=20= 2d946d6d9e9..5209ee3f1ab=20100644=0A---=20= a/src/backend/catalog/system_functions.sql=0A+++=20= b/src/backend/catalog/system_functions.sql=0A@@=20-404,6=20+404,11=20@@=20= CREATE=20OR=20REPLACE=20FUNCTION=0A=20=20=20RETURNS=20boolean=20STRICT=20= VOLATILE=20LANGUAGE=20INTERNAL=20AS=20'pg_terminate_backend'=0A=20=20=20= PARALLEL=20SAFE;=0A=20=0A+CREATE=20OR=20REPLACE=20FUNCTION=0A+=20=20= pg_terminate_backend_msg(pid=20integer,=20timeout=20int8=20DEFAULT=200,=20= msg=20text=20DEFAULT=20'')=0A+=20=20RETURNS=20boolean=20STRICT=20= VOLATILE=20LANGUAGE=20INTERNAL=20AS=20'pg_terminate_backend_msg'=0A+=20=20= PARALLEL=20SAFE;=0A+=0A=20--=20legacy=20definition=20for=20compatibility=20= with=209.3=0A=20CREATE=20OR=20REPLACE=20FUNCTION=0A=20=20=20= json_populate_record(base=20anyelement,=20from_json=20json,=20= use_json_as_text=20boolean=20DEFAULT=20false)=0Adiff=20--git=20= a/src/backend/storage/ipc/ipci.c=20b/src/backend/storage/ipc/ipci.c=0A= index=20b23d0c19360..94a89ff5e57=20100644=0A---=20= a/src/backend/storage/ipc/ipci.c=0A+++=20= b/src/backend/storage/ipc/ipci.c=0A@@=20-52,6=20+52,7=20@@=0A=20#include=20= "storage/sinvaladt.h"=0A=20#include=20"utils/guc.h"=0A=20#include=20= "utils/injection_point.h"=0A+#include=20"utils/backend_msg.h"=0A=20=0A=20= /*=20GUCs=20*/=0A=20int=09=09=09shared_memory_type=20=3D=20= DEFAULT_SHARED_MEMORY_TYPE;=0A@@=20-140,6=20+141,7=20@@=20= CalculateShmemSize(void)=0A=20=09size=20=3D=20add_size(size,=20= SlotSyncShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= AioShmemSize());=0A=20=09size=20=3D=20add_size(size,=20= WaitLSNShmemSize());=0A+=09size=20=3D=20add_size(size,=20= BackendStatusShmemSize());=0A=20=0A=20=09/*=20include=20additional=20= requested=20shmem=20from=20preload=20libraries=20*/=0A=20=09size=20=3D=20= add_size(size,=20total_addin_request);=0A@@=20-328,6=20+330,7=20@@=20= CreateOrAttachShmemStructs(void)=0A=20=09InjectionPointShmemInit();=0A=20= =09AioShmemInit();=0A=20=09WaitLSNShmemInit();=0A+=09= BackendMsgShmemInit();=0A=20}=0A=20=0A=20/*=0Adiff=20--git=20= a/src/backend/storage/ipc/signalfuncs.c=20= b/src/backend/storage/ipc/signalfuncs.c=0Aindex=20= a3a670ba247..d7ca2d77186=20100644=0A---=20= a/src/backend/storage/ipc/signalfuncs.c=0A+++=20= b/src/backend/storage/ipc/signalfuncs.c=0A@@=20-25,6=20+25,8=20@@=0A=20= #include=20"storage/procarray.h"=0A=20#include=20"utils/acl.h"=0A=20= #include=20"utils/fmgrprotos.h"=0A+#include=20"utils/builtins.h"=0A= +#include=20"utils/backend_msg.h"=0A=20=0A=20=0A=20/*=0A@@=20-48,7=20= +50,7=20@@=0A=20#define=20SIGNAL_BACKEND_NOSUPERUSER=203=0A=20#define=20= SIGNAL_BACKEND_NOAUTOVAC=204=0A=20static=20int=0A-pg_signal_backend(int=20= pid,=20int=20sig)=0A+pg_signal_backend(int=20pid,=20int=20sig,=20const=20= char=20*msg)=0A=20{=0A=20=09PGPROC=09=20=20=20*proc=20=3D=20= BackendPidGetProc(pid);=0A=20=0A@@=20-111,6=20+113,15=20@@=20= pg_signal_backend(int=20pid,=20int=20sig)=0A=20=09=20*=20too=20unlikely=20= to=20worry=20about.=0A=20=09=20*/=0A=20=0A+=09if=20(msg=20!=3D=20NULL)=0A= +=09{=0A+=09=09int=09=09r=20=3D=20BackendMsgSet(pid,=20msg);=0A+=0A+=09=09= if=20(r=20!=3D=20-1=20&&=20r=20!=3D=20strlen(msg))=0A+=09=09=09= ereport(NOTICE,=0A+=09=09=09=09=09(errmsg("message=20is=20too=20long,=20= truncated=20to=20%d",=20r)));=0A+=09}=0A+=0A=20=09/*=20If=20we=20have=20= setsid(),=20signal=20the=20backend's=20whole=20process=20group=20*/=0A=20= #ifdef=20HAVE_SETSID=0A=20=09if=20(kill(-pid,=20sig))=0A@@=20-132,10=20= +143,10=20@@=20pg_signal_backend(int=20pid,=20int=20sig)=0A=20=20*=0A=20=20= *=20Note=20that=20only=20superusers=20can=20signal=20superuser-owned=20= processes.=0A=20=20*/=0A-Datum=0A-pg_cancel_backend(PG_FUNCTION_ARGS)=0A= +static=20Datum=0A+pg_cancel_backend_internal(pid_t=20pid,=20const=20= char=20*msg)=0A=20{=0A-=09int=09=09=09r=20=3D=20= pg_signal_backend(PG_GETARG_INT32(0),=20SIGINT);=0A+=09int=09=09=09r=20=3D= =20pg_signal_backend(pid,=20SIGINT,=20msg);=0A=20=0A=20=09if=20(r=20=3D=3D= =20SIGNAL_BACKEND_NOSUPERUSER)=0A=20=09=09ereport(ERROR,=0A@@=20-161,6=20= +172,28=20@@=20pg_cancel_backend(PG_FUNCTION_ARGS)=0A=20=09= PG_RETURN_BOOL(r=20=3D=3D=20SIGNAL_BACKEND_SUCCESS);=0A=20}=0A=20=0A= +Datum=0A+pg_cancel_backend(PG_FUNCTION_ARGS)=0A+{=0A+=09int=09=09pid;=0A= +=09=0A+=09pid=20=3D=20PG_GETARG_INT32(0);=0A+=0A+=09return=20= pg_cancel_backend_internal(pid,=20NULL);=0A+}=0A+=0A+Datum=0A= +pg_cancel_backend_msg(PG_FUNCTION_ARGS)=0A+{=0A+=09int=09=09=09pid;=0A+=09= char=09=09*msg;=0A+=0A+=09pid=20=3D=20PG_GETARG_INT32(0);=0A+=09msg=20=3D=20= text_to_cstring(PG_GETARG_TEXT_PP(1));=0A+=0A+=09return=20= pg_cancel_backend_internal(pid,=20msg);=0A+}=0A+=0A=20/*=0A=20=20*=20= Wait=20until=20there=20is=20no=20backend=20process=20with=20the=20given=20= PID=20and=20return=20true.=0A=20=20*=20On=20timeout,=20a=20warning=20is=20= emitted=20and=20false=20is=20returned.=0A@@=20-233,22=20+266,17=20@@=20= pg_wait_until_termination(int=20pid,=20int64=20timeout)=0A=20=20*=0A=20=20= *=20Note=20that=20only=20superusers=20can=20signal=20superuser-owned=20= processes.=0A=20=20*/=0A-Datum=0A-pg_terminate_backend(PG_FUNCTION_ARGS)=0A= +static=20Datum=0A+pg_terminate_backend_internal(int=20pid,=20int=20= timeout,=20const=20char=20*msg)=0A=20{=0A-=09int=09=09=09pid;=0A=20=09= int=09=09=09r;=0A-=09int=09=09=09timeout;=09=09/*=20milliseconds=20*/=0A= -=0A-=09pid=20=3D=20PG_GETARG_INT32(0);=0A-=09timeout=20=3D=20= PG_GETARG_INT64(1);=0A=20=0A=20=09if=20(timeout=20<=200)=0A=20=09=09= ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),=0A=20=09=09=09=09=20= errmsg("\"timeout\"=20must=20not=20be=20negative")));=0A=20=0A-=09r=20=3D=20= pg_signal_backend(pid,=20SIGTERM);=0A+=09r=20=3D=20= pg_signal_backend(pid,=20SIGTERM,=20msg);=0A=20=0A=20=09if=20(r=20=3D=3D=20= SIGNAL_BACKEND_NOSUPERUSER)=0A=20=09=09ereport(ERROR,=0A@@=20-278,6=20= +306,32=20@@=20pg_terminate_backend(PG_FUNCTION_ARGS)=0A=20=09=09= PG_RETURN_BOOL(r=20=3D=3D=20SIGNAL_BACKEND_SUCCESS);=0A=20}=0A=20=0A= +Datum=0A+pg_terminate_backend(PG_FUNCTION_ARGS)=0A+{=0A+=09int=09=09=09= pid;=0A+=09int=09=09=09timeout;=09=09/*=20milliseconds=20*/=0A+=0A+=09= pid=20=3D=20PG_GETARG_INT32(0);=0A+=09timeout=20=3D=20= PG_GETARG_INT64(1);=0A+=0A+=09return=20= pg_terminate_backend_internal(pid,=20timeout,=20NULL);=0A+}=0A+=0A+Datum=0A= +pg_terminate_backend_msg(PG_FUNCTION_ARGS)=0A+{=0A+=09int=09=09=09pid;=0A= +=09int=09=09=09timeout;=09=09/*=20milliseconds=20*/=0A+=09char=09=09= *msg;=0A+=0A+=09pid=20=3D=20PG_GETARG_INT32(0);=0A+=09timeout=20=3D=20= PG_GETARG_INT64(1);=0A+=09msg=20=3D=20= text_to_cstring(PG_GETARG_TEXT_PP(2));=0A+=0A+=09return=20= pg_terminate_backend_internal(pid,=20timeout,=20msg);=0A+}=0A+=0A=20/*=0A= =20=20*=20Signal=20to=20reload=20the=20database=20configuration=0A=20=20= *=0Adiff=20--git=20a/src/backend/tcop/postgres.c=20= b/src/backend/tcop/postgres.c=0Aindex=207dd75a490aa..94c1636c7e7=20= 100644=0A---=20a/src/backend/tcop/postgres.c=0A+++=20= b/src/backend/tcop/postgres.c=0A@@=20-81,6=20+81,7=20@@=0A=20#include=20= "utils/timeout.h"=0A=20#include=20"utils/timestamp.h"=0A=20#include=20= "utils/varlena.h"=0A+#include=20"utils/backend_msg.h"=0A=20=0A=20/*=20= ----------------=0A=20=20*=09=09global=20variables=0A@@=20-3356,9=20= +3357,22=20@@=20ProcessInterrupts(void)=0A=20=09=09=09proc_exit(0);=0A=20= =09=09}=0A=20=09=09else=0A+=09=09{=0A+=09=09=09if=20(BackendMsgIsSet())=0A= +=09=09=09{=0A+=09=09=09=09char=20msg[BACKEND_MSG_MAX_LEN];=0A+=0A+=09=09= =09=09BackendMsgGet(msg,=20sizeof(msg));=0A+=0A+=09=09=09=09= ereport(FATAL,=0A+=09=09=09=09=09=09(errcode(ERRCODE_ADMIN_SHUTDOWN),=0A= +=09=09=09=09=09=09errmsg("terminating=20connection=20due=20to=20= administrator=20command:=20%s",=20msg)));=0A+=09=09=09}=0A+=0A=20=09=09=09= ereport(FATAL,=0A=20=09=09=09=09=09(errcode(ERRCODE_ADMIN_SHUTDOWN),=0A=20= =09=09=09=09=09=20errmsg("terminating=20connection=20due=20to=20= administrator=20command")));=0A+=09=09}=0A=20=09}=0A=20=0A=20=09if=20= (CheckClientConnectionPending)=0A@@=20-3466,9=20+3480,21=20@@=20= ProcessInterrupts(void)=0A=20=09=09if=20(!DoingCommandRead)=0A=20=09=09{=0A= =20=09=09=09LockErrorCleanup();=0A-=09=09=09ereport(ERROR,=0A-=09=09=09=09= =09(errcode(ERRCODE_QUERY_CANCELED),=0A-=09=09=09=09=09=20= errmsg("canceling=20statement=20due=20to=20user=20request")));=0A+=0A+=09= =09=09if=20(BackendMsgIsSet())=0A+=09=09=09{=0A+=09=09=09=09char=20= msg[BACKEND_MSG_MAX_LEN];=0A+=0A+=09=09=09=09BackendMsgGet(msg,=20= sizeof(msg));=0A+=0A+=09=09=09=09ereport(ERROR,=0A+=09=09=09=09=09=09= (errcode(ERRCODE_QUERY_CANCELED),=0A+=09=09=09=09=09=09=20= errmsg("canceling=20statement=20due=20to=20user=20request:=20%s",=20= msg)));=0A+=09=09=09}=0A+=09=09=09else=0A+=09=09=09=09ereport(ERROR,=0A+=09= =09=09=09=09=09(errcode(ERRCODE_QUERY_CANCELED),=0A+=09=09=09=09=09=09=20= errmsg("canceling=20statement=20due=20to=20user=20request")));=0A=20=09=09= }=0A=20=09}=0A=20=0Adiff=20--git=20a/src/backend/utils/init/postinit.c=20= b/src/backend/utils/init/postinit.c=0Aindex=204ed69ac7ba2..c653bcc12c5=20= 100644=0A---=20a/src/backend/utils/init/postinit.c=0A+++=20= b/src/backend/utils/init/postinit.c=0A@@=20-69,6=20+69,7=20@@=0A=20= #include=20"utils/snapmgr.h"=0A=20#include=20"utils/syscache.h"=0A=20= #include=20"utils/timeout.h"=0A+#include=20"utils/backend_msg.h"=0A=20=0A= =20static=20HeapTuple=20GetDatabaseTuple(const=20char=20*dbname);=0A=20= static=20HeapTuple=20GetDatabaseTupleByOid(Oid=20dboid);=0A@@=20-899,6=20= +900,7=20@@=20InitPostgres(const=20char=20*in_dbname,=20Oid=20dboid,=0A=20= =09=09=09InitializeSystemUser(MyClientConnectionInfo.authn_id,=0A=20=09=09= =09=09=09=09=09=09=20hba_authname(MyClientConnectionInfo.auth_method));=0A= =20=09=09am_superuser=20=3D=20superuser();=0A+=09=09= BackendMsgInit(MyProcNumber);=0A=20=09}=0A=20=0A=20=09/*=20Report=20any=20= SSL/GSS=20details=20for=20the=20session.=20*/=0Adiff=20--git=20= a/src/backend/utils/misc/Makefile=20b/src/backend/utils/misc/Makefile=0A= index=20f142d17178b..5494994669f=20100644=0A---=20= a/src/backend/utils/misc/Makefile=0A+++=20= b/src/backend/utils/misc/Makefile=0A@@=20-32,7=20+32,8=20@@=20OBJS=20=3D=20= \=0A=20=09stack_depth.o=20\=0A=20=09superuser.o=20\=0A=20=09timeout.o=20= \=0A-=09tzparser.o=0A+=09tzparser.o=20\=0A+=09backend_msg.o=0A=20=0A=20#=20= This=20location=20might=20depend=20on=20the=20installation=20= directories.=20Therefore=0A=20#=20we=20can't=20substitute=20it=20into=20= pg_config.h.=0Adiff=20--git=20a/src/backend/utils/misc/backend_msg.c=20= b/src/backend/utils/misc/backend_msg.c=0Anew=20file=20mode=20100644=0A= index=2000000000000..7f638c864bc=0A---=20/dev/null=0A+++=20= b/src/backend/utils/misc/backend_msg.c=0A@@=20-0,0=20+1,155=20@@=0A= +/*--------------------------------------------------------------------=0A= +=20*=20backend_msg.h=0A+=20*=0A+=20*=20Utility=20to=20pass=20additional=20= message=20to=20backend=20processes.=0A+=20*=20Ex:=20cancel=20or=20= terminate=20messages=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2025,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20src/include/utils/misc/backend_msg.c=0A= +=20*=0A+=20= *--------------------------------------------------------------------=0A= +=20*/=0A+=0A+#include=20"postgres.h"=0A+=0A+#include=20"miscadmin.h"=0A= +#include=20"storage/shmem.h"=0A+#include=20"storage/spin.h"=0A+#include=20= "storage/ipc.h"=0A+#include=20"utils/backend_msg.h"=0A+=0A+typedef=20= struct=20{=0A+=09pid_t=20pid;=0A+=09slock_t=20lock;=0A+=09char=20= msg[BACKEND_MSG_MAX_LEN];=0A+}=20BackendMsgSlot;=0A+=0A+=0A+static=20= BackendMsgSlot=20*BackendMsgSlots;=0A+static=20BackendMsgSlot=20= *MyBackendMsgSlot;=0A+=0A+static=20void=0A+backend_msg_slot_clean(int=20= code,=20Datum=20arg)=0A+{=0A+=09(void)=20code;=0A+=09(void)=20arg;=0A+=0A= +=09Assert(MyBackendMsgSlot=20!=3D=20NULL);=0A+=0A+=09= SpinLockAcquire(&MyBackendMsgSlot->lock);=0A+=0A+=09= MyBackendMsgSlot->msg[0]=20=3D=20'\0';=0A+=09MyBackendMsgSlot->pid=20=3D=20= 0;=0A+=0A+=09SpinLockRelease(&MyBackendMsgSlot->lock);=0A+=0A+=09= MyBackendMsgSlot=20=3D=20NULL;=0A+}=0A+=0A+=0A+void=20= BackendMsgShmemInit(void)=0A+{=0A+=09Size=09size;=0A+=09bool=09found;=0A= +=0A+=09size=20=3D=20BackendMsgShmemSize();=0A+=09BackendMsgSlots=20=3D=20= ShmemInitStruct("BackendMsgSlots",=20size,=20&found);=0A+=0A+=09if=20= (found)=0A+=09=09return;=0A+=09=0A+=09memset(BackendMsgSlots,=200,=20= size);=0A+=0A+=09for=20(int=20i=20=3D=200;=20i=20<=20MaxBackends;=20++i)=0A= +=09=09SpinLockInit(&BackendMsgSlots[i].lock);=0A+}=0A+=0A+Size=0A= +BackendMsgShmemSize(void)=0A+{=0A+=09return=20mul_size(MaxBackends,=20= sizeof(BackendMsgSlot));=0A+}=0A+=0A+void=20BackendMsgInit(int=20id)=0A= +{=0A+=09BackendMsgSlot=09=09*slot;=0A+=0A+=09slot=20=3D=20= &BackendMsgSlots[id];=0A+=0A+=09slot->msg[0]=20=3D=20'\0';=0A+=09= slot->pid=20=3D=20MyProcPid;=0A+=0A+=09MyBackendMsgSlot=20=3D=20slot;=0A= +=0A+=09on_shmem_exit(backend_msg_slot_clean,=20Int32GetDatum(0)=20/*=20= not=20used=20*/);=0A+}=0A+=0A+int=20BackendMsgSet(pid_t=20pid,=20const=20= char=20*msg)=0A+{=0A+=09BackendMsgSlot=09=09*slot;=0A+=09int=09=09=09=09=09= len;=0A+=0A+=09if=20(msg=20=3D=3D=20NULL=20||=20msg[0]=20=3D=3D=20'\0')=0A= +=09=09return=200;=0A+=0A+=09for=20(int=20i=20=3D=200;=20i=20<=20= MaxBackends;=20++i)=0A+=09{=0A+=09=09slot=20=3D=20&BackendMsgSlots[i];=0A= +=0A+=09=09if=20(slot->pid=20=3D=3D=200=20||=20slot->pid=20!=3D=20pid)=0A= +=09=09=09continue;=0A+=0A+=09=09SpinLockAcquire(&slot->lock);=0A+=0A+=09= =09if=20(slot->pid=20!=3D=20pid)=0A+=09=09{=0A+=09=09=09= SpinLockRelease(&slot->lock);=0A+=09=09=09break;=0A+=09=09}=0A+=0A+=09=09= len=20=3D=20stpncpy(slot->msg,=20msg,=20sizeof(slot->msg))=20-=20= slot->msg;=0A+=0A+=09=09SpinLockRelease(&slot->lock);=0A+=0A+=09=09= return=20len;=0A+=09}=0A+=0A+=09ereport(LOG,=0A+=09=09=09(errmsg("Can't=20= set=20message=20for=20missing=20backend=20%d,=20requested=20by=20%d",=0A= +=09=09=09=09pid,=20MyProcPid)));=0A+=0A+=09return=20-1;=0A+}=0A+=0A+int=20= BackendMsgGet(char=20*buf,=20int=20max_len)=0A+{=0A+=09int=09=09len;=0A+=0A= +=09if=20(MyBackendMsgSlot=20=3D=3D=20NULL)=0A+=09=09return=200;=0A+=0A+=09= SpinLockAcquire(&MyBackendMsgSlot->lock);=0A+=0A+=09len=20=3D=20= strlcpy(buf,=20MyBackendMsgSlot->msg,=20max_len);=0A+=09= memset(MyBackendMsgSlot->msg,=20'\0',=20sizeof(MyBackendMsgSlot->msg));=0A= +=0A+=09SpinLockRelease(&MyBackendMsgSlot->lock);=0A+=0A+=09return=20= len;=0A+}=0A+=0A+bool=20BackendMsgIsSet(void)=0A+{=0A+=09bool=20result=20= =3D=20false;=0A+=0A+=09if=20(MyBackendMsgSlot=20=3D=3D=20NULL)=0A+=09=09= return=20false;=0A+=0A+=09SpinLockAcquire(&MyBackendMsgSlot->lock);=0A+=09= result=20=3D=20MyBackendMsgSlot->msg[0]=20!=3D=20'\0';=0A+=09= SpinLockRelease(&MyBackendMsgSlot->lock);=0A+=0A+=09return=20result;=0A= +}=0Adiff=20--git=20a/src/include/catalog/pg_proc.dat=20= b/src/include/catalog/pg_proc.dat=0Aindex=20fd9448ec7b9..66b4a397284=20= 100644=0A---=20a/src/include/catalog/pg_proc.dat=0A+++=20= b/src/include/catalog/pg_proc.dat=0A@@=20-6713,6=20+6713,13=20@@=0A=20=20= =20proname=20=3D>=20'pg_terminate_backend',=20provolatile=20=3D>=20'v',=20= prorettype=20=3D>=20'bool',=0A=20=20=20proargtypes=20=3D>=20'int4=20= int8',=20proargnames=20=3D>=20'{pid,timeout}',=0A=20=20=20prosrc=20=3D>=20= 'pg_terminate_backend'=20},=0A+{=20oid=20=3D>=20'8328',=20descr=20=3D>=20= 'cancel=20a=20server=20process\'=20current=20query=20with=20message',=0A= +=20=20proname=20=3D>=20'pg_cancel_backend_msg',=20provolatile=20=3D>=20= 'v',=20prorettype=20=3D>=20'bool',=0A+=20=20proargtypes=20=3D>=20'int4=20= text',=20prosrc=20=3D>=20'pg_cancel_backend_msg'=20},=0A+{=20oid=20=3D>=20= '8329',=20descr=20=3D>=20'terminate=20a=20server=20process=20with=20= message',=0A+=20=20proname=20=3D>=20'pg_terminate_backend_msg',=20= provolatile=20=3D>=20'v',=20prorettype=20=3D>=20'bool',=0A+=20=20= proargtypes=20=3D>=20'int4=20int8=20text',=20proargnames=20=3D>=20= '{pid,timeout,msg}',=0A+=20=20prosrc=20=3D>=20'pg_terminate_backend_msg'=20= },=0A=20{=20oid=20=3D>=20'2172',=20descr=20=3D>=20'prepare=20for=20= taking=20an=20online=20backup',=0A=20=20=20proname=20=3D>=20= 'pg_backup_start',=20provolatile=20=3D>=20'v',=20proparallel=20=3D>=20= 'r',=0A=20=20=20prorettype=20=3D>=20'pg_lsn',=20proargtypes=20=3D>=20= 'text=20bool',=0Adiff=20--git=20a/src/include/utils/backend_msg.h=20= b/src/include/utils/backend_msg.h=0Anew=20file=20mode=20100644=0Aindex=20= 00000000000..db69efbe915=0A---=20/dev/null=0A+++=20= b/src/include/utils/backend_msg.h=0A@@=20-0,0=20+1,30=20@@=0A= +/*--------------------------------------------------------------------=0A= +=20*=20backend_msg.h=0A+=20*=0A+=20*=20Utility=20to=20pass=20additional=20= message=20to=20backend=20processes.=0A+=20*=20Ex:=20cancel=20or=20= terminate=20messages=0A+=20*=0A+=20*=20Portions=20Copyright=20(c)=20= 1996-2025,=20PostgreSQL=20Global=20Development=20Group=0A+=20*=20= Portions=20Copyright=20(c)=201994,=20Regents=20of=20the=20University=20= of=20California=0A+=20*=0A+=20*=20src/include/utils/backend_msg.h=0A+=20= *=0A+=20= *--------------------------------------------------------------------=0A= +=20*/=0A+=0A+#ifndef=20BACKEND_MSG_H=0A+#define=20BACKEND_MSG_H=0A+=0A= +#include=20=0A+=0A+#define=20BACKEND_MSG_MAX_LEN=20128=0A+=0A= +extern=20void=20BackendMsgShmemInit(void);=0A+extern=20Size=20= BackendMsgShmemSize(void);=0A+extern=20void=20BackendMsgInit(int=20id);=0A= +extern=20int=20BackendMsgSet(pid_t=20pid,=20const=20char=20*msg);=0A= +extern=20int=20BackendMsgGet(char=20*buf,=20int=20max_len);=0A+extern=20= bool=20BackendMsgIsSet(void);=0A+=0A+=0A+#endif=20/*=20BACKEND_MSG_H=20= */=0Adiff=20--git=20a/src/test/modules/test_misc/t/010_backend_msg.pl=20= b/src/test/modules/test_misc/t/010_backend_msg.pl=0Anew=20file=20mode=20= 100644=0Aindex=2000000000000..d0d68b453f2=0A---=20/dev/null=0A+++=20= b/src/test/modules/test_misc/t/010_backend_msg.pl=0A@@=20-0,0=20+1,31=20= @@=0A+#=20Copyright=20(c)=202025,=20PostgreSQL=20Global=20Development=20= Group=0A+=0A+#=20Check=20that=20messages=20are=20passed=20to=20backends=20= by=0A+#=20pg_terminate_backend_msg,=20pg_cancel_backend_msg=0A+=0A+use=20= strict;=0A+use=20warnings=20FATAL=20=3D>=20'all';=0A+use=20= PostgreSQL::Test::Cluster;=0A+use=20PostgreSQL::Test::Utils;=0A+use=20= Test::More;=0A+=0A+my=20$node=20=3D=20= PostgreSQL::Test::Cluster->new('primary');=0A+$node->init();=0A= +$node->start;=0A+=0A+my=20($stdout,=20$stderr);=0A= +$node->psql('postgres',=0A+=09q[select=20= pg_terminate_backend_msg(pg_backend_pid(),=200,=20'Have=20you=20seen=20= my=20coffee=20cup?');],=0A+=09stdout=20=3D>=20\$stdout,=20stderr=20=3D>=20= \$stderr);=0A+like($stderr,=20qr/Have=20you=20seen=20my=20coffee=20= cup\?/,=20"expected=20message=20to=20be=20passed");=0A+=0A+$stdout=20=3D=20= '';=0A+$stderr=20=3D=20'';=0A+$node->psql('postgres',=0A+=09q[select=20= pg_cancel_backend_msg(pg_backend_pid(),=20'You=20have=20to=20wear=20some=20= ridiculous=20tie');],=0A+=09stdout=20=3D>=20\$stdout,=20stderr=20=3D>=20= \$stderr);=0A+like($stderr,=20qr/You=20have=20to=20wear=20some=20= ridiculous=20tie/,=20"expected=20message=20to=20be=20passed");=0A+=0A= +$node->stop;=0A+=0A+done_testing();=0A--=20=0A2.43.0=0A=0A= --Apple-Mail=_43E0BEC6-50D6-4CC2-8CAD-D6E97D725D0B Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii --Apple-Mail=_43E0BEC6-50D6-4CC2-8CAD-D6E97D725D0B--