PostgreSQL Source Code  git master
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  */
119  ereport(FATAL,
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:1202
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#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:105
#define IPC_CREAT
Definition: win32_port.h:104
#define EIDRM
Definition: win32_port.h:112

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:448
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:103
#define kill(pid, sig)
Definition: win32_port.h:482

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:119

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:117

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 
151  ereport(FATAL,
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:1156
static struct @143 value
#define SETVAL
Definition: win32_port.h:118

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

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)
321  ereport(FATAL,
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. (This ordering is necessary when we
329  * are emulating spinlocks with semaphores.)
330  */
333  numSharedSemas = 0;
334  maxSharedSemas = maxSemas;
335 
336  maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
338  malloc(maxSemaSets * sizeof(IpcSemaphoreId));
339  if (mySemaSets == NULL)
340  elog(PANIC, "out of memory");
341  numSemaSets = 0;
342  nextSemaKey = statbuf.st_ino;
343  nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
344 
346 }
int errcode_for_file_access(void)
Definition: elog.c:881
#define PANIC
Definition: elog.h:42
char * DataDir
Definition: globals.c:66
#define malloc(a)
Definition: header.h:50
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
struct PGSemaphoreData * PGSemaphore
Definition: pg_sema.h:34
void * ShmemAllocUnlocked(Size size)
Definition: shmem.c:247
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:354
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:64
#define stat
Definition: win32_port.h:286

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 369 of file sysv_sema.c.

370 {
371  PGSemaphore sema;
372 
373  /* Can't do this in a backend, because static state is postmaster's */
375 
377  {
378  /* Time to allocate another semaphore set */
379  if (numSemaSets >= maxSemaSets)
380  elog(PANIC, "too many semaphores created");
382  numSemaSets++;
383  nextSemaNumber = 0;
384  }
385  /* Use the next shared PGSemaphoreData */
387  elog(PANIC, "too many semaphores created");
388  sema = &sharedSemas[numSharedSemas++];
389  /* Assign the next free semaphore in the current set */
390  sema->semId = mySemaSets[numSemaSets - 1];
391  sema->semNum = nextSemaNumber++;
392  /* Initialize it to count 1 */
393  IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
394 
395  return sema;
396 }
bool IsUnderPostmaster
Definition: globals.c:113
Assert(fmt[strlen(fmt) - 1] !='\n')
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 415 of file sysv_sema.c.

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

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

◆ PGSemaphoreReset()

void PGSemaphoreReset ( PGSemaphore  sema)

Definition at line 404 of file sysv_sema.c.

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

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:519

References mul_size().

Referenced by PGReserveSemaphores().

◆ PGSemaphoreTryLock()

bool PGSemaphoreTryLock ( PGSemaphore  sema)

Definition at line 478 of file sysv_sema.c.

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

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

◆ PGSemaphoreUnlock()

void PGSemaphoreUnlock ( PGSemaphore  sema)

Definition at line 448 of file sysv_sema.c.

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

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

Referenced by IpcSemaphoreCreate().

◆ ReleaseSemaphores()

static void ReleaseSemaphores ( int  status,
Datum  arg 
)
static

Definition at line 354 of file sysv_sema.c.

355 {
356  int i;
357 
358  for (i = 0; i < numSemaSets; i++)
360  free(mySemaSets);
361 }
#define free(a)
Definition: header.h:65
int i
Definition: isn.c:73
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().