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-2024, 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)
42 void *ShmemProtectiveRegion = NULL;
43 
44 HANDLE UsedShmemSegID = INVALID_HANDLE_VALUE;
45 void *UsedShmemSegAddr = NULL;
47 
48 static bool EnableLockPagesPrivilege(int elevel);
49 static 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  */
64 static 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  */
112 bool
113 PGSharedMemoryIsInUse(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  */
136 static 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 
223  ShmemProtectiveRegion = VirtualAlloc(NULL, PROTECTIVE_REGION_SIZE,
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")));
245  ereport(DEBUG1,
246  (errmsg_internal("disabling huge pages")));
247  }
249  {
250  ereport(DEBUG1,
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 
264 retry:
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
312  ereport(FATAL,
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)
338  ereport(FATAL,
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))
348  ereport(FATAL,
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)
373  ereport(FATAL,
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  */
423 void
425 {
426  PGShmemHeader *hdr;
427  void *origUsedShmemSegAddr = UsedShmemSegAddr;
428 
429  Assert(ShmemProtectiveRegion != NULL);
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  */
471 void
473 {
474  Assert(ShmemProtectiveRegion != NULL);
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  */
504 void
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 
517  ShmemProtectiveRegion = NULL;
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  */
548 static 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  */
572 int
574 {
575  void *address;
576 
577  Assert(ShmemProtectiveRegion != NULL);
578  Assert(UsedShmemSegAddr != NULL);
579  Assert(UsedShmemSegSize != 0);
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  */
629 void
630 GetHugePageSize(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  */
641 bool
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:802
#define Assert(condition)
Definition: c.h:849
size_t Size
Definition: c.h:596
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:4290
#define newval
#define GUC_check_errdetail
Definition: guc.h:476
GucSource
Definition: guc.h:108
@ PGC_S_DYNAMIC_DEFAULT
Definition: guc.h:110
@ PGC_INTERNAL
Definition: guc.h:69
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:73
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:322
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
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
PGShmemHeader * PGSharedMemoryCreate(Size size, PGShmemHeader **shim)
Definition: win32_shmem.c:207
void PGSharedMemoryDetach(void)
Definition: win32_shmem.c:505
void PGSharedMemoryReAttach(void)
Definition: win32_shmem.c:424
bool check_huge_page_size(int *newval, void **extra, GucSource source)
Definition: win32_shmem.c:642
void * ShmemProtectiveRegion
Definition: win32_shmem.c:42
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
static char * GetSharedMemName(void)
Definition: win32_shmem.c:65