PostgreSQL Source Code  git master
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 "utils/pidfile.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

◆ USE_ANONYMOUS_SHMEM

#define USE_ANONYMOUS_SHMEM

Definition at line 67 of file sysv_shmem.c.

Typedef Documentation

◆ IpcMemoryId

Definition at line 72 of file sysv_shmem.c.

◆ IpcMemoryKey

Definition at line 71 of file sysv_shmem.c.

Function Documentation

◆ AnonymousShmemDetach()

static void AnonymousShmemDetach ( int  status,
Datum  arg 
)
static

Definition at line 525 of file sysv_shmem.c.

References AnonymousShmem, AnonymousShmemSize, elog, and LOG.

Referenced by PGSharedMemoryCreate().

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

◆ CreateAnonymousSegment()

static void* CreateAnonymousSegment ( Size size)
static

Definition at line 457 of file sysv_shmem.c.

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

Referenced by PGSharedMemoryCreate().

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

◆ InternalIpcMemoryCreate()

static void * InternalIpcMemoryCreate ( IpcMemoryKey  memKey,
Size  size 
)
static

Definition at line 103 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, on_shmem_exit(), PG_SHMAT_FLAGS, and PointerGetDatum.

Referenced by PGSharedMemoryCreate().

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

◆ IpcMemoryDelete()

static void IpcMemoryDelete ( int  status,
Datum  shmId 
)
static

Definition at line 270 of file sysv_shmem.c.

References DatumGetInt32, elog, IPC_RMID, and LOG.

Referenced by InternalIpcMemoryCreate().

271 {
272  if (shmctl(DatumGetInt32(shmId), IPC_RMID, NULL) < 0)
273  elog(LOG, "shmctl(%d, %d, 0) failed: %m",
274  DatumGetInt32(shmId), IPC_RMID);
275 }
#define DatumGetInt32(X)
Definition: postgres.h:478
#define LOG
Definition: elog.h:26
#define IPC_RMID
Definition: win32_port.h:81
#define elog
Definition: elog.h:219

◆ IpcMemoryDetach()

static void IpcMemoryDetach ( int  status,
Datum  shmaddr 
)
static

Definition at line 258 of file sysv_shmem.c.

References DatumGetPointer, elog, and LOG.

Referenced by InternalIpcMemoryCreate().

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

◆ PGSharedMemoryAttach()

static PGShmemHeader * PGSharedMemoryAttach ( IpcMemoryKey  key,
IpcMemoryId shmid 
)
static

Definition at line 822 of file sysv_shmem.c.

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

Referenced by PGSharedMemoryCreate().

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

◆ PGSharedMemoryCreate()

PGShmemHeader* PGSharedMemoryCreate ( Size  size,
bool  makePrivate,
int  port,
PGShmemHeader **  shim 
)

Definition at line 558 of file sysv_shmem.c.

Referenced by CreateSharedMemoryAndSemaphores().

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

◆ PGSharedMemoryDetach()

void PGSharedMemoryDetach ( void  )

Definition at line 790 of file sysv_shmem.c.

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

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

◆ PGSharedMemoryIsInUse()

bool PGSharedMemoryIsInUse ( unsigned long  id1,
unsigned long  id2 
)

Definition at line 289 of file sysv_shmem.c.

Referenced by CreateLockFile().

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

Variable Documentation

◆ AnonymousShmem

void* AnonymousShmem = NULL
static

Definition at line 80 of file sysv_shmem.c.

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

◆ AnonymousShmemSize

Size AnonymousShmemSize
static

Definition at line 79 of file sysv_shmem.c.

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

◆ UsedShmemSegAddr

void* UsedShmemSegAddr = NULL

◆ UsedShmemSegID

unsigned long UsedShmemSegID = 0

Definition at line 75 of file sysv_shmem.c.

Referenced by PGSharedMemoryCreate(), and PostmasterMarkPIDForWorkerNotify().