mirror of https://github.com/postgres/postgres
Uses same underlying tech as before, but not the sysv emulation layer.REL8_3_STABLE
parent
3b765dba78
commit
18d82d03b5
@ -1,128 +0,0 @@ |
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
* |
|
||||||
* shmem.c |
|
||||||
* Microsoft Windows Win32 Shared Memory Emulation |
|
||||||
* |
|
||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group |
|
||||||
* |
|
||||||
* IDENTIFICATION |
|
||||||
* $PostgreSQL: pgsql/src/backend/port/win32/shmem.c,v 1.14 2007/01/05 22:19:35 momjian Exp $ |
|
||||||
* |
|
||||||
*------------------------------------------------------------------------- |
|
||||||
*/ |
|
||||||
|
|
||||||
#include "postgres.h" |
|
||||||
|
|
||||||
static DWORD s_segsize = 0; |
|
||||||
|
|
||||||
/* Detach from a shared mem area based on its address */ |
|
||||||
int |
|
||||||
shmdt(const void *shmaddr) |
|
||||||
{ |
|
||||||
if (UnmapViewOfFile((LPCVOID *) shmaddr)) |
|
||||||
return 0; |
|
||||||
else |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
/* Attach to an existing area */ |
|
||||||
void * |
|
||||||
shmat(int memId, void *shmaddr, int flag) |
|
||||||
{ |
|
||||||
/* TODO -- shmat needs to count # attached to shared mem */ |
|
||||||
void *lpmem = MapViewOfFileEx((HANDLE) memId, |
|
||||||
FILE_MAP_WRITE | FILE_MAP_READ, |
|
||||||
0, 0, /* (DWORD)pshmdsc->segsize */ 0 /* s_segsize */ , shmaddr); |
|
||||||
|
|
||||||
if (lpmem == NULL) |
|
||||||
{ |
|
||||||
lpmem = (void *) -1; |
|
||||||
_dosmaperr(GetLastError()); |
|
||||||
} |
|
||||||
|
|
||||||
return lpmem; |
|
||||||
} |
|
||||||
|
|
||||||
/* Control a shared mem area */ |
|
||||||
int |
|
||||||
shmctl(int shmid, int flag, struct shmid_ds * dummy) |
|
||||||
{ |
|
||||||
if (flag == IPC_RMID) |
|
||||||
{ |
|
||||||
/* Delete the area */ |
|
||||||
CloseHandle((HANDLE) shmid); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
if (flag == IPC_STAT) |
|
||||||
{ |
|
||||||
/* Can only test for if exists */ |
|
||||||
int hmap = shmget(shmid, 0, 0); |
|
||||||
|
|
||||||
if (hmap < 0) |
|
||||||
{ |
|
||||||
/* Shared memory does not exist */ |
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
/* Shared memory does exist and must be in use */ |
|
||||||
shmctl(hmap, IPC_RMID, NULL); /* Release our hold on it */ |
|
||||||
errno = 0; |
|
||||||
return 0; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
errno = EINVAL; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
/* Get an area based on the IPC key */ |
|
||||||
int |
|
||||||
shmget(int memKey, int size, int flag) |
|
||||||
{ |
|
||||||
HANDLE hmap; |
|
||||||
char szShareMem[32]; |
|
||||||
DWORD dwRet; |
|
||||||
|
|
||||||
s_segsize = size; |
|
||||||
sprintf(szShareMem, "PostgreSQL.%d", memKey); |
|
||||||
|
|
||||||
if (flag & IPC_CREAT) |
|
||||||
{ |
|
||||||
hmap = CreateFileMapping((HANDLE) 0xFFFFFFFF, /* Use the swap file */ |
|
||||||
NULL, |
|
||||||
PAGE_READWRITE, /* Memory is Read/Write */ |
|
||||||
0L, /* Size Upper 32 Bits */ |
|
||||||
(DWORD) s_segsize, /* Size Lower 32 bits */ |
|
||||||
szShareMem); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
hmap = OpenFileMapping(FILE_MAP_ALL_ACCESS, |
|
||||||
FALSE, |
|
||||||
szShareMem); |
|
||||||
if (!hmap) |
|
||||||
{ |
|
||||||
errno = ENOENT; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
dwRet = GetLastError(); |
|
||||||
if (dwRet == ERROR_ALREADY_EXISTS && hmap && (flag & (IPC_CREAT | IPC_EXCL))) |
|
||||||
{ |
|
||||||
/* Caller wanted to create the segment -- error if already exists */ |
|
||||||
CloseHandle(hmap); |
|
||||||
errno = EEXIST; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
else if (!hmap) |
|
||||||
{ |
|
||||||
/* Unable to get shared memory */ |
|
||||||
_dosmaperr(GetLastError()); |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
return (int) hmap; |
|
||||||
} |
|
@ -0,0 +1,287 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* win32_shmem.c |
||||||
|
* Implement shared memory using win32 facilities |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group |
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/src/backend/port/win32_shmem.c,v 1.1 2007/03/21 14:39:23 mha Exp $ |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
#include "postgres.h" |
||||||
|
|
||||||
|
#include "miscadmin.h" |
||||||
|
#include "storage/ipc.h" |
||||||
|
#include "storage/pg_shmem.h" |
||||||
|
|
||||||
|
unsigned long UsedShmemSegID = 0; |
||||||
|
void *UsedShmemSegAddr = NULL; |
||||||
|
|
||||||
|
static void pgwin32_SharedMemoryDelete(int status, Datum shmId); |
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate shared memory segment name. Expand the data directory, to generate |
||||||
|
* an identifier unique for this data directory. Then replace all backslashes |
||||||
|
* with forward slashes, since backslashes aren't permitted in global object names. |
||||||
|
* |
||||||
|
* Store the shared memory segment in the Global\ namespace (requires NT2 TSE or |
||||||
|
* 2000, but that's all we support for other reasons as well), to make sure you can't |
||||||
|
* open two postmasters in different sessions against the same data directory. |
||||||
|
* |
||||||
|
* XXX: What happens with junctions? It's only someone breaking things on purpose, |
||||||
|
* and this is still better than before, but we might want to do something about |
||||||
|
* that sometime in the future. |
||||||
|
*/ |
||||||
|
static char * |
||||||
|
GetSharedMemName(void) |
||||||
|
{ |
||||||
|
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: %lu", |
||||||
|
DataDir, GetLastError()); |
||||||
|
|
||||||
|
retptr = malloc(bufsize + 1 + 18); /* 1 NULL and 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 + 11, NULL); |
||||||
|
if (r == 0 || r > bufsize) |
||||||
|
elog(FATAL, "could not generate full pathname for datadir %s: %lu", |
||||||
|
DataDir, GetLastError()); |
||||||
|
|
||||||
|
for (cp = retptr; *cp; cp++) |
||||||
|
if (*cp == '\\') |
||||||
|
*cp = '/'; |
||||||
|
|
||||||
|
return retptr; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PGSharedMemoryIsInUse |
||||||
|
* |
||||||
|
* Is a previously-existing shmem segment still existing and in use? |
||||||
|
* |
||||||
|
* The point of this exercise is to detect the case where a prior postmaster |
||||||
|
* crashed, but it left child backends that are still running. Therefore |
||||||
|
* we only care about shmem segments that are associated with the intended |
||||||
|
* DataDir. This is an important consideration since accidental matches of |
||||||
|
* shmem segment IDs are reasonably common. |
||||||
|
* |
||||||
|
*/ |
||||||
|
bool |
||||||
|
PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2) |
||||||
|
{ |
||||||
|
char *szShareMem; |
||||||
|
HANDLE hmap; |
||||||
|
|
||||||
|
szShareMem = GetSharedMemName(); |
||||||
|
|
||||||
|
hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem); |
||||||
|
|
||||||
|
free(szShareMem); |
||||||
|
|
||||||
|
if (hmap == NULL) |
||||||
|
return false; |
||||||
|
|
||||||
|
CloseHandle(hmap); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PGSharedMemoryCreate |
||||||
|
* |
||||||
|
* Create a shared memory segment of the given size and initialize its |
||||||
|
* standard header. |
||||||
|
* |
||||||
|
* makePrivate means to always create a new segment, rather than attach to |
||||||
|
* or recycle any existing segment. On win32, we always create a new segment, |
||||||
|
* since there is no need for recycling (segments go away automatically |
||||||
|
* when the last backend exits) |
||||||
|
* |
||||||
|
*/ |
||||||
|
PGShmemHeader * |
||||||
|
PGSharedMemoryCreate(Size size, bool makePrivate, int port) |
||||||
|
{ |
||||||
|
void *memAddress; |
||||||
|
PGShmemHeader *hdr; |
||||||
|
HANDLE hmap, |
||||||
|
hmap2; |
||||||
|
char *szShareMem; |
||||||
|
|
||||||
|
/* Room for a header? */ |
||||||
|
Assert(size > MAXALIGN(sizeof(PGShmemHeader))); |
||||||
|
|
||||||
|
szShareMem = GetSharedMemName(); |
||||||
|
|
||||||
|
UsedShmemSegAddr = NULL; |
||||||
|
|
||||||
|
hmap = CreateFileMapping((HANDLE) 0xFFFFFFFF, /* Use the pagefile */ |
||||||
|
NULL, /* Default security attrs */ |
||||||
|
PAGE_READWRITE, /* Memory is Read/Write */ |
||||||
|
0L, /* Size Upper 32 Bits */ |
||||||
|
(DWORD) size, /* Size Lower 32 bits */ |
||||||
|
szShareMem); |
||||||
|
|
||||||
|
if (!hmap) |
||||||
|
ereport(FATAL, |
||||||
|
(errmsg("could not create shared memory segment: %lu", GetLastError()), |
||||||
|
errdetail("Failed system call was CreateFileMapping(size=%lu, name=%s)", size, szShareMem))); |
||||||
|
|
||||||
|
/*
|
||||||
|
* If the segment already existed, CreateFileMapping() will return a |
||||||
|
* handle to the existing one. |
||||||
|
*/ |
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS) |
||||||
|
{ |
||||||
|
/*
|
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
CloseHandle(hmap); /* Close the old handle, since we got a valid
|
||||||
|
* one to the previous segment. */ |
||||||
|
|
||||||
|
Sleep(1000); |
||||||
|
|
||||||
|
hmap = CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0L, (DWORD) size, szShareMem); |
||||||
|
if (!hmap) |
||||||
|
ereport(FATAL, |
||||||
|
(errmsg("could not create shared memory segment: %lu", GetLastError()), |
||||||
|
errdetail("Failed system call was CreateFileMapping(size=%lu, name=%s)", size, szShareMem))); |
||||||
|
|
||||||
|
if (GetLastError() == ERROR_ALREADY_EXISTS) |
||||||
|
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: %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: %lu", GetLastError()); |
||||||
|
|
||||||
|
|
||||||
|
/* Register on-exit routine to delete the new segment */ |
||||||
|
on_shmem_exit(pgwin32_SharedMemoryDelete, Int32GetDatum((unsigned long) 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: %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; |
||||||
|
UsedShmemSegID = (unsigned long) hmap2; |
||||||
|
|
||||||
|
return hdr; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* PGSharedMemoryReAttach |
||||||
|
* |
||||||
|
* Re-attach to an already existing shared memory segment. Use the |
||||||
|
* handle inherited from the postmaster. |
||||||
|
* |
||||||
|
* UsedShmemSegID and UsedShmemSegAddr are implicit parameters to this |
||||||
|
* routine. The caller must have already restored them to the postmaster's |
||||||
|
* values. |
||||||
|
*/ |
||||||
|
void |
||||||
|
PGSharedMemoryReAttach(void) |
||||||
|
{ |
||||||
|
PGShmemHeader *hdr; |
||||||
|
void *origUsedShmemSegAddr = UsedShmemSegAddr; |
||||||
|
|
||||||
|
Assert(UsedShmemSegAddr != NULL); |
||||||
|
Assert(IsUnderPostmaster); |
||||||
|
|
||||||
|
hdr = (PGShmemHeader *) MapViewOfFileEx((HANDLE) UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr); |
||||||
|
if (!hdr) |
||||||
|
elog(FATAL, "could not reattach to shared memory (key=%d, addr=%p): %lu", |
||||||
|
(int) 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 */ |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* PGSharedMemoryDetach |
||||||
|
* |
||||||
|
* Detach from the shared memory segment, if still attached. This is not |
||||||
|
* intended for use by the process that originally created the segment. Rather, |
||||||
|
* this is for subprocesses that have inherited an attachment and want to |
||||||
|
* get rid of it. |
||||||
|
*/ |
||||||
|
void |
||||||
|
PGSharedMemoryDetach(void) |
||||||
|
{ |
||||||
|
if (UsedShmemSegAddr != NULL) |
||||||
|
{ |
||||||
|
if (!UnmapViewOfFile(UsedShmemSegAddr)) |
||||||
|
elog(LOG, "could not unmap view of shared memory: %lu", GetLastError()); |
||||||
|
|
||||||
|
UsedShmemSegAddr = NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pgwin32_SharedMemoryDelete(status, shmId) deletes a shared memory segment |
||||||
|
* (called as an on_shmem_exit callback, hence funny argument list) |
||||||
|
*/ |
||||||
|
static void |
||||||
|
pgwin32_SharedMemoryDelete(int status, Datum shmId) |
||||||
|
{ |
||||||
|
PGSharedMemoryDetach(); |
||||||
|
if (!CloseHandle((HANDLE) DatumGetInt32(shmId))) |
||||||
|
elog(LOG, "could not close handle to shared memory: %lu", GetLastError()); |
||||||
|
} |
Loading…
Reference in new issue