PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
sysv_sema.c File Reference
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/stat.h>
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_sema.h"
#include "storage/shmem.h"
Include dependency graph for sysv_sema.c:

Go to the source code of this file.

Data Structures

struct  PGSemaphoreData
 
union  semun
 

Macros

#define SEMAS_PER_SET   16
 
#define IPCProtection   (0600) /* access/modify by user only */
 
#define PGSemaMagic   537 /* must be less than SEMVMX */
 

Typedefs

typedef struct PGSemaphoreData PGSemaphoreData
 
typedef key_t IpcSemaphoreKey
 
typedef int IpcSemaphoreId
 

Functions

static IpcSemaphoreId InternalIpcSemaphoreCreate (IpcSemaphoreKey semKey, int numSems)
 
static void IpcSemaphoreInitialize (IpcSemaphoreId semId, int semNum, int value)
 
static void IpcSemaphoreKill (IpcSemaphoreId semId)
 
static int IpcSemaphoreGetValue (IpcSemaphoreId semId, int semNum)
 
static pid_t IpcSemaphoreGetLastPID (IpcSemaphoreId semId, int semNum)
 
static IpcSemaphoreId IpcSemaphoreCreate (int numSems)
 
static void ReleaseSemaphores (int status, Datum arg)
 
Size PGSemaphoreShmemSize (int maxSemas)
 
void PGReserveSemaphores (int maxSemas)
 
PGSemaphore PGSemaphoreCreate (void)
 
void PGSemaphoreReset (PGSemaphore sema)
 
void PGSemaphoreLock (PGSemaphore sema)
 
void PGSemaphoreUnlock (PGSemaphore sema)
 
bool PGSemaphoreTryLock (PGSemaphore sema)
 

Variables

static PGSemaphore sharedSemas
 
static int numSharedSemas
 
static int maxSharedSemas
 
static IpcSemaphoreIdmySemaSets
 
static int numSemaSets
 
static int maxSemaSets
 
static IpcSemaphoreKey nextSemaKey
 
static int nextSemaNumber
 

Macro Definition Documentation

◆ IPCProtection

#define IPCProtection   (0600) /* access/modify by user only */

Definition at line 56 of file sysv_sema.c.

◆ PGSemaMagic

#define PGSemaMagic   537 /* must be less than SEMVMX */

Definition at line 58 of file sysv_sema.c.

◆ SEMAS_PER_SET

#define SEMAS_PER_SET   16

Definition at line 54 of file sysv_sema.c.

Typedef Documentation

◆ IpcSemaphoreId

typedef int IpcSemaphoreId

Definition at line 46 of file sysv_sema.c.

◆ IpcSemaphoreKey

Definition at line 45 of file sysv_sema.c.

◆ PGSemaphoreData

Function Documentation

◆ InternalIpcSemaphoreCreate()

static IpcSemaphoreId InternalIpcSemaphoreCreate ( IpcSemaphoreKey  semKey,
int  numSems 
)
static

Definition at line 93 of file sysv_sema.c.

94{
95 int semId;
96
97 semId = semget(semKey, numSems, IPC_CREAT | IPC_EXCL | IPCProtection);
98
99 if (semId < 0)
100 {
101 int saved_errno = errno;
102
103 /*
104 * Fail quietly if error indicates a collision with existing set. One
105 * would expect EEXIST, given that we said IPC_EXCL, but perhaps we
106 * could get a permission violation instead? Also, EIDRM might occur
107 * if an old set is slated for destruction but not gone yet.
108 */
109 if (saved_errno == EEXIST || saved_errno == EACCES
110#ifdef EIDRM
111 || saved_errno == EIDRM
112#endif
113 )
114 return -1;
115
116 /*
117 * Else complain and abort
118 */
120 (errmsg("could not create semaphores: %m"),
121 errdetail("Failed system call was semget(%lu, %d, 0%o).",
122 (unsigned long) semKey, numSems,
124 (saved_errno == ENOSPC) ?
125 errhint("This error does *not* mean that you have run out of disk space. "
126 "It occurs when either the system limit for the maximum number of "
127 "semaphore sets (SEMMNI), or the system wide maximum number of "
128 "semaphores (SEMMNS), would be exceeded. You need to raise the "
129 "respective kernel parameter. Alternatively, reduce PostgreSQL's "
130 "consumption of semaphores by reducing its \"max_connections\" parameter.\n"
131 "The PostgreSQL documentation contains more information about "
132 "configuring your system for PostgreSQL.") : 0));
133 }
134
135 return semId;
136}
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int errhint(const char *fmt,...)
Definition: elog.c:1318
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:149
static int numSems
Definition: posix_sema.c:66
#define IPCProtection
Definition: sysv_sema.c:56
#define IPC_EXCL
Definition: win32_port.h:95
#define IPC_CREAT
Definition: win32_port.h:94
#define EIDRM
Definition: win32_port.h:102

References EIDRM, ereport, errdetail(), errhint(), errmsg(), FATAL, IPC_CREAT, IPC_EXCL, IPCProtection, and numSems.

Referenced by IpcSemaphoreCreate().

◆ IpcSemaphoreCreate()

static IpcSemaphoreId IpcSemaphoreCreate ( int  numSems)
static

Definition at line 208 of file sysv_sema.c.

209{
210 IpcSemaphoreId semId;
211 union semun semun;
212 PGSemaphoreData mysema;
213
214 /* Loop till we find a free IPC key */
215 for (nextSemaKey++;; nextSemaKey++)
216 {
217 pid_t creatorPID;
218
219 /* Try to create new semaphore set */
221 if (semId >= 0)
222 break; /* successful create */
223
224 /* See if it looks to be leftover from a dead Postgres process */
225 semId = semget(nextSemaKey, numSems + 1, 0);
226 if (semId < 0)
227 continue; /* failed: must be some other app's */
229 continue; /* sema belongs to a non-Postgres app */
230
231 /*
232 * If the creator PID is my own PID or does not belong to any extant
233 * process, it's safe to zap it.
234 */
235 creatorPID = IpcSemaphoreGetLastPID(semId, numSems);
236 if (creatorPID <= 0)
237 continue; /* oops, GETPID failed */
238 if (creatorPID != getpid())
239 {
240 if (kill(creatorPID, 0) == 0 || errno != ESRCH)
241 continue; /* sema belongs to a live process */
242 }
243
244 /*
245 * The sema set appears to be from a dead Postgres process, or from a
246 * previous cycle of life in this same process. Zap it, if possible.
247 * This probably shouldn't fail, but if it does, assume the sema set
248 * belongs to someone else after all, and continue quietly.
249 */
250 semun.val = 0; /* unused, but keep compiler quiet */
251 if (semctl(semId, 0, IPC_RMID, semun) < 0)
252 continue;
253
254 /*
255 * Now try again to create the sema set.
256 */
258 if (semId >= 0)
259 break; /* successful create */
260
261 /*
262 * Can only get here if some other process managed to create the same
263 * sema key before we did. Let him have that one, loop around to try
264 * next key.
265 */
266 }
267
268 /*
269 * OK, we created a new sema set. Mark it as created by this process. We
270 * do this by setting the spare semaphore to PGSemaMagic-1 and then
271 * incrementing it with semop(). That leaves it with value PGSemaMagic
272 * and sempid referencing this process.
273 */
275 mysema.semId = semId;
276 mysema.semNum = numSems;
277 PGSemaphoreUnlock(&mysema);
278
279 return semId;
280}
#define PGSemaMagic
Definition: sysv_sema.c:58
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: sysv_sema.c:447
static pid_t IpcSemaphoreGetLastPID(IpcSemaphoreId semId, int semNum)
Definition: sysv_sema.c:188
static int IpcSemaphoreGetValue(IpcSemaphoreId semId, int semNum)
Definition: sysv_sema.c:177
int IpcSemaphoreId
Definition: sysv_sema.c:46
static IpcSemaphoreKey nextSemaKey
Definition: sysv_sema.c:67
static IpcSemaphoreId InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems)
Definition: sysv_sema.c:93
static void IpcSemaphoreInitialize(IpcSemaphoreId semId, int semNum, int value)
Definition: sysv_sema.c:142
int val
Definition: sysv_sema.c:39
#define IPC_RMID
Definition: win32_port.h:93
#define kill(pid, sig)
Definition: win32_port.h:493

References InternalIpcSemaphoreCreate(), IPC_RMID, IpcSemaphoreGetLastPID(), IpcSemaphoreGetValue(), IpcSemaphoreInitialize(), kill, nextSemaKey, numSems, PGSemaMagic, PGSemaphoreUnlock(), and semun::val.

Referenced by PGSemaphoreCreate().

◆ IpcSemaphoreGetLastPID()

static pid_t IpcSemaphoreGetLastPID ( IpcSemaphoreId  semId,
int  semNum 
)
static

Definition at line 188 of file sysv_sema.c.

189{
190 union semun dummy; /* for Solaris */
191
192 dummy.val = 0; /* unused */
193
194 return semctl(semId, semNum, GETPID, dummy);
195}
#define GETPID
Definition: win32_port.h:109

References GETPID, and semun::val.

Referenced by IpcSemaphoreCreate().

◆ IpcSemaphoreGetValue()

static int IpcSemaphoreGetValue ( IpcSemaphoreId  semId,
int  semNum 
)
static

Definition at line 177 of file sysv_sema.c.

178{
179 union semun dummy; /* for Solaris */
180
181 dummy.val = 0; /* unused */
182
183 return semctl(semId, semNum, GETVAL, dummy);
184}
#define GETVAL
Definition: win32_port.h:107

References GETVAL, and semun::val.

Referenced by IpcSemaphoreCreate().

◆ IpcSemaphoreInitialize()

static void IpcSemaphoreInitialize ( IpcSemaphoreId  semId,
int  semNum,
int  value 
)
static

Definition at line 142 of file sysv_sema.c.

143{
144 union semun semun;
145
146 semun.val = value;
147 if (semctl(semId, semNum, SETVAL, semun) < 0)
148 {
149 int saved_errno = errno;
150
152 (errmsg_internal("semctl(%d, %d, SETVAL, %d) failed: %m",
153 semId, semNum, value),
154 (saved_errno == ERANGE) ?
155 errhint("You possibly need to raise your kernel's SEMVMX value to be at least "
156 "%d. Look into the PostgreSQL documentation for details.",
157 value) : 0));
158 }
159}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1158
static struct @165 value
#define SETVAL
Definition: win32_port.h:108

References ereport, errhint(), errmsg_internal(), FATAL, SETVAL, semun::val, and value.

Referenced by IpcSemaphoreCreate(), PGSemaphoreCreate(), and PGSemaphoreReset().

◆ IpcSemaphoreKill()

static void IpcSemaphoreKill ( IpcSemaphoreId  semId)
static

Definition at line 165 of file sysv_sema.c.

166{
167 union semun semun;
168
169 semun.val = 0; /* unused, but keep compiler quiet */
170
171 if (semctl(semId, 0, IPC_RMID, semun) < 0)
172 elog(LOG, "semctl(%d, 0, IPC_RMID, ...) failed: %m", semId);
173}
#define LOG
Definition: elog.h:31
#define elog(elevel,...)
Definition: elog.h:225

References elog, IPC_RMID, LOG, and semun::val.

Referenced by ReleaseSemaphores().

◆ PGReserveSemaphores()

void PGReserveSemaphores ( int  maxSemas)

Definition at line 310 of file sysv_sema.c.

311{
312 struct stat statbuf;
313
314 /*
315 * We use the data directory's inode number to seed the search for free
316 * semaphore keys. This minimizes the odds of collision with other
317 * postmasters, while maximizing the odds that we will detect and clean up
318 * semaphores left over from a crashed postmaster in our own directory.
319 */
320 if (stat(DataDir, &statbuf) < 0)
323 errmsg("could not stat data directory \"%s\": %m",
324 DataDir)));
325
326 /*
327 * We must use ShmemAllocUnlocked(), since the spinlock protecting
328 * ShmemAlloc() won't be ready yet.
329 */
332 numSharedSemas = 0;
333 maxSharedSemas = maxSemas;
334
335 maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
338 if (mySemaSets == NULL)
339 elog(PANIC, "out of memory");
340 numSemaSets = 0;
341 nextSemaKey = statbuf.st_ino;
342 nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
343
345}
int errcode_for_file_access(void)
Definition: elog.c:877
#define PANIC
Definition: elog.h:42
char * DataDir
Definition: globals.c:71
#define malloc(a)
Definition: header.h:50
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
struct PGSemaphoreData * PGSemaphore
Definition: pg_sema.h:34
void * ShmemAllocUnlocked(Size size)
Definition: shmem.c:238
Size PGSemaphoreShmemSize(int maxSemas)
Definition: sysv_sema.c:287
static int maxSharedSemas
Definition: sysv_sema.c:63
#define SEMAS_PER_SET
Definition: sysv_sema.c:54
static int numSemaSets
Definition: sysv_sema.c:65
static int nextSemaNumber
Definition: sysv_sema.c:68
static PGSemaphore sharedSemas
Definition: sysv_sema.c:61
static int maxSemaSets
Definition: sysv_sema.c:66
static int numSharedSemas
Definition: sysv_sema.c:62
static void ReleaseSemaphores(int status, Datum arg)
Definition: sysv_sema.c:353
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:64
#define stat
Definition: win32_port.h:274

References DataDir, elog, ereport, errcode_for_file_access(), errmsg(), FATAL, malloc, maxSemaSets, maxSharedSemas, mySemaSets, nextSemaKey, nextSemaNumber, numSemaSets, numSharedSemas, on_shmem_exit(), PANIC, PGSemaphoreShmemSize(), ReleaseSemaphores(), SEMAS_PER_SET, sharedSemas, ShmemAllocUnlocked(), stat::st_ino, and stat.

◆ PGSemaphoreCreate()

PGSemaphore PGSemaphoreCreate ( void  )

Definition at line 368 of file sysv_sema.c.

369{
370 PGSemaphore sema;
371
372 /* Can't do this in a backend, because static state is postmaster's */
374
376 {
377 /* Time to allocate another semaphore set */
379 elog(PANIC, "too many semaphores created");
381 numSemaSets++;
382 nextSemaNumber = 0;
383 }
384 /* Use the next shared PGSemaphoreData */
386 elog(PANIC, "too many semaphores created");
387 sema = &sharedSemas[numSharedSemas++];
388 /* Assign the next free semaphore in the current set */
389 sema->semId = mySemaSets[numSemaSets - 1];
390 sema->semNum = nextSemaNumber++;
391 /* Initialize it to count 1 */
392 IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
393
394 return sema;
395}
bool IsUnderPostmaster
Definition: globals.c:120
Assert(PointerIsAligned(start, uint64))
static IpcSemaphoreId IpcSemaphoreCreate(int numSems)
Definition: sysv_sema.c:208

References Assert(), elog, IpcSemaphoreCreate(), IpcSemaphoreInitialize(), IsUnderPostmaster, maxSemaSets, maxSharedSemas, mySemaSets, nextSemaNumber, numSemaSets, numSharedSemas, PANIC, SEMAS_PER_SET, PGSemaphoreData::semId, PGSemaphoreData::semNum, and sharedSemas.

◆ PGSemaphoreLock()

void PGSemaphoreLock ( PGSemaphore  sema)

Definition at line 414 of file sysv_sema.c.

415{
416 int errStatus;
417 struct sembuf sops;
418
419 sops.sem_op = -1; /* decrement */
420 sops.sem_flg = 0;
421 sops.sem_num = sema->semNum;
422
423 /*
424 * Note: if errStatus is -1 and errno == EINTR then it means we returned
425 * from the operation prematurely because we were sent a signal. So we
426 * try and lock the semaphore again.
427 *
428 * We used to check interrupts here, but that required servicing
429 * interrupts directly from signal handlers. Which is hard to do safely
430 * and portably.
431 */
432 do
433 {
434 errStatus = semop(sema->semId, &sops, 1);
435 } while (errStatus < 0 && errno == EINTR);
436
437 if (errStatus < 0)
438 elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
439}
#define EINTR
Definition: win32_port.h:364

References EINTR, elog, FATAL, PGSemaphoreData::semId, and PGSemaphoreData::semNum.

◆ PGSemaphoreReset()

void PGSemaphoreReset ( PGSemaphore  sema)

Definition at line 403 of file sysv_sema.c.

404{
405 IpcSemaphoreInitialize(sema->semId, sema->semNum, 0);
406}

References IpcSemaphoreInitialize(), PGSemaphoreData::semId, and PGSemaphoreData::semNum.

◆ PGSemaphoreShmemSize()

Size PGSemaphoreShmemSize ( int  maxSemas)

Definition at line 287 of file sysv_sema.c.

288{
289 return mul_size(maxSemas, sizeof(PGSemaphoreData));
290}
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

References mul_size().

Referenced by PGReserveSemaphores().

◆ PGSemaphoreTryLock()

bool PGSemaphoreTryLock ( PGSemaphore  sema)

Definition at line 477 of file sysv_sema.c.

478{
479 int errStatus;
480 struct sembuf sops;
481
482 sops.sem_op = -1; /* decrement */
483 sops.sem_flg = IPC_NOWAIT; /* but don't block */
484 sops.sem_num = sema->semNum;
485
486 /*
487 * Note: if errStatus is -1 and errno == EINTR then it means we returned
488 * from the operation prematurely because we were sent a signal. So we
489 * try and lock the semaphore again.
490 */
491 do
492 {
493 errStatus = semop(sema->semId, &sops, 1);
494 } while (errStatus < 0 && errno == EINTR);
495
496 if (errStatus < 0)
497 {
498 /* Expect EAGAIN or EWOULDBLOCK (platform-dependent) */
499#ifdef EAGAIN
500 if (errno == EAGAIN)
501 return false; /* failed to lock it */
502#endif
503#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
504 if (errno == EWOULDBLOCK)
505 return false; /* failed to lock it */
506#endif
507 /* Otherwise we got trouble */
508 elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
509 }
510
511 return true;
512}
#define EWOULDBLOCK
Definition: win32_port.h:370
#define IPC_NOWAIT
Definition: win32_port.h:97
#define EAGAIN
Definition: win32_port.h:362

References EAGAIN, EINTR, elog, EWOULDBLOCK, FATAL, IPC_NOWAIT, PGSemaphoreData::semId, and PGSemaphoreData::semNum.

◆ PGSemaphoreUnlock()

void PGSemaphoreUnlock ( PGSemaphore  sema)

Definition at line 447 of file sysv_sema.c.

448{
449 int errStatus;
450 struct sembuf sops;
451
452 sops.sem_op = 1; /* increment */
453 sops.sem_flg = 0;
454 sops.sem_num = sema->semNum;
455
456 /*
457 * Note: if errStatus is -1 and errno == EINTR then it means we returned
458 * from the operation prematurely because we were sent a signal. So we
459 * try and unlock the semaphore again. Not clear this can really happen,
460 * but might as well cope.
461 */
462 do
463 {
464 errStatus = semop(sema->semId, &sops, 1);
465 } while (errStatus < 0 && errno == EINTR);
466
467 if (errStatus < 0)
468 elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
469}

References EINTR, elog, FATAL, PGSemaphoreData::semId, and PGSemaphoreData::semNum.

Referenced by IpcSemaphoreCreate().

◆ ReleaseSemaphores()

static void ReleaseSemaphores ( int  status,
Datum  arg 
)
static

Definition at line 353 of file sysv_sema.c.

354{
355 int i;
356
357 for (i = 0; i < numSemaSets; i++)
360}
#define free(a)
Definition: header.h:65
int i
Definition: isn.c:77
static void IpcSemaphoreKill(IpcSemaphoreId semId)
Definition: sysv_sema.c:165

References free, i, IpcSemaphoreKill(), mySemaSets, and numSemaSets.

Referenced by PGReserveSemaphores().

Variable Documentation

◆ maxSemaSets

int maxSemaSets
static

Definition at line 66 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ maxSharedSemas

int maxSharedSemas
static

Definition at line 63 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ mySemaSets

IpcSemaphoreId* mySemaSets
static

Definition at line 64 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), PGSemaphoreCreate(), and ReleaseSemaphores().

◆ nextSemaKey

IpcSemaphoreKey nextSemaKey
static

Definition at line 67 of file sysv_sema.c.

Referenced by IpcSemaphoreCreate(), and PGReserveSemaphores().

◆ nextSemaNumber

int nextSemaNumber
static

Definition at line 68 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ numSemaSets

int numSemaSets
static

Definition at line 65 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), PGSemaphoreCreate(), and ReleaseSemaphores().

◆ numSharedSemas

int numSharedSemas
static

Definition at line 62 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ sharedSemas

PGSemaphore sharedSemas
static

Definition at line 61 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().