PostgreSQL Source Code  git master
win32_shmem.c File Reference
#include "postgres.h"
#include "miscadmin.h"
#include "storage/dsm.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
Include dependency graph for win32_shmem.c:

Go to the source code of this file.

Functions

static bool EnableLockPagesPrivilege (int elevel)
 
static void pgwin32_SharedMemoryDelete (int status, Datum shmId)
 
static char * GetSharedMemName (void)
 
bool PGSharedMemoryIsInUse (unsigned long id1, unsigned long id2)
 
PGShmemHeaderPGSharedMemoryCreate (Size size, bool makePrivate, int port, PGShmemHeader **shim)
 
void PGSharedMemoryReAttach (void)
 
void PGSharedMemoryNoReAttach (void)
 
void PGSharedMemoryDetach (void)
 
int pgwin32_ReserveSharedMemoryRegion (HANDLE hChild)
 

Variables

HANDLE UsedShmemSegID = INVALID_HANDLE_VALUE
 
void * UsedShmemSegAddr = NULL
 
static Size UsedShmemSegSize = 0
 

Function Documentation

◆ EnableLockPagesPrivilege()

static bool EnableLockPagesPrivilege ( int  elevel)
static

Definition at line 113 of file win32_shmem.c.

References ereport, errcode(), errdetail(), errhint(), errmsg(), FALSE, and TRUE.

Referenced by PGSharedMemoryCreate().

114 {
115  HANDLE hToken;
116  TOKEN_PRIVILEGES tp;
117  LUID luid;
118 
119  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
120  {
121  ereport(elevel,
122  (errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
123  errdetail("Failed system call was %s.", "OpenProcessToken")));
124  return FALSE;
125  }
126 
127  if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid))
128  {
129  ereport(elevel,
130  (errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
131  errdetail("Failed system call was %s.", "LookupPrivilegeValue")));
132  CloseHandle(hToken);
133  return FALSE;
134  }
135  tp.PrivilegeCount = 1;
136  tp.Privileges[0].Luid = luid;
137  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
138 
139  if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL))
140  {
141  ereport(elevel,
142  (errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
143  errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
144  CloseHandle(hToken);
145  return FALSE;
146  }
147 
148  if (GetLastError() != ERROR_SUCCESS)
149  {
150  if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
151  ereport(elevel,
152  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
153  errmsg("could not enable Lock Pages in Memory user right"),
154  errhint("Assign Lock Pages in Memory user right to the Windows user account which runs PostgreSQL.")));
155  else
156  ereport(elevel,
157  (errmsg("could not enable Lock Pages in Memory user right: error code %lu", GetLastError()),
158  errdetail("Failed system call was %s.", "AdjustTokenPrivileges")));
159  CloseHandle(hToken);
160  return FALSE;
161  }
162 
163  CloseHandle(hToken);
164 
165  return TRUE;
166 }
#define TRUE
Definition: ecpglib.h:35
int errhint(const char *fmt,...)
Definition: elog.c:987
#define FALSE
Definition: ecpglib.h:39
int errcode(int sqlerrcode)
Definition: elog.c:575
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
static int elevel
Definition: vacuumlazy.c:144
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ GetSharedMemName()

static char* GetSharedMemName ( void  )
static

Definition at line 41 of file win32_shmem.c.

References DataDir, elog, FATAL, and malloc.

Referenced by PGSharedMemoryCreate(), and PGSharedMemoryIsInUse().

42 {
43  char *retptr;
44  DWORD bufsize;
45  DWORD r;
46  char *cp;
47 
48  bufsize = GetFullPathName(DataDir, 0, NULL, NULL);
49  if (bufsize == 0)
50  elog(FATAL, "could not get size for full pathname of datadir %s: error code %lu",
51  DataDir, GetLastError());
52 
53  retptr = malloc(bufsize + 18); /* 18 for Global\PostgreSQL: */
54  if (retptr == NULL)
55  elog(FATAL, "could not allocate memory for shared memory name");
56 
57  strcpy(retptr, "Global\\PostgreSQL:");
58  r = GetFullPathName(DataDir, bufsize, retptr + 18, NULL);
59  if (r == 0 || r > bufsize)
60  elog(FATAL, "could not generate full pathname for datadir %s: error code %lu",
61  DataDir, GetLastError());
62 
63  /*
64  * XXX: Intentionally overwriting the Global\ part here. This was not the
65  * original approach, but putting it in the actual Global\ namespace
66  * causes permission errors in a lot of cases, so we leave it in the
67  * default namespace for now.
68  */
69  for (cp = retptr; *cp; cp++)
70  if (*cp == '\\')
71  *cp = '/';
72 
73  return retptr;
74 }
#define malloc(a)
Definition: header.h:50
#define FATAL
Definition: elog.h:52
char * DataDir
Definition: globals.c:61
#define elog
Definition: elog.h:219

◆ PGSharedMemoryCreate()

PGShmemHeader* PGSharedMemoryCreate ( Size  size,
bool  makePrivate,
int  port,
PGShmemHeader **  shim 
)

Definition at line 180 of file win32_shmem.c.

References AnonymousShmem, AnonymousShmemDetach(), AnonymousShmemSize, Assert, CreateAnonymousSegment(), PGShmemHeader::creatorPID, DataDir, DEBUG1, DEBUG3, PGShmemHeader::device, dsm_cleanup_using_control_segment(), PGShmemHeader::dsm_control, dsm_control, elog, EnableLockPagesPrivilege(), ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), ERROR, FATAL, free, PGShmemHeader::freeoffset, GetSharedMemName(), huge_pages, HUGE_PAGES_ON, HUGE_PAGES_TRY, i, PGShmemHeader::inode, InternalIpcMemoryCreate(), IPC_RMID, IsUnderPostmaster, kill, LOG, PGShmemHeader::magic, MAXALIGN, on_shmem_exit(), PGSharedMemoryAttach(), PGSharedMemoryDetach(), PGSharedMemoryNoReAttach(), PGSharedMemoryReAttach(), PGShmemMagic, pgwin32_SharedMemoryDelete(), PointerGetDatum, stat, PGShmemHeader::totalsize, TRUE, UsedShmemSegAddr, UsedShmemSegID, and UsedShmemSegSize.

182 {
183  void *memAddress;
184  PGShmemHeader *hdr;
185  HANDLE hmap,
186  hmap2;
187  char *szShareMem;
188  int i;
189  DWORD size_high;
190  DWORD size_low;
191  SIZE_T largePageSize = 0;
192  Size orig_size = size;
193  DWORD flProtect = PAGE_READWRITE;
194 
195  /* Room for a header? */
196  Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
197 
198  szShareMem = GetSharedMemName();
199 
200  UsedShmemSegAddr = NULL;
201 
203  {
204  /* Does the processor support large pages? */
205  largePageSize = GetLargePageMinimum();
206  if (largePageSize == 0)
207  {
209  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
210  errmsg("the processor does not support large pages")));
211  ereport(DEBUG1,
212  (errmsg("disabling huge pages")));
213  }
214  else if (!EnableLockPagesPrivilege(huge_pages == HUGE_PAGES_ON ? FATAL : DEBUG1))
215  {
216  ereport(DEBUG1,
217  (errmsg("disabling huge pages")));
218  }
219  else
220  {
221  /* Huge pages available and privilege enabled, so turn on */
222  flProtect = PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES;
223 
224  /* Round size up as appropriate. */
225  if (size % largePageSize != 0)
226  size += largePageSize - (size % largePageSize);
227  }
228  }
229 
230 retry:
231 #ifdef _WIN64
232  size_high = size >> 32;
233 #else
234  size_high = 0;
235 #endif
236  size_low = (DWORD) size;
237 
238  /*
239  * When recycling a shared memory segment, it may take a short while
240  * before it gets dropped from the global namespace. So re-try after
241  * sleeping for a second, and continue retrying 10 times. (both the 1
242  * second time and the 10 retries are completely arbitrary)
243  */
244  for (i = 0; i < 10; i++)
245  {
246  /*
247  * In case CreateFileMapping() doesn't set the error code to 0 on
248  * success
249  */
250  SetLastError(0);
251 
252  hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */
253  NULL, /* Default security attrs */
254  flProtect,
255  size_high, /* Size Upper 32 Bits */
256  size_low, /* Size Lower 32 bits */
257  szShareMem);
258 
259  if (!hmap)
260  {
261  if (GetLastError() == ERROR_NO_SYSTEM_RESOURCES &&
263  (flProtect & SEC_LARGE_PAGES) != 0)
264  {
265  elog(DEBUG1, "CreateFileMapping(%zu) with SEC_LARGE_PAGES failed, "
266  "huge pages disabled",
267  size);
268 
269  /*
270  * Use the original size, not the rounded-up value, when
271  * falling back to non-huge pages.
272  */
273  size = orig_size;
274  flProtect = PAGE_READWRITE;
275  goto retry;
276  }
277  else
278  ereport(FATAL,
279  (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
280  errdetail("Failed system call was CreateFileMapping(size=%zu, name=%s).",
281  size, szShareMem)));
282  }
283 
284  /*
285  * If the segment already existed, CreateFileMapping() will return a
286  * handle to the existing one and set ERROR_ALREADY_EXISTS.
287  */
288  if (GetLastError() == ERROR_ALREADY_EXISTS)
289  {
290  CloseHandle(hmap); /* Close the handle, since we got a valid one
291  * to the previous segment. */
292  hmap = NULL;
293  Sleep(1000);
294  continue;
295  }
296  break;
297  }
298 
299  /*
300  * If the last call in the loop still returned ERROR_ALREADY_EXISTS, this
301  * shared memory segment exists and we assume it belongs to somebody else.
302  */
303  if (!hmap)
304  ereport(FATAL,
305  (errmsg("pre-existing shared memory block is still in use"),
306  errhint("Check if there are any old server processes still running, and terminate them.")));
307 
308  free(szShareMem);
309 
310  /*
311  * Make the handle inheritable
312  */
313  if (!DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, TRUE, DUPLICATE_SAME_ACCESS))
314  ereport(FATAL,
315  (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
316  errdetail("Failed system call was DuplicateHandle.")));
317 
318  /*
319  * Close the old, non-inheritable handle. If this fails we don't really
320  * care.
321  */
322  if (!CloseHandle(hmap))
323  elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
324 
325 
326  /*
327  * Get a pointer to the new shared memory segment. Map the whole segment
328  * at once, and let the system decide on the initial address.
329  */
330  memAddress = MapViewOfFileEx(hmap2, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, NULL);
331  if (!memAddress)
332  ereport(FATAL,
333  (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
334  errdetail("Failed system call was MapViewOfFileEx.")));
335 
336 
337 
338  /*
339  * OK, we created a new segment. Mark it as created by this process. The
340  * order of assignments here is critical so that another Postgres process
341  * can't see the header as valid but belonging to an invalid PID!
342  */
343  hdr = (PGShmemHeader *) memAddress;
344  hdr->creatorPID = getpid();
345  hdr->magic = PGShmemMagic;
346 
347  /*
348  * Initialize space allocation status for segment.
349  */
350  hdr->totalsize = size;
351  hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
352  hdr->dsm_control = 0;
353 
354  /* Save info for possible future use */
355  UsedShmemSegAddr = memAddress;
356  UsedShmemSegSize = size;
357  UsedShmemSegID = hmap2;
358 
359  /* Register on-exit routine to delete the new segment */
361 
362  *shim = hdr;
363  return hdr;
364 }
#define TRUE
Definition: ecpglib.h:35
pid_t creatorPID
Definition: pg_shmem.h:33
#define DEBUG1
Definition: elog.h:25
int errhint(const char *fmt,...)
Definition: elog.c:987
dsm_handle dsm_control
Definition: pg_shmem.h:36
#define PointerGetDatum(X)
Definition: postgres.h:541
static bool EnableLockPagesPrivilege(int elevel)
Definition: win32_shmem.c:113
int errcode(int sqlerrcode)
Definition: elog.c:575
#define LOG
Definition: elog.h:26
#define FATAL
Definition: elog.h:52
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:359
HANDLE UsedShmemSegID
Definition: win32_shmem.c:20
int errdetail(const char *fmt,...)
Definition: elog.c:873
static void pgwin32_SharedMemoryDelete(int status, Datum shmId)
Definition: win32_shmem.c:485
#define ereport(elevel, rest)
Definition: elog.h:122
int32 magic
Definition: pg_shmem.h:31
static Size UsedShmemSegSize
Definition: win32_shmem.c:22
Size totalsize
Definition: pg_shmem.h:34
static char * GetSharedMemName(void)
Definition: win32_shmem.c:41
#define free(a)
Definition: header.h:65
#define Assert(condition)
Definition: c.h:699
#define PGShmemMagic
Definition: pg_shmem.h:32
Size freeoffset
Definition: pg_shmem.h:35
size_t Size
Definition: c.h:433
#define MAXALIGN(LEN)
Definition: c.h:652
int huge_pages
Definition: guc.c:490
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define elog
Definition: elog.h:219
void * UsedShmemSegAddr
Definition: win32_shmem.c:21

◆ PGSharedMemoryDetach()

void PGSharedMemoryDetach ( void  )

Definition at line 454 of file win32_shmem.c.

References AnonymousShmem, AnonymousShmemSize, elog, LOG, UsedShmemSegAddr, and UsedShmemSegID.

Referenced by PGSharedMemoryNoReAttach(), and pgwin32_SharedMemoryDelete().

455 {
456  /* Unmap the view, if it's mapped */
457  if (UsedShmemSegAddr != NULL)
458  {
459  if (!UnmapViewOfFile(UsedShmemSegAddr))
460  elog(LOG, "could not unmap view of shared memory: error code %lu",
461  GetLastError());
462 
463  UsedShmemSegAddr = NULL;
464  }
465 
466  /* And close the shmem handle, if we have one */
467  if (UsedShmemSegID != INVALID_HANDLE_VALUE)
468  {
469  if (!CloseHandle(UsedShmemSegID))
470  elog(LOG, "could not close handle to shared memory: error code %lu",
471  GetLastError());
472 
473  UsedShmemSegID = INVALID_HANDLE_VALUE;
474  }
475 }
#define LOG
Definition: elog.h:26
HANDLE UsedShmemSegID
Definition: win32_shmem.c:20
#define elog
Definition: elog.h:219
void * UsedShmemSegAddr
Definition: win32_shmem.c:21

◆ PGSharedMemoryIsInUse()

bool PGSharedMemoryIsInUse ( unsigned long  id1,
unsigned long  id2 
)

Definition at line 89 of file win32_shmem.c.

References AllocateFile(), buf, DataDir, EIDRM, FALSE, free, FreeFile(), GetSharedMemName(), IPC_STAT, PG_SHMAT_FLAGS, PGShmemMagic, and stat.

90 {
91  char *szShareMem;
92  HANDLE hmap;
93 
94  szShareMem = GetSharedMemName();
95 
96  hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem);
97 
98  free(szShareMem);
99 
100  if (hmap == NULL)
101  return false;
102 
103  CloseHandle(hmap);
104  return true;
105 }
#define FALSE
Definition: ecpglib.h:39
static char * GetSharedMemName(void)
Definition: win32_shmem.c:41
#define free(a)
Definition: header.h:65

◆ PGSharedMemoryNoReAttach()

void PGSharedMemoryNoReAttach ( void  )

Definition at line 422 of file win32_shmem.c.

References Assert, IsUnderPostmaster, PGSharedMemoryDetach(), and UsedShmemSegAddr.

Referenced by BackendRun(), and PGSharedMemoryCreate().

423 {
424  Assert(UsedShmemSegAddr != NULL);
426 
427  /*
428  * Under Windows we will not have mapped the segment, so we don't need to
429  * un-map it. Just reset UsedShmemSegAddr to show we're not attached.
430  */
431  UsedShmemSegAddr = NULL;
432 
433  /*
434  * We *must* close the inherited shmem segment handle, else Windows will
435  * consider the existence of this process to mean it can't release the
436  * shmem segment yet. We can now use PGSharedMemoryDetach to do that.
437  */
439 }
void PGSharedMemoryDetach(void)
Definition: win32_shmem.c:454
bool IsUnderPostmaster
Definition: globals.c:108
#define Assert(condition)
Definition: c.h:699
void * UsedShmemSegAddr
Definition: win32_shmem.c:21

◆ PGSharedMemoryReAttach()

void PGSharedMemoryReAttach ( void  )

Definition at line 378 of file win32_shmem.c.

References Assert, PGShmemHeader::dsm_control, elog, FATAL, IsUnderPostmaster, PGShmemHeader::magic, PGShmemMagic, UsedShmemSegAddr, and UsedShmemSegID.

Referenced by BackendRun(), and PGSharedMemoryCreate().

379 {
380  PGShmemHeader *hdr;
381  void *origUsedShmemSegAddr = UsedShmemSegAddr;
382 
383  Assert(UsedShmemSegAddr != NULL);
385 
386  /*
387  * Release memory region reservation that was made by the postmaster
388  */
389  if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0)
390  elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
391  UsedShmemSegAddr, GetLastError());
392 
393  hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
394  if (!hdr)
395  elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
396  UsedShmemSegID, UsedShmemSegAddr, GetLastError());
397  if (hdr != origUsedShmemSegAddr)
398  elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
399  hdr, origUsedShmemSegAddr);
400  if (hdr->magic != PGShmemMagic)
401  elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
402  dsm_set_control_handle(hdr->dsm_control);
403 
404  UsedShmemSegAddr = hdr; /* probably redundant */
405 }
dsm_handle dsm_control
Definition: pg_shmem.h:36
#define FATAL
Definition: elog.h:52
bool IsUnderPostmaster
Definition: globals.c:108
HANDLE UsedShmemSegID
Definition: win32_shmem.c:20
int32 magic
Definition: pg_shmem.h:31
#define Assert(condition)
Definition: c.h:699
#define PGShmemMagic
Definition: pg_shmem.h:32
#define elog
Definition: elog.h:219
void * UsedShmemSegAddr
Definition: win32_shmem.c:21

◆ pgwin32_ReserveSharedMemoryRegion()

int pgwin32_ReserveSharedMemoryRegion ( HANDLE  hChild)

Definition at line 509 of file win32_shmem.c.

References Assert, elog, LOG, UsedShmemSegAddr, and UsedShmemSegSize.

Referenced by BackendRun().

510 {
511  void *address;
512 
513  Assert(UsedShmemSegAddr != NULL);
514  Assert(UsedShmemSegSize != 0);
515 
516  address = VirtualAllocEx(hChild, UsedShmemSegAddr, UsedShmemSegSize,
517  MEM_RESERVE, PAGE_READWRITE);
518  if (address == NULL)
519  {
520  /* Don't use FATAL since we're running in the postmaster */
521  elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
522  UsedShmemSegAddr, hChild, GetLastError());
523  return false;
524  }
525  if (address != UsedShmemSegAddr)
526  {
527  /*
528  * Should never happen - in theory if allocation granularity causes
529  * strange effects it could, so check just in case.
530  *
531  * Don't use FATAL since we're running in the postmaster.
532  */
533  elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
534  address, UsedShmemSegAddr);
535  VirtualFreeEx(hChild, address, 0, MEM_RELEASE);
536  return false;
537  }
538 
539  return true;
540 }
#define LOG
Definition: elog.h:26
static Size UsedShmemSegSize
Definition: win32_shmem.c:22
#define Assert(condition)
Definition: c.h:699
#define elog
Definition: elog.h:219
void * UsedShmemSegAddr
Definition: win32_shmem.c:21

◆ pgwin32_SharedMemoryDelete()

static void pgwin32_SharedMemoryDelete ( int  status,
Datum  shmId 
)
static

Definition at line 485 of file win32_shmem.c.

References Assert, DatumGetPointer, PGSharedMemoryDetach(), and UsedShmemSegID.

Referenced by PGSharedMemoryCreate().

486 {
489 }
void PGSharedMemoryDetach(void)
Definition: win32_shmem.c:454
HANDLE UsedShmemSegID
Definition: win32_shmem.c:20
#define Assert(condition)
Definition: c.h:699
#define DatumGetPointer(X)
Definition: postgres.h:534

Variable Documentation

◆ UsedShmemSegAddr

◆ UsedShmemSegID

HANDLE UsedShmemSegID = INVALID_HANDLE_VALUE

◆ UsedShmemSegSize

Size UsedShmemSegSize = 0
static

Definition at line 22 of file win32_shmem.c.

Referenced by PGSharedMemoryCreate(), and pgwin32_ReserveSharedMemoryRegion().