Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

shmem.c File Reference

#include "postgres.h"
#include "access/transam.h"
#include "miscadmin.h"
#include "storage/lwlock.h"
#include "storage/pg_shmem.h"
#include "storage/shmem.h"
#include "storage/spin.h"
Include dependency graph for shmem.c:

Go to the source code of this file.

Functions

void InitShmemAccess (void *seghdr)
void InitShmemAllocation (void)
void * ShmemAlloc (Size size)
bool ShmemAddrIsValid (const void *addr)
void InitShmemIndex (void)
HTABShmemInitHash (const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
void * ShmemInitStruct (const char *name, Size size, bool *foundPtr)
Size add_size (Size s1, Size s2)
Size mul_size (Size s1, Size s2)

Variables

static PGShmemHeaderShmemSegHdr
static void * ShmemBase
static void * ShmemEnd
slock_tShmemLock
static HTABShmemIndex = NULL

Function Documentation

Size add_size ( Size  s1,
Size  s2 
)
void InitShmemAccess ( void *  seghdr  ) 

Definition at line 97 of file shmem.c.

References ShmemBase, ShmemEnd, and PGShmemHeader::totalsize.

Referenced by CreateSharedMemoryAndSemaphores().

{
    PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr;

    ShmemSegHdr = shmhdr;
    ShmemBase = (void *) shmhdr;
    ShmemEnd = (char *) ShmemBase + shmhdr->totalsize;
}

void InitShmemAllocation ( void   ) 

Definition at line 112 of file shmem.c.

References Assert, MAXALIGN, NULL, ShmemAlloc(), ShmemLock, ShmemVariableCache, and SpinLockInit.

Referenced by CreateSharedMemoryAndSemaphores().

{
    PGShmemHeader *shmhdr = ShmemSegHdr;

    Assert(shmhdr != NULL);

    /*
     * Initialize the spinlock used by ShmemAlloc.  We have to do the space
     * allocation the hard way, since obviously ShmemAlloc can't be called
     * yet.
     */
    ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
    shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
    Assert(shmhdr->freeoffset <= shmhdr->totalsize);

    SpinLockInit(ShmemLock);

    /* ShmemIndex can't be set up yet (need LWLocks first) */
    shmhdr->index = NULL;
    ShmemIndex = (HTAB *) NULL;

    /*
     * Initialize ShmemVariableCache for transaction manager. (This doesn't
     * really belong here, but not worth moving.)
     */
    ShmemVariableCache = (VariableCache)
        ShmemAlloc(sizeof(*ShmemVariableCache));
    memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
}

void InitShmemIndex ( void   ) 

Definition at line 210 of file shmem.c.

References HASHCTL::entrysize, HASHCTL::keysize, SHMEM_INDEX_SIZE, and ShmemInitHash().

Referenced by CreateSharedMemoryAndSemaphores().

{
    HASHCTL     info;
    int         hash_flags;

    /*
     * Create the shared memory shmem index.
     *
     * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
     * hashtable to exist already, we have a bit of a circularity problem in
     * initializing the ShmemIndex itself.  The special "ShmemIndex" hash
     * table name will tell ShmemInitStruct to fake it.
     */
    info.keysize = SHMEM_INDEX_KEYSIZE;
    info.entrysize = sizeof(ShmemIndexEnt);
    hash_flags = HASH_ELEM;

    ShmemIndex = ShmemInitHash("ShmemIndex",
                               SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
                               &info, hash_flags);
}

Size mul_size ( Size  s1,
Size  s2 
)

Definition at line 435 of file shmem.c.

References ereport, errcode(), errmsg(), and ERROR.

Referenced by AsyncShmemInit(), AsyncShmemSize(), AutoVacuumShmemSize(), BackendStatusShmemSize(), BTreeShmemSize(), BufferShmemSize(), CheckpointerShmemSize(), CreateSharedBackendStatus(), CreateSharedInvalidationState(), CreateSharedProcArray(), hash_estimate_size(), InitPredicateLocks(), LWLockShmemSize(), PMSignalShmemSize(), PredicateLockShmemSize(), ProcArrayShmemSize(), ProcGlobalShmemSize(), SInvalShmemSize(), TwoPhaseShmemSize(), WalSndShmemSize(), and XLOGShmemSize().

{
    Size        result;

    if (s1 == 0 || s2 == 0)
        return 0;
    result = s1 * s2;
    /* We are assuming Size is an unsigned type here... */
    if (result / s2 != s1)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("requested shared memory size overflows size_t")));
    return result;
}

bool ShmemAddrIsValid ( const void *  addr  ) 
void* ShmemAlloc ( Size  size  ) 

Definition at line 152 of file shmem.c.

References Assert, BUFFERALIGN, ereport, errcode(), errmsg(), PGShmemHeader::freeoffset, MAXALIGN, NULL, ShmemBase, ShmemLock, SpinLockAcquire, SpinLockRelease, totalsize, and WARNING.

Referenced by CreateLWLocks(), InitPredicateLocks(), InitProcGlobal(), InitShmemAllocation(), and ShmemInitStruct().

{
    Size        newStart;
    Size        newFree;
    void       *newSpace;

    /* use volatile pointer to prevent code rearrangement */
    volatile PGShmemHeader *shmemseghdr = ShmemSegHdr;

    /*
     * ensure all space is adequately aligned.
     */
    size = MAXALIGN(size);

    Assert(shmemseghdr != NULL);

    SpinLockAcquire(ShmemLock);

    newStart = shmemseghdr->freeoffset;

    /* extra alignment for large requests, since they are probably buffers */
    if (size >= BLCKSZ)
        newStart = BUFFERALIGN(newStart);

    newFree = newStart + size;
    if (newFree <= shmemseghdr->totalsize)
    {
        newSpace = (void *) ((char *) ShmemBase + newStart);
        shmemseghdr->freeoffset = newFree;
    }
    else
        newSpace = NULL;

    SpinLockRelease(ShmemLock);

    if (!newSpace)
        ereport(WARNING,
                (errcode(ERRCODE_OUT_OF_MEMORY),
                 errmsg("out of shared memory")));

    return newSpace;
}

HTAB* ShmemInitHash ( const char *  name,
long  init_size,
long  max_size,
HASHCTL infoP,
int  hash_flags 
)

Definition at line 255 of file shmem.c.

References HASHCTL::alloc, HASHCTL::dsize, HASH_ALLOC, hash_create(), hash_get_shared_size(), hash_select_dirsize(), HASH_SHARED_MEM, HASHCTL::hctl, HASHCTL::max_dsize, and ShmemInitStruct().

Referenced by InitBufTable(), InitLocks(), InitPredicateLocks(), InitShmemIndex(), and pgss_shmem_startup().

{
    bool        found;
    void       *location;

    /*
     * Hash tables allocated in shared memory have a fixed directory; it can't
     * grow or other backends wouldn't be able to find it. So, make sure we
     * make it big enough to start with.
     *
     * The shared memory allocator must be specified too.
     */
    infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
    infoP->alloc = ShmemAlloc;
    hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;

    /* look it up in the shmem index */
    location = ShmemInitStruct(name,
                               hash_get_shared_size(infoP, hash_flags),
                               &found);

    /*
     * if it already exists, attach to it rather than allocate and initialize
     * new space
     */
    if (found)
        hash_flags |= HASH_ATTACH;

    /* Pass location of hashtable header to hash_create */
    infoP->hctl = (HASHHDR *) location;

    return hash_create(name, init_size, infoP, hash_flags);
}

void* ShmemInitStruct ( const char *  name,
Size  size,
bool foundPtr 
)

Definition at line 310 of file shmem.c.

References Assert, ereport, errcode(), errmsg(), ERROR, HASH_ENTER_NULL, HASH_REMOVE, hash_search(), PGShmemHeader::index, IsUnderPostmaster, ShmemIndexEnt::location, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), NULL, ShmemAddrIsValid(), ShmemAlloc(), ShmemIndexLock, and ShmemIndexEnt::size.

Referenced by AsyncShmemInit(), AutoVacuumShmemInit(), BTreeShmemInit(), CheckpointerShmemInit(), CreateSharedBackendStatus(), CreateSharedInvalidationState(), CreateSharedProcArray(), InitBufferPool(), InitLocks(), InitPredicateLocks(), InitProcGlobal(), MultiXactShmemInit(), OldSerXidInit(), pgss_shmem_startup(), PMSignalShmemInit(), ProcSignalShmemInit(), ShmemInitHash(), SimpleLruInit(), StrategyInitialize(), SyncScanShmemInit(), TwoPhaseShmemInit(), WalRcvShmemInit(), WalSndShmemInit(), and XLOGShmemInit().

{
    ShmemIndexEnt *result;
    void       *structPtr;

    LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);

    if (!ShmemIndex)
    {
        PGShmemHeader *shmemseghdr = ShmemSegHdr;

        /* Must be trying to create/attach to ShmemIndex itself */
        Assert(strcmp(name, "ShmemIndex") == 0);

        if (IsUnderPostmaster)
        {
            /* Must be initializing a (non-standalone) backend */
            Assert(shmemseghdr->index != NULL);
            structPtr = shmemseghdr->index;
            *foundPtr = TRUE;
        }
        else
        {
            /*
             * If the shmem index doesn't exist, we are bootstrapping: we must
             * be trying to init the shmem index itself.
             *
             * Notice that the ShmemIndexLock is released before the shmem
             * index has been initialized.  This should be OK because no other
             * process can be accessing shared memory yet.
             */
            Assert(shmemseghdr->index == NULL);
            structPtr = ShmemAlloc(size);
            if (structPtr == NULL)
                ereport(ERROR,
                        (errcode(ERRCODE_OUT_OF_MEMORY),
                         errmsg("not enough shared memory for data structure"
                                " \"%s\" (%lu bytes requested)",
                                name, (unsigned long) size)));
            shmemseghdr->index = structPtr;
            *foundPtr = FALSE;
        }
        LWLockRelease(ShmemIndexLock);
        return structPtr;
    }

    /* look it up in the shmem index */
    result = (ShmemIndexEnt *)
        hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr);

    if (!result)
    {
        LWLockRelease(ShmemIndexLock);
        ereport(ERROR,
                (errcode(ERRCODE_OUT_OF_MEMORY),
        errmsg("could not create ShmemIndex entry for data structure \"%s\"",
               name)));
    }

    if (*foundPtr)
    {
        /*
         * Structure is in the shmem index so someone else has allocated it
         * already.  The size better be the same as the size we are trying to
         * initialize to, or there is a name conflict (or worse).
         */
        if (result->size != size)
        {
            LWLockRelease(ShmemIndexLock);
            ereport(ERROR,
                  (errmsg("ShmemIndex entry size is wrong for data structure"
                          " \"%s\": expected %lu, actual %lu",
                          name,
                          (unsigned long) size,
                          (unsigned long) result->size)));
        }
        structPtr = result->location;
    }
    else
    {
        /* It isn't in the table yet. allocate and initialize it */
        structPtr = ShmemAlloc(size);
        if (structPtr == NULL)
        {
            /* out of memory; remove the failed ShmemIndex entry */
            hash_search(ShmemIndex, name, HASH_REMOVE, NULL);
            LWLockRelease(ShmemIndexLock);
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("not enough shared memory for data structure"
                            " \"%s\" (%lu bytes requested)",
                            name, (unsigned long) size)));
        }
        result->size = size;
        result->location = structPtr;
    }

    LWLockRelease(ShmemIndexLock);

    Assert(ShmemAddrIsValid(structPtr));
    return structPtr;
}


Variable Documentation

void* ShmemBase [static]

Definition at line 80 of file shmem.c.

Referenced by InitShmemAccess(), ShmemAddrIsValid(), and ShmemAlloc().

void* ShmemEnd [static]

Definition at line 82 of file shmem.c.

Referenced by InitShmemAccess(), and ShmemAddrIsValid().

HTAB* ShmemIndex = NULL [static]

Definition at line 87 of file shmem.c.

Definition at line 84 of file shmem.c.

Referenced by InitShmemAllocation(), LWLockAssign(), and ShmemAlloc().

Definition at line 78 of file shmem.c.