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-2025, 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
20static HANDLE *mySemSet; /* IDs of sema sets acquired so far */
21static int numSems; /* number of sema sets acquired so far */
22static int maxSems; /* allocated size of mySemaSet array */
23
24static void ReleaseSemaphores(int code, Datum arg);
25
26
27/*
28 * Report amount of shared memory needed for semaphores
29 */
30Size
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 */
46void
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 */
63static void
65{
66 int i;
67
68 for (i = 0; i < numSems; i++)
69 CloseHandle(mySemSet[i]);
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
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 */
115void
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 */
131void
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:
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 */
195void
197{
198 if (!ReleaseSemaphore(sema, 1, NULL))
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 */
209bool
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 */
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:576
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define FATAL
Definition: elog.h:41
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
bool IsUnderPostmaster
Definition: globals.c:119
Assert(PointerIsAligned(start, uint64))
#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:74
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
void * arg
uintptr_t Datum
Definition: postgres.h:69
void pgwin32_dispatch_queued_signals(void)
Definition: signal.c:120
HANDLE pgwin32_signal_event
Definition: signal.c:27
#define EAGAIN
Definition: win32_port.h:362
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