#include "postgres.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
Go to the source code of this file.
Functions | |
static void | pgwin32_SharedMemoryDelete (int status, Datum shmId) |
static char * | GetSharedMemName (void) |
bool | PGSharedMemoryIsInUse (unsigned long id1, unsigned long id2) |
PGShmemHeader * | PGSharedMemoryCreate (Size size, bool makePrivate, int port) |
void | PGSharedMemoryReAttach (void) |
void | PGSharedMemoryDetach (void) |
int | pgwin32_ReserveSharedMemoryRegion (HANDLE hChild) |
Variables | |
HANDLE | UsedShmemSegID = 0 |
void * | UsedShmemSegAddr = NULL |
static Size | UsedShmemSegSize = 0 |
static char* GetSharedMemName | ( | void | ) | [static] |
Definition at line 39 of file win32_shmem.c.
References DataDir, elog, FATAL, malloc, and NULL.
Referenced by PGSharedMemoryCreate(), and PGSharedMemoryIsInUse().
{ char *retptr; DWORD bufsize; DWORD r; char *cp; bufsize = GetFullPathName(DataDir, 0, NULL, NULL); if (bufsize == 0) elog(FATAL, "could not get size for full pathname of datadir %s: error code %lu", DataDir, GetLastError()); retptr = malloc(bufsize + 18); /* 18 for Global\PostgreSQL: */ if (retptr == NULL) elog(FATAL, "could not allocate memory for shared memory name"); strcpy(retptr, "Global\\PostgreSQL:"); r = GetFullPathName(DataDir, bufsize, retptr + 18, NULL); if (r == 0 || r > bufsize) elog(FATAL, "could not generate full pathname for datadir %s: error code %lu", DataDir, GetLastError()); /* * XXX: Intentionally overwriting the Global\ part here. This was not the * original approach, but putting it in the actual Global\ namespace * causes permission errors in a lot of cases, so we leave it in the * default namespace for now. */ for (cp = retptr; *cp; cp++) if (*cp == '\\') *cp = '/'; return retptr; }
PGShmemHeader* PGSharedMemoryCreate | ( | Size | size, | |
bool | makePrivate, | |||
int | port | |||
) |
Definition at line 120 of file win32_shmem.c.
References AnonymousShmem, AnonymousShmemSize, Assert, PGShmemHeader::creatorPID, DataDir, PGShmemHeader::device, elog, ereport, errcode_for_file_access(), errdetail(), errhint(), errmsg(), FATAL, free, PGShmemHeader::freeoffset, GetSharedMemName(), i, PGShmemHeader::inode, InternalIpcMemoryCreate(), IPC_RMID, LOG, PGShmemHeader::magic, MAP_FAILED, MAXALIGN, NULL, on_shmem_exit(), PG_MMAP_FLAGS, PGSharedMemoryAttach(), pgwin32_SharedMemoryDelete(), PointerGetDatum, PGShmemHeader::totalsize, TRUE, UsedShmemSegAddr, UsedShmemSegID, and UsedShmemSegSize.
{ void *memAddress; PGShmemHeader *hdr; HANDLE hmap, hmap2; char *szShareMem; int i; DWORD size_high; DWORD size_low; /* Room for a header? */ Assert(size > MAXALIGN(sizeof(PGShmemHeader))); szShareMem = GetSharedMemName(); UsedShmemSegAddr = NULL; #ifdef _WIN64 size_high = size >> 32; #else size_high = 0; #endif size_low = (DWORD) size; /* * When recycling a shared memory segment, it may take a short while * before it gets dropped from the global namespace. So re-try after * sleeping for a second, and continue retrying 10 times. (both the 1 * second time and the 10 retries are completely arbitrary) */ for (i = 0; i < 10; i++) { /* * In case CreateFileMapping() doesn't set the error code to 0 on * success */ SetLastError(0); hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */ NULL, /* Default security attrs */ PAGE_READWRITE, /* Memory is Read/Write */ size_high, /* Size Upper 32 Bits */ size_low, /* Size Lower 32 bits */ szShareMem); if (!hmap) ereport(FATAL, (errmsg("could not create shared memory segment: error code %lu", GetLastError()), errdetail("Failed system call was CreateFileMapping(size=%lu, name=%s).", (unsigned long) size, szShareMem))); /* * If the segment already existed, CreateFileMapping() will return a * handle to the existing one and set ERROR_ALREADY_EXISTS. */ if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(hmap); /* Close the handle, since we got a valid one * to the previous segment. */ hmap = NULL; Sleep(1000); continue; } break; } /* * If the last call in the loop still returned ERROR_ALREADY_EXISTS, this * shared memory segment exists and we assume it belongs to somebody else. */ if (!hmap) ereport(FATAL, (errmsg("pre-existing shared memory block is still in use"), errhint("Check if there are any old server processes still running, and terminate them."))); free(szShareMem); /* * Make the handle inheritable */ if (!DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, TRUE, DUPLICATE_SAME_ACCESS)) ereport(FATAL, (errmsg("could not create shared memory segment: error code %lu", GetLastError()), errdetail("Failed system call was DuplicateHandle."))); /* * Close the old, non-inheritable handle. If this fails we don't really * care. */ if (!CloseHandle(hmap)) elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError()); /* Register on-exit routine to delete the new segment */ on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2)); /* * Get a pointer to the new shared memory segment. Map the whole segment * at once, and let the system decide on the initial address. */ memAddress = MapViewOfFileEx(hmap2, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, NULL); if (!memAddress) ereport(FATAL, (errmsg("could not create shared memory segment: error code %lu", GetLastError()), errdetail("Failed system call was MapViewOfFileEx."))); /* * OK, we created a new segment. Mark it as created by this process. The * order of assignments here is critical so that another Postgres process * can't see the header as valid but belonging to an invalid PID! */ hdr = (PGShmemHeader *) memAddress; hdr->creatorPID = getpid(); hdr->magic = PGShmemMagic; /* * Initialize space allocation status for segment. */ hdr->totalsize = size; hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); /* Save info for possible future use */ UsedShmemSegAddr = memAddress; UsedShmemSegSize = size; UsedShmemSegID = hmap2; return hdr; }
void PGSharedMemoryDetach | ( | void | ) |
Definition at line 300 of file win32_shmem.c.
References AnonymousShmem, AnonymousShmemSize, elog, LOG, NULL, and UsedShmemSegAddr.
{ if (UsedShmemSegAddr != NULL) { if (!UnmapViewOfFile(UsedShmemSegAddr)) elog(LOG, "could not unmap view of shared memory: error code %lu", GetLastError()); UsedShmemSegAddr = NULL; } }
bool PGSharedMemoryIsInUse | ( | unsigned long | id1, | |
unsigned long | id2 | |||
) |
Definition at line 88 of file win32_shmem.c.
References DataDir, EIDRM, FALSE, free, GetSharedMemName(), IPC_STAT, NULL, PG_SHMAT_FLAGS, and PGShmemMagic.
{ char *szShareMem; HANDLE hmap; szShareMem = GetSharedMemName(); hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem); free(szShareMem); if (hmap == NULL) return false; CloseHandle(hmap); return true; }
void PGSharedMemoryReAttach | ( | void | ) |
Definition at line 263 of file win32_shmem.c.
References Assert, elog, FATAL, IsUnderPostmaster, PGShmemHeader::magic, NULL, PGShmemMagic, UsedShmemSegAddr, and UsedShmemSegID.
{ PGShmemHeader *hdr; void *origUsedShmemSegAddr = UsedShmemSegAddr; Assert(UsedShmemSegAddr != NULL); Assert(IsUnderPostmaster); /* * Release memory region reservation that was made by the postmaster */ if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0) elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu", UsedShmemSegAddr, GetLastError()); hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr); if (!hdr) elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu", UsedShmemSegID, UsedShmemSegAddr, GetLastError()); if (hdr != origUsedShmemSegAddr) elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)", hdr, origUsedShmemSegAddr); if (hdr->magic != PGShmemMagic) elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory"); UsedShmemSegAddr = hdr; /* probably redundant */ }
int pgwin32_ReserveSharedMemoryRegion | ( | HANDLE | hChild | ) |
Definition at line 342 of file win32_shmem.c.
References Assert, elog, LOG, NULL, UsedShmemSegAddr, and UsedShmemSegSize.
{ void *address; Assert(UsedShmemSegAddr != NULL); Assert(UsedShmemSegSize != 0); address = VirtualAllocEx(hChild, UsedShmemSegAddr, UsedShmemSegSize, MEM_RESERVE, PAGE_READWRITE); if (address == NULL) { /* Don't use FATAL since we're running in the postmaster */ elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu", UsedShmemSegAddr, hChild, GetLastError()); return false; } if (address != UsedShmemSegAddr) { /* * Should never happen - in theory if allocation granularity causes * strange effects it could, so check just in case. * * Don't use FATAL since we're running in the postmaster. */ elog(LOG, "reserved shared memory region got incorrect address %p, expected %p", address, UsedShmemSegAddr); VirtualFreeEx(hChild, address, 0, MEM_RELEASE); return false; } return true; }
static void pgwin32_SharedMemoryDelete | ( | int | status, | |
Datum | shmId | |||
) | [static] |
Definition at line 317 of file win32_shmem.c.
References DatumGetPointer, elog, LOG, and PGSharedMemoryDetach().
Referenced by PGSharedMemoryCreate().
{ PGSharedMemoryDetach(); if (!CloseHandle(DatumGetPointer(shmId))) elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError()); }
void* UsedShmemSegAddr = NULL |
Definition at line 20 of file win32_shmem.c.
HANDLE UsedShmemSegID = 0 |
Definition at line 19 of file win32_shmem.c.
Size UsedShmemSegSize = 0 [static] |
Definition at line 21 of file win32_shmem.c.
Referenced by PGSharedMemoryCreate(), and pgwin32_ReserveSharedMemoryRegion().