PostgreSQL Source Code  git master
win32_sema.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * win32_sema.c
4  * Microsoft Windows Win32 Semaphores Emulation
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/backend/port/win32_sema.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 
14 #include "postgres.h"
15 
16 #include "miscadmin.h"
17 #include "storage/ipc.h"
18 #include "storage/pg_sema.h"
19 
20 static HANDLE *mySemSet; /* IDs of sema sets acquired so far */
21 static int numSems; /* number of sema sets acquired so far */
22 static int maxSems; /* allocated size of mySemaSet array */
23 
24 static void ReleaseSemaphores(int code, Datum arg);
25 
26 
27 /*
28  * Report amount of shared memory needed for semaphores
29  */
30 Size
31 PGSemaphoreShmemSize(int maxSemas)
32 {
33  /* No shared memory needed on Windows */
34  return 0;
35 }
36 
37 /*
38  * PGReserveSemaphores --- initialize semaphore support
39  *
40  * In the Win32 implementation, we acquire semaphores on-demand; the
41  * maxSemas parameter is just used to size the array that keeps track of
42  * acquired semas for subsequent releasing. We use anonymous semaphores
43  * so the semaphores are automatically freed when the last referencing
44  * process exits.
45  */
46 void
47 PGReserveSemaphores(int maxSemas, int port)
48 {
49  mySemSet = (HANDLE *) malloc(maxSemas * sizeof(HANDLE));
50  if (mySemSet == NULL)
51  elog(PANIC, "out of memory");
52  numSems = 0;
53  maxSems = maxSemas;
54 
56 }
57 
58 /*
59  * Release semaphores at shutdown or shmem reinitialization
60  *
61  * (called as an on_shmem_exit callback, hence funny argument list)
62  */
63 static void
65 {
66  int i;
67 
68  for (i = 0; i < numSems; i++)
69  CloseHandle(mySemSet[i]);
70  free(mySemSet);
71 }
72 
73 /*
74  * PGSemaphoreCreate
75  *
76  * Allocate a PGSemaphore structure with initial count 1
77  */
80 {
81  HANDLE cur_handle;
82  SECURITY_ATTRIBUTES sec_attrs;
83 
84  /* Can't do this in a backend, because static state is postmaster's */
86 
87  if (numSems >= maxSems)
88  elog(PANIC, "too many semaphores created");
89 
90  ZeroMemory(&sec_attrs, sizeof(sec_attrs));
91  sec_attrs.nLength = sizeof(sec_attrs);
92  sec_attrs.lpSecurityDescriptor = NULL;
93  sec_attrs.bInheritHandle = TRUE;
94 
95  /* We don't need a named semaphore */
96  cur_handle = CreateSemaphore(&sec_attrs, 1, 32767, NULL);
97  if (cur_handle)
98  {
99  /* Successfully done */
100  mySemSet[numSems++] = cur_handle;
101  }
102  else
103  ereport(PANIC,
104  (errmsg("could not create semaphore: error code %lu",
105  GetLastError())));
106 
107  return (PGSemaphore) cur_handle;
108 }
109 
110 /*
111  * PGSemaphoreReset
112  *
113  * Reset a previously-initialized PGSemaphore to have count 0
114  */
115 void
117 {
118  /*
119  * There's no direct API for this in Win32, so we have to ratchet the
120  * semaphore down to 0 with repeated trylock's.
121  */
122  while (PGSemaphoreTryLock(sema))
123  /* loop */ ;
124 }
125 
126 /*
127  * PGSemaphoreLock
128  *
129  * Lock a semaphore (decrement count), blocking if count would be < 0.
130  */
131 void
133 {
134  HANDLE wh[2];
135  bool done = false;
136 
137  /*
138  * Note: pgwin32_signal_event should be first to ensure that it will be
139  * reported when multiple events are set. We want to guarantee that
140  * pending signals are serviced.
141  */
142  wh[0] = pgwin32_signal_event;
143  wh[1] = sema;
144 
145  /*
146  * As in other implementations of PGSemaphoreLock, we need to check for
147  * cancel/die interrupts each time through the loop. But here, there is
148  * no hidden magic about whether the syscall will internally service a
149  * signal --- we do that ourselves.
150  */
151  while (!done)
152  {
153  DWORD rc;
154 
156 
157  rc = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
158  switch (rc)
159  {
160  case WAIT_OBJECT_0:
161  /* Signal event is set - we have a signal to deliver */
163  break;
164  case WAIT_OBJECT_0 + 1:
165  /* We got it! */
166  done = true;
167  break;
168  case WAIT_IO_COMPLETION:
169 
170  /*
171  * The system interrupted the wait to execute an I/O
172  * completion routine or asynchronous procedure call in this
173  * thread. PostgreSQL does not provoke either of these, but
174  * atypical loaded DLLs or even other processes might do so.
175  * Now, resume waiting.
176  */
177  break;
178  case WAIT_FAILED:
179  ereport(FATAL,
180  (errmsg("could not lock semaphore: error code %lu",
181  GetLastError())));
182  break;
183  default:
184  elog(FATAL, "unexpected return code from WaitForMultipleObjectsEx(): %lu", rc);
185  break;
186  }
187  }
188 }
189 
190 /*
191  * PGSemaphoreUnlock
192  *
193  * Unlock a semaphore (increment count)
194  */
195 void
197 {
198  if (!ReleaseSemaphore(sema, 1, NULL))
199  ereport(FATAL,
200  (errmsg("could not unlock semaphore: error code %lu",
201  GetLastError())));
202 }
203 
204 /*
205  * PGSemaphoreTryLock
206  *
207  * Lock a semaphore only if able to do so without blocking
208  */
209 bool
211 {
212  DWORD ret;
213 
214  ret = WaitForSingleObject(sema, 0);
215 
216  if (ret == WAIT_OBJECT_0)
217  {
218  /* We got it! */
219  return true;
220  }
221  else if (ret == WAIT_TIMEOUT)
222  {
223  /* Can't get it */
224  errno = EAGAIN;
225  return false;
226  }
227 
228  /* Otherwise we are in trouble */
229  ereport(FATAL,
230  (errmsg("could not try-lock semaphore: error code %lu",
231  GetLastError())));
232 
233  /* keep compiler quiet */
234  return false;
235 }
PGSemaphore PGSemaphoreCreate(void)
Definition: win32_sema.c:79
static int numSems
Definition: win32_sema.c:21
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: win32_sema.c:196
#define TRUE
Definition: ecpglib.h:35
Size PGSemaphoreShmemSize(int maxSemas)
Definition: win32_sema.c:31
#define EAGAIN
Definition: win32_port.h:330
#define FALSE
Definition: ecpglib.h:39
#define PANIC
Definition: elog.h:53
static int maxSems
Definition: win32_sema.c:22
#define malloc(a)
Definition: header.h:50
HANDLE pgwin32_signal_event
Definition: signal.c:27
void pgwin32_dispatch_queued_signals(void)
Definition: signal.c:108
void PGSemaphoreLock(PGSemaphore sema)
Definition: win32_sema.c:132
#define FATAL
Definition: elog.h:52
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
bool IsUnderPostmaster
Definition: globals.c:109
static HANDLE * mySemSet
Definition: win32_sema.c:20
#define ereport(elevel, rest)
Definition: elog.h:141
static int port
Definition: pg_regress.c:92
static void ReleaseSemaphores(int code, Datum arg)
Definition: win32_sema.c:64
uintptr_t Datum
Definition: postgres.h:367
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:732
size_t Size
Definition: c.h:466
void PGReserveSemaphores(int maxSemas, int port)
Definition: win32_sema.c:47
int errmsg(const char *fmt,...)
Definition: elog.c:784
void PGSemaphoreReset(PGSemaphore sema)
Definition: win32_sema.c:116
#define elog(elevel,...)
Definition: elog.h:226
int i
void * arg
bool PGSemaphoreTryLock(PGSemaphore sema)
Definition: win32_sema.c:210
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99