PostgreSQL Source Code  git master
dsm.h File Reference
#include "storage/dsm_impl.h"
Include dependency graph for dsm.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define DSM_CREATE_NULL_IF_MAXSEGMENTS   0x0001
 
#define DSM_HANDLE_INVALID   0
 

Typedefs

typedef struct dsm_segment dsm_segment
 
typedef void(* on_dsm_detach_callback) (dsm_segment *, Datum arg)
 

Functions

void dsm_cleanup_using_control_segment (dsm_handle old_control_handle)
 
void dsm_postmaster_startup (struct PGShmemHeader *)
 
void dsm_backend_shutdown (void)
 
void dsm_detach_all (void)
 
size_t dsm_estimate_size (void)
 
void dsm_shmem_init (void)
 
dsm_segmentdsm_create (Size size, int flags)
 
dsm_segmentdsm_attach (dsm_handle h)
 
void dsm_detach (dsm_segment *seg)
 
void dsm_pin_mapping (dsm_segment *seg)
 
void dsm_unpin_mapping (dsm_segment *seg)
 
void dsm_pin_segment (dsm_segment *seg)
 
void dsm_unpin_segment (dsm_handle h)
 
dsm_segmentdsm_find_mapping (dsm_handle h)
 
void * dsm_segment_address (dsm_segment *seg)
 
Size dsm_segment_map_length (dsm_segment *seg)
 
dsm_handle dsm_segment_handle (dsm_segment *seg)
 
void on_dsm_detach (dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
 
void cancel_on_dsm_detach (dsm_segment *seg, on_dsm_detach_callback function, Datum arg)
 
void reset_on_dsm_detach (void)
 

Macro Definition Documentation

◆ DSM_CREATE_NULL_IF_MAXSEGMENTS

#define DSM_CREATE_NULL_IF_MAXSEGMENTS   0x0001

Definition at line 20 of file dsm.h.

◆ DSM_HANDLE_INVALID

#define DSM_HANDLE_INVALID   0

Definition at line 23 of file dsm.h.

Typedef Documentation

◆ dsm_segment

typedef struct dsm_segment dsm_segment

Definition at line 1 of file dsm.h.

◆ on_dsm_detach_callback

typedef void(* on_dsm_detach_callback) (dsm_segment *, Datum arg)

Definition at line 57 of file dsm.h.

Function Documentation

◆ cancel_on_dsm_detach()

void cancel_on_dsm_detach ( dsm_segment seg,
on_dsm_detach_callback  function,
Datum  arg 
)

Definition at line 1114 of file dsm.c.

1116 {
1117  slist_mutable_iter iter;
1118 
1119  slist_foreach_modify(iter, &seg->on_detach)
1120  {
1122 
1124  if (cb->function == function && cb->arg == arg)
1125  {
1126  slist_delete_current(&iter);
1127  pfree(cb);
1128  break;
1129  }
1130  }
1131 }
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:671
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:735
#define slist_container(type, membername, ptr)
Definition: ilist.h:693
void pfree(void *pointer)
Definition: mcxt.c:1169
void * arg
on_dsm_detach_callback function
Definition: dsm.c:59
slist_head on_detach
Definition: dsm.c:74
slist_node * cur
Definition: ilist.h:241

References dsm_segment_detach_callback::arg, arg, slist_mutable_iter::cur, dsm_segment_detach_callback::function, dsm_segment::on_detach, pfree(), slist_container, slist_delete_current(), and slist_foreach_modify.

Referenced by shm_mq_detach(), and test_shm_mq_setup().

◆ dsm_attach()

dsm_segment* dsm_attach ( dsm_handle  h)

Definition at line 634 of file dsm.c.

635 {
636  dsm_segment *seg;
637  dlist_iter iter;
638  uint32 i;
639  uint32 nitems;
640 
641  /* Unsafe in postmaster (and pointless in a stand-alone backend). */
643 
644  if (!dsm_init_done)
646 
647  /*
648  * Since this is just a debugging cross-check, we could leave it out
649  * altogether, or include it only in assert-enabled builds. But since the
650  * list of attached segments should normally be very short, let's include
651  * it always for right now.
652  *
653  * If you're hitting this error, you probably want to attempt to find an
654  * existing mapping via dsm_find_mapping() before calling dsm_attach() to
655  * create a new one.
656  */
658  {
659  seg = dlist_container(dsm_segment, node, iter.cur);
660  if (seg->handle == h)
661  elog(ERROR, "can't attach the same segment more than once");
662  }
663 
664  /* Create a new segment descriptor. */
665  seg = dsm_create_descriptor();
666  seg->handle = h;
667 
668  /* Bump reference count for this segment in shared memory. */
669  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
670  nitems = dsm_control->nitems;
671  for (i = 0; i < nitems; ++i)
672  {
673  /*
674  * If the reference count is 0, the slot is actually unused. If the
675  * reference count is 1, the slot is still in use, but the segment is
676  * in the process of going away; even if the handle matches, another
677  * slot may already have started using the same handle value by
678  * coincidence so we have to keep searching.
679  */
680  if (dsm_control->item[i].refcnt <= 1)
681  continue;
682 
683  /* If the handle doesn't match, it's not the slot we want. */
684  if (dsm_control->item[i].handle != seg->handle)
685  continue;
686 
687  /* Otherwise we've found a match. */
688  dsm_control->item[i].refcnt++;
689  seg->control_slot = i;
691  {
692  seg->mapped_address = (char *) dsm_main_space_begin +
695  }
696  break;
697  }
698  LWLockRelease(DynamicSharedMemoryControlLock);
699 
700  /*
701  * If we didn't find the handle we're looking for in the control segment,
702  * it probably means that everyone else who had it mapped, including the
703  * original creator, died before we got to this point. It's up to the
704  * caller to decide what to do about that.
705  */
707  {
708  dsm_detach(seg);
709  return NULL;
710  }
711 
712  /* Here's where we actually try to map the segment. */
715  &seg->mapped_address, &seg->mapped_size, ERROR);
716 
717  return seg;
718 }
unsigned int uint32
Definition: c.h:441
static void dsm_backend_startup(void)
Definition: dsm.c:397
static void * dsm_main_space_begin
Definition: dsm.c:110
void dsm_detach(dsm_segment *seg)
Definition: dsm.c:772
static dlist_head dsm_segment_list
Definition: dsm.c:129
static bool dsm_init_done
Definition: dsm.c:107
static dsm_control_header * dsm_control
Definition: dsm.c:139
static dsm_segment * dsm_create_descriptor(void)
Definition: dsm.c:1168
#define INVALID_CONTROL_SLOT
Definition: dsm.c:54
static bool is_main_region_dsm_handle(dsm_handle handle)
Definition: dsm.c:1248
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: dsm_impl.c:161
@ DSM_OP_ATTACH
Definition: dsm_impl.h:61
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define FPM_PAGE_SIZE
Definition: freepage.h:30
bool IsUnderPostmaster
Definition: globals.c:112
#define dlist_foreach(iter, lhead)
Definition: ilist.h:526
#define dlist_container(type, membername, ptr)
Definition: ilist.h:496
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
@ LW_EXCLUSIVE
Definition: lwlock.h:104
dlist_node * cur
Definition: ilist.h:161
uint32 nitems
Definition: dsm.c:92
dsm_control_item item[FLEXIBLE_ARRAY_MEMBER]
Definition: dsm.c:94
size_t npages
Definition: dsm.c:83
dsm_handle handle
Definition: dsm.c:80
size_t first_page
Definition: dsm.c:82
uint32 refcnt
Definition: dsm.c:81
uint32 control_slot
Definition: dsm.c:70
dsm_handle handle
Definition: dsm.c:69
Size mapped_size
Definition: dsm.c:73
void * impl_private
Definition: dsm.c:71
void * mapped_address
Definition: dsm.c:72

References Assert(), dsm_segment::control_slot, dlist_iter::cur, dlist_container, dlist_foreach, dsm_backend_startup(), dsm_control, dsm_create_descriptor(), dsm_detach(), dsm_impl_op(), dsm_init_done, dsm_main_space_begin, DSM_OP_ATTACH, dsm_segment_list, elog, ERROR, dsm_control_item::first_page, FPM_PAGE_SIZE, dsm_segment::handle, dsm_control_item::handle, i, dsm_segment::impl_private, INVALID_CONTROL_SLOT, is_main_region_dsm_handle(), IsUnderPostmaster, dsm_control_header::item, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), dsm_segment::mapped_address, dsm_segment::mapped_size, dsm_control_header::nitems, dsm_control_item::npages, and dsm_control_item::refcnt.

Referenced by AttachSession(), autoprewarm_database_main(), dsa_attach(), get_segment_by_index(), ParallelWorkerMain(), and test_shm_mq_main().

◆ dsm_backend_shutdown()

void dsm_backend_shutdown ( void  )

Definition at line 726 of file dsm.c.

727 {
729  {
730  dsm_segment *seg;
731 
733  dsm_detach(seg);
734  }
735 }
#define dlist_head_element(type, membername, lhead)
Definition: ilist.h:506
static bool dlist_is_empty(dlist_head *head)
Definition: ilist.h:289

References dlist_head_element, dlist_is_empty(), dsm_detach(), and dsm_segment_list.

Referenced by shmem_exit().

◆ dsm_cleanup_using_control_segment()

void dsm_cleanup_using_control_segment ( dsm_handle  old_control_handle)

Definition at line 212 of file dsm.c.

213 {
214  void *mapped_address = NULL;
215  void *junk_mapped_address = NULL;
216  void *impl_private = NULL;
217  void *junk_impl_private = NULL;
218  Size mapped_size = 0;
219  Size junk_mapped_size = 0;
220  uint32 nitems;
221  uint32 i;
222  dsm_control_header *old_control;
223 
224  /*
225  * Try to attach the segment. If this fails, it probably just means that
226  * the operating system has been rebooted and the segment no longer
227  * exists, or an unrelated process has used the same shm ID. So just fall
228  * out quietly.
229  */
230  if (!dsm_impl_op(DSM_OP_ATTACH, old_control_handle, 0, &impl_private,
231  &mapped_address, &mapped_size, DEBUG1))
232  return;
233 
234  /*
235  * We've managed to reattach it, but the contents might not be sane. If
236  * they aren't, we disregard the segment after all.
237  */
238  old_control = (dsm_control_header *) mapped_address;
239  if (!dsm_control_segment_sane(old_control, mapped_size))
240  {
241  dsm_impl_op(DSM_OP_DETACH, old_control_handle, 0, &impl_private,
242  &mapped_address, &mapped_size, LOG);
243  return;
244  }
245 
246  /*
247  * OK, the control segment looks basically valid, so we can use it to get
248  * a list of segments that need to be removed.
249  */
250  nitems = old_control->nitems;
251  for (i = 0; i < nitems; ++i)
252  {
253  dsm_handle handle;
254  uint32 refcnt;
255 
256  /* If the reference count is 0, the slot is actually unused. */
257  refcnt = old_control->item[i].refcnt;
258  if (refcnt == 0)
259  continue;
260 
261  /* If it was using the main shmem area, there is nothing to do. */
262  handle = old_control->item[i].handle;
263  if (is_main_region_dsm_handle(handle))
264  continue;
265 
266  /* Log debugging information. */
267  elog(DEBUG2, "cleaning up orphaned dynamic shared memory with ID %u (reference count %u)",
268  handle, refcnt);
269 
270  /* Destroy the referenced segment. */
271  dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private,
272  &junk_mapped_address, &junk_mapped_size, LOG);
273  }
274 
275  /* Destroy the old control segment, too. */
276  elog(DEBUG2,
277  "cleaning up dynamic shared memory control segment with ID %u",
278  old_control_handle);
279  dsm_impl_op(DSM_OP_DESTROY, old_control_handle, 0, &impl_private,
280  &mapped_address, &mapped_size, LOG);
281 }
size_t Size
Definition: c.h:540
static bool dsm_control_segment_sane(dsm_control_header *control, Size mapped_size)
Definition: dsm.c:1204
uint32 dsm_handle
Definition: dsm_impl.h:55
@ DSM_OP_DETACH
Definition: dsm_impl.h:62
@ DSM_OP_DESTROY
Definition: dsm_impl.h:63
#define LOG
Definition: elog.h:25
#define DEBUG2
Definition: elog.h:23
#define DEBUG1
Definition: elog.h:24

References DEBUG1, DEBUG2, dsm_control_segment_sane(), dsm_impl_op(), DSM_OP_ATTACH, DSM_OP_DESTROY, DSM_OP_DETACH, elog, dsm_control_item::handle, i, is_main_region_dsm_handle(), dsm_control_header::item, LOG, dsm_control_header::nitems, and dsm_control_item::refcnt.

Referenced by PGSharedMemoryCreate().

◆ dsm_create()

dsm_segment* dsm_create ( Size  size,
int  flags 
)

Definition at line 489 of file dsm.c.

490 {
491  dsm_segment *seg;
492  uint32 i;
493  uint32 nitems;
494  size_t npages = 0;
495  size_t first_page = 0;
496  FreePageManager *dsm_main_space_fpm = dsm_main_space_begin;
497  bool using_main_dsm_region = false;
498 
499  /* Unsafe in postmaster (and pointless in a stand-alone backend). */
501 
502  if (!dsm_init_done)
504 
505  /* Create a new segment descriptor. */
506  seg = dsm_create_descriptor();
507 
508  /*
509  * Lock the control segment while we try to allocate from the main shared
510  * memory area, if configured.
511  */
512  if (dsm_main_space_fpm)
513  {
514  npages = size / FPM_PAGE_SIZE;
515  if (size % FPM_PAGE_SIZE > 0)
516  ++npages;
517 
518  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
519  if (FreePageManagerGet(dsm_main_space_fpm, npages, &first_page))
520  {
521  /* We can carve out a piece of the main shared memory segment. */
522  seg->mapped_address = (char *) dsm_main_space_begin +
523  first_page * FPM_PAGE_SIZE;
524  seg->mapped_size = npages * FPM_PAGE_SIZE;
525  using_main_dsm_region = true;
526  /* We'll choose a handle below. */
527  }
528  }
529 
530  if (!using_main_dsm_region)
531  {
532  /*
533  * We need to create a new memory segment. Loop until we find an
534  * unused segment identifier.
535  */
536  if (dsm_main_space_fpm)
537  LWLockRelease(DynamicSharedMemoryControlLock);
538  for (;;)
539  {
540  Assert(seg->mapped_address == NULL && seg->mapped_size == 0);
541  /* Use even numbers only */
543  if (seg->handle == DSM_HANDLE_INVALID) /* Reserve sentinel */
544  continue;
545  if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private,
546  &seg->mapped_address, &seg->mapped_size, ERROR))
547  break;
548  }
549  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
550  }
551 
552  /* Search the control segment for an unused slot. */
553  nitems = dsm_control->nitems;
554  for (i = 0; i < nitems; ++i)
555  {
556  if (dsm_control->item[i].refcnt == 0)
557  {
558  if (using_main_dsm_region)
559  {
561  dsm_control->item[i].first_page = first_page;
562  dsm_control->item[i].npages = npages;
563  }
564  else
566  dsm_control->item[i].handle = seg->handle;
567  /* refcnt of 1 triggers destruction, so start at 2 */
568  dsm_control->item[i].refcnt = 2;
570  dsm_control->item[i].pinned = false;
571  seg->control_slot = i;
572  LWLockRelease(DynamicSharedMemoryControlLock);
573  return seg;
574  }
575  }
576 
577  /* Verify that we can support an additional mapping. */
578  if (nitems >= dsm_control->maxitems)
579  {
580  if (using_main_dsm_region)
581  FreePageManagerPut(dsm_main_space_fpm, first_page, npages);
582  LWLockRelease(DynamicSharedMemoryControlLock);
583  if (!using_main_dsm_region)
585  &seg->mapped_address, &seg->mapped_size, WARNING);
586  if (seg->resowner != NULL)
587  ResourceOwnerForgetDSM(seg->resowner, seg);
588  dlist_delete(&seg->node);
589  pfree(seg);
590 
591  if ((flags & DSM_CREATE_NULL_IF_MAXSEGMENTS) != 0)
592  return NULL;
593  ereport(ERROR,
594  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
595  errmsg("too many dynamic shared memory segments")));
596  }
597 
598  /* Enter the handle into a new array slot. */
599  if (using_main_dsm_region)
600  {
601  seg->handle = make_main_region_dsm_handle(nitems);
602  dsm_control->item[i].first_page = first_page;
603  dsm_control->item[i].npages = npages;
604  }
605  dsm_control->item[nitems].handle = seg->handle;
606  /* refcnt of 1 triggers destruction, so start at 2 */
607  dsm_control->item[nitems].refcnt = 2;
608  dsm_control->item[nitems].impl_private_pm_handle = NULL;
609  dsm_control->item[nitems].pinned = false;
610  seg->control_slot = nitems;
611  dsm_control->nitems++;
612  LWLockRelease(DynamicSharedMemoryControlLock);
613 
614  return seg;
615 }
static dsm_handle make_main_region_dsm_handle(int slot)
Definition: dsm.c:1229
#define DSM_CREATE_NULL_IF_MAXSEGMENTS
Definition: dsm.h:20
#define DSM_HANDLE_INVALID
Definition: dsm.h:23
@ DSM_OP_CREATE
Definition: dsm_impl.h:60
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define WARNING
Definition: elog.h:30
#define ereport(elevel,...)
Definition: elog.h:143
bool FreePageManagerGet(FreePageManager *fpm, Size npages, Size *first_page)
Definition: freepage.c:210
void FreePageManagerPut(FreePageManager *fpm, Size first_page, Size npages)
Definition: freepage.c:379
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
uint32 pg_prng_uint32(pg_prng_state *state)
Definition: pg_prng.c:185
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:28
void ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
Definition: resowner.c:1351
uint32 maxitems
Definition: dsm.c:93
bool pinned
Definition: dsm.c:85
void * impl_private_pm_handle
Definition: dsm.c:84
dlist_node node
Definition: dsm.c:67
ResourceOwner resowner
Definition: dsm.c:68

References Assert(), dsm_segment::control_slot, dlist_delete(), dsm_backend_startup(), dsm_control, dsm_create_descriptor(), DSM_CREATE_NULL_IF_MAXSEGMENTS, DSM_HANDLE_INVALID, dsm_impl_op(), dsm_init_done, dsm_main_space_begin, DSM_OP_CREATE, DSM_OP_DESTROY, ereport, errcode(), errmsg(), ERROR, dsm_control_item::first_page, FPM_PAGE_SIZE, FreePageManagerGet(), FreePageManagerPut(), dsm_segment::handle, dsm_control_item::handle, i, dsm_segment::impl_private, dsm_control_item::impl_private_pm_handle, is_main_region_dsm_handle(), IsUnderPostmaster, dsm_control_header::item, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), make_main_region_dsm_handle(), dsm_segment::mapped_address, dsm_segment::mapped_size, dsm_control_header::maxitems, dsm_control_header::nitems, dsm_segment::node, dsm_control_item::npages, pfree(), pg_global_prng_state, pg_prng_uint32(), dsm_control_item::pinned, dsm_control_item::refcnt, ResourceOwnerForgetDSM(), dsm_segment::resowner, and WARNING.

Referenced by apw_load_buffers(), dsa_create(), GetSessionDsmHandle(), InitializeParallelDSM(), make_new_segment(), and setup_dynamic_shared_memory().

◆ dsm_detach()

void dsm_detach ( dsm_segment seg)

Definition at line 772 of file dsm.c.

773 {
774  /*
775  * Invoke registered callbacks. Just in case one of those callbacks
776  * throws a further error that brings us back here, pop the callback
777  * before invoking it, to avoid infinite error recursion. Don't allow
778  * interrupts while running the individual callbacks in non-error code
779  * paths, to avoid leaving cleanup work unfinished if we're interrupted by
780  * a statement timeout or similar.
781  */
782  HOLD_INTERRUPTS();
783  while (!slist_is_empty(&seg->on_detach))
784  {
785  slist_node *node;
787  on_dsm_detach_callback function;
788  Datum arg;
789 
790  node = slist_pop_head_node(&seg->on_detach);
792  function = cb->function;
793  arg = cb->arg;
794  pfree(cb);
795 
796  function(seg, arg);
797  }
799 
800  /*
801  * Try to remove the mapping, if one exists. Normally, there will be, but
802  * maybe not, if we failed partway through a create or attach operation.
803  * We remove the mapping before decrementing the reference count so that
804  * the process that sees a zero reference count can be certain that no
805  * remaining mappings exist. Even if this fails, we pretend that it
806  * works, because retrying is likely to fail in the same way.
807  */
808  if (seg->mapped_address != NULL)
809  {
812  &seg->mapped_address, &seg->mapped_size, WARNING);
813  seg->impl_private = NULL;
814  seg->mapped_address = NULL;
815  seg->mapped_size = 0;
816  }
817 
818  /* Reduce reference count, if we previously increased it. */
820  {
821  uint32 refcnt;
822  uint32 control_slot = seg->control_slot;
823 
824  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
825  Assert(dsm_control->item[control_slot].handle == seg->handle);
826  Assert(dsm_control->item[control_slot].refcnt > 1);
827  refcnt = --dsm_control->item[control_slot].refcnt;
829  LWLockRelease(DynamicSharedMemoryControlLock);
830 
831  /* If new reference count is 1, try to destroy the segment. */
832  if (refcnt == 1)
833  {
834  /* A pinned segment should never reach 1. */
835  Assert(!dsm_control->item[control_slot].pinned);
836 
837  /*
838  * If we fail to destroy the segment here, or are killed before we
839  * finish doing so, the reference count will remain at 1, which
840  * will mean that nobody else can attach to the segment. At
841  * postmaster shutdown time, or when a new postmaster is started
842  * after a hard kill, another attempt will be made to remove the
843  * segment.
844  *
845  * The main case we're worried about here is being killed by a
846  * signal before we can finish removing the segment. In that
847  * case, it's important to be sure that the segment still gets
848  * removed. If we actually fail to remove the segment for some
849  * other reason, the postmaster may not have any better luck than
850  * we did. There's not much we can do about that, though.
851  */
852  if (is_main_region_dsm_handle(seg->handle) ||
854  &seg->mapped_address, &seg->mapped_size, WARNING))
855  {
856  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
859  dsm_control->item[control_slot].first_page,
860  dsm_control->item[control_slot].npages);
861  Assert(dsm_control->item[control_slot].handle == seg->handle);
862  Assert(dsm_control->item[control_slot].refcnt == 1);
863  dsm_control->item[control_slot].refcnt = 0;
864  LWLockRelease(DynamicSharedMemoryControlLock);
865  }
866  }
867  }
868 
869  /* Clean up our remaining backend-private data structures. */
870  if (seg->resowner != NULL)
871  ResourceOwnerForgetDSM(seg->resowner, seg);
872  dlist_delete(&seg->node);
873  pfree(seg);
874 }
void(* on_dsm_detach_callback)(dsm_segment *, Datum arg)
Definition: dsm.h:57
static bool slist_is_empty(slist_head *head)
Definition: ilist.h:582
static slist_node * slist_pop_head_node(slist_head *head)
Definition: ilist.h:615
#define RESUME_INTERRUPTS()
Definition: miscadmin.h:133
#define HOLD_INTERRUPTS()
Definition: miscadmin.h:131
uintptr_t Datum
Definition: postgres.h:411

References dsm_segment_detach_callback::arg, arg, Assert(), dsm_segment::control_slot, dlist_delete(), dsm_control, dsm_impl_op(), dsm_main_space_begin, DSM_OP_DESTROY, DSM_OP_DETACH, dsm_control_item::first_page, FreePageManagerPut(), dsm_segment_detach_callback::function, dsm_segment::handle, dsm_control_item::handle, HOLD_INTERRUPTS, dsm_segment::impl_private, INVALID_CONTROL_SLOT, is_main_region_dsm_handle(), dsm_control_header::item, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), dsm_segment::mapped_address, dsm_segment::mapped_size, dsm_segment::node, dsm_control_item::npages, dsm_segment::on_detach, pfree(), dsm_control_item::pinned, dsm_control_item::refcnt, ResourceOwnerForgetDSM(), dsm_segment::resowner, RESUME_INTERRUPTS, slist_container, slist_is_empty(), slist_pop_head_node(), and WARNING.

Referenced by apw_load_buffers(), autoprewarm_database_main(), check_for_freed_segments_locked(), destroy_superblock(), DestroyParallelContext(), DetachSession(), dsa_detach(), dsm_attach(), dsm_backend_shutdown(), dsm_detach_all(), ParallelWorkerShutdown(), ResourceOwnerReleaseInternal(), test_shm_mq(), test_shm_mq_main(), and test_shm_mq_pipelined().

◆ dsm_detach_all()

void dsm_detach_all ( void  )

Definition at line 744 of file dsm.c.

745 {
746  void *control_address = dsm_control;
747 
749  {
750  dsm_segment *seg;
751 
753  dsm_detach(seg);
754  }
755 
756  if (control_address != NULL)
758  &dsm_control_impl_private, &control_address,
760 }
static dsm_handle dsm_control_handle
Definition: dsm.c:138
static Size dsm_control_mapped_size
Definition: dsm.c:140
static void * dsm_control_impl_private
Definition: dsm.c:141

References dlist_head_element, dlist_is_empty(), dsm_control, dsm_control_handle, dsm_control_impl_private, dsm_control_mapped_size, dsm_detach(), dsm_impl_op(), DSM_OP_DETACH, dsm_segment_list, and ERROR.

Referenced by pgstat_start(), and SysLogger_Start().

◆ dsm_estimate_size()

size_t dsm_estimate_size ( void  )

Definition at line 443 of file dsm.c.

444 {
445  return 1024 * 1024 * (size_t) min_dynamic_shared_memory;
446 }
int min_dynamic_shared_memory
Definition: dsm_impl.c:117

References min_dynamic_shared_memory.

Referenced by CalculateShmemSize(), and dsm_shmem_init().

◆ dsm_find_mapping()

dsm_segment* dsm_find_mapping ( dsm_handle  h)

Definition at line 1043 of file dsm.c.

1044 {
1045  dlist_iter iter;
1046  dsm_segment *seg;
1047 
1049  {
1050  seg = dlist_container(dsm_segment, node, iter.cur);
1051  if (seg->handle == h)
1052  return seg;
1053  }
1054 
1055  return NULL;
1056 }

References dlist_iter::cur, dlist_container, dlist_foreach, dsm_segment_list, and dsm_segment::handle.

◆ dsm_pin_mapping()

void dsm_pin_mapping ( dsm_segment seg)

Definition at line 884 of file dsm.c.

885 {
886  if (seg->resowner != NULL)
887  {
888  ResourceOwnerForgetDSM(seg->resowner, seg);
889  seg->resowner = NULL;
890  }
891 }

References ResourceOwnerForgetDSM(), and dsm_segment::resowner.

Referenced by AttachSession(), dsa_pin_mapping(), get_segment_by_index(), GetSessionDsmHandle(), and make_new_segment().

◆ dsm_pin_segment()

void dsm_pin_segment ( dsm_segment seg)

Definition at line 924 of file dsm.c.

925 {
926  void *handle;
927 
928  /*
929  * Bump reference count for this segment in shared memory. This will
930  * ensure that even if there is no session which is attached to this
931  * segment, it will remain until postmaster shutdown or an explicit call
932  * to unpin.
933  */
934  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
935  if (dsm_control->item[seg->control_slot].pinned)
936  elog(ERROR, "cannot pin a segment that is already pinned");
937  dsm_impl_pin_segment(seg->handle, seg->impl_private, &handle);
938  dsm_control->item[seg->control_slot].pinned = true;
941  LWLockRelease(DynamicSharedMemoryControlLock);
942 }
void dsm_impl_pin_segment(dsm_handle handle, void *impl_private, void **impl_private_pm_handle)
Definition: dsm_impl.c:955

References dsm_segment::control_slot, dsm_control, dsm_impl_pin_segment(), elog, ERROR, dsm_segment::handle, dsm_segment::impl_private, dsm_control_item::impl_private_pm_handle, dsm_control_header::item, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), dsm_control_item::pinned, and dsm_control_item::refcnt.

Referenced by dsa_create(), and make_new_segment().

◆ dsm_postmaster_startup()

void dsm_postmaster_startup ( struct PGShmemHeader shim)

Definition at line 150 of file dsm.c.

151 {
152  void *dsm_control_address = NULL;
153  uint32 maxitems;
154  Size segsize;
155 
157 
158  /*
159  * If we're using the mmap implementations, clean up any leftovers.
160  * Cleanup isn't needed on Windows, and happens earlier in startup for
161  * POSIX and System V shared memory, via a direct call to
162  * dsm_cleanup_using_control_segment.
163  */
166 
167  /* Determine size for new control segment. */
168  maxitems = PG_DYNSHMEM_FIXED_SLOTS
170  elog(DEBUG2, "dynamic shared memory system will support %u segments",
171  maxitems);
172  segsize = dsm_control_bytes_needed(maxitems);
173 
174  /*
175  * Loop until we find an unused identifier for the new control segment. We
176  * sometimes use 0 as a sentinel value indicating that no control segment
177  * is known to exist, so avoid using that value for a real control
178  * segment.
179  */
180  for (;;)
181  {
182  Assert(dsm_control_address == NULL);
184  /* Use even numbers only */
187  continue;
189  &dsm_control_impl_private, &dsm_control_address,
191  break;
192  }
193  dsm_control = dsm_control_address;
195  elog(DEBUG2,
196  "created dynamic shared memory control segment %u (%zu bytes)",
197  dsm_control_handle, segsize);
199 
200  /* Initialize control segment. */
202  dsm_control->nitems = 0;
203  dsm_control->maxitems = maxitems;
204 }
static void dsm_postmaster_shutdown(int code, Datum arg)
Definition: dsm.c:332
#define PG_DYNSHMEM_CONTROL_MAGIC
Definition: dsm.c:49
static uint64 dsm_control_bytes_needed(uint32 nitems)
Definition: dsm.c:1222
#define PG_DYNSHMEM_SLOTS_PER_BACKEND
Definition: dsm.c:52
#define PG_DYNSHMEM_FIXED_SLOTS
Definition: dsm.c:51
static void dsm_cleanup_for_mmap(void)
Definition: dsm.c:294
int dynamic_shared_memory_type
Definition: dsm_impl.c:114
#define DSM_IMPL_MMAP
Definition: dsm_impl.h:20
int MaxBackends
Definition: globals.c:139
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
#define PointerGetDatum(X)
Definition: postgres.h:600
dsm_handle dsm_control
Definition: pg_shmem.h:36
uint32 magic
Definition: dsm.c:91

References Assert(), DEBUG2, dsm_cleanup_for_mmap(), dsm_control, PGShmemHeader::dsm_control, dsm_control_bytes_needed(), dsm_control_handle, dsm_control_impl_private, dsm_control_mapped_size, DSM_HANDLE_INVALID, DSM_IMPL_MMAP, dsm_impl_op(), DSM_OP_CREATE, dsm_postmaster_shutdown(), dynamic_shared_memory_type, elog, ERROR, IsUnderPostmaster, dsm_control_header::magic, MaxBackends, dsm_control_header::maxitems, dsm_control_header::nitems, on_shmem_exit(), PG_DYNSHMEM_CONTROL_MAGIC, PG_DYNSHMEM_FIXED_SLOTS, PG_DYNSHMEM_SLOTS_PER_BACKEND, pg_global_prng_state, pg_prng_uint32(), and PointerGetDatum.

Referenced by CreateSharedMemoryAndSemaphores().

◆ dsm_segment_address()

◆ dsm_segment_handle()

◆ dsm_segment_map_length()

Size dsm_segment_map_length ( dsm_segment seg)

Definition at line 1072 of file dsm.c.

1073 {
1074  Assert(seg->mapped_address != NULL);
1075  return seg->mapped_size;
1076 }

References Assert(), dsm_segment::mapped_address, and dsm_segment::mapped_size.

◆ dsm_shmem_init()

void dsm_shmem_init ( void  )

Definition at line 452 of file dsm.c.

453 {
454  size_t size = dsm_estimate_size();
455  bool found;
456 
457  if (size == 0)
458  return;
459 
460  dsm_main_space_begin = ShmemInitStruct("Preallocated DSM", size, &found);
461  if (!found)
462  {
464  size_t first_page = 0;
465  size_t pages;
466 
467  /* Reserve space for the FreePageManager. */
468  while (first_page * FPM_PAGE_SIZE < sizeof(FreePageManager))
469  ++first_page;
470 
471  /* Initialize it and give it all the rest of the space. */
473  pages = (size / FPM_PAGE_SIZE) - first_page;
474  FreePageManagerPut(fpm, first_page, pages);
475  }
476 }
size_t dsm_estimate_size(void)
Definition: dsm.c:443
void FreePageManagerInitialize(FreePageManager *fpm, char *base)
Definition: freepage.c:183
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396

References dsm_estimate_size(), dsm_main_space_begin, FPM_PAGE_SIZE, FreePageManagerInitialize(), FreePageManagerPut(), and ShmemInitStruct().

Referenced by CreateSharedMemoryAndSemaphores().

◆ dsm_unpin_mapping()

void dsm_unpin_mapping ( dsm_segment seg)

Definition at line 903 of file dsm.c.

904 {
905  Assert(seg->resowner == NULL);
909 }
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
void ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
Definition: resowner.c:1342
void ResourceOwnerEnlargeDSMs(ResourceOwner owner)
Definition: resowner.c:1331

References Assert(), CurrentResourceOwner, ResourceOwnerEnlargeDSMs(), ResourceOwnerRememberDSM(), and dsm_segment::resowner.

◆ dsm_unpin_segment()

void dsm_unpin_segment ( dsm_handle  h)

Definition at line 956 of file dsm.c.

957 {
958  uint32 control_slot = INVALID_CONTROL_SLOT;
959  bool destroy = false;
960  uint32 i;
961 
962  /* Find the control slot for the given handle. */
963  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
964  for (i = 0; i < dsm_control->nitems; ++i)
965  {
966  /* Skip unused slots and segments that are concurrently going away. */
967  if (dsm_control->item[i].refcnt <= 1)
968  continue;
969 
970  /* If we've found our handle, we can stop searching. */
971  if (dsm_control->item[i].handle == handle)
972  {
973  control_slot = i;
974  break;
975  }
976  }
977 
978  /*
979  * We should definitely have found the slot, and it should not already be
980  * in the process of going away, because this function should only be
981  * called on a segment which is pinned.
982  */
983  if (control_slot == INVALID_CONTROL_SLOT)
984  elog(ERROR, "cannot unpin unknown segment handle");
985  if (!dsm_control->item[control_slot].pinned)
986  elog(ERROR, "cannot unpin a segment that is not pinned");
987  Assert(dsm_control->item[control_slot].refcnt > 1);
988 
989  /*
990  * Allow implementation-specific code to run. We have to do this before
991  * releasing the lock, because impl_private_pm_handle may get modified by
992  * dsm_impl_unpin_segment.
993  */
994  dsm_impl_unpin_segment(handle,
995  &dsm_control->item[control_slot].impl_private_pm_handle);
996 
997  /* Note that 1 means no references (0 means unused slot). */
998  if (--dsm_control->item[control_slot].refcnt == 1)
999  destroy = true;
1000  dsm_control->item[control_slot].pinned = false;
1001 
1002  /* Now we can release the lock. */
1003  LWLockRelease(DynamicSharedMemoryControlLock);
1004 
1005  /* Clean up resources if that was the last reference. */
1006  if (destroy)
1007  {
1008  void *junk_impl_private = NULL;
1009  void *junk_mapped_address = NULL;
1010  Size junk_mapped_size = 0;
1011 
1012  /*
1013  * For an explanation of how error handling works in this case, see
1014  * comments in dsm_detach. Note that if we reach this point, the
1015  * current process certainly does not have the segment mapped, because
1016  * if it did, the reference count would have still been greater than 1
1017  * even after releasing the reference count held by the pin. The fact
1018  * that there can't be a dsm_segment for this handle makes it OK to
1019  * pass the mapped size, mapped address, and private data as NULL
1020  * here.
1021  */
1022  if (is_main_region_dsm_handle(handle) ||
1023  dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private,
1024  &junk_mapped_address, &junk_mapped_size, WARNING))
1025  {
1026  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
1027  if (is_main_region_dsm_handle(handle))
1029  dsm_control->item[control_slot].first_page,
1030  dsm_control->item[control_slot].npages);
1031  Assert(dsm_control->item[control_slot].handle == handle);
1032  Assert(dsm_control->item[control_slot].refcnt == 1);
1033  dsm_control->item[control_slot].refcnt = 0;
1034  LWLockRelease(DynamicSharedMemoryControlLock);
1035  }
1036  }
1037 }
void dsm_impl_unpin_segment(dsm_handle handle, void **impl_private)
Definition: dsm_impl.c:1005

References Assert(), dsm_control, dsm_impl_op(), dsm_impl_unpin_segment(), dsm_main_space_begin, DSM_OP_DESTROY, elog, ERROR, dsm_control_item::first_page, FreePageManagerPut(), dsm_control_item::handle, i, dsm_control_item::impl_private_pm_handle, INVALID_CONTROL_SLOT, is_main_region_dsm_handle(), dsm_control_header::item, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), dsm_control_header::nitems, dsm_control_item::npages, dsm_control_item::pinned, dsm_control_item::refcnt, and WARNING.

Referenced by destroy_superblock(), and dsa_release_in_place().

◆ on_dsm_detach()

void on_dsm_detach ( dsm_segment seg,
on_dsm_detach_callback  function,
Datum  arg 
)

Definition at line 1099 of file dsm.c.

1100 {
1102 
1104  sizeof(dsm_segment_detach_callback));
1105  cb->function = function;
1106  cb->arg = arg;
1107  slist_push_head(&seg->on_detach, &cb->node);
1108 }
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:593
MemoryContext TopMemoryContext
Definition: mcxt.c:48
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863

References dsm_segment_detach_callback::arg, arg, dsm_segment_detach_callback::function, MemoryContextAlloc(), dsm_segment_detach_callback::node, dsm_segment::on_detach, slist_push_head(), and TopMemoryContext.

Referenced by dsa_attach(), dsa_attach_in_place(), dsa_create(), dsa_create_in_place(), pq_redirect_to_shm_mq(), setup_background_workers(), SharedFileSetAttach(), SharedFileSetInit(), SharedRecordTypmodRegistryAttach(), SharedRecordTypmodRegistryInit(), and shm_mq_attach().

◆ reset_on_dsm_detach()

void reset_on_dsm_detach ( void  )

Definition at line 1137 of file dsm.c.

1138 {
1139  dlist_iter iter;
1140 
1142  {
1143  dsm_segment *seg = dlist_container(dsm_segment, node, iter.cur);
1144 
1145  /* Throw away explicit on-detach actions one by one. */
1146  while (!slist_is_empty(&seg->on_detach))
1147  {
1148  slist_node *node;
1150 
1151  node = slist_pop_head_node(&seg->on_detach);
1152  cb = slist_container(dsm_segment_detach_callback, node, node);
1153  pfree(cb);
1154  }
1155 
1156  /*
1157  * Decrementing the reference count is a sort of implicit on-detach
1158  * action; make sure we don't do that, either.
1159  */
1161  }
1162 }

References dsm_segment::control_slot, dlist_iter::cur, dlist_container, dlist_foreach, dsm_segment_list, INVALID_CONTROL_SLOT, dsm_segment::on_detach, pfree(), slist_container, slist_is_empty(), and slist_pop_head_node().

Referenced by on_exit_reset().