Skip to content
Snippets Groups Projects
Commit 18d82d03 authored by Magnus Hagander's avatar Magnus Hagander
Browse files

Native shared memory implementation for win32.

Uses same underlying tech as before, but not the sysv emulation layer.
parent 3b765dba
No related branches found
No related tags found
No related merge requests found
......@@ -22278,13 +22278,21 @@ fi
 
 
# Select shared-memory implementation type.
if test "$PORTNAME" != "win32"; then
 
cat >>confdefs.h <<\_ACEOF
#define USE_SYSV_SHARED_MEMORY 1
_ACEOF
 
SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
else
cat >>confdefs.h <<\_ACEOF
#define USE_WIN32_SHARED_MEMORY 1
_ACEOF
 
SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
fi
 
# If not set in template file, set bytes to use libc memset()
if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
......
dnl Process this file with autoconf to produce a configure script.
dnl $PostgreSQL: pgsql/configure.in,v 1.502 2007/02/21 15:12:39 momjian Exp $
dnl $PostgreSQL: pgsql/configure.in,v 1.503 2007/03/21 14:39:23 mha Exp $
dnl
dnl Developers, please strive to achieve this order:
dnl
......@@ -1367,9 +1367,13 @@ fi
# Select shared-memory implementation type.
AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.])
SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
if test "$PORTNAME" != "win32"; then
AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.])
SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
else
AC_DEFINE(USE_WIN32_SHARED_MEMORY, 1, [Define to select Win32-style shared memory.])
SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
fi
# If not set in template file, set bytes to use libc memset()
if test x"$MEMSET_LOOP_LIMIT" = x"" ; then
......
......@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.49 2007/02/06 16:20:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.50 2007/03/21 14:39:23 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -195,11 +195,8 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
{
IpcMemoryId shmId = (IpcMemoryId) id2;
struct shmid_ds shmStat;
#ifndef WIN32
struct stat statbuf;
PGShmemHeader *hdr;
#endif
/*
* We detect whether a shared memory segment is in use by seeing whether
......@@ -238,11 +235,8 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
/*
* Try to attach to the segment and see if it matches our data directory.
* This avoids shmid-conflict problems on machines that are running
* several postmasters under the same userid. On Windows, which doesn't
* have useful inode numbers, we can't do this so we punt and assume there
* is a conflict.
* several postmasters under the same userid.
*/
#ifndef WIN32
if (stat(DataDir, &statbuf) < 0)
return true; /* if can't stat, be conservative */
......@@ -265,7 +259,6 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
/* Trouble --- looks a lot like there's still live backends */
shmdt((void *) hdr);
#endif
return true;
}
......@@ -296,10 +289,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
void *memAddress;
PGShmemHeader *hdr;
IpcMemoryId shmid;
#ifndef WIN32
struct stat statbuf;
#endif
/* Room for a header? */
Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
......@@ -372,7 +362,6 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
hdr->creatorPID = getpid();
hdr->magic = PGShmemMagic;
#ifndef WIN32
/* Fill in the data directory ID info, too */
if (stat(DataDir, &statbuf) < 0)
ereport(FATAL,
......@@ -381,7 +370,6 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
DataDir)));
hdr->device = statbuf.st_dev;
hdr->inode = statbuf.st_ino;
#endif
/*
* Initialize space allocation status for segment.
......
......@@ -4,7 +4,7 @@
# Makefile for backend/port/win32
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/port/win32/Makefile,v 1.9 2007/01/20 17:16:12 petere Exp $
# $PostgreSQL: pgsql/src/backend/port/win32/Makefile,v 1.10 2007/03/21 14:39:23 mha Exp $
#
#-------------------------------------------------------------------------
......@@ -12,7 +12,7 @@ subdir = src/backend/port/win32
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = shmem.o timer.o socket.o signal.o security.o
OBJS = timer.o socket.o signal.o security.o
all: SUBSYS.o
......
/*-------------------------------------------------------------------------
*
* 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;
}
/*-------------------------------------------------------------------------
*
* 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());
}
......@@ -2,7 +2,7 @@ package Mkvcbuild;
#
# Package that generates build files for msvc build
#
# $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.3 2007/03/19 09:34:09 mha Exp $
# $PostgreSQL: pgsql/src/tools/msvc/Mkvcbuild.pm,v 1.4 2007/03/21 14:39:23 mha Exp $
#
use Carp;
use Win32;
......@@ -58,7 +58,7 @@ sub mkvcbuild
$postgres->AddFile('src\backend\utils\fmgrtab.c');
$postgres->ReplaceFile('src\backend\port\dynloader.c','src\backend\port\dynloader\win32.c');
$postgres->ReplaceFile('src\backend\port\pg_sema.c','src\backend\port\win32_sema.c');
$postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\sysv_shmem.c');
$postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\win32_shmem.c');
$postgres->AddFiles('src\port',@pgportfiles);
$postgres->AddDir('src\timezone');
$postgres->AddFiles('src\backend\parser','scan.l','gram.y');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment