PostgreSQL Source Code git master
Data Structures | Macros | Typedefs | Functions | Variables
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 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 void  ReleaseSemaphores (int status, Datum arg)
 
Size  PGSemaphoreShmemSize (int maxSemas)
 
void  PGReserveSemaphores (int maxSemas)
 
 
 
 
 
 

Variables

 
static int  numSharedSemas
 
static int  maxSharedSemas
 
 
static int  numSemaSets
 
static int  maxSemaSets
 
 
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,
bool  retry_ok 
)
static

Definition at line 97 of file sysv_sema.c.

98{
99 int semId;
100
101 semId = semget(semKey, numSems, IPC_CREAT | IPC_EXCL | IPCProtection);
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
125#ifdef EIDRM
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 errdetail(const char *fmt,...)
Definition: elog.c:1207
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define FATAL
Definition: elog.h:41
#define ereport(elevel,...)
Definition: elog.h:150
static int numSems
Definition: posix_sema.c:66
#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, 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;
228 PGSemaphoreData mysema;
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;
297 PGSemaphoreUnlock(&mysema);
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:467
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
Definition: sysv_sema.c:38
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 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 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 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 errmsg_internal(const char *fmt,...)
Definition: elog.c:1161
static struct @169 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 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:31
#define elog(elevel,...)
Definition: elog.h:226

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

Referenced by ReleaseSemaphores().

PGReserveSemaphores()

void PGReserveSemaphores ( int  maxSemas )

Definition at line 330 of file sysv_sema.c.

331{
332 struct stat statbuf;
333
334 /*
335 * We use the data directory's inode number to seed the search for free
336 * semaphore keys. This minimizes the odds of collision with other
337 * postmasters, while maximizing the odds that we will detect and clean up
338 * semaphores left over from a crashed postmaster in our own directory.
339 */
340 if (stat(DataDir, &statbuf) < 0)
343 errmsg("could not stat data directory \"%s\": %m",
344 DataDir)));
345
346 /*
347 * We must use ShmemAllocUnlocked(), since the spinlock protecting
348 * ShmemAlloc() won't be ready yet.
349 */
352 numSharedSemas = 0;
353 maxSharedSemas = maxSemas;
354
355 maxSemaSets = (maxSemas + SEMAS_PER_SET - 1) / SEMAS_PER_SET;
358 if (mySemaSets == NULL)
359 elog(PANIC, "out of memory");
360 numSemaSets = 0;
361 nextSemaKey = statbuf.st_ino;
362 nextSemaNumber = SEMAS_PER_SET; /* force sema set alloc on 1st call */
363
365}
int errcode_for_file_access(void)
Definition: elog.c:877
#define PANIC
Definition: elog.h:42
char * DataDir
Definition: globals.c:71
#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:238
Definition: win32_port.h:255
Size PGSemaphoreShmemSize(int maxSemas)
Definition: sysv_sema.c:307
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:373
static IpcSemaphoreId * mySemaSets
Definition: sysv_sema.c:64
#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 388 of file sysv_sema.c.

389{
390 PGSemaphore sema;
391
392 /* Can't do this in a backend, because static state is postmaster's */
394
396 {
397 /* Time to allocate another semaphore set */
399 elog(PANIC, "too many semaphores created");
401 numSemaSets++;
402 nextSemaNumber = 0;
403 }
404 /* Use the next shared PGSemaphoreData */
406 elog(PANIC, "too many semaphores created");
407 sema = &sharedSemas[numSharedSemas++];
408 /* Assign the next free semaphore in the current set */
409 sema->semId = mySemaSets[numSemaSets - 1];
410 sema->semNum = nextSemaNumber++;
411 /* Initialize it to count 1 */
412 IpcSemaphoreInitialize(sema->semId, sema->semNum, 1);
413
414 return sema;
415}
bool IsUnderPostmaster
Definition: globals.c:120
Assert(PointerIsAligned(start, uint64))
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.

PGSemaphoreLock()

void PGSemaphoreLock ( PGSemaphore  sema )

Definition at line 434 of file sysv_sema.c.

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

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

PGSemaphoreReset()

void PGSemaphoreReset ( PGSemaphore  sema )

Definition at line 423 of file sysv_sema.c.

424{
425 IpcSemaphoreInitialize(sema->semId, sema->semNum, 0);
426}

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

PGSemaphoreShmemSize()

Size PGSemaphoreShmemSize ( int  maxSemas )

Definition at line 307 of file sysv_sema.c.

308{
309 return mul_size(maxSemas, sizeof(PGSemaphoreData));
310}
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

References mul_size().

Referenced by PGReserveSemaphores().

PGSemaphoreTryLock()

bool PGSemaphoreTryLock ( PGSemaphore  sema )

Definition at line 497 of file sysv_sema.c.

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

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

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

Referenced by IpcSemaphoreCreate().

ReleaseSemaphores()

static void ReleaseSemaphores ( int  status,
Datum  arg 
)
static

Definition at line 373 of file sysv_sema.c.

374{
375 int i;
376
377 for (i = 0; i < numSemaSets; i++)
380}
#define free(a)
Definition: header.h:65
i
int i
Definition: isn.c:77
static void IpcSemaphoreKill(IpcSemaphoreId semId)
Definition: sysv_sema.c:180

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().

AltStyle によって変換されたページ (->オリジナル) /