PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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  * Serve the interrupt if interruptOK is true.
131  */
132 void
134 {
135  HANDLE wh[2];
136  bool done = false;
137 
138  /*
139  * Note: pgwin32_signal_event should be first to ensure that it will be
140  * reported when multiple events are set. We want to guarantee that
141  * pending signals are serviced.
142  */
143  wh[0] = pgwin32_signal_event;
144  wh[1] = sema;
145 
146  /*
147  * As in other implementations of PGSemaphoreLock, we need to check for
148  * cancel/die interrupts each time through the loop. But here, there is
149  * no hidden magic about whether the syscall will internally service a
150  * signal --- we do that ourselves.
151  */
152  while (!done)
153  {
154  DWORD rc;
155 
157 
158  rc = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
159  switch (rc)
160  {
161  case WAIT_OBJECT_0:
162  /* Signal event is set - we have a signal to deliver */
164  break;
165  case WAIT_OBJECT_0 + 1:
166  /* We got it! */
167  done = true;
168  break;
169  case WAIT_IO_COMPLETION:
170 
171  /*
172  * The system interrupted the wait to execute an I/O
173  * completion routine or asynchronous procedure call in this
174  * thread. PostgreSQL does not provoke either of these, but
175  * atypical loaded DLLs or even other processes might do so.
176  * Now, resume waiting.
177  */
178  break;
179  case WAIT_FAILED:
180  ereport(FATAL,
181  (errmsg("could not lock semaphore: error code %lu",
182  GetLastError())));
183  break;
184  default:
185  elog(FATAL, "unexpected return code from WaitForMultipleObjectsEx(): %lu", rc);
186  break;
187  }
188  }
189 }
190 
191 /*
192  * PGSemaphoreUnlock
193  *
194  * Unlock a semaphore (increment count)
195  */
196 void
198 {
199  if (!ReleaseSemaphore(sema, 1, NULL))
200  ereport(FATAL,
201  (errmsg("could not unlock semaphore: error code %lu",
202  GetLastError())));
203 }
204 
205 /*
206  * PGSemaphoreTryLock
207  *
208  * Lock a semaphore only if able to do so without blocking
209  */
210 bool
212 {
213  DWORD ret;
214 
215  ret = WaitForSingleObject(sema, 0);
216 
217  if (ret == WAIT_OBJECT_0)
218  {
219  /* We got it! */
220  return true;
221  }
222  else if (ret == WAIT_TIMEOUT)
223  {
224  /* Can't get it */
225  errno = EAGAIN;
226  return false;
227  }
228 
229  /* Otherwise we are in trouble */
230  ereport(FATAL,
231  (errmsg("could not try-lock semaphore: error code %lu",
232  GetLastError())));
233 
234  /* keep compiler quiet */
235  return false;
236 }
PGSemaphore PGSemaphoreCreate(void)
Definition: win32_sema.c:79
static int numSems
Definition: win32_sema.c:21
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: win32_sema.c:197
Size PGSemaphoreShmemSize(int maxSemas)
Definition: win32_sema.c:31
#define PANIC
Definition: elog.h:53
static int maxSems
Definition: win32_sema.c:22
#define malloc(a)
Definition: header.h:50
#define EAGAIN
Definition: win32.h:283
HANDLE pgwin32_signal_event
Definition: signal.c:27
void pgwin32_dispatch_queued_signals(void)
Definition: signal.c:107
void PGSemaphoreLock(PGSemaphore sema)
Definition: win32_sema.c:133
#define FALSE
Definition: c.h:219
#define FATAL
Definition: elog.h:52
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:348
bool IsUnderPostmaster
Definition: globals.c:101
static HANDLE * mySemSet
Definition: win32_sema.c:20
#define ereport(elevel, rest)
Definition: elog.h:122
static int port
Definition: pg_regress.c:90
static void ReleaseSemaphores(int code, Datum arg)
Definition: win32_sema.c:64
uintptr_t Datum
Definition: postgres.h:372
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:681
size_t Size
Definition: c.h:350
void PGReserveSemaphores(int maxSemas, int port)
Definition: win32_sema.c:47
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PGSemaphoreReset(PGSemaphore sema)
Definition: win32_sema.c:116
int i
void * arg
bool PGSemaphoreTryLock(PGSemaphore sema)
Definition: win32_sema.c:211
#define TRUE
Definition: c.h:215
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219