Commit 11a65eed authored by Robert Haas's avatar Robert Haas

Get rid of the dynamic shared memory state file.

Instead of storing the ID of the dynamic shared memory control
segment in a file within the data directory, store it in the main
control segment.  This avoids a number of nasty corner cases,
most seriously that doing an online backup and then using it on
the same machine (e.g. to fire up a standby) would result in the
standby clobbering all of the master's dynamic shared memory
segments.

Per complaints from Heikki Linnakangas, Fujii Masao, and Tom
Lane.
parent 0886fc6a
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "portability/mem.h" #include "portability/mem.h"
#include "storage/dsm.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/pg_shmem.h" #include "storage/pg_shmem.h"
#include "utils/guc.h" #include "utils/guc.h"
...@@ -421,7 +422,8 @@ CreateAnonymousSegment(Size *size) ...@@ -421,7 +422,8 @@ CreateAnonymousSegment(Size *size)
* zero will be passed. * zero will be passed.
*/ */
PGShmemHeader * PGShmemHeader *
PGSharedMemoryCreate(Size size, bool makePrivate, int port) PGSharedMemoryCreate(Size size, bool makePrivate, int port,
PGShmemHeader **shim)
{ {
IpcMemoryKey NextShmemSegID; IpcMemoryKey NextShmemSegID;
void *memAddress; void *memAddress;
...@@ -509,10 +511,13 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port) ...@@ -509,10 +511,13 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
/* /*
* The segment appears to be from a dead Postgres process, or from a * 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. * 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 * This probably shouldn't fail, but if it does, assume the segment
* belongs to someone else after all, and continue quietly. * belongs to someone else after all, and continue quietly.
*/ */
if (hdr->dsm_control != 0)
dsm_cleanup_using_control_segment(hdr->dsm_control);
shmdt(memAddress); shmdt(memAddress);
if (shmctl(shmid, IPC_RMID, NULL) < 0) if (shmctl(shmid, IPC_RMID, NULL) < 0)
continue; continue;
...@@ -539,6 +544,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port) ...@@ -539,6 +544,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
hdr = (PGShmemHeader *) memAddress; hdr = (PGShmemHeader *) memAddress;
hdr->creatorPID = getpid(); hdr->creatorPID = getpid();
hdr->magic = PGShmemMagic; hdr->magic = PGShmemMagic;
hdr->dsm_control = 0;
/* Fill in the data directory ID info, too */ /* Fill in the data directory ID info, too */
if (stat(DataDir, &statbuf) < 0) if (stat(DataDir, &statbuf) < 0)
...@@ -554,6 +560,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port) ...@@ -554,6 +560,7 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
*/ */
hdr->totalsize = size; hdr->totalsize = size;
hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
*shim = hdr;
/* Save info for possible future use */ /* Save info for possible future use */
UsedShmemSegAddr = memAddress; UsedShmemSegAddr = memAddress;
...@@ -608,6 +615,7 @@ PGSharedMemoryReAttach(void) ...@@ -608,6 +615,7 @@ PGSharedMemoryReAttach(void)
if (hdr != origUsedShmemSegAddr) if (hdr != origUsedShmemSegAddr)
elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)", elog(FATAL, "reattaching to shared memory returned unexpected address (got %p, expected %p)",
hdr, origUsedShmemSegAddr); hdr, origUsedShmemSegAddr);
dsm_set_control_handle(((PGShmemHeader *) hdr)->dsm_control);
UsedShmemSegAddr = hdr; /* probably redundant */ UsedShmemSegAddr = hdr; /* probably redundant */
} }
......
...@@ -117,7 +117,8 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2) ...@@ -117,7 +117,8 @@ PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2)
* *
*/ */
PGShmemHeader * PGShmemHeader *
PGSharedMemoryCreate(Size size, bool makePrivate, int port) PGSharedMemoryCreate(Size size, bool makePrivate, int port,
PGShmemHeader **shim)
{ {
void *memAddress; void *memAddress;
PGShmemHeader *hdr; PGShmemHeader *hdr;
...@@ -245,12 +246,14 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port) ...@@ -245,12 +246,14 @@ PGSharedMemoryCreate(Size size, bool makePrivate, int port)
*/ */
hdr->totalsize = size; hdr->totalsize = size;
hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader));
hdr->dsm_control = 0;
/* Save info for possible future use */ /* Save info for possible future use */
UsedShmemSegAddr = memAddress; UsedShmemSegAddr = memAddress;
UsedShmemSegSize = size; UsedShmemSegSize = size;
UsedShmemSegID = hmap2; UsedShmemSegID = hmap2;
*shim = NULL;
return hdr; return hdr;
} }
...@@ -289,6 +292,7 @@ PGSharedMemoryReAttach(void) ...@@ -289,6 +292,7 @@ PGSharedMemoryReAttach(void)
hdr, origUsedShmemSegAddr); hdr, origUsedShmemSegAddr);
if (hdr->magic != PGShmemMagic) if (hdr->magic != PGShmemMagic)
elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory"); elog(FATAL, "reattaching to shared memory returned non-PostgreSQL memory");
dsm_set_control_handle(hdr->dsm_control);
UsedShmemSegAddr = hdr; /* probably redundant */ UsedShmemSegAddr = hdr; /* probably redundant */
} }
......
...@@ -39,13 +39,11 @@ ...@@ -39,13 +39,11 @@
#include "storage/dsm.h" #include "storage/dsm.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/lwlock.h" #include "storage/lwlock.h"
#include "storage/pg_shmem.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/resowner_private.h" #include "utils/resowner_private.h"
#define PG_DYNSHMEM_STATE_FILE PG_DYNSHMEM_DIR "/state"
#define PG_DYNSHMEM_NEW_STATE_FILE PG_DYNSHMEM_DIR "/state.new"
#define PG_DYNSHMEM_STATE_BUFSIZ 512
#define PG_DYNSHMEM_CONTROL_MAGIC 0x9a503d32 #define PG_DYNSHMEM_CONTROL_MAGIC 0x9a503d32
/* /*
...@@ -95,10 +93,7 @@ typedef struct dsm_control_header ...@@ -95,10 +93,7 @@ typedef struct dsm_control_header
dsm_control_item item[FLEXIBLE_ARRAY_MEMBER]; dsm_control_item item[FLEXIBLE_ARRAY_MEMBER];
} dsm_control_header; } dsm_control_header;
static void dsm_cleanup_using_control_segment(void);
static void dsm_cleanup_for_mmap(void); static void dsm_cleanup_for_mmap(void);
static bool dsm_read_state_file(dsm_handle *h);
static void dsm_write_state_file(dsm_handle h);
static void dsm_postmaster_shutdown(int code, Datum arg); static void dsm_postmaster_shutdown(int code, Datum arg);
static dsm_segment *dsm_create_descriptor(void); static dsm_segment *dsm_create_descriptor(void);
static bool dsm_control_segment_sane(dsm_control_header *control, static bool dsm_control_segment_sane(dsm_control_header *control,
...@@ -146,7 +141,7 @@ static void *dsm_control_impl_private = NULL; ...@@ -146,7 +141,7 @@ static void *dsm_control_impl_private = NULL;
* startup time. * startup time.
*/ */
void void
dsm_postmaster_startup(void) dsm_postmaster_startup(PGShmemHeader *shim)
{ {
void *dsm_control_address = NULL; void *dsm_control_address = NULL;
uint32 maxitems; uint32 maxitems;
...@@ -159,26 +154,13 @@ dsm_postmaster_startup(void) ...@@ -159,26 +154,13 @@ dsm_postmaster_startup(void)
return; return;
/* /*
* Check for, and remove, shared memory segments left behind by a dead * If we're using the mmap implementations, clean up any leftovers.
* postmaster. This isn't necessary on Windows, which always removes them * Cleanup isn't needed on Windows, and happens earlier in startup for
* when the last reference is gone. * POSIX and System V shared memory, via a direct call to
* dsm_cleanup_using_control_segment.
*/ */
switch (dynamic_shared_memory_type) if (dynamic_shared_memory_type == DSM_IMPL_MMAP)
{ dsm_cleanup_for_mmap();
case DSM_IMPL_POSIX:
case DSM_IMPL_SYSV:
dsm_cleanup_using_control_segment();
break;
case DSM_IMPL_MMAP:
dsm_cleanup_for_mmap();
break;
case DSM_IMPL_WINDOWS:
/* Nothing to do. */
break;
default:
elog(ERROR, "unknown dynamic shared memory type: %d",
dynamic_shared_memory_type);
}
/* Determine size for new control segment. */ /* Determine size for new control segment. */
maxitems = PG_DYNSHMEM_FIXED_SLOTS maxitems = PG_DYNSHMEM_FIXED_SLOTS
...@@ -187,23 +169,30 @@ dsm_postmaster_startup(void) ...@@ -187,23 +169,30 @@ dsm_postmaster_startup(void)
maxitems); maxitems);
segsize = dsm_control_bytes_needed(maxitems); segsize = dsm_control_bytes_needed(maxitems);
/* Loop until we find an unused identifier for the new control segment. */ /*
* Loop until we find an unused identifier for the new control segment.
* We sometimes use 0 as a sentinel value indicating that no control
* segment is known to exist, so avoid using that value for a real
* control segment.
*/
for (;;) for (;;)
{ {
Assert(dsm_control_address == NULL); Assert(dsm_control_address == NULL);
Assert(dsm_control_mapped_size == 0); Assert(dsm_control_mapped_size == 0);
dsm_control_handle = random(); dsm_control_handle = random();
if (dsm_control_handle == 0)
continue;
if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize, if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
&dsm_control_impl_private, &dsm_control_address, &dsm_control_impl_private, &dsm_control_address,
&dsm_control_mapped_size, ERROR)) &dsm_control_mapped_size, ERROR))
break; break;
} }
dsm_control = dsm_control_address; dsm_control = dsm_control_address;
on_shmem_exit(dsm_postmaster_shutdown, 0); on_shmem_exit(dsm_postmaster_shutdown, PointerGetDatum(shim));
elog(DEBUG2, elog(DEBUG2,
"created dynamic shared memory control segment %u (%zu bytes)", "created dynamic shared memory control segment %u (%zu bytes)",
dsm_control_handle, segsize); dsm_control_handle, segsize);
dsm_write_state_file(dsm_control_handle); shim->dsm_control = dsm_control_handle;
/* Initialize control segment. */ /* Initialize control segment. */
dsm_control->magic = PG_DYNSHMEM_CONTROL_MAGIC; dsm_control->magic = PG_DYNSHMEM_CONTROL_MAGIC;
...@@ -216,8 +205,8 @@ dsm_postmaster_startup(void) ...@@ -216,8 +205,8 @@ dsm_postmaster_startup(void)
* invocation still exists. If so, remove the dynamic shared memory * invocation still exists. If so, remove the dynamic shared memory
* segments to which it refers, and then the control segment itself. * segments to which it refers, and then the control segment itself.
*/ */
static void void
dsm_cleanup_using_control_segment(void) dsm_cleanup_using_control_segment(dsm_handle old_control_handle)
{ {
void *mapped_address = NULL; void *mapped_address = NULL;
void *junk_mapped_address = NULL; void *junk_mapped_address = NULL;
...@@ -227,14 +216,10 @@ dsm_cleanup_using_control_segment(void) ...@@ -227,14 +216,10 @@ dsm_cleanup_using_control_segment(void)
Size junk_mapped_size = 0; Size junk_mapped_size = 0;
uint32 nitems; uint32 nitems;
uint32 i; uint32 i;
dsm_handle old_control_handle;
dsm_control_header *old_control; dsm_control_header *old_control;
/* /* If dynamic shared memory is disabled, there's nothing to do. */
* Read the state file. If it doesn't exist or is empty, there's nothing if (dynamic_shared_memory_type == DSM_IMPL_NONE)
* more to do.
*/
if (!dsm_read_state_file(&old_control_handle))
return; return;
/* /*
...@@ -346,111 +331,6 @@ dsm_cleanup_for_mmap(void) ...@@ -346,111 +331,6 @@ dsm_cleanup_for_mmap(void)
FreeDir(dir); FreeDir(dir);
} }
/*
* Read and parse the state file.
*
* If the state file is empty or the contents are garbled, it probably means
* that the operating system rebooted before the data written by the previous
* postmaster made it to disk. In that case, we can just ignore it; any shared
* memory from before the reboot should be gone anyway.
*/
static bool
dsm_read_state_file(dsm_handle *h)
{
int statefd;
char statebuf[PG_DYNSHMEM_STATE_BUFSIZ];
int nbytes = 0;
char *endptr,
*s;
dsm_handle handle;
/* Read the state file to get the ID of the old control segment. */
statefd = BasicOpenFile(PG_DYNSHMEM_STATE_FILE, O_RDONLY | PG_BINARY, 0);
if (statefd < 0)
{
if (errno == ENOENT)
return false;
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open file \"%s\": %m",
PG_DYNSHMEM_STATE_FILE)));
}
nbytes = read(statefd, statebuf, PG_DYNSHMEM_STATE_BUFSIZ - 1);
if (nbytes < 0)
{
close(statefd);
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read file \"%s\": %m",
PG_DYNSHMEM_STATE_FILE)));
}
/* make sure buffer is NUL terminated */
statebuf[nbytes] = '\0';
close(statefd);
/*
* We expect to find the handle of the old control segment here,
* on a line by itself.
*/
handle = strtoul(statebuf, &endptr, 10);
for (s = endptr; *s == ' ' || *s == '\t'; ++s)
;
if (*s != '\n' && *s != '\0')
return false;
/* Looks good. */
*h = handle;
return true;
}
/*
* Write our control segment handle to the state file, so that if the
* postmaster is killed without running it's on_shmem_exit hooks, the
* next postmaster can clean things up after restart.
*/
static void
dsm_write_state_file(dsm_handle h)
{
int statefd;
char statebuf[PG_DYNSHMEM_STATE_BUFSIZ];
int nbytes;
/* Create or truncate the file. */
statefd = open(PG_DYNSHMEM_NEW_STATE_FILE,
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600);
if (statefd < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create file \"%s\": %m",
PG_DYNSHMEM_NEW_STATE_FILE)));
/* Write contents. */
snprintf(statebuf, PG_DYNSHMEM_STATE_BUFSIZ, "%u\n", dsm_control_handle);
nbytes = strlen(statebuf);
if (write(statefd, statebuf, nbytes) != nbytes)
{
if (errno == 0)
errno = ENOSPC; /* if no error signalled, assume no space */
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write file \"%s\": %m",
PG_DYNSHMEM_NEW_STATE_FILE)));
}
/* Close file. */
close(statefd);
/*
* Atomically rename file into place, so that no one ever sees a partially
* written state file.
*/
if (rename(PG_DYNSHMEM_NEW_STATE_FILE, PG_DYNSHMEM_STATE_FILE) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not rename file \"%s\": %m",
PG_DYNSHMEM_NEW_STATE_FILE)));
}
/* /*
* At shutdown time, we iterate over the control segment and remove all * At shutdown time, we iterate over the control segment and remove all
* remaining dynamic shared memory segments. We avoid throwing errors here; * remaining dynamic shared memory segments. We avoid throwing errors here;
...@@ -466,6 +346,7 @@ dsm_postmaster_shutdown(int code, Datum arg) ...@@ -466,6 +346,7 @@ dsm_postmaster_shutdown(int code, Datum arg)
void *junk_mapped_address = NULL; void *junk_mapped_address = NULL;
void *junk_impl_private = NULL; void *junk_impl_private = NULL;
Size junk_mapped_size = 0; Size junk_mapped_size = 0;
PGShmemHeader *shim = (PGShmemHeader *) DatumGetPointer(arg);
/* /*
* If some other backend exited uncleanly, it might have corrupted the * If some other backend exited uncleanly, it might have corrupted the
...@@ -510,13 +391,7 @@ dsm_postmaster_shutdown(int code, Datum arg) ...@@ -510,13 +391,7 @@ dsm_postmaster_shutdown(int code, Datum arg)
&dsm_control_impl_private, &dsm_control_address, &dsm_control_impl_private, &dsm_control_address,
&dsm_control_mapped_size, LOG); &dsm_control_mapped_size, LOG);
dsm_control = dsm_control_address; dsm_control = dsm_control_address;
shim->dsm_control = 0;
/* And, finally, remove the state file. */
if (unlink(PG_DYNSHMEM_STATE_FILE) < 0)
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not unlink file \"%s\": %m",
PG_DYNSHMEM_STATE_FILE)));
} }
/* /*
...@@ -536,25 +411,18 @@ dsm_backend_startup(void) ...@@ -536,25 +411,18 @@ dsm_backend_startup(void)
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
{ {
dsm_handle control_handle;
void *control_address = NULL; void *control_address = NULL;
/* Read the control segment information from the state file. */
if (!dsm_read_state_file(&control_handle))
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not parse dynamic shared memory state file")));
/* Attach control segment. */ /* Attach control segment. */
dsm_impl_op(DSM_OP_ATTACH, control_handle, 0, Assert(dsm_control_handle != 0);
dsm_impl_op(DSM_OP_ATTACH, dsm_control_handle, 0,
&dsm_control_impl_private, &control_address, &dsm_control_impl_private, &control_address,
&dsm_control_mapped_size, ERROR); &dsm_control_mapped_size, ERROR);
dsm_control_handle = control_handle;
dsm_control = control_address; dsm_control = control_address;
/* If control segment doesn't look sane, something is badly wrong. */ /* If control segment doesn't look sane, something is badly wrong. */
if (!dsm_control_segment_sane(dsm_control, dsm_control_mapped_size)) if (!dsm_control_segment_sane(dsm_control, dsm_control_mapped_size))
{ {
dsm_impl_op(DSM_OP_DETACH, control_handle, 0, dsm_impl_op(DSM_OP_DETACH, dsm_control_handle, 0,
&dsm_control_impl_private, &control_address, &dsm_control_impl_private, &control_address,
&dsm_control_mapped_size, WARNING); &dsm_control_mapped_size, WARNING);
ereport(FATAL, ereport(FATAL,
...@@ -567,6 +435,20 @@ dsm_backend_startup(void) ...@@ -567,6 +435,20 @@ dsm_backend_startup(void)
dsm_init_done = true; dsm_init_done = true;
} }
#ifdef EXEC_BACKEND
/*
* When running under EXEC_BACKEND, we get a callback here when the main
* shared memory segment is re-attached, so that we can record the control
* handle retrieved from it.
*/
void
dsm_set_control_handle(dsm_handle h)
{
Assert(dsm_control_handle == 0 && h != 0);
dsm_control_handle = h;
}
#endif
/* /*
* Create a new dynamic shared memory segment. * Create a new dynamic shared memory segment.
*/ */
......
...@@ -90,6 +90,8 @@ RequestAddinShmemSpace(Size size) ...@@ -90,6 +90,8 @@ RequestAddinShmemSpace(Size size)
void void
CreateSharedMemoryAndSemaphores(bool makePrivate, int port) CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
{ {
PGShmemHeader *shim = NULL;
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
PGShmemHeader *seghdr; PGShmemHeader *seghdr;
...@@ -149,7 +151,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ...@@ -149,7 +151,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
/* /*
* Create the shmem segment * Create the shmem segment
*/ */
seghdr = PGSharedMemoryCreate(size, makePrivate, port); seghdr = PGSharedMemoryCreate(size, makePrivate, port, &shim);
InitShmemAccess(seghdr); InitShmemAccess(seghdr);
...@@ -254,7 +256,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port) ...@@ -254,7 +256,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
/* Initialize dynamic shared memory facilities. */ /* Initialize dynamic shared memory facilities. */
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
dsm_postmaster_startup(); dsm_postmaster_startup(shim);
/* /*
* Now give loadable modules a chance to set up their shmem allocations * Now give loadable modules a chance to set up their shmem allocations
......
...@@ -18,10 +18,16 @@ ...@@ -18,10 +18,16 @@
typedef struct dsm_segment dsm_segment; typedef struct dsm_segment dsm_segment;
/* Startup and shutdown functions. */ /* Startup and shutdown functions. */
extern void dsm_postmaster_startup(void); struct PGShmemHeader; /* avoid including pg_shmem.h */
extern void dsm_cleanup_using_control_segment(dsm_handle old_control_handle);
extern void dsm_postmaster_startup(struct PGShmemHeader *);
extern void dsm_backend_shutdown(void); extern void dsm_backend_shutdown(void);
extern void dsm_detach_all(void); extern void dsm_detach_all(void);
#ifdef EXEC_BACKEND
extern void dsm_set_control_handle(dsm_handle h);
#endif
/* Functions that create, update, or remove mappings. */ /* Functions that create, update, or remove mappings. */
extern dsm_segment *dsm_create(Size size); extern dsm_segment *dsm_create(Size size);
extern dsm_segment *dsm_attach(dsm_handle h); extern dsm_segment *dsm_attach(dsm_handle h);
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#ifndef PG_SHMEM_H #ifndef PG_SHMEM_H
#define PG_SHMEM_H #define PG_SHMEM_H
#include "storage/dsm_impl.h"
typedef struct PGShmemHeader /* standard header for all Postgres shmem */ typedef struct PGShmemHeader /* standard header for all Postgres shmem */
{ {
int32 magic; /* magic # to identify Postgres segments */ int32 magic; /* magic # to identify Postgres segments */
...@@ -31,6 +33,7 @@ typedef struct PGShmemHeader /* standard header for all Postgres shmem */ ...@@ -31,6 +33,7 @@ typedef struct PGShmemHeader /* standard header for all Postgres shmem */
pid_t creatorPID; /* PID of creating process */ pid_t creatorPID; /* PID of creating process */
Size totalsize; /* total size of segment */ Size totalsize; /* total size of segment */
Size freeoffset; /* offset to first free space */ Size freeoffset; /* offset to first free space */
dsm_handle dsm_control; /* ID of dynamic shared memory control seg */
void *index; /* pointer to ShmemIndex table */ void *index; /* pointer to ShmemIndex table */
#ifndef WIN32 /* Windows doesn't have useful inode#s */ #ifndef WIN32 /* Windows doesn't have useful inode#s */
dev_t device; /* device data directory is on */ dev_t device; /* device data directory is on */
...@@ -61,7 +64,7 @@ extern void PGSharedMemoryReAttach(void); ...@@ -61,7 +64,7 @@ extern void PGSharedMemoryReAttach(void);
#endif #endif
extern PGShmemHeader *PGSharedMemoryCreate(Size size, bool makePrivate, extern PGShmemHeader *PGSharedMemoryCreate(Size size, bool makePrivate,
int port); int port, PGShmemHeader **shim);
extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2); extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2);
extern void PGSharedMemoryDetach(void); extern void PGSharedMemoryDetach(void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment