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   19
 
#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 62 of file sysv_sema.c.

◆ PGSemaMagic

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

Definition at line 64 of file sysv_sema.c.

◆ SEMAS_PER_SET

#define SEMAS_PER_SET   19

Definition at line 60 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 99 of file sysv_sema.c.

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

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

195{
196 union semun dummy; /* for Solaris */
197
198 dummy.val = 0; /* unused */
199
200 return semctl(semId, semNum, GETPID, dummy);
201}
#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 183 of file sysv_sema.c.

184{
185 union semun dummy; /* for Solaris */
186
187 dummy.val = 0; /* unused */
188
189 return semctl(semId, semNum, GETVAL, dummy);
190}
#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 148 of file sysv_sema.c.

149{
150 union semun semun;
151
152 semun.val = value;
153 if (semctl(semId, semNum, SETVAL, semun) < 0)
154 {
155 int saved_errno = errno;
156
158 (errmsg_internal("semctl(%d, %d, SETVAL, %d) failed: %m",
159 semId, semNum, value),
160 (saved_errno == ERANGE) ?
161 errhint("You possibly need to raise your kernel's SEMVMX value to be at least "
162 "%d. Look into the PostgreSQL documentation for details.",
163 value) : 0));
164 }
165}
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
static struct @162 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 171 of file sysv_sema.c.

172{
173 union semun semun;
174
175 semun.val = 0; /* unused, but keep compiler quiet */
176
177 if (semctl(semId, 0, IPC_RMID, semun) < 0)
178 elog(LOG, "semctl(%d, 0, IPC_RMID, ...) failed: %m", semId);
179}
#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 316 of file sysv_sema.c.

317{
318 struct stat statbuf;
319
320 /*
321 * We use the data directory's inode number to seed the search for free
322 * semaphore keys. This minimizes the odds of collision with other
323 * postmasters, while maximizing the odds that we will detect and clean up
324 * semaphores left over from a crashed postmaster in our own directory.
325 */
326 if (stat(DataDir, &statbuf) < 0)
329 errmsg("could not stat data directory \"%s\": %m",
330 DataDir)));
331
332 /*
333 * We must use ShmemAllocUnlocked(), since the spinlock protecting
334 * ShmemAlloc() won't be ready yet.
335 */
338 numSharedSemas = 0;
339 maxSharedSemas = maxSemas;
340
341 maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
344 if (mySemaSets == NULL)
345 elog(PANIC, "out of memory");
346 numSemaSets = 0;
347 nextSemaKey = statbuf.st_ino;
348 nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
349
351}
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:293
static int maxSharedSemas
Definition: sysv_sema.c:69
#define SEMAS_PER_SET
Definition: sysv_sema.c:60
static int numSemaSets
Definition: sysv_sema.c:71
static int nextSemaNumber
Definition: sysv_sema.c:74
static PGSemaphore sharedSemas
Definition: sysv_sema.c:67
static int maxSemaSets
Definition: sysv_sema.c:72
static int numSharedSemas
Definition: sysv_sema.c:68
static void ReleaseSemaphores(int status, Datum arg)
Definition: sysv_sema.c:359
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:70
#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 374 of file sysv_sema.c.

375{
376 PGSemaphore sema;
377
378 /* Can't do this in a backend, because static state is postmaster's */
380
382 {
383 /* Time to allocate another semaphore set */
385 elog(PANIC, "too many semaphores created");
387 numSemaSets++;
388 nextSemaNumber = 0;
389 }
390 /* Use the next shared PGSemaphoreData */
392 elog(PANIC, "too many semaphores created");
393 sema = &sharedSemas[numSharedSemas++];
394 /* Assign the next free semaphore in the current set */
395 sema->semId = mySemaSets[numSemaSets - 1];
396 sema->semNum = nextSemaNumber++;
397 /* Initialize it to count 1 */
398 IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
399
400 return sema;
401}
#define Assert(condition)
Definition: c.h:815
bool IsUnderPostmaster
Definition: globals.c:119
static IpcSemaphoreId IpcSemaphoreCreate(int numSems)
Definition: sysv_sema.c:214

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

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

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

◆ PGSemaphoreReset()

void PGSemaphoreReset ( PGSemaphore  sema)

Definition at line 409 of file sysv_sema.c.

410{
411 IpcSemaphoreInitialize(sema->semId, sema->semNum, 0);
412}

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

◆ PGSemaphoreShmemSize()

Size PGSemaphoreShmemSize ( int  maxSemas)

Definition at line 293 of file sysv_sema.c.

294{
295 return mul_size(maxSemas, sizeof(PGSemaphoreData));
296}
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 483 of file sysv_sema.c.

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

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

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

Referenced by IpcSemaphoreCreate().

◆ ReleaseSemaphores()

static void ReleaseSemaphores ( int  status,
Datum  arg 
)
static

Definition at line 359 of file sysv_sema.c.

360{
361 int i;
362
363 for (i = 0; i < numSemaSets; i++)
366}
#define free(a)
Definition: header.h:65
int i
Definition: isn.c:72
static void IpcSemaphoreKill(IpcSemaphoreId semId)
Definition: sysv_sema.c:171

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

Referenced by PGReserveSemaphores().

Variable Documentation

◆ maxSemaSets

int maxSemaSets
static

Definition at line 72 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ maxSharedSemas

int maxSharedSemas
static

Definition at line 69 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ mySemaSets

IpcSemaphoreId* mySemaSets
static

Definition at line 70 of file sysv_sema.c.

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

◆ nextSemaKey

IpcSemaphoreKey nextSemaKey
static

Definition at line 73 of file sysv_sema.c.

Referenced by IpcSemaphoreCreate(), and PGReserveSemaphores().

◆ nextSemaNumber

int nextSemaNumber
static

Definition at line 74 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ numSemaSets

int numSemaSets
static

Definition at line 71 of file sysv_sema.c.

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

◆ numSharedSemas

int numSharedSemas
static

Definition at line 68 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().

◆ sharedSemas

PGSemaphore sharedSemas
static

Definition at line 67 of file sysv_sema.c.

Referenced by PGReserveSemaphores(), and PGSemaphoreCreate().