PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
posix_sema.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * posix_sema.c
4  * Implement PGSemaphores using POSIX semaphore facilities
5  *
6  * We prefer the unnamed style of POSIX semaphore (the kind made with
7  * sem_init). We can cope with the kind made with sem_open, however.
8  *
9  * In either implementation, typedef PGSemaphore is equivalent to "sem_t *".
10  * With unnamed semaphores, the sem_t structs live in an array in shared
11  * memory. With named semaphores, that's not true because we cannot persuade
12  * sem_open to do its allocation there. Therefore, the named-semaphore code
13  * *does not cope with EXEC_BACKEND*. The sem_t structs will just be in the
14  * postmaster's private memory, where they are successfully inherited by
15  * forked backends, but they could not be accessed by exec'd backends.
16  *
17  *
18  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
19  * Portions Copyright (c) 1994, Regents of the University of California
20  *
21  * IDENTIFICATION
22  * src/backend/port/posix_sema.c
23  *
24  *-------------------------------------------------------------------------
25  */
26 #include "postgres.h"
27 
28 #include <fcntl.h>
29 #include <semaphore.h>
30 #include <signal.h>
31 #include <unistd.h>
32 
33 #include "miscadmin.h"
34 #include "storage/ipc.h"
35 #include "storage/pg_sema.h"
36 #include "storage/shmem.h"
37 
38 
39 /* see file header comment */
40 #if defined(USE_NAMED_POSIX_SEMAPHORES) && defined(EXEC_BACKEND)
41 #error cannot use named POSIX semaphores with EXEC_BACKEND
42 #endif
43 
44 /* typedef PGSemaphore is equivalent to pointer to sem_t */
45 typedef struct PGSemaphoreData
46 {
47  sem_t pgsem;
49 
50 #define PG_SEM_REF(x) (&(x)->pgsem)
51 
52 #define IPCProtection (0600) /* access/modify by user only */
53 
54 #ifdef USE_NAMED_POSIX_SEMAPHORES
55 static sem_t **mySemPointers; /* keep track of created semaphores */
56 #else
57 static PGSemaphore sharedSemas; /* array of PGSemaphoreData in shared memory */
58 #endif
59 static int numSems; /* number of semas acquired so far */
60 static int maxSems; /* allocated size of above arrays */
61 static int nextSemKey; /* next name to try */
62 
63 
64 static void ReleaseSemaphores(int status, Datum arg);
65 
66 
67 #ifdef USE_NAMED_POSIX_SEMAPHORES
68 
69 /*
70  * PosixSemaphoreCreate
71  *
72  * Attempt to create a new named semaphore.
73  *
74  * If we fail with a failure code other than collision-with-existing-sema,
75  * print out an error and abort. Other types of errors suggest nonrecoverable
76  * problems.
77  */
78 static sem_t *
80 {
81  int semKey;
82  char semname[64];
83  sem_t *mySem;
84 
85  for (;;)
86  {
87  semKey = nextSemKey++;
88 
89  snprintf(semname, sizeof(semname), "/pgsql-%d", semKey);
90 
91  mySem = sem_open(semname, O_CREAT | O_EXCL,
92  (mode_t) IPCProtection, (unsigned) 1);
93 
94 #ifdef SEM_FAILED
95  if (mySem != (sem_t *) SEM_FAILED)
96  break;
97 #else
98  if (mySem != (sem_t *) (-1))
99  break;
100 #endif
101 
102  /* Loop if error indicates a collision */
103  if (errno == EEXIST || errno == EACCES || errno == EINTR)
104  continue;
105 
106  /*
107  * Else complain and abort
108  */
109  elog(FATAL, "sem_open(\"%s\") failed: %m", semname);
110  }
111 
112  /*
113  * Unlink the semaphore immediately, so it can't be accessed externally.
114  * This also ensures that it will go away if we crash.
115  */
116  sem_unlink(semname);
117 
118  return mySem;
119 }
120 #else /* !USE_NAMED_POSIX_SEMAPHORES */
121 
122 /*
123  * PosixSemaphoreCreate
124  *
125  * Attempt to create a new unnamed semaphore.
126  */
127 static void
129 {
130  if (sem_init(sem, 1, 1) < 0)
131  elog(FATAL, "sem_init failed: %m");
132 }
133 #endif /* USE_NAMED_POSIX_SEMAPHORES */
134 
135 
136 /*
137  * PosixSemaphoreKill - removes a semaphore
138  */
139 static void
140 PosixSemaphoreKill(sem_t * sem)
141 {
142 #ifdef USE_NAMED_POSIX_SEMAPHORES
143  /* Got to use sem_close for named semaphores */
144  if (sem_close(sem) < 0)
145  elog(LOG, "sem_close failed: %m");
146 #else
147  /* Got to use sem_destroy for unnamed semaphores */
148  if (sem_destroy(sem) < 0)
149  elog(LOG, "sem_destroy failed: %m");
150 #endif
151 }
152 
153 
154 /*
155  * Report amount of shared memory needed for semaphores
156  */
157 Size
158 PGSemaphoreShmemSize(int maxSemas)
159 {
160 #ifdef USE_NAMED_POSIX_SEMAPHORES
161  /* No shared memory needed in this case */
162  return 0;
163 #else
164  /* Need a PGSemaphoreData per semaphore */
165  return mul_size(maxSemas, sizeof(PGSemaphoreData));
166 #endif
167 }
168 
169 /*
170  * PGReserveSemaphores --- initialize semaphore support
171  *
172  * This is called during postmaster start or shared memory reinitialization.
173  * It should do whatever is needed to be able to support up to maxSemas
174  * subsequent PGSemaphoreCreate calls. Also, if any system resources
175  * are acquired here or in PGSemaphoreCreate, register an on_shmem_exit
176  * callback to release them.
177  *
178  * The port number is passed for possible use as a key (for Posix, we use
179  * it to generate the starting semaphore name). In a standalone backend,
180  * zero will be passed.
181  *
182  * In the Posix implementation, we acquire semaphores on-demand; the
183  * maxSemas parameter is just used to size the arrays. For unnamed
184  * semaphores, there is an array of PGSemaphoreData structs in shared memory.
185  * For named semaphores, we keep a postmaster-local array of sem_t pointers,
186  * which we use for releasing the semphores when done.
187  * (This design minimizes the dependency of postmaster shutdown on the
188  * contents of shared memory, which a failed backend might have clobbered.
189  * We can't do much about the possibility of sem_destroy() crashing, but
190  * we don't have to expose the counters to other processes.)
191  */
192 void
193 PGReserveSemaphores(int maxSemas, int port)
194 {
195 #ifdef USE_NAMED_POSIX_SEMAPHORES
196  mySemPointers = (sem_t **) malloc(maxSemas * sizeof(sem_t *));
197  if (mySemPointers == NULL)
198  elog(PANIC, "out of memory");
199 #else
200 
201  /*
202  * We must use ShmemAllocUnlocked(), since the spinlock protecting
203  * ShmemAlloc() won't be ready yet. (This ordering is necessary when we
204  * are emulating spinlocks with semaphores.)
205  */
206  sharedSemas = (PGSemaphore)
208 #endif
209 
210  numSems = 0;
211  maxSems = maxSemas;
212  nextSemKey = port * 1000;
213 
215 }
216 
217 /*
218  * Release semaphores at shutdown or shmem reinitialization
219  *
220  * (called as an on_shmem_exit callback, hence funny argument list)
221  */
222 static void
224 {
225  int i;
226 
227 #ifdef USE_NAMED_POSIX_SEMAPHORES
228  for (i = 0; i < numSems; i++)
229  PosixSemaphoreKill(mySemPointers[i]);
230  free(mySemPointers);
231 #endif
232 
233 #ifdef USE_UNNAMED_POSIX_SEMAPHORES
234  for (i = 0; i < numSems; i++)
235  PosixSemaphoreKill(PG_SEM_REF(sharedSemas + i));
236 #endif
237 }
238 
239 /*
240  * PGSemaphoreCreate
241  *
242  * Allocate a PGSemaphore structure with initial count 1
243  */
246 {
247  PGSemaphore sema;
248  sem_t *newsem;
249 
250  /* Can't do this in a backend, because static state is postmaster's */
252 
253  if (numSems >= maxSems)
254  elog(PANIC, "too many semaphores created");
255 
256 #ifdef USE_NAMED_POSIX_SEMAPHORES
257  newsem = PosixSemaphoreCreate();
258  /* Remember new sema for ReleaseSemaphores */
259  mySemPointers[numSems] = newsem;
260  sema = (PGSemaphore) newsem;
261 #else
262  sema = &sharedSemas[numSems];
263  newsem = PG_SEM_REF(sema);
264  PosixSemaphoreCreate(newsem);
265 #endif
266 
267  numSems++;
268 
269  return sema;
270 }
271 
272 /*
273  * PGSemaphoreReset
274  *
275  * Reset a previously-initialized PGSemaphore to have count 0
276  */
277 void
279 {
280  /*
281  * There's no direct API for this in POSIX, so we have to ratchet the
282  * semaphore down to 0 with repeated trywait's.
283  */
284  for (;;)
285  {
286  if (sem_trywait(PG_SEM_REF(sema)) < 0)
287  {
288  if (errno == EAGAIN || errno == EDEADLK)
289  break; /* got it down to 0 */
290  if (errno == EINTR)
291  continue; /* can this happen? */
292  elog(FATAL, "sem_trywait failed: %m");
293  }
294  }
295 }
296 
297 /*
298  * PGSemaphoreLock
299  *
300  * Lock a semaphore (decrement count), blocking if count would be < 0
301  */
302 void
304 {
305  int errStatus;
306 
307  /* See notes in sysv_sema.c's implementation of PGSemaphoreLock. */
308  do
309  {
310  errStatus = sem_wait(PG_SEM_REF(sema));
311  } while (errStatus < 0 && errno == EINTR);
312 
313  if (errStatus < 0)
314  elog(FATAL, "sem_wait failed: %m");
315 }
316 
317 /*
318  * PGSemaphoreUnlock
319  *
320  * Unlock a semaphore (increment count)
321  */
322 void
324 {
325  int errStatus;
326 
327  /*
328  * Note: if errStatus is -1 and errno == EINTR then it means we returned
329  * from the operation prematurely because we were sent a signal. So we
330  * try and unlock the semaphore again. Not clear this can really happen,
331  * but might as well cope.
332  */
333  do
334  {
335  errStatus = sem_post(PG_SEM_REF(sema));
336  } while (errStatus < 0 && errno == EINTR);
337 
338  if (errStatus < 0)
339  elog(FATAL, "sem_post failed: %m");
340 }
341 
342 /*
343  * PGSemaphoreTryLock
344  *
345  * Lock a semaphore only if able to do so without blocking
346  */
347 bool
349 {
350  int errStatus;
351 
352  /*
353  * Note: if errStatus is -1 and errno == EINTR then it means we returned
354  * from the operation prematurely because we were sent a signal. So we
355  * try and lock the semaphore again.
356  */
357  do
358  {
359  errStatus = sem_trywait(PG_SEM_REF(sema));
360  } while (errStatus < 0 && errno == EINTR);
361 
362  if (errStatus < 0)
363  {
364  if (errno == EAGAIN || errno == EDEADLK)
365  return false; /* failed to lock it */
366  /* Otherwise we got trouble */
367  elog(FATAL, "sem_trywait failed: %m");
368  }
369 
370  return true;
371 }
static void PosixSemaphoreKill(sem_t *sem)
Definition: posix_sema.c:140
static void PosixSemaphoreCreate(sem_t *sem)
Definition: posix_sema.c:128
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: posix_sema.c:323
#define IPCProtection
Definition: posix_sema.c:52
void PGReserveSemaphores(int maxSemas, int port)
Definition: posix_sema.c:193
void PGSemaphoreReset(PGSemaphore sema)
Definition: posix_sema.c:278
static int numSems
Definition: posix_sema.c:59
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define LOG
Definition: elog.h:26
#define PANIC
Definition: elog.h:53
PGSemaphore PGSemaphoreCreate(void)
Definition: posix_sema.c:245
#define malloc(a)
Definition: header.h:45
#define EAGAIN
Definition: win32.h:293
struct PGSemaphoreData PGSemaphoreData
#define FATAL
Definition: elog.h:52
static PGSemaphore sharedSemas
Definition: posix_sema.c:57
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:348
bool IsUnderPostmaster
Definition: globals.c:100
static void ReleaseSemaphores(int status, Datum arg)
Definition: posix_sema.c:223
static int port
Definition: pg_regress.c:87
static int maxSems
Definition: posix_sema.c:60
static int nextSemKey
Definition: posix_sema.c:61
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
uintptr_t Datum
Definition: postgres.h:374
void * ShmemAllocUnlocked(Size size)
Definition: shmem.c:227
#define EINTR
Definition: win32.h:295
#define free(a)
Definition: header.h:60
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
size_t Size
Definition: c.h:353
void PGSemaphoreLock(PGSemaphore sema)
Definition: posix_sema.c:303
struct PGSemaphoreData * PGSemaphore
Definition: pg_sema.h:34
int i
#define PG_SEM_REF(x)
Definition: posix_sema.c:50
Size PGSemaphoreShmemSize(int maxSemas)
Definition: posix_sema.c:158
void * arg
bool PGSemaphoreTryLock(PGSemaphore sema)
Definition: posix_sema.c:348
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:222