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
 

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 handle)
 
dsm_segmentdsm_find_mapping (dsm_handle handle)
 
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.

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 54 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 1148 of file dsm.c.

1150 {
1151  slist_mutable_iter iter;
1152 
1153  slist_foreach_modify(iter, &seg->on_detach)
1154  {
1156 
1158  if (cb->function == function && cb->arg == arg)
1159  {
1160  slist_delete_current(&iter);
1161  pfree(cb);
1162  break;
1163  }
1164  }
1165 }
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:1084
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:1148
#define slist_container(type, membername, ptr)
Definition: ilist.h:1106
void pfree(void *pointer)
Definition: mcxt.c:1456
void * arg
on_dsm_detach_callback function
Definition: dsm.c:61
slist_head on_detach
Definition: dsm.c:76
slist_node * cur
Definition: ilist.h:274

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 666 of file dsm.c.

667 {
668  dsm_segment *seg;
669  dlist_iter iter;
670  uint32 i;
671  uint32 nitems;
672 
673  /* Unsafe in postmaster (and pointless in a stand-alone backend). */
675 
676  if (!dsm_init_done)
678 
679  /*
680  * Since this is just a debugging cross-check, we could leave it out
681  * altogether, or include it only in assert-enabled builds. But since the
682  * list of attached segments should normally be very short, let's include
683  * it always for right now.
684  *
685  * If you're hitting this error, you probably want to attempt to find an
686  * existing mapping via dsm_find_mapping() before calling dsm_attach() to
687  * create a new one.
688  */
690  {
691  seg = dlist_container(dsm_segment, node, iter.cur);
692  if (seg->handle == h)
693  elog(ERROR, "can't attach the same segment more than once");
694  }
695 
696  /* Create a new segment descriptor. */
697  seg = dsm_create_descriptor();
698  seg->handle = h;
699 
700  /* Bump reference count for this segment in shared memory. */
701  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
703  for (i = 0; i < nitems; ++i)
704  {
705  /*
706  * If the reference count is 0, the slot is actually unused. If the
707  * reference count is 1, the slot is still in use, but the segment is
708  * in the process of going away; even if the handle matches, another
709  * slot may already have started using the same handle value by
710  * coincidence so we have to keep searching.
711  */
712  if (dsm_control->item[i].refcnt <= 1)
713  continue;
714 
715  /* If the handle doesn't match, it's not the slot we want. */
716  if (dsm_control->item[i].handle != seg->handle)
717  continue;
718 
719  /* Otherwise we've found a match. */
720  dsm_control->item[i].refcnt++;
721  seg->control_slot = i;
723  {
724  seg->mapped_address = (char *) dsm_main_space_begin +
727  }
728  break;
729  }
730  LWLockRelease(DynamicSharedMemoryControlLock);
731 
732  /*
733  * If we didn't find the handle we're looking for in the control segment,
734  * it probably means that everyone else who had it mapped, including the
735  * original creator, died before we got to this point. It's up to the
736  * caller to decide what to do about that.
737  */
739  {
740  dsm_detach(seg);
741  return NULL;
742  }
743 
744  /* Here's where we actually try to map the segment. */
747  &seg->mapped_address, &seg->mapped_size, ERROR);
748 
749  return seg;
750 }
unsigned int uint32
Definition: c.h:495
static void dsm_backend_startup(void)
Definition: dsm.c:424
static void * dsm_main_space_begin
Definition: dsm.c:112
void dsm_detach(dsm_segment *seg)
Definition: dsm.c:804
static dlist_head dsm_segment_list
Definition: dsm.c:131
static bool dsm_init_done
Definition: dsm.c:109
static dsm_control_header * dsm_control
Definition: dsm.c:141
static dsm_segment * dsm_create_descriptor(void)
Definition: dsm.c:1202
#define INVALID_CONTROL_SLOT
Definition: dsm.c:56
static bool is_main_region_dsm_handle(dsm_handle handle)
Definition: dsm.c:1282
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:159
@ DSM_OP_ATTACH
Definition: dsm_impl.h:64
#define ERROR
Definition: elog.h:39
#define FPM_PAGE_SIZE
Definition: freepage.h:30
bool IsUnderPostmaster
Definition: globals.c:115
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
#define nitems(x)
Definition: indent.h:31
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
@ LW_EXCLUSIVE
Definition: lwlock.h:116
dlist_node * cur
Definition: ilist.h:179
uint32 nitems
Definition: dsm.c:94
dsm_control_item item[FLEXIBLE_ARRAY_MEMBER]
Definition: dsm.c:96
size_t npages
Definition: dsm.c:85
dsm_handle handle
Definition: dsm.c:82
size_t first_page
Definition: dsm.c:84
uint32 refcnt
Definition: dsm.c:83
uint32 control_slot
Definition: dsm.c:72
dsm_handle handle
Definition: dsm.c:71
Size mapped_size
Definition: dsm.c:75
void * impl_private
Definition: dsm.c:73
void * mapped_address
Definition: dsm.c:74

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, nitems, dsm_control_item::npages, and dsm_control_item::refcnt.

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

◆ dsm_backend_shutdown()

void dsm_backend_shutdown ( void  )

Definition at line 758 of file dsm.c.

759 {
761  {
762  dsm_segment *seg;
763 
765  dsm_detach(seg);
766  }
767 }
#define dlist_head_element(type, membername, lhead)
Definition: ilist.h:603
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336

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 239 of file dsm.c.

240 {
241  void *mapped_address = NULL;
242  void *junk_mapped_address = NULL;
243  void *impl_private = NULL;
244  void *junk_impl_private = NULL;
245  Size mapped_size = 0;
246  Size junk_mapped_size = 0;
247  uint32 nitems;
248  uint32 i;
249  dsm_control_header *old_control;
250 
251  /*
252  * Try to attach the segment. If this fails, it probably just means that
253  * the operating system has been rebooted and the segment no longer
254  * exists, or an unrelated process has used the same shm ID. So just fall
255  * out quietly.
256  */
257  if (!dsm_impl_op(DSM_OP_ATTACH, old_control_handle, 0, &impl_private,
258  &mapped_address, &mapped_size, DEBUG1))
259  return;
260 
261  /*
262  * We've managed to reattach it, but the contents might not be sane. If
263  * they aren't, we disregard the segment after all.
264  */
265  old_control = (dsm_control_header *) mapped_address;
266  if (!dsm_control_segment_sane(old_control, mapped_size))
267  {
268  dsm_impl_op(DSM_OP_DETACH, old_control_handle, 0, &impl_private,
269  &mapped_address, &mapped_size, LOG);
270  return;
271  }
272 
273  /*
274  * OK, the control segment looks basically valid, so we can use it to get
275  * a list of segments that need to be removed.
276  */
277  nitems = old_control->nitems;
278  for (i = 0; i < nitems; ++i)
279  {
280  dsm_handle handle;
281  uint32 refcnt;
282 
283  /* If the reference count is 0, the slot is actually unused. */
284  refcnt = old_control->item[i].refcnt;
285  if (refcnt == 0)
286  continue;
287 
288  /* If it was using the main shmem area, there is nothing to do. */
289  handle = old_control->item[i].handle;
290  if (is_main_region_dsm_handle(handle))
291  continue;
292 
293  /* Log debugging information. */
294  elog(DEBUG2, "cleaning up orphaned dynamic shared memory with ID %u (reference count %u)",
295  handle, refcnt);
296 
297  /* Destroy the referenced segment. */
298  dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private,
299  &junk_mapped_address, &junk_mapped_size, LOG);
300  }
301 
302  /* Destroy the old control segment, too. */
303  elog(DEBUG2,
304  "cleaning up dynamic shared memory control segment with ID %u",
305  old_control_handle);
306  dsm_impl_op(DSM_OP_DESTROY, old_control_handle, 0, &impl_private,
307  &mapped_address, &mapped_size, LOG);
308 }
size_t Size
Definition: c.h:594
static bool dsm_control_segment_sane(dsm_control_header *control, Size mapped_size)
Definition: dsm.c:1238
uint32 dsm_handle
Definition: dsm_impl.h:55
@ DSM_OP_DETACH
Definition: dsm_impl.h:65
@ DSM_OP_DESTROY
Definition: dsm_impl.h:66
#define LOG
Definition: elog.h:31
#define DEBUG2
Definition: elog.h:29
#define DEBUG1
Definition: elog.h:30

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, nitems, and dsm_control_item::refcnt.

Referenced by PGSharedMemoryCreate().

◆ dsm_create()

dsm_segment* dsm_create ( Size  size,
int  flags 
)

Definition at line 517 of file dsm.c.

518 {
519  dsm_segment *seg;
520  uint32 i;
521  uint32 nitems;
522  size_t npages = 0;
523  size_t first_page = 0;
524  FreePageManager *dsm_main_space_fpm = dsm_main_space_begin;
525  bool using_main_dsm_region = false;
526 
527  /*
528  * Unsafe in postmaster. It might seem pointless to allow use of dsm in
529  * single user mode, but otherwise some subsystems will need dedicated
530  * single user mode code paths.
531  */
533 
534  if (!dsm_init_done)
536 
537  /* Create a new segment descriptor. */
538  seg = dsm_create_descriptor();
539 
540  /*
541  * Lock the control segment while we try to allocate from the main shared
542  * memory area, if configured.
543  */
544  if (dsm_main_space_fpm)
545  {
546  npages = size / FPM_PAGE_SIZE;
547  if (size % FPM_PAGE_SIZE > 0)
548  ++npages;
549 
550  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
551  if (FreePageManagerGet(dsm_main_space_fpm, npages, &first_page))
552  {
553  /* We can carve out a piece of the main shared memory segment. */
554  seg->mapped_address = (char *) dsm_main_space_begin +
555  first_page * FPM_PAGE_SIZE;
556  seg->mapped_size = npages * FPM_PAGE_SIZE;
557  using_main_dsm_region = true;
558  /* We'll choose a handle below. */
559  }
560  }
561 
562  if (!using_main_dsm_region)
563  {
564  /*
565  * We need to create a new memory segment. Loop until we find an
566  * unused segment identifier.
567  */
568  if (dsm_main_space_fpm)
569  LWLockRelease(DynamicSharedMemoryControlLock);
570  for (;;)
571  {
572  Assert(seg->mapped_address == NULL && seg->mapped_size == 0);
573  /* Use even numbers only */
575  if (seg->handle == DSM_HANDLE_INVALID) /* Reserve sentinel */
576  continue;
577  if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private,
578  &seg->mapped_address, &seg->mapped_size, ERROR))
579  break;
580  }
581  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
582  }
583 
584  /* Search the control segment for an unused slot. */
586  for (i = 0; i < nitems; ++i)
587  {
588  if (dsm_control->item[i].refcnt == 0)
589  {
590  if (using_main_dsm_region)
591  {
593  dsm_control->item[i].first_page = first_page;
594  dsm_control->item[i].npages = npages;
595  }
596  else
598  dsm_control->item[i].handle = seg->handle;
599  /* refcnt of 1 triggers destruction, so start at 2 */
600  dsm_control->item[i].refcnt = 2;
602  dsm_control->item[i].pinned = false;
603  seg->control_slot = i;
604  LWLockRelease(DynamicSharedMemoryControlLock);
605  return seg;
606  }
607  }
608 
609  /* Verify that we can support an additional mapping. */
610  if (nitems >= dsm_control->maxitems)
611  {
612  if (using_main_dsm_region)
613  FreePageManagerPut(dsm_main_space_fpm, first_page, npages);
614  LWLockRelease(DynamicSharedMemoryControlLock);
615  if (!using_main_dsm_region)
617  &seg->mapped_address, &seg->mapped_size, WARNING);
618  if (seg->resowner != NULL)
619  ResourceOwnerForgetDSM(seg->resowner, seg);
620  dlist_delete(&seg->node);
621  pfree(seg);
622 
623  if ((flags & DSM_CREATE_NULL_IF_MAXSEGMENTS) != 0)
624  return NULL;
625  ereport(ERROR,
626  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
627  errmsg("too many dynamic shared memory segments")));
628  }
629 
630  /* Enter the handle into a new array slot. */
631  if (using_main_dsm_region)
632  {
634  dsm_control->item[i].first_page = first_page;
635  dsm_control->item[i].npages = npages;
636  }
638  /* refcnt of 1 triggers destruction, so start at 2 */
641  dsm_control->item[nitems].pinned = false;
642  seg->control_slot = nitems;
643  dsm_control->nitems++;
644  LWLockRelease(DynamicSharedMemoryControlLock);
645 
646  return seg;
647 }
static void ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *seg)
Definition: dsm.c:166
static dsm_handle make_main_region_dsm_handle(int slot)
Definition: dsm.c:1263
#define DSM_CREATE_NULL_IF_MAXSEGMENTS
Definition: dsm.h:20
@ DSM_OP_CREATE
Definition: dsm_impl.h:63
#define DSM_HANDLE_INVALID
Definition: dsm_impl.h:58
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define ereport(elevel,...)
Definition: elog.h:149
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
bool IsPostmasterEnvironment
Definition: globals.c:114
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
uint32 pg_prng_uint32(pg_prng_state *state)
Definition: pg_prng.c:191
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:34
uint32 maxitems
Definition: dsm.c:95
bool pinned
Definition: dsm.c:87
void * impl_private_pm_handle
Definition: dsm.c:86
dlist_node node
Definition: dsm.c:69
ResourceOwner resowner
Definition: dsm.c:70

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(), IsPostmasterEnvironment, 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, 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(), pa_setup_dsm(), and setup_dynamic_shared_memory().

◆ dsm_detach()

void dsm_detach ( dsm_segment seg)

Definition at line 804 of file dsm.c.

805 {
806  /*
807  * Invoke registered callbacks. Just in case one of those callbacks
808  * throws a further error that brings us back here, pop the callback
809  * before invoking it, to avoid infinite error recursion. Don't allow
810  * interrupts while running the individual callbacks in non-error code
811  * paths, to avoid leaving cleanup work unfinished if we're interrupted by
812  * a statement timeout or similar.
813  */
814  HOLD_INTERRUPTS();
815  while (!slist_is_empty(&seg->on_detach))
816  {
817  slist_node *node;
819  on_dsm_detach_callback function;
820  Datum arg;
821 
822  node = slist_pop_head_node(&seg->on_detach);
824  function = cb->function;
825  arg = cb->arg;
826  pfree(cb);
827 
828  function(seg, arg);
829  }
831 
832  /*
833  * Try to remove the mapping, if one exists. Normally, there will be, but
834  * maybe not, if we failed partway through a create or attach operation.
835  * We remove the mapping before decrementing the reference count so that
836  * the process that sees a zero reference count can be certain that no
837  * remaining mappings exist. Even if this fails, we pretend that it
838  * works, because retrying is likely to fail in the same way.
839  */
840  if (seg->mapped_address != NULL)
841  {
844  &seg->mapped_address, &seg->mapped_size, WARNING);
845  seg->impl_private = NULL;
846  seg->mapped_address = NULL;
847  seg->mapped_size = 0;
848  }
849 
850  /* Reduce reference count, if we previously increased it. */
852  {
853  uint32 refcnt;
854  uint32 control_slot = seg->control_slot;
855 
856  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
857  Assert(dsm_control->item[control_slot].handle == seg->handle);
858  Assert(dsm_control->item[control_slot].refcnt > 1);
859  refcnt = --dsm_control->item[control_slot].refcnt;
861  LWLockRelease(DynamicSharedMemoryControlLock);
862 
863  /* If new reference count is 1, try to destroy the segment. */
864  if (refcnt == 1)
865  {
866  /* A pinned segment should never reach 1. */
867  Assert(!dsm_control->item[control_slot].pinned);
868 
869  /*
870  * If we fail to destroy the segment here, or are killed before we
871  * finish doing so, the reference count will remain at 1, which
872  * will mean that nobody else can attach to the segment. At
873  * postmaster shutdown time, or when a new postmaster is started
874  * after a hard kill, another attempt will be made to remove the
875  * segment.
876  *
877  * The main case we're worried about here is being killed by a
878  * signal before we can finish removing the segment. In that
879  * case, it's important to be sure that the segment still gets
880  * removed. If we actually fail to remove the segment for some
881  * other reason, the postmaster may not have any better luck than
882  * we did. There's not much we can do about that, though.
883  */
884  if (is_main_region_dsm_handle(seg->handle) ||
886  &seg->mapped_address, &seg->mapped_size, WARNING))
887  {
888  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
891  dsm_control->item[control_slot].first_page,
892  dsm_control->item[control_slot].npages);
893  Assert(dsm_control->item[control_slot].handle == seg->handle);
894  Assert(dsm_control->item[control_slot].refcnt == 1);
895  dsm_control->item[control_slot].refcnt = 0;
896  LWLockRelease(DynamicSharedMemoryControlLock);
897  }
898  }
899  }
900 
901  /* Clean up our remaining backend-private data structures. */
902  if (seg->resowner != NULL)
903  ResourceOwnerForgetDSM(seg->resowner, seg);
904  dlist_delete(&seg->node);
905  pfree(seg);
906 }
void(* on_dsm_detach_callback)(dsm_segment *, Datum arg)
Definition: dsm.h:54
static bool slist_is_empty(const slist_head *head)
Definition: ilist.h:995
static slist_node * slist_pop_head_node(slist_head *head)
Definition: ilist.h:1028
#define RESUME_INTERRUPTS()
Definition: miscadmin.h:134
#define HOLD_INTERRUPTS()
Definition: miscadmin.h:132
uintptr_t Datum
Definition: postgres.h:64

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(), pa_free_worker_info(), pa_shutdown(), ParallelWorkerShutdown(), ResOwnerReleaseDSM(), test_shm_mq(), test_shm_mq_main(), and test_shm_mq_pipelined().

◆ dsm_detach_all()

void dsm_detach_all ( void  )

Definition at line 776 of file dsm.c.

777 {
778  void *control_address = dsm_control;
779 
781  {
782  dsm_segment *seg;
783 
785  dsm_detach(seg);
786  }
787 
788  if (control_address != NULL)
790  &dsm_control_impl_private, &control_address,
792 }
static dsm_handle dsm_control_handle
Definition: dsm.c:140
static Size dsm_control_mapped_size
Definition: dsm.c:142
static void * dsm_control_impl_private
Definition: dsm.c:143

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 SysLogger_Start().

◆ dsm_estimate_size()

size_t dsm_estimate_size ( void  )

Definition at line 471 of file dsm.c.

472 {
473  return 1024 * 1024 * (size_t) min_dynamic_shared_memory;
474 }
int min_dynamic_shared_memory
Definition: dsm_impl.c:115

References min_dynamic_shared_memory.

Referenced by CalculateShmemSize(), and dsm_shmem_init().

◆ dsm_find_mapping()

dsm_segment* dsm_find_mapping ( dsm_handle  handle)

Definition at line 1077 of file dsm.c.

1078 {
1079  dlist_iter iter;
1080  dsm_segment *seg;
1081 
1083  {
1084  seg = dlist_container(dsm_segment, node, iter.cur);
1085  if (seg->handle == handle)
1086  return seg;
1087  }
1088 
1089  return NULL;
1090 }

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 916 of file dsm.c.

917 {
918  if (seg->resowner != NULL)
919  {
920  ResourceOwnerForgetDSM(seg->resowner, seg);
921  seg->resowner = NULL;
922  }
923 }

References ResourceOwnerForgetDSM(), and dsm_segment::resowner.

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

◆ dsm_pin_segment()

void dsm_pin_segment ( dsm_segment seg)

Definition at line 956 of file dsm.c.

957 {
958  void *handle = NULL;
959 
960  /*
961  * Bump reference count for this segment in shared memory. This will
962  * ensure that even if there is no session which is attached to this
963  * segment, it will remain until postmaster shutdown or an explicit call
964  * to unpin.
965  */
966  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
967  if (dsm_control->item[seg->control_slot].pinned)
968  elog(ERROR, "cannot pin a segment that is already pinned");
970  dsm_impl_pin_segment(seg->handle, seg->impl_private, &handle);
971  dsm_control->item[seg->control_slot].pinned = true;
974  LWLockRelease(DynamicSharedMemoryControlLock);
975 }
void dsm_impl_pin_segment(dsm_handle handle, void *impl_private, void **impl_private_pm_handle)
Definition: dsm_impl.c:963

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, is_main_region_dsm_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 178 of file dsm.c.

179 {
180  void *dsm_control_address = NULL;
181  uint32 maxitems;
182  Size segsize;
183 
185 
186  /*
187  * If we're using the mmap implementations, clean up any leftovers.
188  * Cleanup isn't needed on Windows, and happens earlier in startup for
189  * POSIX and System V shared memory, via a direct call to
190  * dsm_cleanup_using_control_segment.
191  */
194 
195  /* Determine size for new control segment. */
196  maxitems = PG_DYNSHMEM_FIXED_SLOTS
198  elog(DEBUG2, "dynamic shared memory system will support %u segments",
199  maxitems);
200  segsize = dsm_control_bytes_needed(maxitems);
201 
202  /*
203  * Loop until we find an unused identifier for the new control segment. We
204  * sometimes use DSM_HANDLE_INVALID as a sentinel value indicating "no
205  * control segment", so avoid generating that value for a real handle.
206  */
207  for (;;)
208  {
209  Assert(dsm_control_address == NULL);
211  /* Use even numbers only */
214  continue;
216  &dsm_control_impl_private, &dsm_control_address,
218  break;
219  }
220  dsm_control = dsm_control_address;
222  elog(DEBUG2,
223  "created dynamic shared memory control segment %u (%zu bytes)",
224  dsm_control_handle, segsize);
226 
227  /* Initialize control segment. */
229  dsm_control->nitems = 0;
230  dsm_control->maxitems = maxitems;
231 }
static void dsm_postmaster_shutdown(int code, Datum arg)
Definition: dsm.c:359
#define PG_DYNSHMEM_CONTROL_MAGIC
Definition: dsm.c:51
static uint64 dsm_control_bytes_needed(uint32 nitems)
Definition: dsm.c:1256
#define PG_DYNSHMEM_SLOTS_PER_BACKEND
Definition: dsm.c:54
#define PG_DYNSHMEM_FIXED_SLOTS
Definition: dsm.c:53
static void dsm_cleanup_for_mmap(void)
Definition: dsm.c:321
int dynamic_shared_memory_type
Definition: dsm_impl.c:112
#define DSM_IMPL_MMAP
Definition: dsm_impl.h:20
int MaxBackends
Definition: globals.c:142
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
dsm_handle dsm_control
Definition: pg_shmem.h:36
uint32 magic
Definition: dsm.c:93

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 1106 of file dsm.c.

1107 {
1108  Assert(seg->mapped_address != NULL);
1109  return seg->mapped_size;
1110 }

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

◆ dsm_shmem_init()

void dsm_shmem_init ( void  )

Definition at line 480 of file dsm.c.

481 {
482  size_t size = dsm_estimate_size();
483  bool found;
484 
485  if (size == 0)
486  return;
487 
488  dsm_main_space_begin = ShmemInitStruct("Preallocated DSM", size, &found);
489  if (!found)
490  {
492  size_t first_page = 0;
493  size_t pages;
494 
495  /* Reserve space for the FreePageManager. */
496  while (first_page * FPM_PAGE_SIZE < sizeof(FreePageManager))
497  ++first_page;
498 
499  /* Initialize it and give it all the rest of the space. */
501  pages = (size / FPM_PAGE_SIZE) - first_page;
502  FreePageManagerPut(fpm, first_page, pages);
503  }
504 }
size_t dsm_estimate_size(void)
Definition: dsm.c:471
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 CreateOrAttachShmemStructs().

◆ dsm_unpin_mapping()

void dsm_unpin_mapping ( dsm_segment seg)

Definition at line 935 of file dsm.c.

936 {
937  Assert(seg->resowner == NULL);
941 }
static void ResourceOwnerRememberDSM(ResourceOwner owner, dsm_segment *seg)
Definition: dsm.c:161
ResourceOwner CurrentResourceOwner
Definition: resowner.c:164
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:448

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

◆ dsm_unpin_segment()

void dsm_unpin_segment ( dsm_handle  handle)

Definition at line 989 of file dsm.c.

990 {
991  uint32 control_slot = INVALID_CONTROL_SLOT;
992  bool destroy = false;
993  uint32 i;
994 
995  /* Find the control slot for the given handle. */
996  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
997  for (i = 0; i < dsm_control->nitems; ++i)
998  {
999  /* Skip unused slots and segments that are concurrently going away. */
1000  if (dsm_control->item[i].refcnt <= 1)
1001  continue;
1002 
1003  /* If we've found our handle, we can stop searching. */
1004  if (dsm_control->item[i].handle == handle)
1005  {
1006  control_slot = i;
1007  break;
1008  }
1009  }
1010 
1011  /*
1012  * We should definitely have found the slot, and it should not already be
1013  * in the process of going away, because this function should only be
1014  * called on a segment which is pinned.
1015  */
1016  if (control_slot == INVALID_CONTROL_SLOT)
1017  elog(ERROR, "cannot unpin unknown segment handle");
1018  if (!dsm_control->item[control_slot].pinned)
1019  elog(ERROR, "cannot unpin a segment that is not pinned");
1020  Assert(dsm_control->item[control_slot].refcnt > 1);
1021 
1022  /*
1023  * Allow implementation-specific code to run. We have to do this before
1024  * releasing the lock, because impl_private_pm_handle may get modified by
1025  * dsm_impl_unpin_segment.
1026  */
1027  if (!is_main_region_dsm_handle(handle))
1028  dsm_impl_unpin_segment(handle,
1029  &dsm_control->item[control_slot].impl_private_pm_handle);
1030 
1031  /* Note that 1 means no references (0 means unused slot). */
1032  if (--dsm_control->item[control_slot].refcnt == 1)
1033  destroy = true;
1034  dsm_control->item[control_slot].pinned = false;
1035 
1036  /* Now we can release the lock. */
1037  LWLockRelease(DynamicSharedMemoryControlLock);
1038 
1039  /* Clean up resources if that was the last reference. */
1040  if (destroy)
1041  {
1042  void *junk_impl_private = NULL;
1043  void *junk_mapped_address = NULL;
1044  Size junk_mapped_size = 0;
1045 
1046  /*
1047  * For an explanation of how error handling works in this case, see
1048  * comments in dsm_detach. Note that if we reach this point, the
1049  * current process certainly does not have the segment mapped, because
1050  * if it did, the reference count would have still been greater than 1
1051  * even after releasing the reference count held by the pin. The fact
1052  * that there can't be a dsm_segment for this handle makes it OK to
1053  * pass the mapped size, mapped address, and private data as NULL
1054  * here.
1055  */
1056  if (is_main_region_dsm_handle(handle) ||
1057  dsm_impl_op(DSM_OP_DESTROY, handle, 0, &junk_impl_private,
1058  &junk_mapped_address, &junk_mapped_size, WARNING))
1059  {
1060  LWLockAcquire(DynamicSharedMemoryControlLock, LW_EXCLUSIVE);
1061  if (is_main_region_dsm_handle(handle))
1063  dsm_control->item[control_slot].first_page,
1064  dsm_control->item[control_slot].npages);
1065  Assert(dsm_control->item[control_slot].handle == handle);
1066  Assert(dsm_control->item[control_slot].refcnt == 1);
1067  dsm_control->item[control_slot].refcnt = 0;
1068  LWLockRelease(DynamicSharedMemoryControlLock);
1069  }
1070  }
1071 }
void dsm_impl_unpin_segment(dsm_handle handle, void **impl_private)
Definition: dsm_impl.c:1014

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 1133 of file dsm.c.

1134 {
1136 
1138  sizeof(dsm_segment_detach_callback));
1139  cb->function = function;
1140  cb->arg = arg;
1141  slist_push_head(&seg->on_detach, &cb->node);
1142 }
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:1006
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021

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 1171 of file dsm.c.

1172 {
1173  dlist_iter iter;
1174 
1176  {
1177  dsm_segment *seg = dlist_container(dsm_segment, node, iter.cur);
1178 
1179  /* Throw away explicit on-detach actions one by one. */
1180  while (!slist_is_empty(&seg->on_detach))
1181  {
1182  slist_node *node;
1184 
1185  node = slist_pop_head_node(&seg->on_detach);
1186  cb = slist_container(dsm_segment_detach_callback, node, node);
1187  pfree(cb);
1188  }
1189 
1190  /*
1191  * Decrementing the reference count is a sort of implicit on-detach
1192  * action; make sure we don't do that, either.
1193  */
1195  }
1196 }

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().