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-2024, 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)
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 }
size_t Size
Definition: c.h:592
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define FATAL
Definition: elog.h:41
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
bool IsUnderPostmaster
Definition: globals.c:117
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
void * arg
uintptr_t Datum
Definition: postgres.h:64
void pgwin32_dispatch_queued_signals(void)
Definition: signal.c:120
HANDLE pgwin32_signal_event
Definition: signal.c:27
#define EAGAIN
Definition: win32_port.h:372
Size PGSemaphoreShmemSize(int maxSemas)
Definition: win32_sema.c:31
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: win32_sema.c:196
static int maxSems
Definition: win32_sema.c:22
void PGReserveSemaphores(int maxSemas)
Definition: win32_sema.c:47
void PGSemaphoreReset(PGSemaphore sema)
Definition: win32_sema.c:116
void PGSemaphoreLock(PGSemaphore sema)
Definition: win32_sema.c:132
static int numSems
Definition: win32_sema.c:21
bool PGSemaphoreTryLock(PGSemaphore sema)
Definition: win32_sema.c:210
static HANDLE * mySemSet
Definition: win32_sema.c:20
PGSemaphore PGSemaphoreCreate(void)
Definition: win32_sema.c:79
static void ReleaseSemaphores(int code, Datum arg)
Definition: win32_sema.c:64