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