mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
Backpatch reservation of shared memory region during backend startup on
Windows, so that memory allocated by starting third party DLLs doesn't end up conflicting. The same functionality has been in 8.3 and 8.4 for almost a year, and seems to have solved some of the more common shared memory errors on Windows.
This commit is contained in:
parent
ae1b65b5aa
commit
90e15467b4
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.47.2.2 2010/05/01 22:46:50 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/port/sysv_shmem.c,v 1.47.2.3 2010/07/23 13:53:29 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -49,6 +49,9 @@ typedef int IpcMemoryId; /* shared memory ID returned by shmget(2) */
|
|||||||
|
|
||||||
unsigned long UsedShmemSegID = 0;
|
unsigned long UsedShmemSegID = 0;
|
||||||
void *UsedShmemSegAddr = NULL;
|
void *UsedShmemSegAddr = NULL;
|
||||||
|
#ifdef WIN32
|
||||||
|
Size UsedShmemSegSize = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size);
|
static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size);
|
||||||
static void IpcMemoryDetach(int status, Datum shmaddr);
|
static void IpcMemoryDetach(int status, Datum shmaddr);
|
||||||
@ -446,6 +449,9 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
|
|||||||
/* Save info for possible future use */
|
/* Save info for possible future use */
|
||||||
UsedShmemSegAddr = memAddress;
|
UsedShmemSegAddr = memAddress;
|
||||||
UsedShmemSegID = (unsigned long) NextShmemSegID;
|
UsedShmemSegID = (unsigned long) NextShmemSegID;
|
||||||
|
#ifdef WIN32
|
||||||
|
UsedShmemSegSize = size;
|
||||||
|
#endif
|
||||||
|
|
||||||
return hdr;
|
return hdr;
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,17 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/port/win32/shmem.c,v 1.13.2.1 2009/05/04 08:36:42 mha Exp $
|
* $PostgreSQL: pgsql/src/backend/port/win32/shmem.c,v 1.13.2.2 2010/07/23 13:53:30 mha Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
|
|
||||||
static DWORD s_segsize = 0;
|
static DWORD s_segsize = 0;
|
||||||
|
extern void *UsedShmemSegAddr;
|
||||||
|
extern Size UsedShmemSegSize;
|
||||||
|
|
||||||
/* Detach from a shared mem area based on its address */
|
/* Detach from a shared mem area based on its address */
|
||||||
int
|
int
|
||||||
@ -29,6 +32,13 @@ shmdt(const void *shmaddr)
|
|||||||
void *
|
void *
|
||||||
shmat(int memId, void *shmaddr, int flag)
|
shmat(int memId, void *shmaddr, int flag)
|
||||||
{
|
{
|
||||||
|
/* Release the memory region reserved in the postmaster */
|
||||||
|
if (IsUnderPostmaster)
|
||||||
|
{
|
||||||
|
if (VirtualFree(shmaddr, 0, MEM_RELEASE) == 0)
|
||||||
|
elog(FATAL, "failed to release reserved memory region (addr=%p): %lu",
|
||||||
|
shmaddr, GetLastError());
|
||||||
|
}
|
||||||
/* TODO -- shmat needs to count # attached to shared mem */
|
/* TODO -- shmat needs to count # attached to shared mem */
|
||||||
void *lpmem = MapViewOfFileEx((HANDLE) memId,
|
void *lpmem = MapViewOfFileEx((HANDLE) memId,
|
||||||
FILE_MAP_WRITE | FILE_MAP_READ,
|
FILE_MAP_WRITE | FILE_MAP_READ,
|
||||||
@ -128,3 +138,53 @@ shmget(int memKey, int size, int flag)
|
|||||||
|
|
||||||
return (int) hmap;
|
return (int) hmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pgwin32_ReserveSharedMemoryRegion(hChild)
|
||||||
|
*
|
||||||
|
* Reserve the memory region that will be used for shared memory in a child
|
||||||
|
* process. It is called before the child process starts, to make sure the
|
||||||
|
* memory is available.
|
||||||
|
*
|
||||||
|
* Once the child starts, DLLs loading in different order or threads getting
|
||||||
|
* scheduled differently may allocate memory which can conflict with the
|
||||||
|
* address space we need for our shared memory. By reserving the shared
|
||||||
|
* memory region before the child starts, and freeing it only just before we
|
||||||
|
* attempt to get access to the shared memory forces these allocations to
|
||||||
|
* be given different address ranges that don't conflict.
|
||||||
|
*
|
||||||
|
* NOTE! This function executes in the postmaster, and should for this
|
||||||
|
* reason not use elog(FATAL) since that would take down the postmaster.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pgwin32_ReserveSharedMemoryRegion(HANDLE hChild)
|
||||||
|
{
|
||||||
|
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 %lu: %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;
|
||||||
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.505.2.8 2010/04/01 20:12:42 heikki Exp $
|
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.505.2.9 2010/07/23 13:53:30 mha Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
*
|
*
|
||||||
@ -3186,7 +3186,7 @@ internal_forkexec(int argc, char *argv[], Port *port)
|
|||||||
return -1; /* log made by save_backend_variables */
|
return -1; /* log made by save_backend_variables */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop the shared memory that is now inherited to the backend */
|
/* Drop the parameter shared memory that is now inherited to the backend */
|
||||||
if (!UnmapViewOfFile(param))
|
if (!UnmapViewOfFile(param))
|
||||||
elog(LOG, "could not unmap view of backend parameter file: error code %d",
|
elog(LOG, "could not unmap view of backend parameter file: error code %d",
|
||||||
(int) GetLastError());
|
(int) GetLastError());
|
||||||
@ -3194,6 +3194,25 @@ internal_forkexec(int argc, char *argv[], Port *port)
|
|||||||
elog(LOG, "could not close handle to backend parameter file: error code %d",
|
elog(LOG, "could not close handle to backend parameter file: error code %d",
|
||||||
(int) GetLastError());
|
(int) GetLastError());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserve the memory region used by our main shared memory segment before we
|
||||||
|
* resume the child process.
|
||||||
|
*/
|
||||||
|
if (!pgwin32_ReserveSharedMemoryRegion(pi.hProcess))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Failed to reserve the memory, so terminate the newly created
|
||||||
|
* process and give up.
|
||||||
|
*/
|
||||||
|
if (!TerminateProcess(pi.hProcess, 255))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg_internal("could not terminate process that failed to reserve memory: error code %d",
|
||||||
|
(int) GetLastError())));
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
return -1; /* logging done made by pgwin32_ReserveSharedMemoryRegion() */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that the backend variables are written out, we start the child
|
* Now that the backend variables are written out, we start the child
|
||||||
* thread so it can start initializing while we set up the rest of the
|
* thread so it can start initializing while we set up the rest of the
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.63.2.3 2007/11/29 16:44:26 mha Exp $ */
|
/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.63.2.4 2010/07/23 13:53:30 mha Exp $ */
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||||
#define WIN32_ONLY_COMPILER
|
#define WIN32_ONLY_COMPILER
|
||||||
@ -263,6 +263,9 @@ extern int pgwin32_is_admin(void);
|
|||||||
extern int pgwin32_is_service(void);
|
extern int pgwin32_is_service(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* in backend/port/win32/shmem.c */
|
||||||
|
extern int pgwin32_ReserveSharedMemoryRegion(HANDLE);
|
||||||
|
|
||||||
/* in port/win32error.c */
|
/* in port/win32error.c */
|
||||||
extern void _dosmaperr(unsigned long);
|
extern void _dosmaperr(unsigned long);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user