PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pg_shmem.h File Reference
#include "storage/dsm_impl.h"
Include dependency graph for pg_shmem.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PGShmemHeader

Macros

#define PGShmemMagic   679834894

Typedefs

typedef struct PGShmemHeader PGShmemHeader

Enumerations

enum  HugePagesType { HUGE_PAGES_OFF, HUGE_PAGES_ON, HUGE_PAGES_TRY }

Functions

PGShmemHeaderPGSharedMemoryCreate (Size size, bool makePrivate, int port, PGShmemHeader **shim)
bool PGSharedMemoryIsInUse (unsigned long id1, unsigned long id2)
void PGSharedMemoryDetach (void)

Variables

int huge_pages
unsigned long UsedShmemSegID
void * UsedShmemSegAddr

Macro Definition Documentation

#define PGShmemMagic   679834894

Typedef Documentation

Enumeration Type Documentation

Enumerator:
HUGE_PAGES_OFF 
HUGE_PAGES_ON 
HUGE_PAGES_TRY 

Definition at line 48 of file pg_shmem.h.

Function Documentation

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

Definition at line 425 of file sysv_shmem.c.

References AnonymousShmem, AnonymousShmemSize, Assert, CreateAnonymousSegment(), PGShmemHeader::creatorPID, DataDir, PGShmemHeader::device, dsm_cleanup_using_control_segment(), PGShmemHeader::dsm_control, elog, ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), ERROR, FATAL, free, PGShmemHeader::freeoffset, GetSharedMemName(), huge_pages, HUGE_PAGES_ON, i, PGShmemHeader::inode, InternalIpcMemoryCreate(), IPC_RMID, LOG, PGShmemHeader::magic, MAXALIGN, NULL, on_shmem_exit(), PGSharedMemoryAttach(), PGShmemMagic, pgwin32_SharedMemoryDelete(), PointerGetDatum, PGShmemHeader::totalsize, TRUE, UsedShmemSegAddr, UsedShmemSegID, and UsedShmemSegSize.

Referenced by CreateSharedMemoryAndSemaphores().

{
IpcMemoryKey NextShmemSegID;
void *memAddress;
IpcMemoryId shmid;
struct stat statbuf;
Size sysvsize;
#if defined(EXEC_BACKEND) || !defined(MAP_HUGETLB)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge pages not supported on this platform")));
#endif
/* Room for a header? */
Assert(size > MAXALIGN(sizeof(PGShmemHeader)));
/*
* As of PostgreSQL 9.3, we normally allocate only a very small amount of
* System V shared memory, and only for the purposes of providing an
* interlock to protect the data directory. The real shared memory block
* is allocated using mmap(). This works around the problem that many
* systems have very low limits on the amount of System V shared memory
* that can be allocated. Even a limit of a few megabytes will be enough
* to run many copies of PostgreSQL without needing to adjust system
* settings.
*
* We assume that no one will attempt to run PostgreSQL 9.3 or later on
* systems that are ancient enough that anonymous shared memory is not
* supported, such as pre-2.4 versions of Linux. If that turns out to be
* false, we might need to add a run-time test here and do this only if
* the running kernel supports it.
*
* However, we disable this logic in the EXEC_BACKEND case, and fall back
* to the old method of allocating the entire segment using System V
* shared memory, because there's no way to attach an mmap'd segment to a
* process after exec(). Since EXEC_BACKEND is intended only for
* developer use, this shouldn't be a big problem.
*/
#ifndef EXEC_BACKEND
/* Now we need only allocate a minimal-sized SysV shmem block. */
sysvsize = sizeof(PGShmemHeader);
#else
sysvsize = size;
#endif
/* Make sure PGSharedMemoryAttach doesn't fail without need */
/* Loop till we find a free IPC key */
NextShmemSegID = port * 1000;
for (NextShmemSegID++;; NextShmemSegID++)
{
/* Try to create new segment */
memAddress = InternalIpcMemoryCreate(NextShmemSegID, sysvsize);
if (memAddress)
break; /* successful create and attach */
/* Check shared memory and possibly remove and recreate */
if (makePrivate) /* a standalone backend shouldn't do this */
continue;
if ((memAddress = PGSharedMemoryAttach(NextShmemSegID, &shmid)) == NULL)
continue; /* can't attach, not one of mine */
/*
* If I am not the creator and it belongs to an extant process,
* continue.
*/
hdr = (PGShmemHeader *) memAddress;
if (hdr->creatorPID != getpid())
{
if (kill(hdr->creatorPID, 0) == 0 || errno != ESRCH)
{
shmdt(memAddress);
continue; /* segment belongs to a live process */
}
}
/*
* The segment appears to be from a dead Postgres process, or from a
* previous cycle of life in this same process. Zap it, if possible,
* and any associated dynamic shared memory segments, as well. This
* probably shouldn't fail, but if it does, assume the segment belongs
* to someone else after all, and continue quietly.
*/
if (hdr->dsm_control != 0)
shmdt(memAddress);
if (shmctl(shmid, IPC_RMID, NULL) < 0)
continue;
/*
* Now try again to create the segment.
*/
memAddress = InternalIpcMemoryCreate(NextShmemSegID, sysvsize);
if (memAddress)
break; /* successful create and attach */
/*
* Can only get here if some other process managed to create the same
* shmem key before we did. Let him have that one, loop around to try
* next key.
*/
}
/*
* OK, we created a new segment. Mark it as created by this process. The
* order of assignments here is critical so that another Postgres process
* can't see the header as valid but belonging to an invalid PID!
*/
hdr = (PGShmemHeader *) memAddress;
hdr->creatorPID = getpid();
hdr->dsm_control = 0;
/* Fill in the data directory ID info, too */
if (stat(DataDir, &statbuf) < 0)
errmsg("could not stat data directory \"%s\": %m",
DataDir)));
hdr->device = statbuf.st_dev;
hdr->inode = statbuf.st_ino;
/*
* Initialize space allocation status for segment.
*/
hdr->totalsize = size;
*shim = hdr;
/* Save info for possible future use */
UsedShmemSegAddr = memAddress;
UsedShmemSegID = (unsigned long) NextShmemSegID;
/*
* If AnonymousShmem is NULL here, then we're not using anonymous shared
* memory, and should return a pointer to the System V shared memory
* block. Otherwise, the System V shared memory block is only a shim, and
* we must return a pointer to the real block.
*/
return hdr;
memcpy(AnonymousShmem, hdr, sizeof(PGShmemHeader));
}
void PGSharedMemoryDetach ( void  )

Definition at line 634 of file sysv_shmem.c.

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

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

{
{
if ((shmdt(UsedShmemSegAddr) < 0)
#if defined(EXEC_BACKEND) && defined(__CYGWIN__)
/* Work-around for cygipc exec bug */
&& shmdt(NULL) < 0
#endif
)
elog(LOG, "shmdt(%p) failed: %m", UsedShmemSegAddr);
}
/* Release anonymous shared memory block, if any. */
elog(LOG, "munmap(%p) failed: %m", AnonymousShmem);
}
bool PGSharedMemoryIsInUse ( unsigned long  id1,
unsigned long  id2 
)

Definition at line 237 of file sysv_shmem.c.

References DataDir, EIDRM, FALSE, free, GetSharedMemName(), IPC_STAT, NULL, PG_SHMAT_FLAGS, and PGShmemMagic.

Referenced by CreateLockFile().

{
IpcMemoryId shmId = (IpcMemoryId) id2;
struct shmid_ds shmStat;
struct stat statbuf;
/*
* We detect whether a shared memory segment is in use by seeing whether
* it (a) exists and (b) has any processes attached to it.
*/
if (shmctl(shmId, IPC_STAT, &shmStat) < 0)
{
/*
* EINVAL actually has multiple possible causes documented in the
* shmctl man page, but we assume it must mean the segment no longer
* exists.
*/
if (errno == EINVAL)
return false;
/*
* EACCES implies that the segment belongs to some other userid, which
* means it is not a Postgres shmem segment (or at least, not one that
* is relevant to our data directory).
*/
if (errno == EACCES)
return false;
/*
* Some Linux kernel versions (in fact, all of them as of July 2007)
* sometimes return EIDRM when EINVAL is correct. The Linux kernel
* actually does not have any internal state that would justify
* returning EIDRM, so we can get away with assuming that EIDRM is
* equivalent to EINVAL on that platform.
*/
#ifdef HAVE_LINUX_EIDRM_BUG
if (errno == EIDRM)
return false;
#endif
/*
* Otherwise, we had better assume that the segment is in use. The
* only likely case is EIDRM, which implies that the segment has been
* IPC_RMID'd but there are still processes attached to it.
*/
return true;
}
/* If it has no attached processes, it's not in use */
if (shmStat.shm_nattch == 0)
return false;
/*
* Try to attach to the segment and see if it matches our data directory.
* This avoids shmid-conflict problems on machines that are running
* several postmasters under the same userid.
*/
if (stat(DataDir, &statbuf) < 0)
return true; /* if can't stat, be conservative */
hdr = (PGShmemHeader *) shmat(shmId, NULL, PG_SHMAT_FLAGS);
if (hdr == (PGShmemHeader *) -1)
return true; /* if can't attach, be conservative */
if (hdr->magic != PGShmemMagic ||
hdr->device != statbuf.st_dev ||
hdr->inode != statbuf.st_ino)
{
/*
* It's either not a Postgres segment, or not one for my data
* directory. In either case it poses no threat.
*/
shmdt((void *) hdr);
return false;
}
/* Trouble --- looks a lot like there's still live backends */
shmdt((void *) hdr);
return true;
}

Variable Documentation

int huge_pages

Definition at line 485 of file guc.c.

Referenced by CreateAnonymousSegment(), and PGSharedMemoryCreate().

unsigned long UsedShmemSegID

Definition at line 43 of file sysv_shmem.c.

Referenced by PGSharedMemoryCreate(), and PGSharedMemoryReAttach().