PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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, bool retry_ok)
 
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)
 
void PGSemaphoreShmemRequest (int maxSemas)
 
void PGSemaphoreInit (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

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,
bool  retry_ok 
)
static

Definition at line 97 of file sysv_sema.c.

98{
99 int semId;
100
102
103 if (semId < 0)
104 {
105 int saved_errno = errno;
106
107 /*
108 * Fail quietly if error suggests a collision with an existing set and
109 * our caller has not lost patience.
110 *
111 * One would expect EEXIST, given that we said IPC_EXCL, but perhaps
112 * we could get a permission violation instead. On some platforms
113 * EINVAL will be reported if the existing set has too few semaphores.
114 * Also, EIDRM might occur if an old set is slated for destruction but
115 * not gone yet.
116 *
117 * EINVAL is the key reason why we need the caller-level loop limit,
118 * as it can also mean that the platform's SEMMSL is less than
119 * numSems, and that condition can't be fixed by trying another key.
120 */
121 if (retry_ok &&
122 (saved_errno == EEXIST
123 || saved_errno == EACCES
124 || saved_errno == EINVAL
126 || saved_errno == EIDRM
127#endif
128 ))
129 return -1;
130
131 /*
132 * Else complain and abort
133 */
135 (errmsg("could not create semaphores: %m"),
136 errdetail("Failed system call was semget(%lu, %d, 0%o).",
137 (unsigned long) semKey, numSems,
139 (saved_errno == ENOSPC) ?
140 errhint("This error does *not* mean that you have run out of disk space. "
141 "It occurs when either the system limit for the maximum number of "
142 "semaphore sets (SEMMNI), or the system wide maximum number of "
143 "semaphores (SEMMNS), would be exceeded. You need to raise the "
144 "respective kernel parameter. Alternatively, reduce PostgreSQL's "
145 "consumption of semaphores by reducing its \"max_connections\" parameter.\n"
146 "The PostgreSQL documentation contains more information about "
147 "configuring your system for PostgreSQL.") : 0));
148 }
149
150 return semId;
151}
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define FATAL
Definition elog.h:42
#define ereport(elevel,...)
Definition elog.h:152
static char * errmsg
static int numSems
Definition posix_sema.c:66
static int fb(int x)
#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, fb(), IPC_CREAT, IPC_EXCL, IPCProtection, and numSems.

Referenced by IpcSemaphoreCreate().

◆ IpcSemaphoreCreate()

static IpcSemaphoreId IpcSemaphoreCreate ( int  numSems)
static

Definition at line 223 of file sysv_sema.c.

224{
225 int num_tries = 0;
226 IpcSemaphoreId semId;
227 union semun semun;
229
230 /* Loop till we find a free IPC key */
231 for (nextSemaKey++;; nextSemaKey++, num_tries++)
232 {
233 pid_t creatorPID;
234
235 /*
236 * Try to create new semaphore set. Give up after trying 1000
237 * distinct IPC keys.
238 */
240 num_tries < 1000);
241 if (semId >= 0)
242 break; /* successful create */
243
244 /* See if it looks to be leftover from a dead Postgres process */
245 semId = semget(nextSemaKey, numSems + 1, 0);
246 if (semId < 0)
247 continue; /* failed: must be some other app's */
249 continue; /* sema belongs to a non-Postgres app */
250
251 /*
252 * If the creator PID is my own PID or does not belong to any extant
253 * process, it's safe to zap it.
254 */
255 creatorPID = IpcSemaphoreGetLastPID(semId, numSems);
256 if (creatorPID <= 0)
257 continue; /* oops, GETPID failed */
258 if (creatorPID != getpid())
259 {
260 if (kill(creatorPID, 0) == 0 || errno != ESRCH)
261 continue; /* sema belongs to a live process */
262 }
263
264 /*
265 * The sema set appears to be from a dead Postgres process, or from a
266 * previous cycle of life in this same process. Zap it, if possible.
267 * This probably shouldn't fail, but if it does, assume the sema set
268 * belongs to someone else after all, and continue quietly.
269 */
270 semun.val = 0; /* unused, but keep compiler quiet */
271 if (semctl(semId, 0, IPC_RMID, semun) < 0)
272 continue;
273
274 /*
275 * Now try again to create the sema set.
276 */
278 if (semId >= 0)
279 break; /* successful create */
280
281 /*
282 * Can only get here if some other process managed to create the same
283 * sema key before we did. Let him have that one, loop around to try
284 * next key.
285 */
286 }
287
288 /*
289 * OK, we created a new sema set. Mark it as created by this process. We
290 * do this by setting the spare semaphore to PGSemaMagic-1 and then
291 * incrementing it with semop(). That leaves it with value PGSemaMagic
292 * and sempid referencing this process.
293 */
295 mysema.semId = semId;
296 mysema.semNum = numSems;
298
299 return semId;
300}
#define PGSemaMagic
Definition sysv_sema.c:58
static IpcSemaphoreId InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, int numSems, bool retry_ok)
Definition sysv_sema.c:97
void PGSemaphoreUnlock(PGSemaphore sema)
Definition sysv_sema.c:465
static pid_t IpcSemaphoreGetLastPID(IpcSemaphoreId semId, int semNum)
Definition sysv_sema.c:203
static int IpcSemaphoreGetValue(IpcSemaphoreId semId, int semNum)
Definition sysv_sema.c:192
int IpcSemaphoreId
Definition sysv_sema.c:46
static IpcSemaphoreKey nextSemaKey
Definition sysv_sema.c:67
static void IpcSemaphoreInitialize(IpcSemaphoreId semId, int semNum, int value)
Definition sysv_sema.c:157
int val
Definition sysv_sema.c:39
#define IPC_RMID
Definition win32_port.h:93
#define kill(pid, sig)
Definition win32_port.h:490

References fb(), 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 203 of file sysv_sema.c.

204{
205 union semun dummy; /* for Solaris */
206
207 dummy.val = 0; /* unused */
208
209 return semctl(semId, semNum, GETPID, dummy);
210}
#define GETPID
Definition win32_port.h:109

References fb(), GETPID, and semun::val.

Referenced by IpcSemaphoreCreate().

◆ IpcSemaphoreGetValue()

static int IpcSemaphoreGetValue ( IpcSemaphoreId  semId,
int  semNum 
)
static

Definition at line 192 of file sysv_sema.c.

193{
194 union semun dummy; /* for Solaris */
195
196 dummy.val = 0; /* unused */
197
198 return semctl(semId, semNum, GETVAL, dummy);
199}
#define GETVAL
Definition win32_port.h:107

References fb(), GETVAL, and semun::val.

Referenced by IpcSemaphoreCreate().

◆ IpcSemaphoreInitialize()

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

Definition at line 157 of file sysv_sema.c.

158{
159 union semun semun;
160
161 semun.val = value;
162 if (semctl(semId, semNum, SETVAL, semun) < 0)
163 {
164 int saved_errno = errno;
165
167 (errmsg_internal("semctl(%d, %d, SETVAL, %d) failed: %m",
168 semId, semNum, value),
169 (saved_errno == ERANGE) ?
170 errhint("You possibly need to raise your kernel's SEMVMX value to be at least "
171 "%d. Look into the PostgreSQL documentation for details.",
172 value) : 0));
173 }
174}
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
static struct @177 value
#define SETVAL
Definition win32_port.h:108

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

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

◆ IpcSemaphoreKill()

static void IpcSemaphoreKill ( IpcSemaphoreId  semId)
static

Definition at line 180 of file sysv_sema.c.

181{
182 union semun semun;
183
184 semun.val = 0; /* unused, but keep compiler quiet */
185
186 if (semctl(semId, 0, IPC_RMID, semun) < 0)
187 elog(LOG, "semctl(%d, 0, IPC_RMID, ...) failed: %m", semId);
188}
#define LOG
Definition elog.h:32
#define elog(elevel,...)
Definition elog.h:228

References elog, fb(), IPC_RMID, LOG, and semun::val.

Referenced by ReleaseSemaphores().

◆ PGSemaphoreCreate()

PGSemaphore PGSemaphoreCreate ( void  )

Definition at line 386 of file sysv_sema.c.

387{
388 PGSemaphore sema;
389
390 /* Can't do this in a backend, because static state is postmaster's */
392
394 {
395 /* Time to allocate another semaphore set */
397 elog(PANIC, "too many semaphores created");
399 numSemaSets++;
400 nextSemaNumber = 0;
401 }
402 /* Use the next shared PGSemaphoreData */
404 elog(PANIC, "too many semaphores created");
405 sema = &sharedSemas[numSharedSemas++];
406 /* Assign the next free semaphore in the current set */
407 sema->semId = mySemaSets[numSemaSets - 1];
408 sema->semNum = nextSemaNumber++;
409 /* Initialize it to count 1 */
410 IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
411
412 return sema;
413}
#define Assert(condition)
Definition c.h:943
#define PANIC
Definition elog.h:44
bool IsUnderPostmaster
Definition globals.c:122
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 IpcSemaphoreId * mySemaSets
Definition sysv_sema.c:64
static IpcSemaphoreId IpcSemaphoreCreate(int numSems)
Definition sysv_sema.c:223

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

◆ PGSemaphoreInit()

void PGSemaphoreInit ( int  maxSemas)

Definition at line 334 of file sysv_sema.c.

335{
336 struct stat statbuf;
337
338 /*
339 * We use the data directory's inode number to seed the search for free
340 * semaphore keys. This minimizes the odds of collision with other
341 * postmasters, while maximizing the odds that we will detect and clean up
342 * semaphores left over from a crashed postmaster in our own directory.
343 */
344 if (stat(DataDir, &statbuf) < 0)
347 errmsg("could not stat data directory \"%s\": %m",
348 DataDir)));
349
350 numSharedSemas = 0;
352
356 if (mySemaSets == NULL)
357 elog(PANIC, "out of memory");
358 numSemaSets = 0;
359 nextSemaKey = statbuf.st_ino;
360 nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
361
363}
int errcode_for_file_access(void)
Definition elog.c:897
char * DataDir
Definition globals.c:73
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
#define malloc(a)
static void ReleaseSemaphores(int status, Datum arg)
Definition sysv_sema.c:371
#define stat
Definition win32_port.h:74

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

◆ PGSemaphoreLock()

void PGSemaphoreLock ( PGSemaphore  sema)

Definition at line 432 of file sysv_sema.c.

433{
434 int errStatus;
435 struct sembuf sops;
436
437 sops.sem_op = -1; /* decrement */
438 sops.sem_flg = 0;
439 sops.sem_num = sema->semNum;
440
441 /*
442 * Note: if errStatus is -1 and errno == EINTR then it means we returned
443 * from the operation prematurely because we were sent a signal. So we
444 * try and lock the semaphore again.
445 *
446 * We used to check interrupts here, but that required servicing
447 * interrupts directly from signal handlers. Which is hard to do safely
448 * and portably.
449 */
450 do
451 {
452 errStatus = semop(sema->semId, &sops, 1);
453 } while (errStatus < 0 && errno == EINTR);
454
455 if (errStatus < 0)
456 elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
457}
#define EINTR
Definition win32_port.h:361

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

◆ PGSemaphoreReset()

void PGSemaphoreReset ( PGSemaphore  sema)

Definition at line 421 of file sysv_sema.c.

422{
423 IpcSemaphoreInitialize(sema->semId, sema->semNum, 0);
424}

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

◆ PGSemaphoreShmemRequest()

void PGSemaphoreShmemRequest ( int  maxSemas)

Definition at line 307 of file sysv_sema.c.

308{
309 /* Need a PGSemaphoreData per semaphore */
310 ShmemRequestStruct(.name = "Semaphores",
311 .size = mul_size(maxSemas, sizeof(PGSemaphoreData)),
312 .ptr = (void **) &sharedSemas,
313 );
314}
Size mul_size(Size s1, Size s2)
Definition shmem.c:1063
#define ShmemRequestStruct(...)
Definition shmem.h:176
const char * name

References fb(), mul_size(), name, sharedSemas, and ShmemRequestStruct.

◆ PGSemaphoreTryLock()

bool PGSemaphoreTryLock ( PGSemaphore  sema)

Definition at line 495 of file sysv_sema.c.

496{
497 int errStatus;
498 struct sembuf sops;
499
500 sops.sem_op = -1; /* decrement */
501 sops.sem_flg = IPC_NOWAIT; /* but don't block */
502 sops.sem_num = sema->semNum;
503
504 /*
505 * Note: if errStatus is -1 and errno == EINTR then it means we returned
506 * from the operation prematurely because we were sent a signal. So we
507 * try and lock the semaphore again.
508 */
509 do
510 {
511 errStatus = semop(sema->semId, &sops, 1);
512 } while (errStatus < 0 && errno == EINTR);
513
514 if (errStatus < 0)
515 {
516 /* Expect EAGAIN or EWOULDBLOCK (platform-dependent) */
517#ifdef EAGAIN
518 if (errno == EAGAIN)
519 return false; /* failed to lock it */
520#endif
521#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
522 if (errno == EWOULDBLOCK)
523 return false; /* failed to lock it */
524#endif
525 /* Otherwise we got trouble */
526 elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
527 }
528
529 return true;
530}
#define EWOULDBLOCK
Definition win32_port.h:367
#define IPC_NOWAIT
Definition win32_port.h:97
#define EAGAIN
Definition win32_port.h:359

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

◆ PGSemaphoreUnlock()

void PGSemaphoreUnlock ( PGSemaphore  sema)

Definition at line 465 of file sysv_sema.c.

466{
467 int errStatus;
468 struct sembuf sops;
469
470 sops.sem_op = 1; /* increment */
471 sops.sem_flg = 0;
472 sops.sem_num = sema->semNum;
473
474 /*
475 * Note: if errStatus is -1 and errno == EINTR then it means we returned
476 * from the operation prematurely because we were sent a signal. So we
477 * try and unlock the semaphore again. Not clear this can really happen,
478 * but might as well cope.
479 */
480 do
481 {
482 errStatus = semop(sema->semId, &sops, 1);
483 } while (errStatus < 0 && errno == EINTR);
484
485 if (errStatus < 0)
486 elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
487}

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

Referenced by IpcSemaphoreCreate().

◆ ReleaseSemaphores()

static void ReleaseSemaphores ( int  status,
Datum  arg 
)
static

Definition at line 371 of file sysv_sema.c.

372{
373 int i;
374
375 for (i = 0; i < numSemaSets; i++)
378}
int i
Definition isn.c:77
#define free(a)
static void IpcSemaphoreKill(IpcSemaphoreId semId)
Definition sysv_sema.c:180

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

Referenced by PGSemaphoreInit().

Variable Documentation

◆ maxSemaSets

int maxSemaSets
static

Definition at line 66 of file sysv_sema.c.

Referenced by PGSemaphoreCreate(), and PGSemaphoreInit().

◆ maxSharedSemas

int maxSharedSemas
static

Definition at line 63 of file sysv_sema.c.

Referenced by PGSemaphoreCreate(), and PGSemaphoreInit().

◆ mySemaSets

IpcSemaphoreId* mySemaSets
static

Definition at line 64 of file sysv_sema.c.

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

◆ nextSemaKey

IpcSemaphoreKey nextSemaKey
static

Definition at line 67 of file sysv_sema.c.

Referenced by IpcSemaphoreCreate(), and PGSemaphoreInit().

◆ nextSemaNumber

int nextSemaNumber
static

Definition at line 68 of file sysv_sema.c.

Referenced by PGSemaphoreCreate(), and PGSemaphoreInit().

◆ numSemaSets

int numSemaSets
static

Definition at line 65 of file sysv_sema.c.

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

◆ numSharedSemas

int numSharedSemas
static

Definition at line 62 of file sysv_sema.c.

Referenced by PGSemaphoreCreate(), and PGSemaphoreInit().

◆ sharedSemas

PGSemaphore sharedSemas
static

Definition at line 61 of file sysv_sema.c.

Referenced by PGSemaphoreCreate(), and PGSemaphoreShmemRequest().