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  */
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:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#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:97
#define IPC_CREAT
Definition: win32_port.h:96
#define EIDRM
Definition: win32_port.h:104

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

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

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

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:1157
static struct @160 value
#define SETVAL
Definition: win32_port.h:110

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)
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.
329  */
332  numSharedSemas = 0;
333  maxSharedSemas = maxSemas;
334 
335  maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
337  malloc(maxSemaSets * sizeof(IpcSemaphoreId));
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:876
#define PANIC
Definition: elog.h:42
char * DataDir
Definition: globals.c:70
#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:233
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:284

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 */
378  if (numSemaSets >= maxSemaSets)
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 }
#define Assert(condition)
Definition: c.h:863
bool IsUnderPostmaster
Definition: globals.c:119
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:374

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

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:380
#define IPC_NOWAIT
Definition: win32_port.h:99
#define EAGAIN
Definition: win32_port.h:372

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++)
359  free(mySemaSets);
360 }
#define free(a)
Definition: header.h:65
int i
Definition: isn.c:72
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().