PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
sysv_sema.c File Reference
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include <sys/file.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, int port)
 
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

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

Definition at line 59 of file sysv_sema.c.

Referenced by InternalIpcSemaphoreCreate().

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

Definition at line 61 of file sysv_sema.c.

Referenced by IpcSemaphoreCreate().

#define SEMAS_PER_SET   16

Definition at line 57 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

Typedef Documentation

Definition at line 49 of file sysv_sema.c.

Definition at line 48 of file sysv_sema.c.

Function Documentation

static IpcSemaphoreId InternalIpcSemaphoreCreate ( IpcSemaphoreKey  semKey,
int  numSems 
)
static

Definition at line 96 of file sysv_sema.c.

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

Referenced by IpcSemaphoreCreate().

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

Definition at line 211 of file sysv_sema.c.

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

Referenced by PGSemaphoreCreate().

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

Definition at line 191 of file sysv_sema.c.

References GETPID, and semun::val.

Referenced by IpcSemaphoreCreate().

192 {
193  union semun dummy; /* for Solaris */
194 
195  dummy.val = 0; /* unused */
196 
197  return semctl(semId, semNum, GETPID, dummy);
198 }
int val
Definition: sysv_sema.c:42
#define GETPID
Definition: win32.h:122
static int IpcSemaphoreGetValue ( IpcSemaphoreId  semId,
int  semNum 
)
static

Definition at line 180 of file sysv_sema.c.

References GETVAL, and semun::val.

Referenced by IpcSemaphoreCreate().

181 {
182  union semun dummy; /* for Solaris */
183 
184  dummy.val = 0; /* unused */
185 
186  return semctl(semId, semNum, GETVAL, dummy);
187 }
int val
Definition: sysv_sema.c:42
#define GETVAL
Definition: win32.h:120
static void IpcSemaphoreInitialize ( IpcSemaphoreId  semId,
int  semNum,
int  value 
)
static

Definition at line 145 of file sysv_sema.c.

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

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

146 {
147  union semun semun;
148 
149  semun.val = value;
150  if (semctl(semId, semNum, SETVAL, semun) < 0)
151  {
152  int saved_errno = errno;
153 
154  ereport(FATAL,
155  (errmsg_internal("semctl(%d, %d, SETVAL, %d) failed: %m",
156  semId, semNum, value),
157  (saved_errno == ERANGE) ?
158  errhint("You possibly need to raise your kernel's SEMVMX value to be at least "
159  "%d. Look into the PostgreSQL documentation for details.",
160  value) : 0));
161  }
162 }
int errhint(const char *fmt,...)
Definition: elog.c:987
#define SETVAL
Definition: win32.h:121
#define FATAL
Definition: elog.h:52
static struct @121 value
int val
Definition: sysv_sema.c:42
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
static void IpcSemaphoreKill ( IpcSemaphoreId  semId)
static

Definition at line 168 of file sysv_sema.c.

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

Referenced by ReleaseSemaphores().

169 {
170  union semun semun;
171 
172  semun.val = 0; /* unused, but keep compiler quiet */
173 
174  if (semctl(semId, 0, IPC_RMID, semun) < 0)
175  elog(LOG, "semctl(%d, 0, IPC_RMID, ...) failed: %m", semId);
176 }
#define LOG
Definition: elog.h:26
int val
Definition: sysv_sema.c:42
#define IPC_RMID
Definition: win32.h:106
#define elog
Definition: elog.h:219
void PGReserveSemaphores ( int  maxSemas,
int  port 
)

Definition at line 317 of file sysv_sema.c.

References elog, malloc, maxSemaSets, maxSharedSemas, mySemaSets, nextSemaKey, nextSemaNumber, NULL, numSemaSets, numSharedSemas, on_shmem_exit(), PANIC, PGSemaphoreShmemSize(), ReleaseSemaphores(), SEMAS_PER_SET, and ShmemAllocUnlocked().

318 {
319  /*
320  * We must use ShmemAllocUnlocked(), since the spinlock protecting
321  * ShmemAlloc() won't be ready yet. (This ordering is necessary when we
322  * are emulating spinlocks with semaphores.)
323  */
326  numSharedSemas = 0;
327  maxSharedSemas = maxSemas;
328 
329  maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
331  malloc(maxSemaSets * sizeof(IpcSemaphoreId));
332  if (mySemaSets == NULL)
333  elog(PANIC, "out of memory");
334  numSemaSets = 0;
335  nextSemaKey = port * 1000;
336  nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
337 
339 }
static int maxSemaSets
Definition: sysv_sema.c:69
static void ReleaseSemaphores(int status, Datum arg)
Definition: sysv_sema.c:347
#define SEMAS_PER_SET
Definition: sysv_sema.c:57
static int maxSharedSemas
Definition: sysv_sema.c:66
static PGSemaphore sharedSemas
Definition: sysv_sema.c:64
#define PANIC
Definition: elog.h:53
int IpcSemaphoreId
Definition: sysv_sema.c:49
#define malloc(a)
Definition: header.h:50
static int nextSemaNumber
Definition: sysv_sema.c:71
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:348
static int port
Definition: pg_regress.c:89
static int numSharedSemas
Definition: sysv_sema.c:65
void * ShmemAllocUnlocked(Size size)
Definition: shmem.c:227
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:67
#define NULL
Definition: c.h:229
Size PGSemaphoreShmemSize(int maxSemas)
Definition: sysv_sema.c:290
struct PGSemaphoreData * PGSemaphore
Definition: pg_sema.h:34
static IpcSemaphoreKey nextSemaKey
Definition: sysv_sema.c:70
#define elog
Definition: elog.h:219
static int numSemaSets
Definition: sysv_sema.c:68
PGSemaphore PGSemaphoreCreate ( void  )

Definition at line 362 of file sysv_sema.c.

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

363 {
364  PGSemaphore sema;
365 
366  /* Can't do this in a backend, because static state is postmaster's */
368 
370  {
371  /* Time to allocate another semaphore set */
372  if (numSemaSets >= maxSemaSets)
373  elog(PANIC, "too many semaphores created");
375  numSemaSets++;
376  nextSemaNumber = 0;
377  }
378  /* Use the next shared PGSemaphoreData */
380  elog(PANIC, "too many semaphores created");
381  sema = &sharedSemas[numSharedSemas++];
382  /* Assign the next free semaphore in the current set */
383  sema->semId = mySemaSets[numSemaSets - 1];
384  sema->semNum = nextSemaNumber++;
385  /* Initialize it to count 1 */
386  IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
387 
388  return sema;
389 }
static int maxSemaSets
Definition: sysv_sema.c:69
#define SEMAS_PER_SET
Definition: sysv_sema.c:57
static int maxSharedSemas
Definition: sysv_sema.c:66
static PGSemaphore sharedSemas
Definition: sysv_sema.c:64
#define PANIC
Definition: elog.h:53
static int nextSemaNumber
Definition: sysv_sema.c:71
static void IpcSemaphoreInitialize(IpcSemaphoreId semId, int semNum, int value)
Definition: sysv_sema.c:145
bool IsUnderPostmaster
Definition: globals.c:101
static int numSharedSemas
Definition: sysv_sema.c:65
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:67
#define Assert(condition)
Definition: c.h:675
static IpcSemaphoreId IpcSemaphoreCreate(int numSems)
Definition: sysv_sema.c:211
#define elog
Definition: elog.h:219
static int numSemaSets
Definition: sysv_sema.c:68
void PGSemaphoreLock ( PGSemaphore  sema)

Definition at line 408 of file sysv_sema.c.

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

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

Definition at line 397 of file sysv_sema.c.

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

398 {
399  IpcSemaphoreInitialize(sema->semId, sema->semNum, 0);
400 }
static void IpcSemaphoreInitialize(IpcSemaphoreId semId, int semNum, int value)
Definition: sysv_sema.c:145
Size PGSemaphoreShmemSize ( int  maxSemas)

Definition at line 290 of file sysv_sema.c.

References mul_size().

Referenced by PGReserveSemaphores().

291 {
292  return mul_size(maxSemas, sizeof(PGSemaphoreData));
293 }
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
bool PGSemaphoreTryLock ( PGSemaphore  sema)

Definition at line 471 of file sysv_sema.c.

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

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

Definition at line 441 of file sysv_sema.c.

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

Referenced by IpcSemaphoreCreate().

442 {
443  int errStatus;
444  struct sembuf sops;
445 
446  sops.sem_op = 1; /* increment */
447  sops.sem_flg = 0;
448  sops.sem_num = sema->semNum;
449 
450  /*
451  * Note: if errStatus is -1 and errno == EINTR then it means we returned
452  * from the operation prematurely because we were sent a signal. So we
453  * try and unlock the semaphore again. Not clear this can really happen,
454  * but might as well cope.
455  */
456  do
457  {
458  errStatus = semop(sema->semId, &sops, 1);
459  } while (errStatus < 0 && errno == EINTR);
460 
461  if (errStatus < 0)
462  elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
463 }
#define FATAL
Definition: elog.h:52
#define EINTR
Definition: win32.h:285
#define elog
Definition: elog.h:219
static void ReleaseSemaphores ( int  status,
Datum  arg 
)
static

Definition at line 347 of file sysv_sema.c.

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

Referenced by PGReserveSemaphores().

348 {
349  int i;
350 
351  for (i = 0; i < numSemaSets; i++)
353  free(mySemaSets);
354 }
static void IpcSemaphoreKill(IpcSemaphoreId semId)
Definition: sysv_sema.c:168
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:67
#define free(a)
Definition: header.h:65
int i
static int numSemaSets
Definition: sysv_sema.c:68

Variable Documentation

int maxSemaSets
static

Definition at line 69 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

int maxSharedSemas
static

Definition at line 66 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

IpcSemaphoreId* mySemaSets
static

Definition at line 67 of file sysv_sema.c.

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

IpcSemaphoreKey nextSemaKey
static

Definition at line 70 of file sysv_sema.c.

Referenced by IpcSemaphoreCreate(), and PGReserveSemaphores().

int nextSemaNumber
static

Definition at line 71 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

int numSemaSets
static

Definition at line 68 of file sysv_sema.c.

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

int numSharedSemas
static

Definition at line 65 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

PGSemaphore sharedSemas
static

Definition at line 64 of file sysv_sema.c.