#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().
1.7.1