v1-0001-When-getting-EINVAL-from-semget-2-probe-for-EEXIS.patch
application/octet-stream
Filename: v1-0001-When-getting-EINVAL-from-semget-2-probe-for-EEXIS.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v1-0001
Subject: When getting EINVAL from semget(2), probe for EEXIST
| File | + | − |
|---|---|---|
| src/backend/port/sysv_sema.c | 35 | 0 |
From c91fcee144f86be2881eb48f215d26fcfa459c2d Mon Sep 17 00:00:00 2001
From: Gavin Panella <gavinpanella@gmail.com>
Date: Sun, 10 Aug 2025 19:30:19 +0200
Subject: [PATCH v1] When getting EINVAL from semget(2), probe for EEXIST
---
src/backend/port/sysv_sema.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c
index 423b2b4f9d6..51308a651cf 100644
--- a/src/backend/port/sysv_sema.c
+++ b/src/backend/port/sysv_sema.c
@@ -113,6 +113,41 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems)
)
return -1;
+ /*
+ * Typically EINVAL means that the number of semaphores requested is
+ * greater than the system imposed maximum per set, or that the set
+ * exists but that it has fewer than numSems semaphores in it. In the
+ * latter case, presumably the set was allocated by another program or
+ * perhaps by another version of PostgreSQL (SEMAS_PER_SET was raised
+ * in version 17, for example).
+ *
+ * On many platforms, including Linux, since the flags passed to
+ * semget(2) includes IPC_CREAT | IPC_EXCL, it would return <0 and set
+ * errno to EEXIST when numSems is greater than the number of
+ * semaphores in a preexisting set.
+ *
+ * On some platforms, e.g. macOS 15.6, when encountering an existing
+ * set, it appears that numSems is checked first, before considering
+ * flags. This means that when numSems is greater than the number of
+ * semaphores in a preexisting set, semget(2) returns <0 and errno is
+ * set to EINVAL. Hence, on these platforms, EINVAL can mean we've hit
+ * a system limit and thus we cannot continue, OR it can mean we've
+ * found an existing set, a benign and anticipated situation; see how
+ * EEXIST is handled above.
+ *
+ * Fortunately we can distinguish these by calling semget(2) again,
+ * asking for _zero_ semaphores. There is a potential race, e.g. the
+ * semaphore set could be removed, but if we take the stance that we
+ * will not use this set in any case, we need only check that errno is
+ * _not_ EINVAL this time.
+ */
+ if (saved_errno == EINVAL)
+ {
+ semId = semget(semKey, 0, IPC_CREAT | IPC_EXCL | IPCProtection);
+ if (semId >= 0 || errno != EINVAL)
+ return -1;
+ }
+
/*
* Else complain and abort
*/
--
2.50.1