summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMagnus Hagander <magnus@hagander.net>2009-08-11 11:51:20 +0000
committerMagnus Hagander <magnus@hagander.net>2009-08-11 11:51:20 +0000
commit0a427ab0722fa7d04cec2216b2afab3d5c09116e (patch)
tree9e380bc571deffca7c7cfc6774b10d01d269464a /src
parent1d6ddebd823f17273e5de8d48b513733a5969644 (diff)
Reserve the shared memory region during backend startup on Windows, so
that memory allocated by starting third party DLLs doesn't end up conflicting with it. Hopefully this solves the long-time issue with "could not reattach to shared memory" errors on Win32. Patch from Tsutomu Yamada and me, based on idea from Trevor Talbot.
Diffstat (limited to 'src')
-rw-r--r--src/backend/port/win32_shmem.c61
-rw-r--r--src/backend/postmaster/postmaster.c23
-rw-r--r--src/include/port/win32.h5
3 files changed, 85 insertions, 4 deletions
diff --git a/src/backend/port/win32_shmem.c b/src/backend/port/win32_shmem.c
index 7c2769655fc..66cbbf78c67 100644
--- a/src/backend/port/win32_shmem.c
+++ b/src/backend/port/win32_shmem.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/port/win32_shmem.c,v 1.4.2.4 2009/05/05 09:48:53 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/port/win32_shmem.c,v 1.4.2.5 2009/08/11 11:51:19 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
unsigned long UsedShmemSegID = 0;
void *UsedShmemSegAddr = NULL;
+static Size UsedShmemSegSize = 0;
static void pgwin32_SharedMemoryDelete(int status, Datum shmId);
@@ -229,6 +230,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
/* Save info for possible future use */
UsedShmemSegAddr = memAddress;
+ UsedShmemSegSize = size;
UsedShmemSegID = (unsigned long) hmap2;
return hdr;
@@ -253,6 +255,13 @@ PGSharedMemoryReAttach(void)
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): %lu",
+ UsedShmemSegAddr, GetLastError());
+
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",
@@ -298,3 +307,53 @@ pgwin32_SharedMemoryDelete(int status, Datum shmId)
if (!CloseHandle((HANDLE) DatumGetInt32(shmId)))
elog(LOG, "could not close handle to shared memory: %lu", GetLastError());
}
+
+/*
+ * 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;
+}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 884b7386292..8c6fb05a257 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.551.2.2 2009/08/07 06:00:09 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.551.2.3 2009/08/11 11:51:20 mha Exp $
*
* NOTES
*
@@ -3448,7 +3448,7 @@ internal_forkexec(int argc, char *argv[], Port *port)
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))
elog(LOG, "could not unmap view of backend parameter file: error code %d",
(int) GetLastError());
@@ -3457,6 +3457,25 @@ internal_forkexec(int argc, char *argv[], Port *port)
(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
* thread so it can start initializing while we set up the rest of the
* parent state.
diff --git a/src/include/port/win32.h b/src/include/port/win32.h
index 54aafa25cc4..f374bd45f0e 100644
--- a/src/include/port/win32.h
+++ b/src/include/port/win32.h
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.83 2008/01/09 09:16:43 mha Exp $ */
+/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.83.2.1 2009/08/11 11:51:20 mha Exp $ */
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define WIN32_ONLY_COMPILER
@@ -286,6 +286,9 @@ extern int pgwin32_is_admin(void);
extern int pgwin32_is_service(void);
#endif
+/* in backend/port/win32_shmem.c */
+extern int pgwin32_ReserveSharedMemoryRegion(HANDLE);
+
/* in port/win32error.c */
extern void _dosmaperr(unsigned long);