PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
sysv_shmem.c File Reference
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "miscadmin.h"
#include "portability/mem.h"
#include "storage/dsm.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
#include "utils/guc.h"
Include dependency graph for sysv_shmem.c:

Go to the source code of this file.

Macros

#define USE_ANONYMOUS_SHMEM
 

Typedefs

typedef key_t IpcMemoryKey
 
typedef int IpcMemoryId
 

Functions

static void * InternalIpcMemoryCreate (IpcMemoryKey memKey, Size size)
 
static void IpcMemoryDetach (int status, Datum shmaddr)
 
static void IpcMemoryDelete (int status, Datum shmId)
 
static PGShmemHeaderPGSharedMemoryAttach (IpcMemoryKey key, IpcMemoryId *shmid)
 
bool PGSharedMemoryIsInUse (unsigned long id1, unsigned long id2)
 
static void * CreateAnonymousSegment (Size *size)
 
static void AnonymousShmemDetach (int status, Datum arg)
 
PGShmemHeaderPGSharedMemoryCreate (Size size, bool makePrivate, int port, PGShmemHeader **shim)
 
void PGSharedMemoryDetach (void)
 

Variables

unsigned long UsedShmemSegID = 0
 
void * UsedShmemSegAddr = NULL
 
static Size AnonymousShmemSize
 
static void * AnonymousShmem = NULL
 

Macro Definition Documentation

#define USE_ANONYMOUS_SHMEM

Definition at line 66 of file sysv_shmem.c.

Typedef Documentation

Definition at line 71 of file sysv_shmem.c.

Definition at line 70 of file sysv_shmem.c.

Function Documentation

static void AnonymousShmemDetach ( int  status,
Datum  arg 
)
static

Definition at line 524 of file sysv_shmem.c.

References AnonymousShmem, AnonymousShmemSize, elog, LOG, and NULL.

Referenced by PGSharedMemoryCreate().

525 {
526  /* Release anonymous shared memory block, if any. */
527  if (AnonymousShmem != NULL)
528  {
529  if (munmap(AnonymousShmem, AnonymousShmemSize) < 0)
530  elog(LOG, "munmap(%p, %zu) failed: %m",
533  }
534 }
static Size AnonymousShmemSize
Definition: sysv_shmem.c:78
#define LOG
Definition: elog.h:26
static void * AnonymousShmem
Definition: sysv_shmem.c:79
#define NULL
Definition: c.h:229
#define elog
Definition: elog.h:219
static void* CreateAnonymousSegment ( Size size)
static

Definition at line 456 of file sysv_shmem.c.

References Assert, DEBUG1, elog, ereport, errhint(), errmsg(), FATAL, huge_pages, HUGE_PAGES_ON, HUGE_PAGES_TRY, MAP_FAILED, NULL, and PG_MMAP_FLAGS.

Referenced by PGSharedMemoryCreate().

457 {
458  Size allocsize = *size;
459  void *ptr = MAP_FAILED;
460  int mmap_errno = 0;
461 
462 #ifndef MAP_HUGETLB
463  /* PGSharedMemoryCreate should have dealt with this case */
465 #else
467  {
468  /*
469  * Round up the request size to a suitable large value.
470  */
471  Size hugepagesize;
472  int mmap_flags;
473 
474  GetHugePageSize(&hugepagesize, &mmap_flags);
475 
476  if (allocsize % hugepagesize != 0)
477  allocsize += hugepagesize - (allocsize % hugepagesize);
478 
479  ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
480  PG_MMAP_FLAGS | mmap_flags, -1, 0);
481  mmap_errno = errno;
482  if (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED)
483  elog(DEBUG1, "mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m",
484  allocsize);
485  }
486 #endif
487 
488  if (ptr == MAP_FAILED && huge_pages != HUGE_PAGES_ON)
489  {
490  /*
491  * Use the original size, not the rounded-up value, when falling back
492  * to non-huge pages.
493  */
494  allocsize = *size;
495  ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
496  PG_MMAP_FLAGS, -1, 0);
497  mmap_errno = errno;
498  }
499 
500  if (ptr == MAP_FAILED)
501  {
502  errno = mmap_errno;
503  ereport(FATAL,
504  (errmsg("could not map anonymous shared memory: %m"),
505  (mmap_errno == ENOMEM) ?
506  errhint("This error usually means that PostgreSQL's request "
507  "for a shared memory segment exceeded available memory, "
508  "swap space, or huge pages. To reduce the request size "
509  "(currently %zu bytes), reduce PostgreSQL's shared "
510  "memory usage, perhaps by reducing shared_buffers or "
511  "max_connections.",
512  *size) : 0));
513  }
514 
515  *size = allocsize;
516  return ptr;
517 }
#define MAP_FAILED
Definition: mem.h:45
#define DEBUG1
Definition: elog.h:25
int errhint(const char *fmt,...)
Definition: elog.c:987
#define FATAL
Definition: elog.h:52
#define PG_MMAP_FLAGS
Definition: mem.h:41
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
size_t Size
Definition: c.h:356
int huge_pages
Definition: guc.c:491
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
static void * InternalIpcMemoryCreate ( IpcMemoryKey  memKey,
Size  size 
)
static

Definition at line 102 of file sysv_shmem.c.

References AddToDataDirLockFile(), EIDRM, elog, ereport, errdetail(), errhint(), errmsg(), FATAL, Int32GetDatum, IPC_CREAT, IPC_EXCL, IPC_RMID, IpcMemoryDelete(), IpcMemoryDetach(), IPCProtection, LOCK_FILE_LINE_SHMEM_KEY, LOG, NULL, on_shmem_exit(), PG_SHMAT_FLAGS, and PointerGetDatum.

Referenced by PGSharedMemoryCreate().

103 {
104  IpcMemoryId shmid;
105  void *requestedAddress = NULL;
106  void *memAddress;
107 
108  /*
109  * Normally we just pass requestedAddress = NULL to shmat(), allowing the
110  * system to choose where the segment gets mapped. But in an EXEC_BACKEND
111  * build, it's possible for whatever is chosen in the postmaster to not
112  * work for backends, due to variations in address space layout. As a
113  * rather klugy workaround, allow the user to specify the address to use
114  * via setting the environment variable PG_SHMEM_ADDR. (If this were of
115  * interest for anything except debugging, we'd probably create a cleaner
116  * and better-documented way to set it, such as a GUC.)
117  */
118 #ifdef EXEC_BACKEND
119  {
120  char *pg_shmem_addr = getenv("PG_SHMEM_ADDR");
121 
122  if (pg_shmem_addr)
123  requestedAddress = (void *) strtoul(pg_shmem_addr, NULL, 0);
124  }
125 #endif
126 
127  shmid = shmget(memKey, size, IPC_CREAT | IPC_EXCL | IPCProtection);
128 
129  if (shmid < 0)
130  {
131  int shmget_errno = errno;
132 
133  /*
134  * Fail quietly if error indicates a collision with existing segment.
135  * One would expect EEXIST, given that we said IPC_EXCL, but perhaps
136  * we could get a permission violation instead? Also, EIDRM might
137  * occur if an old seg is slated for destruction but not gone yet.
138  */
139  if (shmget_errno == EEXIST || shmget_errno == EACCES
140 #ifdef EIDRM
141  || shmget_errno == EIDRM
142 #endif
143  )
144  return NULL;
145 
146  /*
147  * Some BSD-derived kernels are known to return EINVAL, not EEXIST, if
148  * there is an existing segment but it's smaller than "size" (this is
149  * a result of poorly-thought-out ordering of error tests). To
150  * distinguish between collision and invalid size in such cases, we
151  * make a second try with size = 0. These kernels do not test size
152  * against SHMMIN in the preexisting-segment case, so we will not get
153  * EINVAL a second time if there is such a segment.
154  */
155  if (shmget_errno == EINVAL)
156  {
157  shmid = shmget(memKey, 0, IPC_CREAT | IPC_EXCL | IPCProtection);
158 
159  if (shmid < 0)
160  {
161  /* As above, fail quietly if we verify a collision */
162  if (errno == EEXIST || errno == EACCES
163 #ifdef EIDRM
164  || errno == EIDRM
165 #endif
166  )
167  return NULL;
168  /* Otherwise, fall through to report the original error */
169  }
170  else
171  {
172  /*
173  * On most platforms we cannot get here because SHMMIN is
174  * greater than zero. However, if we do succeed in creating a
175  * zero-size segment, free it and then fall through to report
176  * the original error.
177  */
178  if (shmctl(shmid, IPC_RMID, NULL) < 0)
179  elog(LOG, "shmctl(%d, %d, 0) failed: %m",
180  (int) shmid, IPC_RMID);
181  }
182  }
183 
184  /*
185  * Else complain and abort.
186  *
187  * Note: at this point EINVAL should mean that either SHMMIN or SHMMAX
188  * is violated. SHMALL violation might be reported as either ENOMEM
189  * (BSDen) or ENOSPC (Linux); the Single Unix Spec fails to say which
190  * it should be. SHMMNI violation is ENOSPC, per spec. Just plain
191  * not-enough-RAM is ENOMEM.
192  */
193  errno = shmget_errno;
194  ereport(FATAL,
195  (errmsg("could not create shared memory segment: %m"),
196  errdetail("Failed system call was shmget(key=%lu, size=%zu, 0%o).",
197  (unsigned long) memKey, size,
199  (shmget_errno == EINVAL) ?
200  errhint("This error usually means that PostgreSQL's request for a shared memory "
201  "segment exceeded your kernel's SHMMAX parameter, or possibly that "
202  "it is less than "
203  "your kernel's SHMMIN parameter.\n"
204  "The PostgreSQL documentation contains more information about shared "
205  "memory configuration.") : 0,
206  (shmget_errno == ENOMEM) ?
207  errhint("This error usually means that PostgreSQL's request for a shared "
208  "memory segment exceeded your kernel's SHMALL parameter. You might need "
209  "to reconfigure the kernel with larger SHMALL.\n"
210  "The PostgreSQL documentation contains more information about shared "
211  "memory configuration.") : 0,
212  (shmget_errno == ENOSPC) ?
213  errhint("This error does *not* mean that you have run out of disk space. "
214  "It occurs either if all available shared memory IDs have been taken, "
215  "in which case you need to raise the SHMMNI parameter in your kernel, "
216  "or because the system's overall limit for shared memory has been "
217  "reached.\n"
218  "The PostgreSQL documentation contains more information about shared "
219  "memory configuration.") : 0));
220  }
221 
222  /* Register on-exit routine to delete the new segment */
224 
225  /* OK, should be able to attach to the segment */
226  memAddress = shmat(shmid, requestedAddress, PG_SHMAT_FLAGS);
227 
228  if (memAddress == (void *) -1)
229  elog(FATAL, "shmat(id=%d, addr=%p, flags=0x%x) failed: %m",
230  shmid, requestedAddress, PG_SHMAT_FLAGS);
231 
232  /* Register on-exit routine to detach new segment before deleting */
234 
235  /*
236  * Store shmem key and ID in data directory lockfile. Format to try to
237  * keep it the same length always (trailing junk in the lockfile won't
238  * hurt, but might confuse humans).
239  */
240  {
241  char line[64];
242 
243  sprintf(line, "%9lu %9lu",
244  (unsigned long) memKey, (unsigned long) shmid);
246  }
247 
248  return memAddress;
249 }
#define IPC_CREAT
Definition: win32.h:107
#define IPC_EXCL
Definition: win32.h:108
int errhint(const char *fmt,...)
Definition: elog.c:987
static void IpcMemoryDetach(int status, Datum shmaddr)
Definition: sysv_shmem.c:257
void AddToDataDirLockFile(int target_line, const char *str)
Definition: miscinit.c:1156
#define PointerGetDatum(X)
Definition: postgres.h:562
#define IPCProtection
Definition: posix_sema.c:52
#define PG_SHMAT_FLAGS
Definition: mem.h:20
#define LOG
Definition: elog.h:26
#define FATAL
Definition: elog.h:52
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:348
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
static void IpcMemoryDelete(int status, Datum shmId)
Definition: sysv_shmem.c:269
#define IPC_RMID
Definition: win32.h:106
#define LOCK_FILE_LINE_SHMEM_KEY
Definition: miscadmin.h:452
#define NULL
Definition: c.h:229
int IpcMemoryId
Definition: sysv_shmem.c:71
#define Int32GetDatum(X)
Definition: postgres.h:485
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define EIDRM
Definition: win32.h:115
#define elog
Definition: elog.h:219
static void IpcMemoryDelete ( int  status,
Datum  shmId 
)
static

Definition at line 269 of file sysv_shmem.c.

References DatumGetInt32, elog, IPC_RMID, LOG, and NULL.

Referenced by InternalIpcMemoryCreate().

270 {
271  if (shmctl(DatumGetInt32(shmId), IPC_RMID, NULL) < 0)
272  elog(LOG, "shmctl(%d, %d, 0) failed: %m",
273  DatumGetInt32(shmId), IPC_RMID);
274 }
#define DatumGetInt32(X)
Definition: postgres.h:478
#define LOG
Definition: elog.h:26
#define IPC_RMID
Definition: win32.h:106
#define NULL
Definition: c.h:229
#define elog
Definition: elog.h:219
static void IpcMemoryDetach ( int  status,
Datum  shmaddr 
)
static

Definition at line 257 of file sysv_shmem.c.

References DatumGetPointer, elog, and LOG.

Referenced by InternalIpcMemoryCreate().

258 {
259  /* Detach System V shared memory block. */
260  if (shmdt(DatumGetPointer(shmaddr)) < 0)
261  elog(LOG, "shmdt(%p) failed: %m", DatumGetPointer(shmaddr));
262 }
#define LOG
Definition: elog.h:26
#define DatumGetPointer(X)
Definition: postgres.h:555
#define elog
Definition: elog.h:219
static PGShmemHeader * PGSharedMemoryAttach ( IpcMemoryKey  key,
IpcMemoryId shmid 
)
static

Definition at line 821 of file sysv_shmem.c.

References PGShmemHeader::magic, NULL, PG_SHMAT_FLAGS, PGShmemMagic, and UsedShmemSegAddr.

Referenced by PGSharedMemoryCreate().

822 {
823  PGShmemHeader *hdr;
824 
825  if ((*shmid = shmget(key, sizeof(PGShmemHeader), 0)) < 0)
826  return NULL;
827 
828  hdr = (PGShmemHeader *) shmat(*shmid, UsedShmemSegAddr, PG_SHMAT_FLAGS);
829 
830  if (hdr == (PGShmemHeader *) -1)
831  return NULL; /* failed: must be some other app's */
832 
833  if (hdr->magic != PGShmemMagic)
834  {
835  shmdt((void *) hdr);
836  return NULL; /* segment belongs to a non-Postgres app */
837  }
838 
839  return hdr;
840 }
#define PG_SHMAT_FLAGS
Definition: mem.h:20
void * UsedShmemSegAddr
Definition: sysv_shmem.c:75
int32 magic
Definition: pg_shmem.h:31
#define NULL
Definition: c.h:229
#define PGShmemMagic
Definition: pg_shmem.h:32
PGShmemHeader* PGSharedMemoryCreate ( Size  size,
bool  makePrivate,
int  port,
PGShmemHeader **  shim 
)

Definition at line 557 of file sysv_shmem.c.

Referenced by CreateSharedMemoryAndSemaphores().

559 {
560  IpcMemoryKey NextShmemSegID;
561  void *memAddress;
562  PGShmemHeader *hdr;
563  IpcMemoryId shmid;
564  struct stat statbuf;
565  Size sysvsize;
566 
567  /* Complain if hugepages demanded but we can't possibly support them */
568 #if !defined(USE_ANONYMOUS_SHMEM) || !defined(MAP_HUGETLB)
569  if (huge_pages == HUGE_PAGES_ON)
570  ereport(ERROR,
571  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
572  errmsg("huge pages not supported on this platform")));
573 #endif
574 
575  /* Room for a header? */
576  Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
577 
578 #ifdef USE_ANONYMOUS_SHMEM
580  AnonymousShmemSize = size;
581 
582  /* Register on-exit routine to unmap the anonymous segment */
584 
585  /* Now we need only allocate a minimal-sized SysV shmem block. */
586  sysvsize = sizeof(PGShmemHeader);
587 #else
588  sysvsize = size;
589 #endif
590 
591  /* Make sure PGSharedMemoryAttach doesn't fail without need */
593 
594  /* Loop till we find a free IPC key */
595  NextShmemSegID = port * 1000;
596 
597  for (NextShmemSegID++;; NextShmemSegID++)
598  {
599  /* Try to create new segment */
600  memAddress = InternalIpcMemoryCreate(NextShmemSegID, sysvsize);
601  if (memAddress)
602  break; /* successful create and attach */
603 
604  /* Check shared memory and possibly remove and recreate */
605 
606  if (makePrivate) /* a standalone backend shouldn't do this */
607  continue;
608 
609  if ((memAddress = PGSharedMemoryAttach(NextShmemSegID, &shmid)) == NULL)
610  continue; /* can't attach, not one of mine */
611 
612  /*
613  * If I am not the creator and it belongs to an extant process,
614  * continue.
615  */
616  hdr = (PGShmemHeader *) memAddress;
617  if (hdr->creatorPID != getpid())
618  {
619  if (kill(hdr->creatorPID, 0) == 0 || errno != ESRCH)
620  {
621  shmdt(memAddress);
622  continue; /* segment belongs to a live process */
623  }
624  }
625 
626  /*
627  * The segment appears to be from a dead Postgres process, or from a
628  * previous cycle of life in this same process. Zap it, if possible,
629  * and any associated dynamic shared memory segments, as well. This
630  * probably shouldn't fail, but if it does, assume the segment belongs
631  * to someone else after all, and continue quietly.
632  */
633  if (hdr->dsm_control != 0)
635  shmdt(memAddress);
636  if (shmctl(shmid, IPC_RMID, NULL) < 0)
637  continue;
638 
639  /*
640  * Now try again to create the segment.
641  */
642  memAddress = InternalIpcMemoryCreate(NextShmemSegID, sysvsize);
643  if (memAddress)
644  break; /* successful create and attach */
645 
646  /*
647  * Can only get here if some other process managed to create the same
648  * shmem key before we did. Let him have that one, loop around to try
649  * next key.
650  */
651  }
652 
653  /*
654  * OK, we created a new segment. Mark it as created by this process. The
655  * order of assignments here is critical so that another Postgres process
656  * can't see the header as valid but belonging to an invalid PID!
657  */
658  hdr = (PGShmemHeader *) memAddress;
659  hdr->creatorPID = getpid();
660  hdr->magic = PGShmemMagic;
661  hdr->dsm_control = 0;
662 
663  /* Fill in the data directory ID info, too */
664  if (stat(DataDir, &statbuf) < 0)
665  ereport(FATAL,
667  errmsg("could not stat data directory \"%s\": %m",
668  DataDir)));
669  hdr->device = statbuf.st_dev;
670  hdr->inode = statbuf.st_ino;
671 
672  /*
673  * Initialize space allocation status for segment.
674  */
675  hdr->totalsize = size;
676  hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
677  *shim = hdr;
678 
679  /* Save info for possible future use */
680  UsedShmemSegAddr = memAddress;
681  UsedShmemSegID = (unsigned long) NextShmemSegID;
682 
683  /*
684  * If AnonymousShmem is NULL here, then we're not using anonymous shared
685  * memory, and should return a pointer to the System V shared memory
686  * block. Otherwise, the System V shared memory block is only a shim, and
687  * we must return a pointer to the real block.
688  */
689 #ifdef USE_ANONYMOUS_SHMEM
690  if (AnonymousShmem == NULL)
691  return hdr;
692  memcpy(AnonymousShmem, hdr, sizeof(PGShmemHeader));
693  return (PGShmemHeader *) AnonymousShmem;
694 #else
695  return hdr;
696 #endif
697 }
pid_t creatorPID
Definition: pg_shmem.h:33
void dsm_cleanup_using_control_segment(dsm_handle old_control_handle)
Definition: dsm.c:210
static PGShmemHeader * PGSharedMemoryAttach(IpcMemoryKey key, IpcMemoryId *shmid)
Definition: sysv_shmem.c:821
dsm_handle dsm_control
Definition: pg_shmem.h:36
struct PGShmemHeader PGShmemHeader
static Size AnonymousShmemSize
Definition: sysv_shmem.c:78
int errcode(int sqlerrcode)
Definition: elog.c:575
static void * InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size)
Definition: sysv_shmem.c:102
#define ERROR
Definition: elog.h:43
#define FATAL
Definition: elog.h:52
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:348
key_t IpcMemoryKey
Definition: sysv_shmem.c:70
int errcode_for_file_access(void)
Definition: elog.c:598
void * UsedShmemSegAddr
Definition: sysv_shmem.c:75
static void AnonymousShmemDetach(int status, Datum arg)
Definition: sysv_shmem.c:524
#define ereport(elevel, rest)
Definition: elog.h:122
static int port
Definition: pg_regress.c:89
int32 magic
Definition: pg_shmem.h:31
static void * CreateAnonymousSegment(Size *size)
Definition: sysv_shmem.c:456
Size totalsize
Definition: pg_shmem.h:34
uintptr_t Datum
Definition: postgres.h:372
unsigned long UsedShmemSegID
Definition: sysv_shmem.c:74
#define IPC_RMID
Definition: win32.h:106
static void * AnonymousShmem
Definition: sysv_shmem.c:79
ino_t inode
Definition: pg_shmem.h:40
dev_t device
Definition: pg_shmem.h:39
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define PGShmemMagic
Definition: pg_shmem.h:32
Size freeoffset
Definition: pg_shmem.h:35
size_t Size
Definition: c.h:356
#define MAXALIGN(LEN)
Definition: c.h:588
int IpcMemoryId
Definition: sysv_shmem.c:71
int huge_pages
Definition: guc.c:491
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * DataDir
Definition: globals.c:59
void PGSharedMemoryDetach ( void  )

Definition at line 789 of file sysv_shmem.c.

Referenced by pgarch_start(), pgstat_start(), StartBackgroundWorker(), and SysLogger_Start().

790 {
791  if (UsedShmemSegAddr != NULL)
792  {
793  if ((shmdt(UsedShmemSegAddr) < 0)
794 #if defined(EXEC_BACKEND) && defined(__CYGWIN__)
795  /* Work-around for cygipc exec bug */
796  && shmdt(NULL) < 0
797 #endif
798  )
799  elog(LOG, "shmdt(%p) failed: %m", UsedShmemSegAddr);
801  }
802 
803 #ifdef USE_ANONYMOUS_SHMEM
804  if (AnonymousShmem != NULL)
805  {
806  if (munmap(AnonymousShmem, AnonymousShmemSize) < 0)
807  elog(LOG, "munmap(%p, %zu) failed: %m",
810  }
811 #endif
812 }
static Size AnonymousShmemSize
Definition: sysv_shmem.c:78
#define LOG
Definition: elog.h:26
void * UsedShmemSegAddr
Definition: sysv_shmem.c:75
static void * AnonymousShmem
Definition: sysv_shmem.c:79
#define NULL
Definition: c.h:229
#define elog
Definition: elog.h:219
bool PGSharedMemoryIsInUse ( unsigned long  id1,
unsigned long  id2 
)

Definition at line 288 of file sysv_shmem.c.

Referenced by CreateLockFile().

289 {
290  IpcMemoryId shmId = (IpcMemoryId) id2;
291  struct shmid_ds shmStat;
292  struct stat statbuf;
293  PGShmemHeader *hdr;
294 
295  /*
296  * We detect whether a shared memory segment is in use by seeing whether
297  * it (a) exists and (b) has any processes attached to it.
298  */
299  if (shmctl(shmId, IPC_STAT, &shmStat) < 0)
300  {
301  /*
302  * EINVAL actually has multiple possible causes documented in the
303  * shmctl man page, but we assume it must mean the segment no longer
304  * exists.
305  */
306  if (errno == EINVAL)
307  return false;
308 
309  /*
310  * EACCES implies that the segment belongs to some other userid, which
311  * means it is not a Postgres shmem segment (or at least, not one that
312  * is relevant to our data directory).
313  */
314  if (errno == EACCES)
315  return false;
316 
317  /*
318  * Some Linux kernel versions (in fact, all of them as of July 2007)
319  * sometimes return EIDRM when EINVAL is correct. The Linux kernel
320  * actually does not have any internal state that would justify
321  * returning EIDRM, so we can get away with assuming that EIDRM is
322  * equivalent to EINVAL on that platform.
323  */
324 #ifdef HAVE_LINUX_EIDRM_BUG
325  if (errno == EIDRM)
326  return false;
327 #endif
328 
329  /*
330  * Otherwise, we had better assume that the segment is in use. The
331  * only likely case is EIDRM, which implies that the segment has been
332  * IPC_RMID'd but there are still processes attached to it.
333  */
334  return true;
335  }
336 
337  /* If it has no attached processes, it's not in use */
338  if (shmStat.shm_nattch == 0)
339  return false;
340 
341  /*
342  * Try to attach to the segment and see if it matches our data directory.
343  * This avoids shmid-conflict problems on machines that are running
344  * several postmasters under the same userid.
345  */
346  if (stat(DataDir, &statbuf) < 0)
347  return true; /* if can't stat, be conservative */
348 
349  hdr = (PGShmemHeader *) shmat(shmId, NULL, PG_SHMAT_FLAGS);
350 
351  if (hdr == (PGShmemHeader *) -1)
352  return true; /* if can't attach, be conservative */
353 
354  if (hdr->magic != PGShmemMagic ||
355  hdr->device != statbuf.st_dev ||
356  hdr->inode != statbuf.st_ino)
357  {
358  /*
359  * It's either not a Postgres segment, or not one for my data
360  * directory. In either case it poses no threat.
361  */
362  shmdt((void *) hdr);
363  return false;
364  }
365 
366  /* Trouble --- looks a lot like there's still live backends */
367  shmdt((void *) hdr);
368 
369  return true;
370 }
#define PG_SHMAT_FLAGS
Definition: mem.h:20
#define IPC_STAT
Definition: win32.h:111
#define NULL
Definition: c.h:229
#define PGShmemMagic
Definition: pg_shmem.h:32
int IpcMemoryId
Definition: sysv_shmem.c:71
char * DataDir
Definition: globals.c:59
#define EIDRM
Definition: win32.h:115

Variable Documentation

void* AnonymousShmem = NULL
static

Definition at line 79 of file sysv_shmem.c.

Referenced by AnonymousShmemDetach(), PGSharedMemoryCreate(), and PGSharedMemoryDetach().

Size AnonymousShmemSize
static

Definition at line 78 of file sysv_shmem.c.

Referenced by AnonymousShmemDetach(), PGSharedMemoryCreate(), and PGSharedMemoryDetach().

void* UsedShmemSegAddr = NULL

Definition at line 75 of file sysv_shmem.c.

Referenced by PGSharedMemoryAttach(), PGSharedMemoryCreate(), and PGSharedMemoryDetach().

unsigned long UsedShmemSegID = 0

Definition at line 74 of file sysv_shmem.c.

Referenced by PGSharedMemoryCreate().