From 2443e2fdd01beb9be1b18b94119e1538c6e414ad Mon Sep 17 00:00:00 2001
From: Jakub Wartak <jakub.wartak@enterprisedb.com>
Date: Mon, 22 Jun 2026 13:17:59 +0200
Subject: [PATCH v1] Allow pg_log_backend_memory_contexts() for postmaster

Previously, it was not possible to gather memory context dump using
pg_log_backend_memory_contexts() on postmaster process as it would report:
   PID <postmasterPID> is not a PostgreSQL server process

This commit adds special case to the above function to allow postmaster to log
usage of it's own memory contexts from the main ServerLoop() using already
existing ProcessLogMemoryContextInterrupt().

Author: Jakub Wartak <jakub.wartak@enterprisedb.com>
Discussion:
---
 doc/src/sgml/func/func-admin.sgml            |  3 ++-
 src/backend/postmaster/postmaster.c          |  6 ++++++
 src/backend/utils/adt/mcxtfuncs.c            | 21 ++++++++++++++++++--
 src/include/storage/pmsignal.h               |  4 +++-
 src/test/regress/expected/misc_functions.out |  7 +++++++
 src/test/regress/sql/misc_functions.sql      |  3 +++
 6 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/doc/src/sgml/func/func-admin.sgml b/doc/src/sgml/func/func-admin.sgml
index 0eae1c1f616..2e8b5d75c6f 100644
--- a/doc/src/sgml/func/func-admin.sgml
+++ b/doc/src/sgml/func/func-admin.sgml
@@ -174,7 +174,8 @@
        <para>
         Requests to log the memory contexts of the backend with the
         specified process ID.  This function can send the request to
-        backends and auxiliary processes except logger.  These memory contexts
+        backends and auxiliary processes except logger, as well as to the
+        postmaster.  These memory contexts
         will be logged at
         <literal>LOG</literal> message level. They will appear in
         the server log based on the log configuration set
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 90c7c4528e8..b9be40008d4 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -3909,6 +3909,12 @@ process_pm_pmsignal(void)
 		request_state_update = true;
 	}
 
+	/* Log the postmaster's memory contexts if requested. */
+	if (CheckPostmasterSignal(PMSIGNAL_LOG_MEMORY_CONTEXT))
+	{
+		ProcessLogMemoryContextInterrupt();
+	}
+
 	/*
 	 * Try to advance postmaster's state machine, if a child requests it.
 	 */
diff --git a/src/backend/utils/adt/mcxtfuncs.c b/src/backend/utils/adt/mcxtfuncs.c
index 1a4dbbeb8db..02a3a2df0b1 100644
--- a/src/backend/utils/adt/mcxtfuncs.c
+++ b/src/backend/utils/adt/mcxtfuncs.c
@@ -18,6 +18,8 @@
 #include "catalog/pg_type_d.h"
 #include "funcapi.h"
 #include "mb/pg_wchar.h"
+#include "miscadmin.h"
+#include "storage/pmsignal.h"
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "storage/procsignal.h"
@@ -252,7 +254,8 @@ pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
 
 /*
  * pg_log_backend_memory_contexts
- *		Signal a backend or an auxiliary process to log its memory contexts.
+ *		Signal a backend, an auxiliary process, or the postmaster to log its
+ *		memory contexts.
  *
  * By default, only superusers are allowed to signal to log the memory
  * contexts because allowing any users to issue this request at an unbounded
@@ -261,7 +264,9 @@ pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
  *
  * On receipt of this signal, a backend or an auxiliary process sets the flag
  * in the signal handler, which causes the next CHECK_FOR_INTERRUPTS()
- * or process-specific interrupt handler to log the memory contexts.
+ * or process-specific interrupt handler to log the memory contexts.  The
+ * postmaster doesn't participate in ProcSignal signaling so it is handled
+ * separately.
  */
 Datum
 pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
@@ -270,6 +275,18 @@ pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
 	PGPROC	   *proc;
 	ProcNumber	procNumber = INVALID_PROC_NUMBER;
 
+	/*
+	 * The postmaster does not participate in ProcSignal signaling, so
+	 * SendProcSignal() won't work for it.  Instead, ask it to log its memory
+	 * contexts through the postmaster signaling, which it checks in its main
+	 * loop.
+	 */
+	if (pid == PostmasterPid)
+	{
+		SendPostmasterSignal(PMSIGNAL_LOG_MEMORY_CONTEXT);
+		PG_RETURN_BOOL(true);
+	}
+
 	/*
 	 * See if the process with given pid is a backend or an auxiliary process.
 	 */
diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h
index bcce4011790..bd0d644b9b0 100644
--- a/src/include/storage/pmsignal.h
+++ b/src/include/storage/pmsignal.h
@@ -43,9 +43,11 @@ typedef enum
 	PMSIGNAL_START_WALRECEIVER, /* start a walreceiver */
 	PMSIGNAL_ADVANCE_STATE_MACHINE, /* advance postmaster's state machine */
 	PMSIGNAL_XLOG_IS_SHUTDOWN,	/* ShutdownXLOG() completed */
+	PMSIGNAL_LOG_MEMORY_CONTEXT,	/* ask postmaster to log its memory
+									 * contexts */
 } PMSignalReason;
 
-#define NUM_PMSIGNALS (PMSIGNAL_XLOG_IS_SHUTDOWN+1)
+#define NUM_PMSIGNALS (PMSIGNAL_LOG_MEMORY_CONTEXT+1)
 
 /*
  * Reasons why the postmaster would send SIGQUIT to its children.
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
index c3261bff209..3addd0b01ec 100644
--- a/src/test/regress/expected/misc_functions.out
+++ b/src/test/regress/expected/misc_functions.out
@@ -328,6 +328,13 @@ SELECT pg_log_backend_memory_contexts(pid) FROM pg_stat_activity
  t
 (1 row)
 
+-- First line of postmaster.pid is the PID.
+SELECT pg_log_backend_memory_contexts(split_part(pg_read_file('postmaster.pid'), E'\n', 1)::int);
+ pg_log_backend_memory_contexts 
+--------------------------------
+ t
+(1 row)
+
 CREATE ROLE regress_log_memory;
 SELECT has_function_privilege('regress_log_memory',
   'pg_log_backend_memory_contexts(integer)', 'EXECUTE'); -- no
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
index 946ee5726cd..6fb51f29e5b 100644
--- a/src/test/regress/sql/misc_functions.sql
+++ b/src/test/regress/sql/misc_functions.sql
@@ -93,6 +93,9 @@ SELECT pg_log_backend_memory_contexts(pg_backend_pid());
 SELECT pg_log_backend_memory_contexts(pid) FROM pg_stat_activity
   WHERE backend_type = 'checkpointer';
 
+-- First line of postmaster.pid is the PID.
+SELECT pg_log_backend_memory_contexts(split_part(pg_read_file('postmaster.pid'), E'\n', 1)::int);
+
 CREATE ROLE regress_log_memory;
 
 SELECT has_function_privilege('regress_log_memory',
-- 
2.43.0

