PostgreSQL Source Code git master
win32_shmem.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * win32_shmem.c
4 * Implement shared memory using win32 facilities
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/backend/port/win32_shmem.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "miscadmin.h"
16#include "storage/dsm.h"
17#include "storage/ipc.h"
18#include "storage/pg_shmem.h"
19#include "utils/guc_hooks.h"
20
21
22/*
23 * Early in a process's life, Windows asynchronously creates threads for the
24 * process's "default thread pool"
25 * (https://docs.microsoft.com/en-us/windows/desktop/ProcThread/thread-pools).
26 * Occasionally, thread creation allocates a stack after
27 * PGSharedMemoryReAttach() has released UsedShmemSegAddr and before it has
28 * mapped shared memory at UsedShmemSegAddr. This would cause mapping to fail
29 * if the allocator preferred the just-released region for allocating the new
30 * thread stack. We observed such failures in some Windows Server 2016
31 * configurations. To give the system another region to prefer, reserve and
32 * release an additional, protective region immediately before reserving or
33 * releasing shared memory. The idea is that, if the allocator handed out
34 * REGION1 pages before REGION2 pages at one occasion, it will do so whenever
35 * both regions are free. Windows Server 2016 exhibits that behavior, and a
36 * system behaving differently would have less need to protect
37 * UsedShmemSegAddr. The protective region must be at least large enough for
38 * one thread stack. However, ten times as much is less than 2% of the 32-bit
39 * address space and is negligible relative to the 64-bit address space.
40 */
41#define PROTECTIVE_REGION_SIZE (10 * WIN32_STACK_RLIMIT)
43
44HANDLE UsedShmemSegID = INVALID_HANDLE_VALUE;
45void *UsedShmemSegAddr = NULL;
47
48static bool EnableLockPagesPrivilege(int elevel);
49static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
50
51/*
52 * Generate shared memory segment name. Expand the data directory, to generate
53 * an identifier unique for this data directory. Then replace all backslashes
54 * with forward slashes, since backslashes aren't permitted in global object names.
55 *
56 * Store the shared memory segment in the Global\ namespace (requires NT2 TSE or
57 * 2000, but that's all we support for other reasons as well), to make sure you can't
58 * open two postmasters in different sessions against the same data directory.
59 *
60 * XXX: What happens with junctions? It's only someone breaking things on purpose,
61 * and this is still better than before, but we might want to do something about
62 * that sometime in the future.
63 */
64static char *
66{
67 char *retptr;
68 DWORD bufsize;
69 DWORD r;
70 char *cp;
71
72 bufsize = GetFullPathName(DataDir, 0, NULL, NULL);
73 if (bufsize == 0)
74 elog(FATAL, "could not get size for full pathname of datadir %s: error code %lu",
75 DataDir, GetLastError());
76
77 retptr = malloc(bufsize + 18); /* 18 for Global\PostgreSQL: */
78 if (retptr == NULL)
79 elog(FATAL, "could not allocate memory for shared memory name");
80
81 strcpy(retptr, "Global\\PostgreSQL:");
82 r = GetFullPathName(DataDir, bufsize, retptr + 18, NULL);
83 if (r == 0 || r > bufsize)
84 elog(FATAL, "could not generate full pathname for datadir %s: error code %lu",
85 DataDir, GetLastError());
86
87 /*
88 * XXX: Intentionally overwriting the Global\ part here. This was not the
89 * original approach, but putting it in the actual Global\ namespace
90 * causes permission errors in a lot of cases, so we leave it in the
91 * default namespace for now.
92 */
93 for (cp = retptr; *cp; cp++)
94 if (*cp == '\\')
95 *cp = '/';
96
97 return retptr;
98}
99
100
101/*
102 * PGSharedMemoryIsInUse
103 *
104 * Is a previously-existing shmem segment still existing and in use?
105 *
106 * The point of this exercise is to detect the case where a prior postmaster
107 * crashed, but it left child backends that are still running. Therefore
108 * we only care about shmem segments that are associated with the intended
109 * DataDir. This is an important consideration since accidental matches of
110 * shmem segment IDs are reasonably common.
111 */
112bool
113PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
114{
115 char *szShareMem;
116 HANDLE hmap;
117
118 szShareMem = GetSharedMemName();
119
120 hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem);
121
122 free(szShareMem);
123
124 if (hmap == NULL)
125 return false;
126
127 CloseHandle(hmap);
128 return true;
129}
130
131/*
132 * EnableLockPagesPrivilege
133 *
134 * Try to acquire SeLockMemoryPrivilege so we can use large pages.
135 */
136static bool
138{
139 HANDLE hToken;
140 TOKEN_PRIVILEGES tp;
141 LUID luid;
142
143 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
144 {
145 ereport(elevel,
146 (errmsg("could not enable user right \"%s\": error code %lu",
147
148 /*
149 * translator: This is a term from Windows and should be translated to
150 * match the Windows localization.
151 */
152 _("Lock pages in memory"),
153 GetLastError()),
154 errdetail("Failed system call was %s.", "OpenProcessToken")));
155 return FALSE;
156 }
157
158 if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
159 {
160 ereport(elevel,
161 (errmsg("could not enable user right \"%s\": error code %lu", _("Lock pages in memory"), GetLastError()),
162 errdetail("Failed system call was %s.", "LookupPrivilegeValue")));
163 CloseHandle(hToken);
164 return FALSE;
165 }
166 tp.PrivilegeCount = 1;
167 tp.Privileges[0].Luid = luid;
168 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
169
170 if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
171 {
172 ereport(elevel,
173 (errmsg("could not enable user right \"%s\": error code %lu", _("Lock pages in memory"), GetLastError()),
174 errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
175 CloseHandle(hToken);
176 return FALSE;
177 }
178
179 if (GetLastError() != ERROR_SUCCESS)
180 {
181 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
182 ereport(elevel,
183 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
184 errmsg("could not enable user right \"%s\"", _("Lock pages in memory")),
185 errhint("Assign user right \"%s\" to the Windows user account which runs PostgreSQL.",
186 _("Lock pages in memory"))));
187 else
188 ereport(elevel,
189 (errmsg("could not enable user right \"%s\": error code %lu", _("Lock pages in memory"), GetLastError()),
190 errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
191 CloseHandle(hToken);
192 return FALSE;
193 }
194
195 CloseHandle(hToken);
196
197 return TRUE;
198}
199
200/*
201 * PGSharedMemoryCreate
202 *
203 * Create a shared memory segment of the given size and initialize its
204 * standard header.
205 */
208 PGShmemHeader **shim)
209{
210 void *memAddress;
211 PGShmemHeader *hdr;
212 HANDLE hmap,
213 hmap2;
214 char *szShareMem;
215 int i;
216 DWORD size_high;
217 DWORD size_low;
218 SIZE_T largePageSize = 0;
219 Size orig_size = size;
220 DWORD flProtect = PAGE_READWRITE;
221 DWORD desiredAccess;
222
224 MEM_RESERVE, PAGE_NOACCESS);
225 if (ShmemProtectiveRegion == NULL)
226 elog(FATAL, "could not reserve memory region: error code %lu",
227 GetLastError());
228
229 /* Room for a header? */
230 Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
231
232 szShareMem = GetSharedMemName();
233
234 UsedShmemSegAddr = NULL;
235
237 {
238 /* Does the processor support large pages? */
239 largePageSize = GetLargePageMinimum();
240 if (largePageSize == 0)
241 {
243 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
244 errmsg("the processor does not support large pages")));
246 (errmsg_internal("disabling huge pages")));
247 }
249 {
251 (errmsg_internal("disabling huge pages")));
252 }
253 else
254 {
255 /* Huge pages available and privilege enabled, so turn on */
256 flProtect = PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES;
257
258 /* Round size up as appropriate. */
259 if (size % largePageSize != 0)
260 size += largePageSize - (size % largePageSize);
261 }
262 }
263
264retry:
265#ifdef _WIN64
266 size_high = size >> 32;
267#else
268 size_high = 0;
269#endif
270 size_low = (DWORD) size;
271
272 /*
273 * When recycling a shared memory segment, it may take a short while
274 * before it gets dropped from the global namespace. So re-try after
275 * sleeping for a second, and continue retrying 10 times. (both the 1
276 * second time and the 10 retries are completely arbitrary)
277 */
278 for (i = 0; i < 10; i++)
279 {
280 /*
281 * In case CreateFileMapping() doesn't set the error code to 0 on
282 * success
283 */
284 SetLastError(0);
285
286 hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */
287 NULL, /* Default security attrs */
288 flProtect,
289 size_high, /* Size Upper 32 Bits */
290 size_low, /* Size Lower 32 bits */
291 szShareMem);
292
293 if (!hmap)
294 {
295 if (GetLastError() == ERROR_NO_SYSTEM_RESOURCES &&
297 (flProtect & SEC_LARGE_PAGES) != 0)
298 {
299 elog(DEBUG1, "CreateFileMapping(%zu) with SEC_LARGE_PAGES failed, "
300 "huge pages disabled",
301 size);
302
303 /*
304 * Use the original size, not the rounded-up value, when
305 * falling back to non-huge pages.
306 */
307 size = orig_size;
308 flProtect = PAGE_READWRITE;
309 goto retry;
310 }
311 else
313 (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
314 errdetail("Failed system call was CreateFileMapping(size=%zu, name=%s).",
315 size, szShareMem)));
316 }
317
318 /*
319 * If the segment already existed, CreateFileMapping() will return a
320 * handle to the existing one and set ERROR_ALREADY_EXISTS.
321 */
322 if (GetLastError() == ERROR_ALREADY_EXISTS)
323 {
324 CloseHandle(hmap); /* Close the handle, since we got a valid one
325 * to the previous segment. */
326 hmap = NULL;
327 Sleep(1000);
328 continue;
329 }
330 break;
331 }
332
333 /*
334 * If the last call in the loop still returned ERROR_ALREADY_EXISTS, this
335 * shared memory segment exists and we assume it belongs to somebody else.
336 */
337 if (!hmap)
339 (errmsg("pre-existing shared memory block is still in use"),
340 errhint("Check if there are any old server processes still running, and terminate them.")));
341
342 free(szShareMem);
343
344 /*
345 * Make the handle inheritable
346 */
347 if (!DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, TRUE, DUPLICATE_SAME_ACCESS))
349 (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
350 errdetail("Failed system call was DuplicateHandle.")));
351
352 /*
353 * Close the old, non-inheritable handle. If this fails we don't really
354 * care.
355 */
356 if (!CloseHandle(hmap))
357 elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
358
359 desiredAccess = FILE_MAP_WRITE | FILE_MAP_READ;
360
361#ifdef FILE_MAP_LARGE_PAGES
362 /* Set large pages if wanted. */
363 if ((flProtect & SEC_LARGE_PAGES) != 0)
364 desiredAccess |= FILE_MAP_LARGE_PAGES;
365#endif
366
367 /*
368 * Get a pointer to the new shared memory segment. Map the whole segment
369 * at once, and let the system decide on the initial address.
370 */
371 memAddress = MapViewOfFileEx(hmap2, desiredAccess, 0, 0, 0, NULL);
372 if (!memAddress)
374 (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
375 errdetail("Failed system call was MapViewOfFileEx.")));
376
377
378
379 /*
380 * OK, we created a new segment. Mark it as created by this process. The
381 * order of assignments here is critical so that another Postgres process
382 * can't see the header as valid but belonging to an invalid PID!
383 */
384 hdr = (PGShmemHeader *) memAddress;
385 hdr->creatorPID = getpid();
386 hdr->magic = PGShmemMagic;
387
388 /*
389 * Initialize space allocation status for segment.
390 */
391 hdr->totalsize = size;
392 hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
393 hdr->dsm_control = 0;
394
395 /* Save info for possible future use */
396 UsedShmemSegAddr = memAddress;
398 UsedShmemSegID = hmap2;
399
400 /* Register on-exit routine to delete the new segment */
402
403 *shim = hdr;
404
405 /* Report whether huge pages are in use */
406 SetConfigOption("huge_pages_status", (flProtect & SEC_LARGE_PAGES) ?
407 "on" : "off", PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
408
409 return hdr;
410}
411
412/*
413 * PGSharedMemoryReAttach
414 *
415 * This is called during startup of a postmaster child process to re-attach to
416 * an already existing shared memory segment, using the handle inherited from
417 * the postmaster.
418 *
419 * ShmemProtectiveRegion, UsedShmemSegID and UsedShmemSegAddr are implicit
420 * parameters to this routine. The caller must have already restored them to
421 * the postmaster's values.
422 */
423void
425{
426 PGShmemHeader *hdr;
427 void *origUsedShmemSegAddr = UsedShmemSegAddr;
428
430 Assert(UsedShmemSegAddr != NULL);
432
433 /*
434 * Release memory region reservations made by the postmaster
435 */
436 if (VirtualFree(ShmemProtectiveRegion, 0, MEM_RELEASE) == 0)
437 elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
438 ShmemProtectiveRegion, GetLastError());
439 if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0)
440 elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
441 UsedShmemSegAddr, GetLastError());
442
443 hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
444 if (!hdr)
445 elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
446 UsedShmemSegID, UsedShmemSegAddr, GetLastError());
447 if (hdr != origUsedShmemSegAddr)
448 elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
449 hdr, origUsedShmemSegAddr);
450 if (hdr->magic != PGShmemMagic)
451 elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
452 dsm_set_control_handle(hdr->dsm_control);
453
454 UsedShmemSegAddr = hdr; /* probably redundant */
455}
456
457/*
458 * PGSharedMemoryNoReAttach
459 *
460 * This is called during startup of a postmaster child process when we choose
461 * *not* to re-attach to the existing shared memory segment. We must clean up
462 * to leave things in the appropriate state.
463 *
464 * The child process startup logic might or might not call PGSharedMemoryDetach
465 * after this; make sure that it will be a no-op if called.
466 *
467 * ShmemProtectiveRegion, UsedShmemSegID and UsedShmemSegAddr are implicit
468 * parameters to this routine. The caller must have already restored them to
469 * the postmaster's values.
470 */
471void
473{
475 Assert(UsedShmemSegAddr != NULL);
477
478 /*
479 * Under Windows we will not have mapped the segment, so we don't need to
480 * un-map it. Just reset UsedShmemSegAddr to show we're not attached.
481 */
482 UsedShmemSegAddr = NULL;
483
484 /*
485 * We *must* close the inherited shmem segment handle, else Windows will
486 * consider the existence of this process to mean it can't release the
487 * shmem segment yet. We can now use PGSharedMemoryDetach to do that.
488 */
490}
491
492/*
493 * PGSharedMemoryDetach
494 *
495 * Detach from the shared memory segment, if still attached. This is not
496 * intended to be called explicitly by the process that originally created the
497 * segment (it will have an on_shmem_exit callback registered to do that).
498 * Rather, this is for subprocesses that have inherited an attachment and want
499 * to get rid of it.
500 *
501 * ShmemProtectiveRegion, UsedShmemSegID and UsedShmemSegAddr are implicit
502 * parameters to this routine.
503 */
504void
506{
507 /*
508 * Releasing the protective region liberates an unimportant quantity of
509 * address space, but be tidy.
510 */
511 if (ShmemProtectiveRegion != NULL)
512 {
513 if (VirtualFree(ShmemProtectiveRegion, 0, MEM_RELEASE) == 0)
514 elog(LOG, "failed to release reserved memory region (addr=%p): error code %lu",
515 ShmemProtectiveRegion, GetLastError());
516
518 }
519
520 /* Unmap the view, if it's mapped */
521 if (UsedShmemSegAddr != NULL)
522 {
523 if (!UnmapViewOfFile(UsedShmemSegAddr))
524 elog(LOG, "could not unmap view of shared memory: error code %lu",
525 GetLastError());
526
527 UsedShmemSegAddr = NULL;
528 }
529
530 /* And close the shmem handle, if we have one */
531 if (UsedShmemSegID != INVALID_HANDLE_VALUE)
532 {
533 if (!CloseHandle(UsedShmemSegID))
534 elog(LOG, "could not close handle to shared memory: error code %lu",
535 GetLastError());
536
537 UsedShmemSegID = INVALID_HANDLE_VALUE;
538 }
539}
540
541
542/*
543 * pgwin32_SharedMemoryDelete
544 *
545 * Detach from and delete the shared memory segment
546 * (called as an on_shmem_exit callback, hence funny argument list)
547 */
548static void
550{
553}
554
555/*
556 * pgwin32_ReserveSharedMemoryRegion(hChild)
557 *
558 * Reserve the memory region that will be used for shared memory in a child
559 * process. It is called before the child process starts, to make sure the
560 * memory is available.
561 *
562 * Once the child starts, DLLs loading in different order or threads getting
563 * scheduled differently may allocate memory which can conflict with the
564 * address space we need for our shared memory. By reserving the shared
565 * memory region before the child starts, and freeing it only just before we
566 * attempt to get access to the shared memory forces these allocations to
567 * be given different address ranges that don't conflict.
568 *
569 * NOTE! This function executes in the postmaster, and should for this
570 * reason not use elog(FATAL) since that would take down the postmaster.
571 */
572int
574{
575 void *address;
576
578 Assert(UsedShmemSegAddr != NULL);
580
581 /* ShmemProtectiveRegion */
582 address = VirtualAllocEx(hChild, ShmemProtectiveRegion,
584 MEM_RESERVE, PAGE_NOACCESS);
585 if (address == NULL)
586 {
587 /* Don't use FATAL since we're running in the postmaster */
588 elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
589 ShmemProtectiveRegion, hChild, GetLastError());
590 return false;
591 }
592 if (address != ShmemProtectiveRegion)
593 {
594 /*
595 * Should never happen - in theory if allocation granularity causes
596 * strange effects it could, so check just in case.
597 *
598 * Don't use FATAL since we're running in the postmaster.
599 */
600 elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
601 address, ShmemProtectiveRegion);
602 return false;
603 }
604
605 /* UsedShmemSegAddr */
606 address = VirtualAllocEx(hChild, UsedShmemSegAddr, UsedShmemSegSize,
607 MEM_RESERVE, PAGE_READWRITE);
608 if (address == NULL)
609 {
610 elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
611 UsedShmemSegAddr, hChild, GetLastError());
612 return false;
613 }
614 if (address != UsedShmemSegAddr)
615 {
616 elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
617 address, UsedShmemSegAddr);
618 return false;
619 }
620
621 return true;
622}
623
624/*
625 * This function is provided for consistency with sysv_shmem.c and does not
626 * provide any useful information for Windows. To obtain the large page size,
627 * use GetLargePageMinimum() instead.
628 */
629void
630GetHugePageSize(Size *hugepagesize, int *mmap_flags)
631{
632 if (hugepagesize)
633 *hugepagesize = 0;
634 if (mmap_flags)
635 *mmap_flags = 0;
636}
637
638/*
639 * GUC check_hook for huge_page_size
640 */
641bool
643{
644 if (*newval != 0)
645 {
646 GUC_check_errdetail("\"huge_page_size\" must be 0 on this platform.");
647 return false;
648 }
649 return true;
650}
#define MAXALIGN(LEN)
Definition: c.h:768
#define Assert(condition)
Definition: c.h:815
size_t Size
Definition: c.h:562
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define _(x)
Definition: elog.c:90
#define LOG
Definition: elog.h:31
#define FATAL
Definition: elog.h:41
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
bool IsUnderPostmaster
Definition: globals.c:119
char * DataDir
Definition: globals.c:70
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
Definition: guc.c:4332
#define newval
#define GUC_check_errdetail
Definition: guc.h:480
GucSource
Definition: guc.h:112
@ PGC_S_DYNAMIC_DEFAULT
Definition: guc.h:114
@ PGC_INTERNAL
Definition: guc.h:73
int huge_pages
Definition: guc_tables.c:562
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
#define bufsize
Definition: indent_globs.h:36
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
int i
Definition: isn.c:72
static rewind_source * source
Definition: pg_rewind.c:89
@ HUGE_PAGES_ON
Definition: pg_shmem.h:53
@ HUGE_PAGES_TRY
Definition: pg_shmem.h:54
#define PGShmemMagic
Definition: pg_shmem.h:32
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static pg_noinline void Size size
Definition: slab.c:607
dsm_handle dsm_control
Definition: pg_shmem.h:36
Size freeoffset
Definition: pg_shmem.h:35
pid_t creatorPID
Definition: pg_shmem.h:33
int32 magic
Definition: pg_shmem.h:31
Size totalsize
Definition: pg_shmem.h:34
#define PROTECTIVE_REGION_SIZE
Definition: win32_shmem.c:41
void PGSharedMemoryDetach(void)
Definition: win32_shmem.c:505
void PGSharedMemoryReAttach(void)
Definition: win32_shmem.c:424
PGShmemHeader * PGSharedMemoryCreate(Size size, PGShmemHeader **shim)
Definition: win32_shmem.c:207
bool check_huge_page_size(int *newval, void **extra, GucSource source)
Definition: win32_shmem.c:642
void * ShmemProtectiveRegion
Definition: win32_shmem.c:42
static char * GetSharedMemName(void)
Definition: win32_shmem.c:65
HANDLE UsedShmemSegID
Definition: win32_shmem.c:44
void GetHugePageSize(Size *hugepagesize, int *mmap_flags)
Definition: win32_shmem.c:630
void * UsedShmemSegAddr
Definition: win32_shmem.c:45
int pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
Definition: win32_shmem.c:573
static bool EnableLockPagesPrivilege(int elevel)
Definition: win32_shmem.c:137
bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
Definition: win32_shmem.c:113
static void pgwin32_SharedMemoryDelete(int status, Datum shmId)
Definition: win32_shmem.c:549
static Size UsedShmemSegSize
Definition: win32_shmem.c:46
void PGSharedMemoryNoReAttach(void)
Definition: win32_shmem.c:472