1/*-------------------------------------------------------------------------
4 * Implement PGSemaphores using POSIX semaphore facilities
6 * We prefer the unnamed style of POSIX semaphore (the kind made with
7 * sem_init). We can cope with the kind made with sem_open, however.
9 * In either implementation, typedef PGSemaphore is equivalent to "sem_t *".
10 * With unnamed semaphores, the sem_t structs live in an array in shared
11 * memory. With named semaphores, that's not true because we cannot persuade
12 * sem_open to do its allocation there. Therefore, the named-semaphore code
13 * *does not cope with EXEC_BACKEND*. The sem_t structs will just be in the
14 * postmaster's private memory, where they are successfully inherited by
15 * forked backends, but they could not be accessed by exec'd backends.
18 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
19 * Portions Copyright (c) 1994, Regents of the University of California
22 * src/backend/port/posix_sema.c
24 *-------------------------------------------------------------------------
40/* see file header comment */
41#if defined(USE_NAMED_POSIX_SEMAPHORES) && defined(EXEC_BACKEND)
42#error cannot use named POSIX semaphores with EXEC_BACKEND
51/* typedef PGSemaphore is equivalent to pointer to sem_t */
57 #define PG_SEM_REF(x) (&(x)->sem_padded.pgsem)
59 #define IPCProtection (0600) /* access/modify by user only */
61#ifdef USE_NAMED_POSIX_SEMAPHORES
62static sem_t **mySemPointers;
/* keep track of created semaphores */
66 static int numSems;
/* number of semas acquired so far */
67 static int maxSems;
/* allocated size of above arrays */
74#ifdef USE_NAMED_POSIX_SEMAPHORES
77 * PosixSemaphoreCreate
79 * Attempt to create a new named semaphore.
81 * If we fail with a failure code other than collision-with-existing-sema,
82 * print out an error and abort. Other types of errors suggest nonrecoverable
96 snprintf(semname,
sizeof(semname),
"/pgsql-%d", semKey);
98 mySem = sem_open(semname, O_CREAT | O_EXCL,
102 if (mySem != (sem_t *) SEM_FAILED)
105 if (mySem != (sem_t *) (-1))
109 /* Loop if error indicates a collision */
110 if (errno == EEXIST || errno == EACCES || errno ==
EINTR)
114 * Else complain and abort
116 elog(
FATAL,
"sem_open(\"%s\") failed: %m", semname);
120 * Unlink the semaphore immediately, so it can't be accessed externally.
121 * This also ensures that it will go away if we crash.
127#else /* !USE_NAMED_POSIX_SEMAPHORES */
130 * PosixSemaphoreCreate
132 * Attempt to create a new unnamed semaphore.
137 if (sem_init(
sem, 1, 1) < 0)
140#endif /* USE_NAMED_POSIX_SEMAPHORES */
144 * PosixSemaphoreKill - removes a semaphore
149#ifdef USE_NAMED_POSIX_SEMAPHORES
150 /* Got to use sem_close for named semaphores */
151 if (sem_close(
sem) < 0)
152 elog(
LOG,
"sem_close failed: %m");
154 /* Got to use sem_destroy for unnamed semaphores */
155 if (sem_destroy(
sem) < 0)
156 elog(
LOG,
"sem_destroy failed: %m");
162 * Report amount of shared memory needed for semaphores
167#ifdef USE_NAMED_POSIX_SEMAPHORES
168 /* No shared memory needed in this case */
171 /* Need a PGSemaphoreData per semaphore */
177 * PGReserveSemaphores --- initialize semaphore support
179 * This is called during postmaster start or shared memory reinitialization.
180 * It should do whatever is needed to be able to support up to maxSemas
181 * subsequent PGSemaphoreCreate calls. Also, if any system resources
182 * are acquired here or in PGSemaphoreCreate, register an on_shmem_exit
183 * callback to release them.
185 * In the Posix implementation, we acquire semaphores on-demand; the
186 * maxSemas parameter is just used to size the arrays. For unnamed
187 * semaphores, there is an array of PGSemaphoreData structs in shared memory.
188 * For named semaphores, we keep a postmaster-local array of sem_t pointers,
189 * which we use for releasing the semaphores when done.
190 * (This design minimizes the dependency of postmaster shutdown on the
191 * contents of shared memory, which a failed backend might have clobbered.
192 * We can't do much about the possibility of sem_destroy() crashing, but
193 * we don't have to expose the counters to other processes.)
201 * We use the data directory's inode number to seed the search for free
202 * semaphore keys. This minimizes the odds of collision with other
203 * postmasters, while maximizing the odds that we will detect and clean up
204 * semaphores left over from a crashed postmaster in our own directory.
209 errmsg(
"could not stat data directory \"%s\": %m",
212#ifdef USE_NAMED_POSIX_SEMAPHORES
213 mySemPointers = (sem_t **)
malloc(maxSemas *
sizeof(sem_t *));
214 if (mySemPointers == NULL)
219 * We must use ShmemAllocUnlocked(), since the spinlock protecting
220 * ShmemAlloc() won't be ready yet.
234 * Release semaphores at shutdown or shmem reinitialization
236 * (called as an on_shmem_exit callback, hence funny argument list)
243#ifdef USE_NAMED_POSIX_SEMAPHORES
249#ifdef USE_UNNAMED_POSIX_SEMAPHORES
258 * Allocate a PGSemaphore structure with initial count 1
266 /* Can't do this in a backend, because static state is postmaster's */
270 elog(
PANIC,
"too many semaphores created");
272#ifdef USE_NAMED_POSIX_SEMAPHORES
274 /* Remember new sema for ReleaseSemaphores */
275 mySemPointers[
numSems] = newsem;
291 * Reset a previously-initialized PGSemaphore to have count 0
297 * There's no direct API for this in POSIX, so we have to ratchet the
298 * semaphore down to 0 with repeated trywait's.
304 if (errno ==
EAGAIN || errno == EDEADLK)
305 break;
/* got it down to 0 */
307 continue;
/* can this happen? */
316 * Lock a semaphore (decrement count), blocking if count would be < 0
323 /* See notes in sysv_sema.c's implementation of PGSemaphoreLock. */
327 }
while (errStatus < 0 && errno ==
EINTR);
336 * Unlock a semaphore (increment count)
344 * Note: if errStatus is -1 and errno == EINTR then it means we returned
345 * from the operation prematurely because we were sent a signal. So we
346 * try and unlock the semaphore again. Not clear this can really happen,
347 * but might as well cope.
352 }
while (errStatus < 0 && errno ==
EINTR);
361 * Lock a semaphore only if able to do so without blocking
369 * Note: if errStatus is -1 and errno == EINTR then it means we returned
370 * from the operation prematurely because we were sent a signal. So we
371 * try and lock the semaphore again.
376 }
while (errStatus < 0 && errno ==
EINTR);
380 if (errno ==
EAGAIN || errno == EDEADLK)
381 return false;
/* failed to lock it */
382 /* Otherwise we got trouble */
int errcode_for_file_access(void)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Assert(PointerIsAligned(start, uint64))
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
#define PG_CACHE_LINE_SIZE
struct PGSemaphoreData * PGSemaphore
Size PGSemaphoreShmemSize(int maxSemas)
void PGSemaphoreUnlock(PGSemaphore sema)
union SemTPadded SemTPadded
static void PosixSemaphoreKill(sem_t *sem)
struct PGSemaphoreData PGSemaphoreData
void PGReserveSemaphores(int maxSemas)
void PGSemaphoreReset(PGSemaphore sema)
void PGSemaphoreLock(PGSemaphore sema)
bool PGSemaphoreTryLock(PGSemaphore sema)
static PGSemaphore sharedSemas
PGSemaphore PGSemaphoreCreate(void)
static void ReleaseSemaphores(int status, Datum arg)
static void PosixSemaphoreCreate(sem_t *sem)
void * ShmemAllocUnlocked(Size size)
Size mul_size(Size s1, Size s2)
char pad[PG_CACHE_LINE_SIZE]