From c6ce449f225bbbe5f2eff78d0b931f0d7f7df620 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 25 Oct 2026 22:01:06 -0400
Subject: [PATCH v1] Drop support for named POSIX semaphores (the sem_open()
 kind).

Commit 72a3902a6 introduced support for sem_open() semaphores
partially as proof of concept of the flexibility of the semaphore API
it introduced, but mostly because that was then the only standardized
semaphore API supported by macOS.  However, macOS has had SysV-style
semaphores since 2002, and we long ago switched to preferring those
on that platform.

Named POSIX semaphores are less nice than unnamed or SysV style, first
because they don't work with EXEC_BACKEND, and second because they
typically consume a file descriptor (or some other resource) per
semaphore per backend, i.e. O(N^2) cost for N backends.  Hence there
are no platforms where they are the preferred approach, and we might
as well drop our long-untested code to support them.
---
 configure                     |  77 ++----------------
 configure.ac                  |  22 ++---
 src/backend/port/meson.build  |   2 +-
 src/backend/port/posix_sema.c | 149 +++-------------------------------
 src/include/pg_config.h.in    |   3 -
 src/template/darwin           |  13 ---
 6 files changed, 24 insertions(+), 242 deletions(-)

diff --git a/configure b/configure
index 6b05d4c84ab..2b0226a4490 100755
--- a/configure
+++ b/configure
@@ -18545,65 +18545,6 @@ fi
 
 # Select semaphore implementation type.
 if test "$PORTNAME" != "win32"; then
-  if test x"$PREFERRED_SEMAPHORES" = x"NAMED_POSIX" ; then
-    # Need sem_open for this
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_open" >&5
-$as_echo_n "checking for library containing sem_open... " >&6; }
-if ${ac_cv_search_sem_open+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sem_open ();
-int
-main ()
-{
-return sem_open ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' rt pthread; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_sem_open=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_sem_open+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_sem_open+:} false; then :
-
-else
-  ac_cv_search_sem_open=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_sem_open" >&5
-$as_echo "$ac_cv_search_sem_open" >&6; }
-ac_res=$ac_cv_search_sem_open
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-  USE_NAMED_POSIX_SEMAPHORES=1
-fi
-
-  fi
   if test x"$PREFERRED_SEMAPHORES" = x"UNNAMED_POSIX" ; then
     # Need sem_init for this
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing sem_init" >&5
@@ -18665,26 +18606,18 @@ fi
   fi
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking which semaphore API to use" >&5
 $as_echo_n "checking which semaphore API to use... " >&6; }
-  if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then
+  if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then
 
-$as_echo "#define USE_NAMED_POSIX_SEMAPHORES 1" >>confdefs.h
+$as_echo "#define USE_UNNAMED_POSIX_SEMAPHORES 1" >>confdefs.h
 
     SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c"
-    sematype="named POSIX"
+    sematype="unnamed POSIX"
   else
-    if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then
-
-$as_echo "#define USE_UNNAMED_POSIX_SEMAPHORES 1" >>confdefs.h
-
-      SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c"
-      sematype="unnamed POSIX"
-    else
 
 $as_echo "#define USE_SYSV_SEMAPHORES 1" >>confdefs.h
 
-      SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c"
-      sematype="System V"
-    fi
+    SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c"
+    sematype="System V"
   fi
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sematype" >&5
 $as_echo "$sematype" >&6; }
diff --git a/configure.ac b/configure.ac
index 6864268eaa0..72f0e13aee9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2354,29 +2354,19 @@ fi
 
 # Select semaphore implementation type.
 if test "$PORTNAME" != "win32"; then
-  if test x"$PREFERRED_SEMAPHORES" = x"NAMED_POSIX" ; then
-    # Need sem_open for this
-    AC_SEARCH_LIBS(sem_open, [rt pthread], [USE_NAMED_POSIX_SEMAPHORES=1])
-  fi
   if test x"$PREFERRED_SEMAPHORES" = x"UNNAMED_POSIX" ; then
     # Need sem_init for this
     AC_SEARCH_LIBS(sem_init, [rt pthread], [USE_UNNAMED_POSIX_SEMAPHORES=1])
   fi
   AC_MSG_CHECKING([which semaphore API to use])
-  if test x"$USE_NAMED_POSIX_SEMAPHORES" = x"1" ; then
-    AC_DEFINE(USE_NAMED_POSIX_SEMAPHORES, 1, [Define to select named POSIX semaphores.])
+  if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then
+    AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.])
     SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c"
-    sematype="named POSIX"
+    sematype="unnamed POSIX"
   else
-    if test x"$USE_UNNAMED_POSIX_SEMAPHORES" = x"1" ; then
-      AC_DEFINE(USE_UNNAMED_POSIX_SEMAPHORES, 1, [Define to select unnamed POSIX semaphores.])
-      SEMA_IMPLEMENTATION="src/backend/port/posix_sema.c"
-      sematype="unnamed POSIX"
-    else
-      AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.])
-      SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c"
-      sematype="System V"
-    fi
+    AC_DEFINE(USE_SYSV_SEMAPHORES, 1, [Define to select SysV-style semaphores.])
+    SEMA_IMPLEMENTATION="src/backend/port/sysv_sema.c"
+    sematype="System V"
   fi
   AC_MSG_RESULT([$sematype])
 else
diff --git a/src/backend/port/meson.build b/src/backend/port/meson.build
index 29e88ef3541..ccb8df10889 100644
--- a/src/backend/port/meson.build
+++ b/src/backend/port/meson.build
@@ -5,7 +5,7 @@ backend_sources += files(
 )
 
 
-if cdata.has('USE_UNNAMED_POSIX_SEMAPHORES') or cdata.has('USE_NAMED_POSIX_SEMAPHORES')
+if cdata.has('USE_UNNAMED_POSIX_SEMAPHORES')
   backend_sources += files('posix_sema.c')
 endif
 
diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c
index 05a8b2222aa..e01aa35e77e 100644
--- a/src/backend/port/posix_sema.c
+++ b/src/backend/port/posix_sema.c
@@ -3,16 +3,13 @@
  * posix_sema.c
  *	  Implement PGSemaphores using POSIX semaphore facilities
  *
- * We prefer the unnamed style of POSIX semaphore (the kind made with
- * sem_init).  We can cope with the kind made with sem_open, however.
+ * We use the unnamed style of POSIX semaphore (the kind made with
+ * sem_init).  We used to support the kind made with sem_open, but
+ * that has several disadvantages, and there are no longer any
+ * platforms where it is a preferable choice.
  *
- * In either implementation, typedef PGSemaphore is equivalent to "sem_t *".
- * With unnamed semaphores, the sem_t structs live in an array in shared
- * memory.  With named semaphores, that's not true because we cannot persuade
- * sem_open to do its allocation there.  Therefore, the named-semaphore code
- * *does not cope with EXEC_BACKEND*.  The sem_t structs will just be in the
- * postmaster's private memory, where they are successfully inherited by
- * forked backends, but they could not be accessed by exec'd backends.
+ * In this implementation, typedef PGSemaphore is equivalent to "sem_t *".
+ * The sem_t structs live in an array in shared memory.
  *
  *
  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
@@ -37,11 +34,6 @@
 #include "storage/shmem.h"
 
 
-/* see file header comment */
-#if defined(USE_NAMED_POSIX_SEMAPHORES) && defined(EXEC_BACKEND)
-#error cannot use named POSIX semaphores with EXEC_BACKEND
-#endif
-
 typedef union SemTPadded
 {
 	sem_t		pgsem;
@@ -58,77 +50,14 @@ typedef struct PGSemaphoreData
 
 #define IPCProtection	(0600)	/* access/modify by user only */
 
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-static sem_t **mySemPointers;	/* keep track of created semaphores */
-#else
 static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */
-#endif
 static int	numSems;			/* number of semas acquired so far */
 static int	maxSems;			/* allocated size of above arrays */
 
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-static int	nextSemKey;			/* next name to try */
-#endif
-
 
 static void ReleaseSemaphores(int status, Datum arg);
 
 
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-
-/*
- * PosixSemaphoreCreate
- *
- * Attempt to create a new named semaphore.
- *
- * If we fail with a failure code other than collision-with-existing-sema,
- * print out an error and abort.  Other types of errors suggest nonrecoverable
- * problems.
- */
-static sem_t *
-PosixSemaphoreCreate(void)
-{
-	int			semKey;
-	char		semname[64];
-	sem_t	   *mySem;
-
-	for (;;)
-	{
-		semKey = nextSemKey++;
-
-		snprintf(semname, sizeof(semname), "/pgsql-%d", semKey);
-
-		mySem = sem_open(semname, O_CREAT | O_EXCL,
-						 (mode_t) IPCProtection, (unsigned) 1);
-
-#ifdef SEM_FAILED
-		if (mySem != (sem_t *) SEM_FAILED)
-			break;
-#else
-		if (mySem != (sem_t *) (-1))
-			break;
-#endif
-
-		/* Loop if error indicates a collision */
-		if (errno == EEXIST || errno == EACCES || errno == EINTR)
-			continue;
-
-		/*
-		 * Else complain and abort
-		 */
-		elog(FATAL, "sem_open(\"%s\") failed: %m", semname);
-	}
-
-	/*
-	 * Unlink the semaphore immediately, so it can't be accessed externally.
-	 * This also ensures that it will go away if we crash.
-	 */
-	sem_unlink(semname);
-
-	return mySem;
-}
-#else							/* !USE_NAMED_POSIX_SEMAPHORES */
-
 /*
  * PosixSemaphoreCreate
  *
@@ -140,7 +69,6 @@ PosixSemaphoreCreate(sem_t *sem)
 	if (sem_init(sem, 1, 1) < 0)
 		elog(FATAL, "sem_init failed: %m");
 }
-#endif							/* USE_NAMED_POSIX_SEMAPHORES */
 
 
 /*
@@ -149,15 +77,9 @@ PosixSemaphoreCreate(sem_t *sem)
 static void
 PosixSemaphoreKill(sem_t *sem)
 {
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-	/* Got to use sem_close for named semaphores */
-	if (sem_close(sem) < 0)
-		elog(LOG, "sem_close failed: %m");
-#else
 	/* Got to use sem_destroy for unnamed semaphores */
 	if (sem_destroy(sem) < 0)
 		elog(LOG, "sem_destroy failed: %m");
-#endif
 }
 
 
@@ -167,15 +89,11 @@ PosixSemaphoreKill(sem_t *sem)
 void
 PGSemaphoreShmemRequest(int maxSemas)
 {
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-	/* No shared memory needed in this case */
-#else
 	/* Need a PGSemaphoreData per semaphore */
 	ShmemRequestStruct(.name = "Semaphores",
 					   .size = mul_size(maxSemas, sizeof(PGSemaphoreData)),
 					   .ptr = (void **) &sharedSemas,
 		);
-#endif
 }
 
 /*
@@ -188,41 +106,15 @@ PGSemaphoreShmemRequest(int maxSemas)
  * callback to release them.
  *
  * In the Posix implementation, we acquire semaphores on-demand; the
- * maxSemas parameter is just used to size the arrays.  For unnamed
- * semaphores, there is an array of PGSemaphoreData structs in shared memory.
- * For named semaphores, we keep a postmaster-local array of sem_t pointers,
- * which we use for releasing the semaphores when done.
- * (This design minimizes the dependency of postmaster shutdown on the
- * contents of shared memory, which a failed backend might have clobbered.
- * We can't do much about the possibility of sem_destroy() crashing, but
- * we don't have to expose the counters to other processes.)
+ * maxSemas parameter is just used to size the arrays.  We keep track
+ * of them using an array of PGSemaphoreData structs in shared memory.
+ * (In the event that a failing backend scribbles on that array, the
+ * postmaster's subsequent sem_destroy() calls might fail, but with
+ * luck the consequences are no worse than some leaked resources.)
  */
 void
 PGSemaphoreInit(int maxSemas)
 {
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-	struct stat statbuf;
-
-	/*
-	 * We use the data directory's inode number to seed the search for free
-	 * semaphore keys.  This minimizes the odds of collision with other
-	 * postmasters, while maximizing the odds that we will detect and clean up
-	 * semaphores left over from a crashed postmaster in our own directory.
-	 */
-	if (stat(DataDir, &statbuf) < 0)
-		ereport(FATAL,
-				(errcode_for_file_access(),
-				 errmsg("could not stat data directory \"%s\": %m",
-						DataDir)));
-	nextSemKey = statbuf.st_ino;
-#endif
-
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-	mySemPointers = (sem_t **) malloc(maxSemas * sizeof(sem_t *));
-	if (mySemPointers == NULL)
-		elog(PANIC, "out of memory");
-#endif
-
 	numSems = 0;
 	maxSems = maxSemas;
 
@@ -237,18 +129,8 @@ PGSemaphoreInit(int maxSemas)
 static void
 ReleaseSemaphores(int status, Datum arg)
 {
-	int			i;
-
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-	for (i = 0; i < numSems; i++)
-		PosixSemaphoreKill(mySemPointers[i]);
-	free(mySemPointers);
-#endif
-
-#ifdef USE_UNNAMED_POSIX_SEMAPHORES
-	for (i = 0; i < numSems; i++)
+	for (int i = 0; i < numSems; i++)
 		PosixSemaphoreKill(PG_SEM_REF(sharedSemas + i));
-#endif
 }
 
 /*
@@ -268,16 +150,9 @@ PGSemaphoreCreate(void)
 	if (numSems >= maxSems)
 		elog(PANIC, "too many semaphores created");
 
-#ifdef USE_NAMED_POSIX_SEMAPHORES
-	newsem = PosixSemaphoreCreate();
-	/* Remember new sema for ReleaseSemaphores */
-	mySemPointers[numSems] = newsem;
-	sema = (PGSemaphore) newsem;
-#else
 	sema = &sharedSemas[numSems];
 	newsem = PG_SEM_REF(sema);
 	PosixSemaphoreCreate(newsem);
-#endif
 
 	numSems++;
 
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 661c4a9b168..2e5ed6f5693 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -723,9 +723,6 @@
 /* Define to 1 to build with LZ4 support. (--with-lz4) */
 #undef USE_LZ4
 
-/* Define to select named POSIX semaphores. */
-#undef USE_NAMED_POSIX_SEMAPHORES
-
 /* Define to 1 to build with OpenSSL support. (--with-ssl=openssl) */
 #undef USE_OPENSSL
 
diff --git a/src/template/darwin b/src/template/darwin
index e8eb9390687..2486b349aa4 100644
--- a/src/template/darwin
+++ b/src/template/darwin
@@ -14,17 +14,4 @@ fi
 # Extra CFLAGS for code that will go into a shared library
 CFLAGS_SL=""
 
-# Select appropriate semaphore support.  Darwin 6.0 (macOS 10.2) and up
-# support System V semaphores; before that we have to use named POSIX
-# semaphores, which are less good for our purposes because they eat a
-# file descriptor per backend per max_connection slot.
-case $host_os in
-  darwin[015].*)
-    USE_NAMED_POSIX_SEMAPHORES=1
-    ;;
-  *)
-    USE_SYSV_SEMAPHORES=1
-    ;;
-esac
-
 DLSUFFIX=".dylib"
-- 
2.52.0

