On 09/02/2010 4:09 PM, Etienne Dube wrote:
Magnus Hagander wrote:
IIRC, we've had zero reports on whether the patch worked at all on 8.2
in an environment where the problem actually existed. So yes, some
testing and feedback would be much apprecaited.

//Magnus

Thanks for your quick reply.
We upgraded to Service Pack 2 and it solved the problem. Nevertheless, I'll try to reproduce the issue under a Win2008 SP1 VM to see whether the patch makes a difference. 8.2.x win32 binaries are built using MinGW right?

Etienne




The "could not reattach to shared memory" bug came back to bite us, this time on a production machine running Windows Server 2008 R2 x64. I manually applied the patch against the 8.2.17 sources and installed the build on a test server. It has been running for two days without any issue. We'll see after a while if the patch actually fixes the problem (it seems to happen only after the postgres service has been up and running for some time) but in case you want to include this fix in a future 8.2.18 release, I've attached the new patch to apply against the REL8_2_STABLE branch.

Etienne

Index: backend/port/sysv_shmem.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/port/sysv_shmem.c,v
retrieving revision 1.47.2.2
diff -u -r1.47.2.2 sysv_shmem.c
--- backend/port/sysv_shmem.c   1 May 2010 22:46:50 -0000       1.47.2.2
+++ backend/port/sysv_shmem.c   17 Jul 2010 19:19:51 -0000
@@ -49,6 +49,10 @@
 
 unsigned long UsedShmemSegID = 0;
 void      *UsedShmemSegAddr = NULL;
+#ifdef WIN32
+Size           UsedShmemSegSize = 0;
+#endif
+
 
 static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size);
 static void IpcMemoryDetach(int status, Datum shmaddr);
@@ -445,6 +449,7 @@
 
        /* Save info for possible future use */
        UsedShmemSegAddr = memAddress;
+       UsedShmemSegSize = size;
        UsedShmemSegID = (unsigned long) NextShmemSegID;
 
        return hdr;
Index: backend/port/win32/shmem.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/port/win32/Attic/shmem.c,v
retrieving revision 1.13.2.1
diff -u -r1.13.2.1 shmem.c
--- backend/port/win32/shmem.c  4 May 2009 08:36:42 -0000       1.13.2.1
+++ backend/port/win32/shmem.c  17 Jul 2010 19:22:13 -0000
@@ -12,8 +12,11 @@
  */
 
 #include "postgres.h"
+#include "miscadmin.h"
 
 static DWORD s_segsize = 0;
+extern void *UsedShmemSegAddr;
+extern Size UsedShmemSegSize;
 
 /* Detach from a shared mem area based on its address */
 int
@@ -29,6 +32,13 @@
 void *
 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 */
        void       *lpmem = MapViewOfFileEx((HANDLE) memId,
                                                                                
FILE_MAP_WRITE | FILE_MAP_READ,
@@ -128,3 +138,53 @@
 
        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;
+}
Index: backend/postmaster/postmaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.505.2.8
diff -u -r1.505.2.8 postmaster.c
--- backend/postmaster/postmaster.c     1 Apr 2010 20:12:42 -0000       
1.505.2.8
+++ backend/postmaster/postmaster.c     17 Jul 2010 19:24:43 -0000
@@ -3186,7 +3186,7 @@
                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());
@@ -3195,6 +3195,25 @@
                         (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.
Index: include/port/win32.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/port/win32.h,v
retrieving revision 1.63.2.3
diff -u -r1.63.2.3 win32.h
--- include/port/win32.h        29 Nov 2007 16:44:26 -0000      1.63.2.3
+++ include/port/win32.h        17 Jul 2010 19:26:18 -0000
@@ -263,6 +263,9 @@
 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);
 

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to