From 92b0b27733f0f22e230a9139657d9b432ebf6ee0 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Tue, 21 Feb 2023 11:50:08 +1300
Subject: [PATCH v5 3/3] Use pipe2() for postmaster pipe, where available.

The 2-argument variant of pipe() (expected in the next POSIX revision)
saves the need to make a separate fcntl() call later.  It's already
available on all targeted Unixes except macOS and AIX.

Discussion: https://postgr.es/m/CA%2BhUKGKb6FsAdQWcRL35KJsftv%2B9zXqQbzwkfRf1i0J2e57%2BhQ%40mail.gmail.com
---
 configure                           | 12 ++++++++++++
 configure.ac                        |  1 +
 meson.build                         |  1 +
 src/backend/postmaster/postmaster.c | 10 ++++++++++
 src/backend/utils/init/miscinit.c   |  9 ++++++++-
 src/include/pg_config.h.in          |  4 ++++
 6 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/configure b/configure
index d06f64cdbb..0aff9f5732 100755
--- a/configure
+++ b/configure
@@ -16231,6 +16231,18 @@ cat >>confdefs.h <<_ACEOF
 #define HAVE_DECL_ACCEPT4 $ac_have_decl
 _ACEOF
 
+ac_fn_c_check_decl "$LINENO" "pipe2" "ac_cv_have_decl_pipe2" "#include <unistd.h>
+"
+if test "x$ac_cv_have_decl_pipe2" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PIPE2 $ac_have_decl
+_ACEOF
+
 ac_fn_c_check_decl "$LINENO" "preadv" "ac_cv_have_decl_preadv" "#include <sys/uio.h>
 "
 if test "x$ac_cv_have_decl_preadv" = xyes; then :
diff --git a/configure.ac b/configure.ac
index 070a0b33db..d75eb76897 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1844,6 +1844,7 @@ AC_CHECK_DECLS([strlcat, strlcpy, strnlen])
 # We can't use AC_REPLACE_FUNCS to replace these functions, because it
 # won't handle deployment target restrictions on macOS
 AC_CHECK_DECLS([accept4], [], [], [#include <sys/socket.h>])
+AC_CHECK_DECLS([pipe2], [], [], [#include <unistd.h>])
 AC_CHECK_DECLS([preadv], [], [AC_LIBOBJ(preadv)], [#include <sys/uio.h>])
 AC_CHECK_DECLS([pwritev], [], [AC_LIBOBJ(pwritev)], [#include <sys/uio.h>])
 
diff --git a/meson.build b/meson.build
index c91fb05133..ad2faefff4 100644
--- a/meson.build
+++ b/meson.build
@@ -2098,6 +2098,7 @@ decl_checks = [
 # restrictions on macOS
 decl_checks += [
   ['accept4', 'sys/socket.h'],
+  ['pipe2', 'unistd.h'],
   ['preadv', 'sys/uio.h'],
   ['pwritev', 'sys/uio.h'],
 ]
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 2552327d90..fdcfdfd558 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -6506,12 +6506,22 @@ InitPostmasterDeathWatchHandle(void)
 	 * close the write end as soon as possible after forking, because EOF
 	 * won't be signaled in the read end until all processes have closed the
 	 * write fd. That is taken care of in ClosePostmasterPorts().
+	 *
+	 * If this platform has pipe2(), and we're not in an EXEC_BACKEND build,
+	 * then we can avoid a later fcntl() call by asking for O_CLOEXEC now.
 	 */
 	Assert(MyProcPid == PostmasterPid);
+#if HAVE_DECL_PIPE2 && !defined(EXEC_BACKEND)
+	if (pipe2(postmaster_alive_fds, O_CLOEXEC) < 0)
+		ereport(FATAL,
+				(errcode_for_file_access(),
+				 errmsg_internal("could not create pipe to monitor postmaster death: %m")));
+#else
 	if (pipe(postmaster_alive_fds) < 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
 				 errmsg_internal("could not create pipe to monitor postmaster death: %m")));
+#endif
 
 	/* Notify fd.c that we've eaten two FDs for the pipe. */
 	ReserveExternalFD();
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 7eb7fe87f6..f706b73e91 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -164,13 +164,20 @@ InitPostmasterChild(void)
 	/* Request a signal if the postmaster dies, if possible. */
 	PostmasterDeathSignalInit();
 
-	/* Don't give the pipe to subprograms that we execute. */
+	/*
+	 * Don't give the pipe to subprograms that we execute.  We only need to
+	 * do this explicitly here if the platform lacks pipe2(), or we're in an
+	 * EXEC_BACKEND build so the pipe had to survive the first level of
+	 * exec*() to get here.
+	 */
 #ifndef WIN32
+#if !HAVE_DECL_PIPE2 || defined(EXEC_BACKEND)
 	if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFD, FD_CLOEXEC) < 0)
 		ereport(FATAL,
 				(errcode_for_socket_access(),
 				 errmsg_internal("could not set postmaster death monitoring pipe to FD_CLOEXEC mode: %m")));
 #endif
+#endif
 }
 
 /*
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index e21d0f05f5..5cd5acf98e 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -123,6 +123,10 @@
    to 0 if you don't. */
 #undef HAVE_DECL_LLVMORCGETSYMBOLADDRESSIN
 
+/* Define to 1 if you have the declaration of `pipe2', and to 0 if you don't.
+   */
+#undef HAVE_DECL_PIPE2
+
 /* Define to 1 if you have the declaration of `posix_fadvise', and to 0 if you
    don't. */
 #undef HAVE_DECL_POSIX_FADVISE
-- 
2.39.1

