PostgreSQL Source Code  git master
dsm_impl.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include "common/file_perm.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "portability/mem.h"
#include "postmaster/postmaster.h"
#include "storage/dsm_impl.h"
#include "storage/fd.h"
#include "utils/guc.h"
#include "utils/memutils.h"
Include dependency graph for dsm_impl.c:

Go to the source code of this file.

Macros

#define ZBUFFER_SIZE   8192
 
#define SEGMENT_NAME_PREFIX   "Global/PostgreSQL"
 

Functions

static bool dsm_impl_posix (dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
 
static int dsm_impl_posix_resize (int fd, off_t size)
 
static bool dsm_impl_sysv (dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
 
static bool dsm_impl_mmap (dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
 
static int errcode_for_dynamic_shared_memory (void)
 
bool dsm_impl_op (dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
 
void dsm_impl_pin_segment (dsm_handle handle, void *impl_private, void **impl_private_pm_handle)
 
void dsm_impl_unpin_segment (dsm_handle handle, void **impl_private)
 

Variables

const struct config_enum_entry dynamic_shared_memory_options []
 
int dynamic_shared_memory_type = DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE
 
int min_dynamic_shared_memory
 

Macro Definition Documentation

◆ SEGMENT_NAME_PREFIX

#define SEGMENT_NAME_PREFIX   "Global/PostgreSQL"

Definition at line 120 of file dsm_impl.c.

◆ ZBUFFER_SIZE

#define ZBUFFER_SIZE   8192

Definition at line 118 of file dsm_impl.c.

Function Documentation

◆ dsm_impl_mmap()

static bool dsm_impl_mmap ( dsm_op  op,
dsm_handle  handle,
Size  request_size,
void **  impl_private,
void **  mapped_address,
Size mapped_size,
int  elevel 
)
static

Definition at line 791 of file dsm_impl.c.

794 {
795  char name[64];
796  int flags;
797  int fd;
798  char *address;
799 
801  handle);
802 
803  /* Handle teardown cases. */
804  if (op == DSM_OP_DETACH || op == DSM_OP_DESTROY)
805  {
806  if (*mapped_address != NULL
807  && munmap(*mapped_address, *mapped_size) != 0)
808  {
809  ereport(elevel,
811  errmsg("could not unmap shared memory segment \"%s\": %m",
812  name)));
813  return false;
814  }
815  *mapped_address = NULL;
816  *mapped_size = 0;
817  if (op == DSM_OP_DESTROY && unlink(name) != 0)
818  {
819  ereport(elevel,
821  errmsg("could not remove shared memory segment \"%s\": %m",
822  name)));
823  return false;
824  }
825  return true;
826  }
827 
828  /* Create new segment or open an existing one for attach. */
829  flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
830  if ((fd = OpenTransientFile(name, flags)) == -1)
831  {
832  if (op == DSM_OP_ATTACH || errno != EEXIST)
833  ereport(elevel,
835  errmsg("could not open shared memory segment \"%s\": %m",
836  name)));
837  return false;
838  }
839 
840  /*
841  * If we're attaching the segment, determine the current size; if we are
842  * creating the segment, set the size to the requested value.
843  */
844  if (op == DSM_OP_ATTACH)
845  {
846  struct stat st;
847 
848  if (fstat(fd, &st) != 0)
849  {
850  int save_errno;
851 
852  /* Back out what's already been done. */
853  save_errno = errno;
855  errno = save_errno;
856 
857  ereport(elevel,
859  errmsg("could not stat shared memory segment \"%s\": %m",
860  name)));
861  return false;
862  }
863  request_size = st.st_size;
864  }
865  else
866  {
867  /*
868  * Allocate a buffer full of zeros.
869  *
870  * Note: palloc zbuffer, instead of just using a local char array, to
871  * ensure it is reasonably well-aligned; this may save a few cycles
872  * transferring data to the kernel.
873  */
874  char *zbuffer = (char *) palloc0(ZBUFFER_SIZE);
875  uint32 remaining = request_size;
876  bool success = true;
877 
878  /*
879  * Zero-fill the file. We have to do this the hard way to ensure that
880  * all the file space has really been allocated, so that we don't
881  * later seg fault when accessing the memory mapping. This is pretty
882  * pessimal.
883  */
884  while (success && remaining > 0)
885  {
886  Size goal = remaining;
887 
888  if (goal > ZBUFFER_SIZE)
889  goal = ZBUFFER_SIZE;
891  if (write(fd, zbuffer, goal) == goal)
892  remaining -= goal;
893  else
894  success = false;
896  }
897 
898  if (!success)
899  {
900  int save_errno;
901 
902  /* Back out what's already been done. */
903  save_errno = errno;
905  unlink(name);
906  errno = save_errno ? save_errno : ENOSPC;
907 
908  ereport(elevel,
910  errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m",
911  name, request_size)));
912  return false;
913  }
914  }
915 
916  /* Map it. */
917  address = mmap(NULL, request_size, PROT_READ | PROT_WRITE,
918  MAP_SHARED | MAP_HASSEMAPHORE | MAP_NOSYNC, fd, 0);
919  if (address == MAP_FAILED)
920  {
921  int save_errno;
922 
923  /* Back out what's already been done. */
924  save_errno = errno;
926  if (op == DSM_OP_CREATE)
927  unlink(name);
928  errno = save_errno;
929 
930  ereport(elevel,
932  errmsg("could not map shared memory segment \"%s\": %m",
933  name)));
934  return false;
935  }
936  *mapped_address = address;
937  *mapped_size = request_size;
938 
939  if (CloseTransientFile(fd) != 0)
940  {
941  ereport(elevel,
943  errmsg("could not close shared memory segment \"%s\": %m",
944  name)));
945  return false;
946  }
947 
948  return true;
949 }
unsigned int uint32
Definition: c.h:442
size_t Size
Definition: c.h:541
static int errcode_for_dynamic_shared_memory(void)
Definition: dsm_impl.c:1046
#define ZBUFFER_SIZE
Definition: dsm_impl.c:118
@ DSM_OP_DETACH
Definition: dsm_impl.h:62
@ DSM_OP_CREATE
Definition: dsm_impl.h:60
@ DSM_OP_DESTROY
Definition: dsm_impl.h:63
@ DSM_OP_ATTACH
Definition: dsm_impl.h:61
#define PG_DYNSHMEM_MMAP_FILE_PREFIX
Definition: dsm_impl.h:52
#define PG_DYNSHMEM_DIR
Definition: dsm_impl.h:51
int errcode_for_file_access(void)
Definition: elog.c:718
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define ereport(elevel,...)
Definition: elog.h:145
const char * name
Definition: encode.c:561
int CloseTransientFile(int fd)
Definition: fd.c:2609
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2433
int remaining
Definition: informix.c:667
static bool success
Definition: initdb.c:170
#define write(a, b, c)
Definition: win32.h:14
void * palloc0(Size size)
Definition: mcxt.c:1230
#define MAP_FAILED
Definition: mem.h:45
#define MAP_HASSEMAPHORE
Definition: mem.h:30
#define MAP_NOSYNC
Definition: mem.h:38
#define snprintf
Definition: port.h:238
static int fd(const char *x, int i)
Definition: preproc-init.c:105
@ WAIT_EVENT_DSM_FILL_ZERO_WRITE
Definition: wait_event.h:183
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:268
static void pgstat_report_wait_end(void)
Definition: wait_event.h:284
#define fstat
Definition: win32_port.h:285

References CloseTransientFile(), DSM_OP_ATTACH, DSM_OP_CREATE, DSM_OP_DESTROY, DSM_OP_DETACH, ereport, errcode_for_dynamic_shared_memory(), errcode_for_file_access(), errmsg(), fd(), fstat, MAP_FAILED, MAP_HASSEMAPHORE, MAP_NOSYNC, name, OpenTransientFile(), palloc0(), PG_DYNSHMEM_DIR, PG_DYNSHMEM_MMAP_FILE_PREFIX, pgstat_report_wait_end(), pgstat_report_wait_start(), remaining, snprintf, stat::st_size, success, WAIT_EVENT_DSM_FILL_ZERO_WRITE, write, and ZBUFFER_SIZE.

Referenced by dsm_impl_op().

◆ dsm_impl_op()

bool dsm_impl_op ( dsm_op  op,
dsm_handle  handle,
Size  request_size,
void **  impl_private,
void **  mapped_address,
Size mapped_size,
int  elevel 
)

Definition at line 159 of file dsm_impl.c.

162 {
163  Assert(op == DSM_OP_CREATE || request_size == 0);
164  Assert((op != DSM_OP_CREATE && op != DSM_OP_ATTACH) ||
165  (*mapped_address == NULL && *mapped_size == 0));
166 
168  {
169 #ifdef USE_DSM_POSIX
170  case DSM_IMPL_POSIX:
171  return dsm_impl_posix(op, handle, request_size, impl_private,
172  mapped_address, mapped_size, elevel);
173 #endif
174 #ifdef USE_DSM_SYSV
175  case DSM_IMPL_SYSV:
176  return dsm_impl_sysv(op, handle, request_size, impl_private,
177  mapped_address, mapped_size, elevel);
178 #endif
179 #ifdef USE_DSM_WINDOWS
180  case DSM_IMPL_WINDOWS:
181  return dsm_impl_windows(op, handle, request_size, impl_private,
182  mapped_address, mapped_size, elevel);
183 #endif
184 #ifdef USE_DSM_MMAP
185  case DSM_IMPL_MMAP:
186  return dsm_impl_mmap(op, handle, request_size, impl_private,
187  mapped_address, mapped_size, elevel);
188 #endif
189  default:
190  elog(ERROR, "unexpected dynamic shared memory type: %d",
192  return false;
193  }
194 }
int dynamic_shared_memory_type
Definition: dsm_impl.c:112
static bool dsm_impl_sysv(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
Definition: dsm_impl.c:422
static bool dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
Definition: dsm_impl.c:212
static bool dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size, void **impl_private, void **mapped_address, Size *mapped_size, int elevel)
Definition: dsm_impl.c:791
#define DSM_IMPL_WINDOWS
Definition: dsm_impl.h:19
#define DSM_IMPL_POSIX
Definition: dsm_impl.h:17
#define DSM_IMPL_SYSV
Definition: dsm_impl.h:18
#define DSM_IMPL_MMAP
Definition: dsm_impl.h:20
#define ERROR
Definition: elog.h:35
Assert(fmt[strlen(fmt) - 1] !='\n')

References Assert(), dsm_impl_mmap(), DSM_IMPL_MMAP, dsm_impl_posix(), DSM_IMPL_POSIX, dsm_impl_sysv(), DSM_IMPL_SYSV, DSM_IMPL_WINDOWS, DSM_OP_ATTACH, DSM_OP_CREATE, dynamic_shared_memory_type, elog(), and ERROR.

Referenced by dsm_attach(), dsm_backend_startup(), dsm_cleanup_using_control_segment(), dsm_create(), dsm_detach(), dsm_detach_all(), dsm_postmaster_shutdown(), dsm_postmaster_startup(), and dsm_unpin_segment().

◆ dsm_impl_pin_segment()

void dsm_impl_pin_segment ( dsm_handle  handle,
void *  impl_private,
void **  impl_private_pm_handle 
)

Definition at line 962 of file dsm_impl.c.

964 {
966  {
967 #ifdef USE_DSM_WINDOWS
968  case DSM_IMPL_WINDOWS:
969  if (IsUnderPostmaster)
970  {
971  HANDLE hmap;
972 
973  if (!DuplicateHandle(GetCurrentProcess(), impl_private,
974  PostmasterHandle, &hmap, 0, FALSE,
975  DUPLICATE_SAME_ACCESS))
976  {
977  char name[64];
978 
979  snprintf(name, 64, "%s.%u", SEGMENT_NAME_PREFIX, handle);
980  _dosmaperr(GetLastError());
981  ereport(ERROR,
983  errmsg("could not duplicate handle for \"%s\": %m",
984  name)));
985  }
986 
987  /*
988  * Here, we remember the handle that we created in the
989  * postmaster process. This handle isn't actually usable in
990  * any process other than the postmaster, but that doesn't
991  * matter. We're just holding onto it so that, if the segment
992  * is unpinned, dsm_impl_unpin_segment can close it.
993  */
994  *impl_private_pm_handle = hmap;
995  }
996  break;
997 #endif
998  default:
999  break;
1000  }
1001 }
#define SEGMENT_NAME_PREFIX
Definition: dsm_impl.c:120
bool IsUnderPostmaster
Definition: globals.c:113
void _dosmaperr(unsigned long)
Definition: win32error.c:177

References _dosmaperr(), DSM_IMPL_WINDOWS, dynamic_shared_memory_type, ereport, errcode_for_dynamic_shared_memory(), errmsg(), ERROR, IsUnderPostmaster, name, SEGMENT_NAME_PREFIX, and snprintf.

Referenced by dsm_pin_segment().

◆ dsm_impl_posix()

static bool dsm_impl_posix ( dsm_op  op,
dsm_handle  handle,
Size  request_size,
void **  impl_private,
void **  mapped_address,
Size mapped_size,
int  elevel 
)
static

Definition at line 212 of file dsm_impl.c.

215 {
216  char name[64];
217  int flags;
218  int fd;
219  char *address;
220 
221  snprintf(name, 64, "/PostgreSQL.%u", handle);
222 
223  /* Handle teardown cases. */
224  if (op == DSM_OP_DETACH || op == DSM_OP_DESTROY)
225  {
226  if (*mapped_address != NULL
227  && munmap(*mapped_address, *mapped_size) != 0)
228  {
229  ereport(elevel,
231  errmsg("could not unmap shared memory segment \"%s\": %m",
232  name)));
233  return false;
234  }
235  *mapped_address = NULL;
236  *mapped_size = 0;
237  if (op == DSM_OP_DESTROY && shm_unlink(name) != 0)
238  {
239  ereport(elevel,
241  errmsg("could not remove shared memory segment \"%s\": %m",
242  name)));
243  return false;
244  }
245  return true;
246  }
247 
248  /*
249  * Create new segment or open an existing one for attach.
250  *
251  * Even though we will close the FD before returning, it seems desirable
252  * to use Reserve/ReleaseExternalFD, to reduce the probability of EMFILE
253  * failure. The fact that we won't hold the FD open long justifies using
254  * ReserveExternalFD rather than AcquireExternalFD, though.
255  */
257 
258  flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
259  if ((fd = shm_open(name, flags, PG_FILE_MODE_OWNER)) == -1)
260  {
262  if (op == DSM_OP_ATTACH || errno != EEXIST)
263  ereport(elevel,
265  errmsg("could not open shared memory segment \"%s\": %m",
266  name)));
267  return false;
268  }
269 
270  /*
271  * If we're attaching the segment, determine the current size; if we are
272  * creating the segment, set the size to the requested value.
273  */
274  if (op == DSM_OP_ATTACH)
275  {
276  struct stat st;
277 
278  if (fstat(fd, &st) != 0)
279  {
280  int save_errno;
281 
282  /* Back out what's already been done. */
283  save_errno = errno;
284  close(fd);
286  errno = save_errno;
287 
288  ereport(elevel,
290  errmsg("could not stat shared memory segment \"%s\": %m",
291  name)));
292  return false;
293  }
294  request_size = st.st_size;
295  }
296  else if (dsm_impl_posix_resize(fd, request_size) != 0)
297  {
298  int save_errno;
299 
300  /* Back out what's already been done. */
301  save_errno = errno;
302  close(fd);
304  shm_unlink(name);
305  errno = save_errno;
306 
307  ereport(elevel,
309  errmsg("could not resize shared memory segment \"%s\" to %zu bytes: %m",
310  name, request_size)));
311  return false;
312  }
313 
314  /* Map it. */
315  address = mmap(NULL, request_size, PROT_READ | PROT_WRITE,
316  MAP_SHARED | MAP_HASSEMAPHORE | MAP_NOSYNC, fd, 0);
317  if (address == MAP_FAILED)
318  {
319  int save_errno;
320 
321  /* Back out what's already been done. */
322  save_errno = errno;
323  close(fd);
325  if (op == DSM_OP_CREATE)
326  shm_unlink(name);
327  errno = save_errno;
328 
329  ereport(elevel,
331  errmsg("could not map shared memory segment \"%s\": %m",
332  name)));
333  return false;
334  }
335  *mapped_address = address;
336  *mapped_size = request_size;
337  close(fd);
339 
340  return true;
341 }
static int dsm_impl_posix_resize(int fd, off_t size)
Definition: dsm_impl.c:351
void ReleaseExternalFD(void)
Definition: fd.c:1152
void ReserveExternalFD(void)
Definition: fd.c:1134
#define PG_FILE_MODE_OWNER
Definition: file_perm.h:38
#define close(a)
Definition: win32.h:12

References close, dsm_impl_posix_resize(), DSM_OP_ATTACH, DSM_OP_CREATE, DSM_OP_DESTROY, DSM_OP_DETACH, ereport, errcode_for_dynamic_shared_memory(), errmsg(), fd(), fstat, MAP_FAILED, MAP_HASSEMAPHORE, MAP_NOSYNC, name, PG_FILE_MODE_OWNER, ReleaseExternalFD(), ReserveExternalFD(), snprintf, and stat::st_size.

Referenced by dsm_impl_op().

◆ dsm_impl_posix_resize()

static int dsm_impl_posix_resize ( int  fd,
off_t  size 
)
static

Definition at line 351 of file dsm_impl.c.

352 {
353  int rc;
354  int save_errno;
355  sigset_t save_sigmask;
356 
357  /*
358  * Block all blockable signals, except SIGQUIT. posix_fallocate() can run
359  * for quite a long time, and is an all-or-nothing operation. If we
360  * allowed SIGUSR1 to interrupt us repeatedly (for example, due to recovery
361  * conflicts), the retry loop might never succeed.
362  */
363  if (IsUnderPostmaster)
364  sigprocmask(SIG_SETMASK, &BlockSig, &save_sigmask);
365 
367 #if defined(HAVE_POSIX_FALLOCATE) && defined(__linux__)
368  /*
369  * On Linux, a shm_open fd is backed by a tmpfs file. If we were to use
370  * ftruncate, the file would contain a hole. Accessing memory backed by a
371  * hole causes tmpfs to allocate pages, which fails with SIGBUS if there
372  * is no more tmpfs space available. So we ask tmpfs to allocate pages
373  * here, so we can fail gracefully with ENOSPC now rather than risking
374  * SIGBUS later.
375  *
376  * We still use a traditional EINTR retry loop to handle SIGCONT.
377  * posix_fallocate() doesn't restart automatically, and we don't want
378  * this to fail if you attach a debugger.
379  */
380  do
381  {
382  rc = posix_fallocate(fd, 0, size);
383  } while (rc == EINTR);
384 
385  /*
386  * The caller expects errno to be set, but posix_fallocate() doesn't
387  * set it. Instead it returns error numbers directly. So set errno,
388  * even though we'll also return rc to indicate success or failure.
389  */
390  errno = rc;
391 #else
392  /* Extend the file to the requested size. */
393  do
394  {
395  rc = ftruncate(fd, size);
396  } while (rc < 0 && errno == EINTR);
397 #endif
399 
400  if (IsUnderPostmaster)
401  {
402  save_errno = errno;
403  sigprocmask(SIG_SETMASK, &save_sigmask, NULL);
404  errno = save_errno;
405  }
406 
407  return rc;
408 }
sigset_t BlockSig
Definition: pqsignal.c:23
@ WAIT_EVENT_DSM_ALLOCATE
Definition: wait_event.h:182
#define EINTR
Definition: win32_port.h:369
#define ftruncate(a, b)
Definition: win32_port.h:82

References BlockSig, EINTR, fd(), ftruncate, IsUnderPostmaster, pgstat_report_wait_end(), pgstat_report_wait_start(), and WAIT_EVENT_DSM_ALLOCATE.

Referenced by dsm_impl_posix().

◆ dsm_impl_sysv()

static bool dsm_impl_sysv ( dsm_op  op,
dsm_handle  handle,
Size  request_size,
void **  impl_private,
void **  mapped_address,
Size mapped_size,
int  elevel 
)
static

Definition at line 422 of file dsm_impl.c.

425 {
426  key_t key;
427  int ident;
428  char *address;
429  char name[64];
430  int *ident_cache;
431 
432  /*
433  * POSIX shared memory and mmap-based shared memory identify segments with
434  * names. To avoid needless error message variation, we use the handle as
435  * the name.
436  */
437  snprintf(name, 64, "%u", handle);
438 
439  /*
440  * The System V shared memory namespace is very restricted; names are of
441  * type key_t, which is expected to be some sort of integer data type, but
442  * not necessarily the same one as dsm_handle. Since we use dsm_handle to
443  * identify shared memory segments across processes, this might seem like
444  * a problem, but it's really not. If dsm_handle is bigger than key_t,
445  * the cast below might truncate away some bits from the handle the
446  * user-provided, but it'll truncate exactly the same bits away in exactly
447  * the same fashion every time we use that handle, which is all that
448  * really matters. Conversely, if dsm_handle is smaller than key_t, we
449  * won't use the full range of available key space, but that's no big deal
450  * either.
451  *
452  * We do make sure that the key isn't negative, because that might not be
453  * portable.
454  */
455  key = (key_t) handle;
456  if (key < 1) /* avoid compiler warning if type is unsigned */
457  key = -key;
458 
459  /*
460  * There's one special key, IPC_PRIVATE, which can't be used. If we end
461  * up with that value by chance during a create operation, just pretend it
462  * already exists, so that caller will retry. If we run into it anywhere
463  * else, the caller has passed a handle that doesn't correspond to
464  * anything we ever created, which should not happen.
465  */
466  if (key == IPC_PRIVATE)
467  {
468  if (op != DSM_OP_CREATE)
469  elog(DEBUG4, "System V shared memory key may not be IPC_PRIVATE");
470  errno = EEXIST;
471  return false;
472  }
473 
474  /*
475  * Before we can do anything with a shared memory segment, we have to map
476  * the shared memory key to a shared memory identifier using shmget(). To
477  * avoid repeated lookups, we store the key using impl_private.
478  */
479  if (*impl_private != NULL)
480  {
481  ident_cache = *impl_private;
482  ident = *ident_cache;
483  }
484  else
485  {
486  int flags = IPCProtection;
487  size_t segsize;
488 
489  /*
490  * Allocate the memory BEFORE acquiring the resource, so that we don't
491  * leak the resource if memory allocation fails.
492  */
493  ident_cache = MemoryContextAlloc(TopMemoryContext, sizeof(int));
494 
495  /*
496  * When using shmget to find an existing segment, we must pass the
497  * size as 0. Passing a non-zero size which is greater than the
498  * actual size will result in EINVAL.
499  */
500  segsize = 0;
501 
502  if (op == DSM_OP_CREATE)
503  {
504  flags |= IPC_CREAT | IPC_EXCL;
505  segsize = request_size;
506  }
507 
508  if ((ident = shmget(key, segsize, flags)) == -1)
509  {
510  if (op == DSM_OP_ATTACH || errno != EEXIST)
511  {
512  int save_errno = errno;
513 
514  pfree(ident_cache);
515  errno = save_errno;
516  ereport(elevel,
518  errmsg("could not get shared memory segment: %m")));
519  }
520  return false;
521  }
522 
523  *ident_cache = ident;
524  *impl_private = ident_cache;
525  }
526 
527  /* Handle teardown cases. */
528  if (op == DSM_OP_DETACH || op == DSM_OP_DESTROY)
529  {
530  pfree(ident_cache);
531  *impl_private = NULL;
532  if (*mapped_address != NULL && shmdt(*mapped_address) != 0)
533  {
534  ereport(elevel,
536  errmsg("could not unmap shared memory segment \"%s\": %m",
537  name)));
538  return false;
539  }
540  *mapped_address = NULL;
541  *mapped_size = 0;
542  if (op == DSM_OP_DESTROY && shmctl(ident, IPC_RMID, NULL) < 0)
543  {
544  ereport(elevel,
546  errmsg("could not remove shared memory segment \"%s\": %m",
547  name)));
548  return false;
549  }
550  return true;
551  }
552 
553  /* If we're attaching it, we must use IPC_STAT to determine the size. */
554  if (op == DSM_OP_ATTACH)
555  {
556  struct shmid_ds shm;
557 
558  if (shmctl(ident, IPC_STAT, &shm) != 0)
559  {
560  ereport(elevel,
562  errmsg("could not stat shared memory segment \"%s\": %m",
563  name)));
564  return false;
565  }
566  request_size = shm.shm_segsz;
567  }
568 
569  /* Map it. */
570  address = shmat(ident, NULL, PG_SHMAT_FLAGS);
571  if (address == (void *) -1)
572  {
573  int save_errno;
574 
575  /* Back out what's already been done. */
576  save_errno = errno;
577  if (op == DSM_OP_CREATE)
578  shmctl(ident, IPC_RMID, NULL);
579  errno = save_errno;
580 
581  ereport(elevel,
583  errmsg("could not map shared memory segment \"%s\": %m",
584  name)));
585  return false;
586  }
587  *mapped_address = address;
588  *mapped_size = request_size;
589 
590  return true;
591 }
#define DEBUG4
Definition: elog.h:23
void pfree(void *pointer)
Definition: mcxt.c:1306
MemoryContext TopMemoryContext
Definition: mcxt.c:130
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:994
#define PG_SHMAT_FLAGS
Definition: mem.h:20
#define IPCProtection
Definition: posix_sema.c:59
#define IPC_STAT
Definition: win32_port.h:108
#define IPC_RMID
Definition: win32_port.h:103
long key_t
Definition: win32_port.h:249
#define IPC_EXCL
Definition: win32_port.h:105
#define IPC_CREAT
Definition: win32_port.h:104
#define IPC_PRIVATE
Definition: win32_port.h:106

References DEBUG4, DSM_OP_ATTACH, DSM_OP_CREATE, DSM_OP_DESTROY, DSM_OP_DETACH, elog(), ereport, errcode_for_dynamic_shared_memory(), errmsg(), IPC_CREAT, IPC_EXCL, IPC_PRIVATE, IPC_RMID, IPC_STAT, IPCProtection, sort-test::key, MemoryContextAlloc(), name, pfree(), PG_SHMAT_FLAGS, snprintf, and TopMemoryContext.

Referenced by dsm_impl_op().

◆ dsm_impl_unpin_segment()

void dsm_impl_unpin_segment ( dsm_handle  handle,
void **  impl_private 
)

Definition at line 1013 of file dsm_impl.c.

1014 {
1016  {
1017 #ifdef USE_DSM_WINDOWS
1018  case DSM_IMPL_WINDOWS:
1019  if (IsUnderPostmaster)
1020  {
1021  if (*impl_private &&
1022  !DuplicateHandle(PostmasterHandle, *impl_private,
1023  NULL, NULL, 0, FALSE,
1024  DUPLICATE_CLOSE_SOURCE))
1025  {
1026  char name[64];
1027 
1028  snprintf(name, 64, "%s.%u", SEGMENT_NAME_PREFIX, handle);
1029  _dosmaperr(GetLastError());
1030  ereport(ERROR,
1032  errmsg("could not duplicate handle for \"%s\": %m",
1033  name)));
1034  }
1035 
1036  *impl_private = NULL;
1037  }
1038  break;
1039 #endif
1040  default:
1041  break;
1042  }
1043 }

References _dosmaperr(), DSM_IMPL_WINDOWS, dynamic_shared_memory_type, ereport, errcode_for_dynamic_shared_memory(), errmsg(), ERROR, IsUnderPostmaster, name, SEGMENT_NAME_PREFIX, and snprintf.

Referenced by dsm_unpin_segment().

◆ errcode_for_dynamic_shared_memory()

static int errcode_for_dynamic_shared_memory ( void  )
static

Definition at line 1046 of file dsm_impl.c.

1047 {
1048  if (errno == EFBIG || errno == ENOMEM)
1049  return errcode(ERRCODE_OUT_OF_MEMORY);
1050  else
1051  return errcode_for_file_access();
1052 }
int errcode(int sqlerrcode)
Definition: elog.c:695

References errcode(), and errcode_for_file_access().

Referenced by dsm_impl_mmap(), dsm_impl_pin_segment(), dsm_impl_posix(), dsm_impl_sysv(), and dsm_impl_unpin_segment().

Variable Documentation

◆ dynamic_shared_memory_options

const struct config_enum_entry dynamic_shared_memory_options[]
Initial value:
= {
{"posix", DSM_IMPL_POSIX, false},
{"sysv", DSM_IMPL_SYSV, false},
{"mmap", DSM_IMPL_MMAP, false},
{NULL, 0, false}
}

Definition at line 93 of file dsm_impl.c.

◆ dynamic_shared_memory_type

int dynamic_shared_memory_type = DEFAULT_DYNAMIC_SHARED_MEMORY_TYPE

◆ min_dynamic_shared_memory

int min_dynamic_shared_memory

Definition at line 115 of file dsm_impl.c.

Referenced by dsm_estimate_size().