1--- postgresql-9.0.5/configure	2011-09-22 15:00:48.000000000 -0700
2+++ postgresql/configure	2011-10-18 22:58:26.000000000 -0700
3@@ -27775,12 +27775,21 @@
4
5 # Select shared-memory implementation type.
6 if test "$PORTNAME" != "win32"; then
7+  if test x"$USE_POSIX_SHARED_MEMORY" = x"1" ; then
8+
9+cat >>confdefs.h <<\_ACEOF
10+#define USE_POSIX_SHARED_MEMORY 1
11+_ACEOF
12+
13+    SHMEM_IMPLEMENTATION="src/backend/port/posix_shmem.c"
14+  else
15
16 cat >>confdefs.h <<\_ACEOF
17 #define USE_SYSV_SHARED_MEMORY 1
18 _ACEOF
19
20-  SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
21+    SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
22+  fi
23 else
24
25 cat >>confdefs.h <<\_ACEOF
26--- postgresql-9.0.5/configure.in	2011-09-22 15:00:48.000000000 -0700
27+++ postgresql/configure.in	2011-10-18 22:59:19.000000000 -0700
28@@ -1700,8 +1700,13 @@
29 
30 # Select shared-memory implementation type.
31 if test "$PORTNAME" != "win32"; then
32-  AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.])
33-  SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
34+  if test x"$USE_POSIX_SHARED_MEMORY" = x"1" ; then
35+    AC_DEFINE(USE_POSIX_SHARED_MEMORY, 1, [Define to select POSIX-style shared memory.])
36+    SHMEM_IMPLEMENTATION="src/backend/port/posix_shmem.c"
37+  else
38+    AC_DEFINE(USE_SYSV_SHARED_MEMORY, 1, [Define to select SysV-style shared memory.])
39+    SHMEM_IMPLEMENTATION="src/backend/port/sysv_shmem.c"
40+  fi
41 else
42   AC_DEFINE(USE_WIN32_SHARED_MEMORY, 1, [Define to select Win32-style shared memory.])
43   SHMEM_IMPLEMENTATION="src/backend/port/win32_shmem.c"
44diff -Naur postgresql-9.0.1/src/include/pg_config.in postgresql/src/include/pg_config.in
45--- postgresql-9.0.1/src/include/pg_config.h.in	2010-10-01 07:25:44.000000000 -0700
46+++ postgresql/src/include/pg_config.h.in	2010-12-14 18:59:28.000000000 -0800
47@@ -779,6 +779,9 @@
48 /* Define to 1 to build with PAM support. (--with-pam) */
49 #undef USE_PAM
50 
51+/* Define to select POSIX-style shared memory. */
52+#undef USE_POSIX_SHARED_MEMORY
53+
54 /* Use replacement snprintf() functions. */
55 #undef USE_REPL_SNPRINTF
56 
57diff -Naur postgresql-9.0.1/src/template/darwin postgresql/src/template/darwin
58--- postgresql-9.0.1/src/template/darwin	2010-10-01 07:25:44.000000000 -0700
59+++ postgresql/src/template/darwin	2010-12-14 12:36:07.000000000 -0800
60@@ -12,3 +12,5 @@
61     USE_SYSV_SEMAPHORES=1
62     ;;
63 esac
64+
65+USE_POSIX_SHARED_MEMORY=1
66diff -Naur postgresql-9.0.1/src/backend/port/posix_shmem.c postgresql/src/backend/port/posix_shmem.c
67--- postgresql-9.0.1/src/backend/port/posix_shmem.c.orig	1969-12-31 18:00:00.000000000 -0600
68+++ postgresql/src/backend/port/posix_shmem.c	2010-10-05 21:57:01.000000000 -0500
69@@ -0,0 +1,578 @@
70+/*-------------------------------------------------------------------------
71+ *
72+ * posix_shmem.c
73+ *	  Implement shared memory using POSIX facilities
74+ *
75+ * These routines represent a fairly thin layer on top of POSIX shared
76+ * memory functionality. This also requires a single very small SysV segment
77+ * to ensure that oprhaned backends are not still alive in the database after
78+ * a restart, for example after a crash or kill -9 of the postmaster.
79+ *
80+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
81+ * Portions Copyright (c) 1994, Regents of the University of California
82+ * Portions Copyright (c) 2007, Apple Inc.
83+ *
84+ * Permission to use, copy, modify, and distribute this software and its
85+ * documentation for any purpose, without fee, and without a written agreement
86+ * is hereby granted, provided that the above copyright notice and this
87+ * paragraph and the following two paragraphs appear in all copies.
88+ *
89+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA OR APPLE INC. BE LIABLE TO
90+ * ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
91+ * DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
92+ * AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA OR APPLE INC.
93+ * HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
94+ *
95+ * THE UNIVERSITY OF CALIFORNIA AND APPLE INC. SPECIFICALLY DISCLAIM ANY
96+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
97+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED
98+ * HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA OR
99+ * APPLE INC. HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
100+ * ENHANCEMENTS, OR MODIFICATIONS.
101+ *
102+ *-------------------------------------------------------------------------
103+ */
104+
105+#include "postgres.h"
106+
107+#include <signal.h>
108+#include <stdlib.h>
109+#include <unistd.h>
110+#include <sys/file.h>
111+#include <sys/mman.h>
112+#include <sys/param.h>
113+#include <sys/stat.h>
114+#include <sys/types.h>
115+#ifdef HAVE_SYS_IPC_H
116+#include <sys/ipc.h>
117+#endif
118+#ifdef HAVE_SYS_SHM_H
119+#include <sys/shm.h>
120+#endif
121+#ifdef HAVE_KERNEL_OS_H
122+#include <kernel/OS.h>
123+#endif
124+
125+#include "miscadmin.h"
126+#include "storage/ipc.h"
127+#include "storage/pg_shmem.h"
128+
129+
130+#define IPCProtection			(0600)	/* access/modify by user only */
131+#define SYSV_SEGMENT_SIZE		1
132+
133+#ifdef SHM_SHARE_MMU			/* use intimate shared memory on Solaris */
134+#define PG_SHMAT_FLAGS			SHM_SHARE_MMU
135+#else
136+#define PG_SHMAT_FLAGS			0
137+#endif
138+
139+void		   *UsedShmemSegAddr = NULL;
140+unsigned long	UsedShmemSegID = 0;		/* Used for the SysV DB integrity 'mutex' segment */
141+static void	   *usedSysVSegAddr = NULL;	/* Used for the SysV DB integrity 'mutex' segment, 
142+										 * not passed to exec'd backends */
143+
144+static const char *GenerateIPCName();
145+static void *InternalIpcMemoryCreate(Size size);
146+static void IpcMemoryDetach(int status, Datum shmaddr);
147+static void IpcMemoryDelete(int status, Datum notUsed);
148+static void SysVNattachSegMemoryDetach(int status, Datum shmaddr);
149+static void SysVNattachSegMemoryDelete(int status, Datum shmId);
150+#ifdef EXEC_BACKEND
151+static PGShmemHeader *PGSharedMemoryAttach(void);
152+#endif
153+
154+static int shm_open_robust(const char *name, int flags, mode_t mode);
155+static int close_robust(int d);
156+
157+/*
158+ *	GenerateIPCName()
159+ *
160+ * Returns a shared memory object key name using the implicit argument
161+ * DataDir, the data directory's pathname via its device and inode values.
162+ */
163+static const char*
164+GenerateIPCName()
165+{
166+	struct		stat statbuf;
167+
168+	static char	ipcName[100];
169+	static bool	initialized = false;
170+	
171+	if (!initialized)
172+	{
173+		/* Get the data directory's device and inode */
174+		if (stat(DataDir, &statbuf) < 0)
175+			ereport(FATAL,
176+					(errcode_for_file_access(),
177+					 errmsg("could not stat data directory \"%s\": %m",
178+							DataDir)));
179+		
180+		/*
181+		 * POSIX requires that shared memory names begin with a single slash.  
182+		 * They should not have any others slashes or any non-alphanumerics to 
183+		 * maintain the broadest assumption of what is permitted in a filename.
184+		 * Also, case sensitivity should not be presumed.
185+		 */
186+		snprintf(ipcName, sizeof(ipcName), "/PostgreSQL.%jx.%jx",
187+				 (intmax_t) statbuf.st_dev, (intmax_t) statbuf.st_ino);
188+		
189+		initialized = true;
190+	}
191+	
192+	return ipcName;
193+}
194+
195+/*
196+ *	InternalIpcMemoryCreate(size)
197+ *
198+ * Create a new shared memory segment.
199+ * Attaches the segment to the current process and return its attached
200+ * address. Callbacks are registered with on_shmem_exit to detach and
201+ * delete the segment when on_shmem_exit is called.
202+ *
203+ * If we fail for any reason print out an error and abort.
204+ */
205+static void *
206+InternalIpcMemoryCreate(Size size)
207+{
208+	int			fd, sysVNattachSegShmid;
209+	void	   *shmaddr, *sysVNattachSegMemAddr;
210+	const char *ipcName = GenerateIPCName();
211+	
212+	/* Create a small SysV shared memory segment to use to prevent
213+	 * new postmasters from starting up when there are still
214+	 * backends in the database. */
215+	sysVNattachSegShmid = shmget(IPC_PRIVATE, SYSV_SEGMENT_SIZE, IPCProtection);
216+	if (sysVNattachSegShmid < 0)
217+	{
218+		ereport(FATAL,
219+				(errmsg("could not create shared memory segment: %m"),
220+				 errdetail("Failed system call was shmget(key=IPC_PRIVATE, size=%i, 0%o).",
221+						   IPCProtection, SYSV_SEGMENT_SIZE),
222+				 (errno == EINVAL) ?
223+				 errhint("This error usually means that PostgreSQL's request for a shared memory "
224+						 "segment of %i byte(s) exceeded your kernel's SHMMAX parameter. It is also possible "
225+						 "that it is less than your kernel's SHMMIN parameter, in which case "
226+						 "reconfiguring SHMMIN is called for.\n"
227+						 "The PostgreSQL documentation contains more information about shared "
228+						 "memory configuration.", SYSV_SEGMENT_SIZE) : 0,
229+				 (errno == ENOSPC) ?
230+				 errhint("This error does *not* mean that you have run out of disk space. "
231+						 "It occurs either if all available shared memory IDs have been taken, "
232+						 "in which case you need to raise the SHMMNI parameter in your kernel, "
233+						 "or because the system's overall limit for shared memory has been "
234+						 "reached.\n"
235+						 "The PostgreSQL documentation contains more information about shared "
236+						 "memory configuration.") : 0));
237+	}
238+	
239+	/* Register on-exit routine to delete the SysV segment */
240+	on_shmem_exit(SysVNattachSegMemoryDelete, Int32GetDatum(sysVNattachSegShmid));
241+	
242+	/* Attach to the SysV segment */
243+	sysVNattachSegMemAddr = shmat(sysVNattachSegShmid, NULL, PG_SHMAT_FLAGS);
244+	if (sysVNattachSegMemAddr == (void *) -1)
245+		elog(FATAL, "shmat(id=%d) failed: %m", sysVNattachSegShmid);
246+	
247+	/* Register on-exit routine to detach the SysV segment before deleting */
248+	on_shmem_exit(SysVNattachSegMemoryDetach, PointerGetDatum(sysVNattachSegMemAddr));
249+
250+	/* Create new POSIX shared memory segment. We need to unlink any existing 
251+	 * segment since ftruncate is unable to resize an existing segment on
252+	 * some platforms. 
253+	 */
254+	shm_unlink(ipcName);
255+	fd = shm_open_robust(ipcName, O_RDWR | O_CREAT | O_EXCL, IPCProtection);
256+
257+	if (fd < 0)
258+	{
259+		/* Complain and abort */
260+		ereport(FATAL,
261+				(errmsg("could not create shared memory segment: %m"),
262+				 errdetail("Failed system call was shm_open(name=%s, oflag=%lu, mode=%lu).",
263+						   GenerateIPCName(), (unsigned long) O_CREAT | O_EXCL,
264+						   (unsigned long) IPCProtection),
265+				 (errno == EEXIST || errno == EACCES) ?
266+				 errhint("This error means that the shared memory segment for "
267+						 "this data directory is still in use. Is another "
268+						 "postgres running in data directory \"%s\"?", DataDir) : 0,
269+				 (errno == EMFILE) ?
270+				 errhint("This error means that the process has reached its limit "
271+						 "for open file descriptors.") : 0,
272+				 (errno == ENOSPC) ?
273+				 errhint("This error means the process has ran out of address "
274+						 "space.") : 0,
275+				 (errno == ENAMETOOLONG) ?
276+				 errhint("This error means that the shared memory segment name "
277+						 "is too long.") : 0));
278+	}
279+	
280+	/* Register on-exit routine to delete the POSIX segment */
281+	on_shmem_exit(IpcMemoryDelete, 0);
282+	
283+#define OOM_ERROR_HINT errhint("This error usually means that PostgreSQL's request for a shared " \
284+							   "memory segment exceeded available memory or swap space. " \
285+							   "To reduce the request size (currently %lu bytes), reduce " \
286+							   "PostgreSQL's shared_buffers parameter (currently %d) and/or " \
287+							   "its max_connections parameter (currently %d).\n" \
288+							   "The PostgreSQL documentation contains more information about shared " \
289+							   "memory configuration.", \
290+							   (unsigned long) size, NBuffers, MaxBackends)
291+	
292+	/* Increase the size of the file descriptor to the desired length */
293+	if (ftruncate(fd, size) == -1)
294+	{
295+		/* Complain and abort */
296+		ereport(FATAL,
297+				(errmsg("could not set length of shared memory segment: %m"),
298+				 errdetail("Failed system call was ftruncate(fd=%d, size=%lu).",
299+						   fd, (unsigned long) size),
300+				 OOM_ERROR_HINT));
301+	}
302+	
303+	/* OK, should be able to attach to the segment */
304+	shmaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
305+	
306+	/* Close the file descriptor since we don't need it anymore. */
307+	close_robust(fd);
308+
309+	if (shmaddr == (void *) -1)
310+	{
311+		/* Complain and abort */
312+		ereport(FATAL,
313+				(errmsg("could not set length of shared memory segment: %m"),
314+				 errdetail("Failed system call was mmap with size=%lu and fd=%d: %m",
315+						   (unsigned long) size, fd),
316+				 OOM_ERROR_HINT));
317+	}
318+
319+	/* Register on-exit routine to detach new segment before deleting */
320+	on_shmem_exit(IpcMemoryDetach, PointerGetDatum(shmaddr));
321+
322+	/* Record SysV shmid in lockfile for data directory so contending postmasters
323+	 * can detect whether any orpahned backends are still in the database. 
324+	 */
325+	RecordSharedMemoryInLockFile(0, sysVNattachSegShmid);
326+
327+	/* Save address for possible future use */
328+	UsedShmemSegAddr = shmaddr;
329+	UsedShmemSegID = (unsigned long) sysVNattachSegMemAddr;
330+	usedSysVSegAddr = sysVNattachSegMemAddr;
331+	
332+	return shmaddr;
333+}
334+
335+/****************************************************************************/
336+/*	IpcMemoryDetach(status, shmaddr)	removes a shared memory segment		*/
337+/*										from process' address space			*/
338+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
339+/****************************************************************************/
340+static void
341+IpcMemoryDetach(int status, Datum shmaddr)
342+{
343+	PGShmemHeader  *hdr;
344+	hdr = (PGShmemHeader *) DatumGetPointer(shmaddr);
345+	
346+	if (munmap(DatumGetPointer(shmaddr), hdr->totalsize) < 0)
347+		elog(LOG, "munmap(%p) failed: %m", DatumGetPointer(shmaddr));
348+}
349+
350+/****************************************************************************/
351+/*	IpcMemoryDelete(status, notUsed)		deletes a shared memory segment	*/
352+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
353+/****************************************************************************/
354+static void
355+IpcMemoryDelete(int status, Datum notUsed)
356+{
357+	const char *ipcName = GenerateIPCName();
358+	
359+	if (shm_unlink(ipcName) < 0)
360+		elog(LOG, "shm_unlink(%s) failed: %m", ipcName);
361+}
362+
363+/****************************************************************************/
364+/*	SysVNattachSegMemoryDetach(status, shmaddr)	removes a shared memory		*/
365+/*										segment from process' address space	*/
366+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
367+/****************************************************************************/
368+static void
369+SysVNattachSegMemoryDetach(int status, Datum shmaddr)
370+{
371+	if (shmdt(DatumGetPointer(shmaddr)) < 0)
372+		elog(LOG, "shmdt(%p) failed: %m", DatumGetPointer(shmaddr));
373+}
374+
375+/****************************************************************************/
376+/*	SysVNattachSegMemoryDelete(status, shmId)	deletes a shared memory seg.*/
377+/*	(called as an on_shmem_exit callback, hence funny argument list)		*/
378+/****************************************************************************/
379+static void
380+SysVNattachSegMemoryDelete(int status, Datum shmId)
381+{
382+	if (shmctl(DatumGetInt32(shmId), IPC_RMID, NULL) < 0)
383+		elog(LOG, "shmctl(%d, %d, 0) failed: %m",
384+			 DatumGetInt32(shmId), IPC_RMID);
385+}
386+
387+/*
388+ * PGSharedMemoryIsInUse
389+ *
390+ * Is a previously-existing shmem segment still existing and in use?
391+ *
392+ * The point of this exercise is to detect the case where a prior postmaster
393+ * crashed, but it left child backends that are still running.	This only tests
394+ * for shmem segments that are associated with the intended DataDir using the
395+ * SysV segment that was created only for this purpose.
396+ */
397+bool
398+PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
399+{
400+	int shmId = (int) id2;
401+	struct shmid_ds shmStat;
402+	
403+	/*
404+	 * We detect whether a shared memory segment is in use by seeing whether
405+	 * it (a) exists and (b) has any processes are attached to it.
406+	 */
407+	if (shmctl(shmId, IPC_STAT, &shmStat) < 0)
408+	{
409+		/*
410+		 * EINVAL actually has multiple possible causes documented in the
411+		 * shmctl man page, but we assume it must mean the segment no longer
412+		 * exists.
413+		 */
414+		if (errno == EINVAL)
415+			return false;
416+		
417+		/*
418+		 * EACCES implies that the segment belongs to some other userid, which
419+		 * means it is not a Postgres shmem segment (or at least, not one that
420+		 * is relevant to our data directory).
421+		 */
422+		if (errno == EACCES)
423+			return false;
424+		
425+		/*
426+		 * Otherwise, we had better assume that the segment is in use. The
427+		 * only likely case is EIDRM, which implies that the segment has been
428+		 * IPC_RMID'd but there are still processes attached to it.
429+		 */
430+		return true;
431+	}
432+	
433+	/* If it has attached processes, it's in use */
434+	if (shmStat.shm_nattch > 0)
435+		return true;
436+	
437+	/* Otherwise, it is not in use, so free the shmid. (This means that the
438+	 * postmaster must have crashed or been kill -9'd and didn't free it itself.) */
439+	if (shmctl(shmId, IPC_RMID, NULL) < 0)
440+		elog(LOG, "shmctl(%d, %d, 0) failed: %m", shmId, IPC_RMID);
441+	return false;
442+}
443+
444+
445+/*
446+ * PGSharedMemoryCreate
447+ *
448+ * Create a shared memory segment of the given size and initialize its
449+ * standard header.  Also, register an on_shmem_exit callback to release
450+ * the storage.
451+ *
452+ * Dead Postgres segments are released when found, and due to using the inode/device
453+ * combination in the shmem key name, collision with non-Postgres shmem segments is
454+ * effectively impossible. 
455+ *
456+ * makePrivate means to always create a new segment, rather than attach to
457+ * or recycle any existing segment. Currently, this value is ignored as
458+ * all segments are newly created (the dead ones are simply freed either
459+ * immediately or when the orphan backends die). Port is similarly ignored, as
460+ * this POSIX layer bases its shmem segment names only on the inode/device values.
461+ */
462+PGShmemHeader *
463+PGSharedMemoryCreate(Size size, bool makePrivate, int port)
464+{
465+	void		   *shmaddr;
466+	PGShmemHeader  *hdr;
467+	struct stat		statbuf;
468+
469+	/* Room for a header? */
470+	Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
471+	
472+	/* Create the new segment */
473+	shmaddr = InternalIpcMemoryCreate(size);
474+	
475+	/* OK, we created a new segment.  Mark it as created by this process. */
476+	hdr = (PGShmemHeader *) shmaddr;
477+	hdr->creatorPID = getpid();
478+	hdr->magic = PGShmemMagic;
479+
480+	/* Fill in the data directory ID info, too */
481+	if (stat(DataDir, &statbuf) < 0)
482+		ereport(FATAL,
483+				(errcode_for_file_access(),
484+				 errmsg("could not stat data directory \"%s\": %m",
485+						DataDir)));
486+	hdr->device = statbuf.st_dev;
487+	hdr->inode = statbuf.st_ino;
488+
489+	/* Initialize space allocation status for segment. */
490+	hdr->totalsize = size;
491+	hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
492+
493+	return hdr;
494+}
495+
496+#ifdef EXEC_BACKEND
497+
498+/*
499+ * PGSharedMemoryReAttach
500+ *
501+ * Re-attach to an already existing shared memory segment.	In the non
502+ * EXEC_BACKEND case this is not used, because postmaster children inherit
503+ * the shared memory segment attachment via fork().
504+ *
505+ * UsedShmemSegAddr and UsedShmemSegAdd are implicit parameters to this
506+ * routine.  The caller must have already restored them to the postmaster's
507+ * values.
508+ */
509+void
510+PGSharedMemoryReAttach(void)
511+{
512+	void   *hdr;
513+	void   *origUsedShmemSegAddr = UsedShmemSegAddr;
514+
515+	Assert(UsedShmemSegAddr != NULL);
516+	Assert(UsedShmemSegID != NULL);
517+	Assert(IsUnderPostmaster);
518+
519+#ifdef __CYGWIN__
520+	/* cygipc (currently) appears to not detach on exec. */
521+	PGSharedMemoryDetach();
522+	UsedShmemSegAddr = origUsedShmemSegAddr;
523+#endif
524+
525+	elog(DEBUG3, "attaching to %p", UsedShmemSegAddr);
526+	hdr = (void *) PGSharedMemoryAttach();
527+	if (hdr == NULL)
528+		elog(FATAL, "could not reattach to shared memory (addr=%p): %m",
529+			 UsedShmemSegAddr);
530+	if (hdr != origUsedShmemSegAddr)
531+		elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
532+			 hdr, origUsedShmemSegAddr);
533+
534+	UsedShmemSegAddr = hdr;		/* probably redundant */
535+}
536+
537+/*
538+ * PGSharedMemoryAttach
539+ *
540+ * Attach to shared memory and make sure it has a Postgres header
541+ *
542+ * Returns attach address if OK, else NULL
543+ */
544+static PGShmemHeader *
545+PGSharedMemoryAttach(void)
546+{
547+	PGShmemHeader *hdr;
548+	Size		size;
549+	int			fd;
550+	
551+	/* Attach to the token SysV segment */
552+	if (shmat(UsedShmemSegID, NULL, PG_SHMAT_FLAGS) == (void *) -1)
553+		return NULL;
554+	
555+	/* Attach to the POSIX shared memory segment */
556+	if ((fd = shm_open_robust(GenerateIPCName(), O_RDWR, 0)) < 0)
557+		return NULL;
558+	
559+	hdr = (PGShmemHeader *) mmap(UsedShmemSegAddr, sizeof(PGShmemHeader),
560+								 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
561+	
562+	if (hdr == (PGShmemHeader *) -1)
563+	{
564+		close_robust(fd);
565+		return NULL;			/* failed: this should never happen */
566+	}
567+	
568+	if (hdr->magic != PGShmemMagic)
569+	{
570+		close_robust(fd);
571+		munmap((void *) hdr, sizeof(PGShmemHeader));
572+		return NULL;			/* segment belongs to a non-Postgres app, which should be impossible */
573+	}
574+	
575+	/* Since the segment has a valid Postgres header, unmap and re-map it with the proper size */
576+	size = hdr->totalsize;
577+	munmap((void *) hdr, sizeof(PGShmemHeader));
578+	hdr = (PGShmemHeader *) mmap(UsedShmemSegAddr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
579+	close_robust(fd);
580+	
581+	if (hdr == (PGShmemHeader *) -1)   /* this shouldn't happen either */
582+		return NULL;
583+	
584+	return hdr;
585+}
586+#endif   /* EXEC_BACKEND */
587+
588+/*
589+ * PGSharedMemoryDetach
590+ *
591+ * Detach from the shared memory segments, if still attached.  This is not
592+ * intended for use by the process that originally created the segment
593+ * (it will have an on_shmem_exit callback registered to do that).	Rather,
594+ * this is for subprocesses that have inherited an attachment and want to
595+ * get rid of it.
596+ */
597+void
598+PGSharedMemoryDetach(void)
599+{
600+	PGShmemHeader  *hdr;
601+	if (UsedShmemSegAddr != NULL)
602+	{
603+		hdr = (PGShmemHeader *) UsedShmemSegAddr;
604+		if (munmap(UsedShmemSegAddr, hdr->totalsize) < 0)
605+			elog(LOG, "munmap(%p) failed: %m", UsedShmemSegAddr);
606+		UsedShmemSegAddr = NULL;
607+	}
608+	
609+	if (usedSysVSegAddr != NULL)
610+	{
611+		if (shmdt(usedSysVSegAddr) < 0)
612+			elog(LOG, "shmdt(%p) failed: %m", usedSysVSegAddr);
613+		usedSysVSegAddr = NULL;
614+	}
615+}
616+
617+/*
618+ * shm_open_robust
619+ *
620+ * Wrapper to call shm_open until it is not interrupted.
621+ */
622+static int
623+shm_open_robust(const char *name, int flags, mode_t mode)
624+{
625+	int fd;
626+	do
627+	{
628+		fd = shm_open(name, flags, mode);
629+	} while (fd < 0 && errno == EINTR);
630+	return fd;
631+}
632+
633+/*
634+ * close_robust
635+ *
636+ * Wrapper to call close until it is not interrupted.
637+ */
638+static int
639+close_robust(int d)
640+{
641+	int result;
642+	do
643+	{
644+		result = close(d);
645+	} while (result == -1 && errno == EINTR);
646+	return result;
647+}
648