Header And Logo

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

Functions | Variables

win32_shmem.c File Reference

#include "postgres.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
Include dependency graph for win32_shmem.c:

Go to the source code of this file.

Functions

static void pgwin32_SharedMemoryDelete (int status, Datum shmId)
static char * GetSharedMemName (void)
bool PGSharedMemoryIsInUse (unsigned long id1, unsigned long id2)
PGShmemHeaderPGSharedMemoryCreate (Size size, bool makePrivate, int port)
void PGSharedMemoryReAttach (void)
void PGSharedMemoryDetach (void)
int pgwin32_ReserveSharedMemoryRegion (HANDLE hChild)

Variables

HANDLE UsedShmemSegID = 0
void * UsedShmemSegAddr = NULL
static Size UsedShmemSegSize = 0

Function Documentation

static char* GetSharedMemName ( void   )  [static]

Definition at line 39 of file win32_shmem.c.

References DataDir, elog, FATAL, malloc, and NULL.

Referenced by PGSharedMemoryCreate(), and PGSharedMemoryIsInUse().

{
    char       *retptr;
    DWORD       bufsize;
    DWORD       r;
    char       *cp;

    bufsize = GetFullPathName(DataDir, 0, NULL, NULL);
    if (bufsize == 0)
        elog(FATAL, "could not get size for full pathname of datadir %s: error code %lu",
             DataDir, GetLastError());

    retptr = malloc(bufsize + 18);      /* 18 for Global\PostgreSQL: */
    if (retptr == NULL)
        elog(FATAL, "could not allocate memory for shared memory name");

    strcpy(retptr, "Global\\PostgreSQL:");
    r = GetFullPathName(DataDir, bufsize, retptr + 18, NULL);
    if (r == 0 || r > bufsize)
        elog(FATAL, "could not generate full pathname for datadir %s: error code %lu",
             DataDir, GetLastError());

    /*
     * XXX: Intentionally overwriting the Global\ part here. This was not the
     * original approach, but putting it in the actual Global\ namespace
     * causes permission errors in a lot of cases, so we leave it in the
     * default namespace for now.
     */
    for (cp = retptr; *cp; cp++)
        if (*cp == '\\')
            *cp = '/';

    return retptr;
}

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

Definition at line 120 of file win32_shmem.c.

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

{
    void       *memAddress;
    PGShmemHeader *hdr;
    HANDLE      hmap,
                hmap2;
    char       *szShareMem;
    int         i;
    DWORD       size_high;
    DWORD       size_low;

    /* Room for a header? */
    Assert(size > MAXALIGN(sizeof(PGShmemHeader)));

    szShareMem = GetSharedMemName();

    UsedShmemSegAddr = NULL;

#ifdef _WIN64
    size_high = size >> 32;
#else
    size_high = 0;
#endif
    size_low = (DWORD) size;

    /*
     * When recycling a shared memory segment, it may take a short while
     * before it gets dropped from the global namespace. So re-try after
     * sleeping for a second, and continue retrying 10 times. (both the 1
     * second time and the 10 retries are completely arbitrary)
     */
    for (i = 0; i < 10; i++)
    {
        /*
         * In case CreateFileMapping() doesn't set the error code to 0 on
         * success
         */
        SetLastError(0);

        hmap = CreateFileMapping(INVALID_HANDLE_VALUE,  /* Use the pagefile */
                                 NULL,  /* Default security attrs */
                                 PAGE_READWRITE,        /* Memory is Read/Write */
                                 size_high,     /* Size Upper 32 Bits   */
                                 size_low,      /* Size Lower 32 bits */
                                 szShareMem);

        if (!hmap)
            ereport(FATAL,
                    (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
                     errdetail("Failed system call was CreateFileMapping(size=%lu, name=%s).",
                               (unsigned long) size, szShareMem)));

        /*
         * If the segment already existed, CreateFileMapping() will return a
         * handle to the existing one and set ERROR_ALREADY_EXISTS.
         */
        if (GetLastError() == ERROR_ALREADY_EXISTS)
        {
            CloseHandle(hmap);  /* Close the handle, since we got a valid one
                                 * to the previous segment. */
            hmap = NULL;
            Sleep(1000);
            continue;
        }
        break;
    }

    /*
     * If the last call in the loop still returned ERROR_ALREADY_EXISTS, this
     * shared memory segment exists and we assume it belongs to somebody else.
     */
    if (!hmap)
        ereport(FATAL,
                (errmsg("pre-existing shared memory block is still in use"),
                 errhint("Check if there are any old server processes still running, and terminate them.")));

    free(szShareMem);

    /*
     * Make the handle inheritable
     */
    if (!DuplicateHandle(GetCurrentProcess(), hmap, GetCurrentProcess(), &hmap2, 0, TRUE, DUPLICATE_SAME_ACCESS))
        ereport(FATAL,
                (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
                 errdetail("Failed system call was DuplicateHandle.")));

    /*
     * Close the old, non-inheritable handle. If this fails we don't really
     * care.
     */
    if (!CloseHandle(hmap))
        elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());


    /* Register on-exit routine to delete the new segment */
    on_shmem_exit(pgwin32_SharedMemoryDelete, PointerGetDatum(hmap2));

    /*
     * Get a pointer to the new shared memory segment. Map the whole segment
     * at once, and let the system decide on the initial address.
     */
    memAddress = MapViewOfFileEx(hmap2, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, NULL);
    if (!memAddress)
        ereport(FATAL,
                (errmsg("could not create shared memory segment: error code %lu", GetLastError()),
                 errdetail("Failed system call was MapViewOfFileEx.")));



    /*
     * 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->magic = PGShmemMagic;

    /*
     * Initialize space allocation status for segment.
     */
    hdr->totalsize = size;
    hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));

    /* Save info for possible future use */
    UsedShmemSegAddr = memAddress;
    UsedShmemSegSize = size;
    UsedShmemSegID = hmap2;

    return hdr;
}

void PGSharedMemoryDetach ( void   ) 

Definition at line 300 of file win32_shmem.c.

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

{
    if (UsedShmemSegAddr != NULL)
    {
        if (!UnmapViewOfFile(UsedShmemSegAddr))
            elog(LOG, "could not unmap view of shared memory: error code %lu", GetLastError());

        UsedShmemSegAddr = NULL;
    }
}

bool PGSharedMemoryIsInUse ( unsigned long  id1,
unsigned long  id2 
)

Definition at line 88 of file win32_shmem.c.

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

{
    char       *szShareMem;
    HANDLE      hmap;

    szShareMem = GetSharedMemName();

    hmap = OpenFileMapping(FILE_MAP_READ, FALSE, szShareMem);

    free(szShareMem);

    if (hmap == NULL)
        return false;

    CloseHandle(hmap);
    return true;
}

void PGSharedMemoryReAttach ( void   ) 

Definition at line 263 of file win32_shmem.c.

References Assert, elog, FATAL, IsUnderPostmaster, PGShmemHeader::magic, NULL, PGShmemMagic, UsedShmemSegAddr, and UsedShmemSegID.

{
    PGShmemHeader *hdr;
    void       *origUsedShmemSegAddr = UsedShmemSegAddr;

    Assert(UsedShmemSegAddr != NULL);
    Assert(IsUnderPostmaster);

    /*
     * Release memory region reservation that was made by the postmaster
     */
    if (VirtualFree(UsedShmemSegAddr, 0, MEM_RELEASE) == 0)
        elog(FATAL, "failed to release reserved memory region (addr=%p): error code %lu",
             UsedShmemSegAddr, GetLastError());

    hdr = (PGShmemHeader *) MapViewOfFileEx(UsedShmemSegID, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0, UsedShmemSegAddr);
    if (!hdr)
        elog(FATAL, "could not reattach to shared memory (key=%p, addr=%p): error code %lu",
             UsedShmemSegID, UsedShmemSegAddr, GetLastError());
    if (hdr != origUsedShmemSegAddr)
        elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
             hdr, origUsedShmemSegAddr);
    if (hdr->magic != PGShmemMagic)
        elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");

    UsedShmemSegAddr = hdr;     /* probably redundant */
}

int pgwin32_ReserveSharedMemoryRegion ( HANDLE  hChild  ) 

Definition at line 342 of file win32_shmem.c.

References Assert, elog, LOG, NULL, UsedShmemSegAddr, and UsedShmemSegSize.

{
    void       *address;

    Assert(UsedShmemSegAddr != NULL);
    Assert(UsedShmemSegSize != 0);

    address = VirtualAllocEx(hChild, UsedShmemSegAddr, UsedShmemSegSize,
                             MEM_RESERVE, PAGE_READWRITE);
    if (address == NULL)
    {
        /* Don't use FATAL since we're running in the postmaster */
        elog(LOG, "could not reserve shared memory region (addr=%p) for child %p: error code %lu",
             UsedShmemSegAddr, hChild, GetLastError());
        return false;
    }
    if (address != UsedShmemSegAddr)
    {
        /*
         * Should never happen - in theory if allocation granularity causes
         * strange effects it could, so check just in case.
         *
         * Don't use FATAL since we're running in the postmaster.
         */
        elog(LOG, "reserved shared memory region got incorrect address %p, expected %p",
             address, UsedShmemSegAddr);
        VirtualFreeEx(hChild, address, 0, MEM_RELEASE);
        return false;
    }

    return true;
}

static void pgwin32_SharedMemoryDelete ( int  status,
Datum  shmId 
) [static]

Definition at line 317 of file win32_shmem.c.

References DatumGetPointer, elog, LOG, and PGSharedMemoryDetach().

Referenced by PGSharedMemoryCreate().

{
    PGSharedMemoryDetach();
    if (!CloseHandle(DatumGetPointer(shmId)))
        elog(LOG, "could not close handle to shared memory: error code %lu", GetLastError());
}


Variable Documentation

void* UsedShmemSegAddr = NULL

Definition at line 20 of file win32_shmem.c.

HANDLE UsedShmemSegID = 0

Definition at line 19 of file win32_shmem.c.

Size UsedShmemSegSize = 0 [static]

Definition at line 21 of file win32_shmem.c.

Referenced by PGSharedMemoryCreate(), and pgwin32_ReserveSharedMemoryRegion().