PostgreSQL Source Code git master
Loading...
Searching...
No Matches
shmem.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/slru.h"
#include "fmgr.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "port/pg_bitutils.h"
#include "port/pg_numa.h"
#include "storage/lwlock.h"
#include "storage/pg_shmem.h"
#include "storage/shmem.h"
#include "storage/shmem_internal.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/tuplestore.h"
Include dependency graph for shmem.c:

Go to the source code of this file.

Data Structures

struct  ShmemRequest
 
struct  ShmemAllocatorData
 
struct  ShmemIndexEnt
 

Macros

#define ShmemIndexLock   (&ShmemAllocator->index_lock)
 
#define SHMEM_INDEX_KEYSIZE   (48)
 
#define SHMEM_INDEX_ADDITIONAL_SIZE   (128)
 
#define PG_GET_SHMEM_SIZES_COLS   4
 
#define PG_GET_SHMEM_NUMA_SIZES_COLS   3
 

Typedefs

typedef struct ShmemAllocatorData ShmemAllocatorData
 

Enumerations

enum  shmem_request_state {
  SRS_INITIAL , SRS_REQUESTING , SRS_INITIALIZING , SRS_ATTACHING ,
  SRS_AFTER_STARTUP_ATTACH_OR_INIT , SRS_DONE
}
 

Functions

static voidShmemAllocRaw (Size size, Size alignment, Size *allocated_size)
 
static void CallShmemCallbacksAfterStartup (const ShmemCallbacks *callbacks)
 
static void InitShmemIndexEntry (ShmemRequest *request)
 
static bool AttachShmemIndexEntry (ShmemRequest *request, bool missing_ok)
 
Datum pg_numa_available (PG_FUNCTION_ARGS)
 
void ShmemRequestStructWithOpts (const ShmemStructOpts *options)
 
void ShmemRequestInternal (ShmemStructOpts *options, ShmemRequestKind kind)
 
size_t ShmemGetRequestedSize (void)
 
void ShmemInitRequested (void)
 
void InitShmemAllocator (PGShmemHeader *seghdr)
 
void ResetShmemAllocator (void)
 
voidShmemAlloc (Size size)
 
voidShmemAllocNoError (Size size)
 
bool ShmemAddrIsValid (const void *addr)
 
void RegisterShmemCallbacks (const ShmemCallbacks *callbacks)
 
void ShmemCallRequestCallbacks (void)
 
voidShmemInitStruct (const char *name, Size size, bool *foundPtr)
 
Datum pg_get_shmem_allocations (PG_FUNCTION_ARGS)
 
Datum pg_get_shmem_allocations_numa (PG_FUNCTION_ARGS)
 
Size pg_get_shmem_pagesize (void)
 

Variables

static Listregistered_shmem_callbacks
 
static Listpending_shmem_requests
 
static enum shmem_request_state shmem_request_state = SRS_INITIAL
 
static PGShmemHeaderShmemSegHdr
 
static voidShmemBase
 
static voidShmemEnd
 
static ShmemAllocatorDataShmemAllocator
 
static HTABShmemIndex
 
static bool firstNumaTouch = true
 

Macro Definition Documentation

◆ PG_GET_SHMEM_NUMA_SIZES_COLS

#define PG_GET_SHMEM_NUMA_SIZES_COLS   3

◆ PG_GET_SHMEM_SIZES_COLS

#define PG_GET_SHMEM_SIZES_COLS   4

◆ SHMEM_INDEX_ADDITIONAL_SIZE

#define SHMEM_INDEX_ADDITIONAL_SIZE   (128)

Definition at line 262 of file shmem.c.

◆ SHMEM_INDEX_KEYSIZE

#define SHMEM_INDEX_KEYSIZE   (48)

Definition at line 255 of file shmem.c.

◆ ShmemIndexLock

#define ShmemIndexLock   (&ShmemAllocator->index_lock)

Definition at line 236 of file shmem.c.

Typedef Documentation

◆ ShmemAllocatorData

Enumeration Type Documentation

◆ shmem_request_state

Enumerator
SRS_INITIAL 
SRS_REQUESTING 
SRS_INITIALIZING 
SRS_ATTACHING 
SRS_AFTER_STARTUP_ATTACH_OR_INIT 
SRS_DONE 

Definition at line 184 of file shmem.c.

185{
186 /* Initial state */
188
189 /*
190 * When we start calling the shmem_request callbacks, we enter the
191 * SRS_REQUESTING phase. All ShmemRequestStruct calls happen in this
192 * state.
193 */
195
196 /*
197 * Postmaster has finished all shmem requests, and is now initializing the
198 * shared memory segment. init_fn callbacks are called in this state.
199 */
201
202 /*
203 * A postmaster child process is starting up. attach_fn callbacks are
204 * called in this state.
205 */
207
208 /* An after-startup allocation or attachment is in progress */
210
211 /* Normal state after shmem initialization / attachment */
212 SRS_DONE,
213};
@ SRS_INITIALIZING
Definition shmem.c:200
@ SRS_DONE
Definition shmem.c:212
@ SRS_ATTACHING
Definition shmem.c:206
@ SRS_INITIAL
Definition shmem.c:187
@ SRS_AFTER_STARTUP_ATTACH_OR_INIT
Definition shmem.c:209
@ SRS_REQUESTING
Definition shmem.c:194

Function Documentation

◆ AttachShmemIndexEntry()

static bool AttachShmemIndexEntry ( ShmemRequest request,
bool  missing_ok 
)
static

Definition at line 580 of file shmem.c.

581{
582 const char *name = request->options->name;
584
585 /* Look it up in the shmem index */
588 if (!index_entry)
589 {
590 if (!missing_ok)
592 (errmsg("could not find ShmemIndex entry for data structure \"%s\"",
593 request->options->name)));
594 return false;
595 }
596
597 /* Check that the size in the index matches the request */
598 if (index_entry->size != request->options->size &&
599 request->options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
600 {
602 (errmsg("shared memory struct \"%s\" was created with"
603 " different size: existing %zu, requested %zd",
604 name, index_entry->size, request->options->size)));
605 }
606
607 /*
608 * Re-establish the caller's pointer variable, or do other actions to
609 * attach depending on the kind of shmem area it is.
610 */
611 switch (request->kind)
612 {
614 if (request->options->ptr)
615 *(request->options->ptr) = index_entry->location;
616 break;
617 case SHMEM_KIND_HASH:
618 shmem_hash_attach(index_entry->location, request->options);
619 break;
620 case SHMEM_KIND_SLRU:
621 shmem_slru_attach(index_entry->location, request->options);
622 break;
623 }
624
625 return true;
626}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
@ HASH_FIND
Definition hsearch.h:108
static char * errmsg
static int fb(int x)
static HTAB * ShmemIndex
Definition shmem.c:252
#define SHMEM_ATTACH_UNKNOWN_SIZE
Definition shmem.h:69
void shmem_hash_attach(void *location, ShmemStructOpts *base_options)
Definition shmem_hash.c:79
@ SHMEM_KIND_SLRU
@ SHMEM_KIND_HASH
@ SHMEM_KIND_STRUCT
void shmem_slru_attach(void *location, ShmemStructOpts *base_options)
Definition slru.c:359
const char * name

References ereport, errmsg, ERROR, fb(), HASH_FIND, hash_search(), name, SHMEM_ATTACH_UNKNOWN_SIZE, shmem_hash_attach(), SHMEM_KIND_HASH, SHMEM_KIND_SLRU, SHMEM_KIND_STRUCT, shmem_slru_attach(), and ShmemIndex.

Referenced by CallShmemCallbacksAfterStartup(), and ShmemInitStruct().

◆ CallShmemCallbacksAfterStartup()

static void CallShmemCallbacksAfterStartup ( const ShmemCallbacks callbacks)
static

Definition at line 898 of file shmem.c.

899{
900 bool found_any;
901 bool notfound_any;
902
905
906 /*
907 * Call the request callback first. The callback makes ShmemRequest*()
908 * calls for each shmem area, adding them to pending_shmem_requests.
909 */
911 if (callbacks->request_fn)
912 callbacks->request_fn(callbacks->opaque_arg);
914
916 {
918 return;
919 }
920
921 /* Hold ShmemIndexLock while we allocate all the shmem entries */
923
924 /*
925 * Check if the requested shared memory areas have already been
926 * initialized. We assume all the areas requested by the request callback
927 * to form a coherent unit such that they're all already initialized or
928 * none. Otherwise it would be ambiguous which callback, init or attach,
929 * to callback afterwards.
930 */
931 found_any = notfound_any = false;
933 {
934 if (hash_search(ShmemIndex, request->options->name, HASH_FIND, NULL))
935 found_any = true;
936 else
937 notfound_any = true;
938 }
939 if (found_any && notfound_any)
940 elog(ERROR, "found some but not all");
941
942 /*
943 * Allocate or attach all the shmem areas requested by the request_fn
944 * callback.
945 */
947 {
948 if (found_any)
950 else
952
953 pfree(request->options);
954 }
957
958 /* Finish by calling the appropriate subsystem-specific callback */
959 if (found_any)
960 {
961 if (callbacks->attach_fn)
962 callbacks->attach_fn(callbacks->opaque_arg);
963 }
964 else
965 {
966 if (callbacks->init_fn)
967 callbacks->init_fn(callbacks->opaque_arg);
968 }
969
972}
#define Assert(condition)
Definition c.h:943
#define elog(elevel,...)
Definition elog.h:228
void list_free_deep(List *list)
Definition list.c:1560
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
void pfree(void *pointer)
Definition mcxt.c:1619
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
static void InitShmemIndexEntry(ShmemRequest *request)
Definition shmem.c:511
shmem_request_state
Definition shmem.c:185
static List * pending_shmem_requests
Definition shmem.c:169
#define ShmemIndexLock
Definition shmem.c:236
static bool AttachShmemIndexEntry(ShmemRequest *request, bool missing_ok)
Definition shmem.c:580
ShmemRequestCallback request_fn
Definition shmem.h:133
ShmemInitCallback init_fn
Definition shmem.h:139
void * opaque_arg
Definition shmem.h:153
ShmemAttachCallback attach_fn
Definition shmem.h:147

References Assert, ShmemCallbacks::attach_fn, AttachShmemIndexEntry(), elog, ERROR, fb(), foreach_ptr, HASH_FIND, hash_search(), ShmemCallbacks::init_fn, InitShmemIndexEntry(), list_free_deep(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), NIL, ShmemCallbacks::opaque_arg, pending_shmem_requests, pfree(), ShmemCallbacks::request_fn, ShmemIndex, ShmemIndexLock, SRS_AFTER_STARTUP_ATTACH_OR_INIT, SRS_DONE, and SRS_REQUESTING.

Referenced by RegisterShmemCallbacks().

◆ InitShmemAllocator()

void InitShmemAllocator ( PGShmemHeader seghdr)

Definition at line 637 of file shmem.c.

638{
639 Size offset;
641 HASHCTL info;
642 int hash_flags;
643
644#ifndef EXEC_BACKEND
646#endif
647 Assert(seghdr != NULL);
648
650 {
652 }
653 else
654 {
657 }
658
659 /*
660 * We assume the pointer and offset are MAXALIGN. Not a hard requirement,
661 * but it's true today and keeps the math below simpler.
662 */
663 Assert(seghdr == (void *) MAXALIGN(seghdr));
664 Assert(seghdr->content_offset == MAXALIGN(seghdr->content_offset));
665
666 /*
667 * Allocations after this point should go through ShmemAlloc, which
668 * expects to allocate everything on cache line boundaries. Make sure the
669 * first allocation begins on a cache line boundary.
670 */
671 offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
672 if (offset > seghdr->totalsize)
675 errmsg("out of shared memory (%zu bytes requested)",
676 offset)));
677
678 /*
679 * In postmaster or stand-alone backend, initialize the shared memory
680 * allocator so that we can allocate shared memory for ShmemIndex using
681 * ShmemAlloc(). In a regular backend just set up the pointers required
682 * by ShmemAlloc().
683 */
684 ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
686 {
688 ShmemAllocator->free_offset = offset;
690 }
691
694 ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
695
696 /*
697 * Create (or attach to) the shared memory index of shmem areas.
698 *
699 * This is the same initialization as ShmemInitHash() does, but we cannot
700 * use ShmemInitHash() here because it relies on ShmemIndex being already
701 * initialized.
702 */
704
706 info.entrysize = sizeof(ShmemIndexEnt);
707 hash_flags = HASH_ELEM | HASH_STRINGS | HASH_FIXED_SIZE;
708
710 {
713 }
717 "ShmemIndex", hash_nelems,
718 &info, hash_flags);
720
721 /*
722 * Add an entry for ShmemIndex itself into ShmemIndex, so that it's
723 * visible in the pg_shmem_allocations view
724 */
726 {
727 bool found;
729 hash_search(ShmemIndex, "ShmemIndex", HASH_ENTER, &found);
730
731 Assert(!found);
733 result->allocated_size = ShmemAllocator->index_size;
734 result->location = ShmemAllocator->index;
735 }
736}
#define CACHELINEALIGN(LEN)
Definition c.h:899
#define MAXALIGN(LEN)
Definition c.h:896
int64_t int64
Definition c.h:621
size_t Size
Definition c.h:689
uint32 result
Size hash_estimate_size(int64 num_entries, Size entrysize)
Definition dynahash.c:763
int errcode(int sqlerrcode)
Definition elog.c:875
bool IsUnderPostmaster
Definition globals.c:122
#define HASH_STRINGS
Definition hsearch.h:91
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_FIXED_SIZE
Definition hsearch.h:100
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:670
static int list_length(const List *l)
Definition pg_list.h:152
static void * ShmemBase
Definition shmem.c:243
static void * ShmemEnd
Definition shmem.c:244
void * ShmemAlloc(Size size)
Definition shmem.c:763
static PGShmemHeader * ShmemSegHdr
Definition shmem.c:242
#define SHMEM_INDEX_ADDITIONAL_SIZE
Definition shmem.c:262
static ShmemAllocatorData * ShmemAllocator
Definition shmem.c:246
#define SHMEM_INDEX_KEYSIZE
Definition shmem.c:255
HTAB * shmem_hash_create(void *location, size_t size, bool found, const char *name, int64 nelems, HASHCTL *infoP, int hash_flags)
Definition shmem_hash.c:149
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
Size keysize
Definition hsearch.h:69
Size entrysize
Definition hsearch.h:70
Size totalsize
Definition pg_shmem.h:34
HASHHDR * index
Definition shmem.c:231
LWLock index_lock
Definition shmem.c:233
slock_t shmem_lock
Definition shmem.c:229
size_t index_size
Definition shmem.c:232

References Assert, CACHELINEALIGN, HASHCTL::entrysize, ereport, errcode(), errmsg, ERROR, fb(), ShmemAllocatorData::free_offset, HASH_ELEM, HASH_ENTER, hash_estimate_size(), HASH_FIXED_SIZE, hash_search(), HASH_STRINGS, ShmemAllocatorData::index, ShmemAllocatorData::index_lock, ShmemAllocatorData::index_size, IsUnderPostmaster, HASHCTL::keysize, list_length(), LWLockInitialize(), MAXALIGN, pending_shmem_requests, result, shmem_hash_create(), SHMEM_INDEX_ADDITIONAL_SIZE, SHMEM_INDEX_KEYSIZE, ShmemAllocatorData::shmem_lock, ShmemAlloc(), ShmemAllocator, ShmemBase, ShmemEnd, ShmemIndex, ShmemSegHdr, SpinLockInit(), SRS_INITIAL, SRS_INITIALIZING, SRS_REQUESTING, and PGShmemHeader::totalsize.

Referenced by CreateSharedMemoryAndSemaphores().

◆ InitShmemIndexEntry()

static void InitShmemIndexEntry ( ShmemRequest request)
static

Definition at line 511 of file shmem.c.

512{
513 const char *name = request->options->name;
515 bool found;
516 size_t allocated_size;
517 void *structPtr;
518
519 /* look it up in the shmem index */
522 if (found)
523 elog(ERROR, "shared memory struct \"%s\" is already initialized", name);
524 if (!index_entry)
525 {
526 /* tried to add it to the hash table, but there was no space */
529 errmsg("could not create ShmemIndex entry for data structure \"%s\"",
530 name)));
531 }
532
533 /*
534 * We inserted the entry to the shared memory index. Allocate requested
535 * amount of shared memory for it, and initialize the index entry.
536 */
537 structPtr = ShmemAllocRaw(request->options->size,
538 request->options->alignment,
539 &allocated_size);
540 if (structPtr == NULL)
541 {
542 /* out of memory; remove the failed ShmemIndex entry */
546 errmsg("not enough shared memory for data structure"
547 " \"%s\" (%zd bytes requested)",
548 name, request->options->size)));
549 }
550 index_entry->size = request->options->size;
551 index_entry->allocated_size = allocated_size;
552 index_entry->location = structPtr;
553
554 /* Initialize depending on the kind of shmem area it is */
555 switch (request->kind)
556 {
558 if (request->options->ptr)
559 *(request->options->ptr) = index_entry->location;
560 break;
561 case SHMEM_KIND_HASH:
563 break;
564 case SHMEM_KIND_SLRU:
566 break;
567 }
568}
@ HASH_REMOVE
Definition hsearch.h:110
@ HASH_ENTER_NULL
Definition hsearch.h:111
static void * ShmemAllocRaw(Size size, Size alignment, Size *allocated_size)
Definition shmem.c:797
void shmem_hash_init(void *location, ShmemStructOpts *base_options)
Definition shmem_hash.c:63
void shmem_slru_init(void *location, ShmemStructOpts *base_options)
Definition slru.c:267

References elog, ereport, errcode(), errmsg, ERROR, fb(), HASH_ENTER_NULL, HASH_REMOVE, hash_search(), name, shmem_hash_init(), SHMEM_KIND_HASH, SHMEM_KIND_SLRU, SHMEM_KIND_STRUCT, shmem_slru_init(), ShmemAllocRaw(), and ShmemIndex.

Referenced by CallShmemCallbacksAfterStartup(), ShmemInitRequested(), and ShmemInitStruct().

◆ pg_get_shmem_allocations()

Datum pg_get_shmem_allocations ( PG_FUNCTION_ARGS  )

Definition at line 1045 of file shmem.c.

1046{
1047#define PG_GET_SHMEM_SIZES_COLS 4
1048 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1053 bool nulls[PG_GET_SHMEM_SIZES_COLS];
1054
1055 InitMaterializedSRF(fcinfo, 0);
1056
1058
1060
1061 /* output all allocated entries */
1062 memset(nulls, 0, sizeof(nulls));
1063 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
1064 {
1065 values[0] = CStringGetTextDatum(ent->key);
1066 values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
1067 values[2] = Int64GetDatum(ent->size);
1068 values[3] = Int64GetDatum(ent->allocated_size);
1069 named_allocated += ent->allocated_size;
1070
1071 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1072 values, nulls);
1073 }
1074
1075 /* output shared memory allocated but not counted via the shmem index */
1076 values[0] = CStringGetTextDatum("<anonymous>");
1077 nulls[1] = true;
1079 values[3] = values[2];
1080 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1081
1082 /* output as-of-yet unused shared memory */
1083 nulls[0] = true;
1085 nulls[1] = false;
1087 values[3] = values[2];
1088 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1089
1091
1092 return (Datum) 0;
1093}
static Datum values[MAXATTR]
Definition bootstrap.c:190
#define CStringGetTextDatum(s)
Definition builtins.h:98
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
@ LW_SHARED
Definition lwlock.h:105
static Datum Int64GetDatum(int64 X)
Definition postgres.h:426
uint64_t Datum
Definition postgres.h:70
#define PG_GET_SHMEM_SIZES_COLS
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785

References CStringGetTextDatum, fb(), ShmemAllocatorData::free_offset, hash_seq_init(), hash_seq_search(), InitMaterializedSRF(), Int64GetDatum(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PG_GET_SHMEM_SIZES_COLS, ShmemAllocator, ShmemIndex, ShmemIndexLock, ShmemSegHdr, PGShmemHeader::totalsize, tuplestore_putvalues(), and values.

◆ pg_get_shmem_allocations_numa()

Datum pg_get_shmem_allocations_numa ( PG_FUNCTION_ARGS  )

Definition at line 1102 of file shmem.c.

1103{
1104#define PG_GET_SHMEM_NUMA_SIZES_COLS 3
1105 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1109 bool nulls[PG_GET_SHMEM_NUMA_SIZES_COLS];
1111 void **page_ptrs;
1112 int *pages_status;
1115 max_nodes;
1116 Size *nodes;
1117
1118 if (pg_numa_init() == -1)
1119 elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
1120
1121 InitMaterializedSRF(fcinfo, 0);
1122
1125
1126 /*
1127 * Shared memory allocations can vary in size and may not align with OS
1128 * memory page boundaries, while NUMA queries work on pages.
1129 *
1130 * To correctly map each allocation to NUMA nodes, we need to: 1.
1131 * Determine the OS memory page size. 2. Align each allocation's start/end
1132 * addresses to page boundaries. 3. Query NUMA node information for all
1133 * pages spanning the allocation.
1134 */
1136
1137 /*
1138 * Allocate memory for page pointers and status based on total shared
1139 * memory size. This simplified approach allocates enough space for all
1140 * pages in shared memory rather than calculating the exact requirements
1141 * for each segment.
1142 *
1143 * Add 1, because we don't know how exactly the segments align to OS
1144 * pages, so the allocation might use one more memory page. In practice
1145 * this is not very likely, and moreover we have more entries, each of
1146 * them using only fraction of the total pages.
1147 */
1151
1152 if (firstNumaTouch)
1153 elog(DEBUG1, "NUMA: page-faulting shared memory segments for proper NUMA readouts");
1154
1156
1158
1159 /* output all allocated entries */
1160 while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
1161 {
1162 int i;
1163 char *startptr,
1164 *endptr;
1165 Size total_len;
1166
1167 /*
1168 * Calculate the range of OS pages used by this segment. The segment
1169 * may start / end half-way through a page, we want to count these
1170 * pages too. So we align the start/end pointers down/up, and then
1171 * calculate the number of pages from that.
1172 */
1173 startptr = (char *) TYPEALIGN_DOWN(os_page_size, ent->location);
1174 endptr = (char *) TYPEALIGN(os_page_size,
1175 (char *) ent->location + ent->allocated_size);
1176 total_len = (endptr - startptr);
1177
1178 shm_ent_page_count = total_len / os_page_size;
1179
1180 /*
1181 * If we ever get 0xff (-1) back from kernel inquiry, then we probably
1182 * have a bug in mapping buffers to OS pages.
1183 */
1184 memset(pages_status, 0xff, sizeof(int) * shm_ent_page_count);
1185
1186 /*
1187 * Setup page_ptrs[] with pointers to all OS pages for this segment,
1188 * and get the NUMA status using pg_numa_query_pages.
1189 *
1190 * In order to get reliable results we also need to touch memory
1191 * pages, so that inquiry about NUMA memory node doesn't return -2
1192 * (ENOENT, which indicates unmapped/unallocated pages).
1193 */
1194 for (i = 0; i < shm_ent_page_count; i++)
1195 {
1196 page_ptrs[i] = startptr + (i * os_page_size);
1197
1198 if (firstNumaTouch)
1200
1202 }
1203
1205 elog(ERROR, "failed NUMA pages inquiry status: %m");
1206
1207 /* Count number of NUMA nodes used for this shared memory entry */
1208 memset(nodes, 0, sizeof(Size) * (max_nodes + 2));
1209
1210 for (i = 0; i < shm_ent_page_count; i++)
1211 {
1212 int s = pages_status[i];
1213
1214 /* Ensure we are adding only valid index to the array */
1215 if (s >= 0 && s <= max_nodes)
1216 {
1217 /* valid NUMA node */
1218 nodes[s]++;
1219 continue;
1220 }
1221 else if (s == -2)
1222 {
1223 /* -2 means ENOENT (e.g. page was moved to swap) */
1224 nodes[max_nodes + 1]++;
1225 continue;
1226 }
1227
1228 elog(ERROR, "invalid NUMA node id outside of allowed range "
1229 "[0, " UINT64_FORMAT "]: %d", max_nodes, s);
1230 }
1231
1232 /* no NULLs for regular nodes */
1233 memset(nulls, 0, sizeof(nulls));
1234
1235 /*
1236 * Add one entry for each NUMA node, including those without allocated
1237 * memory for this segment.
1238 */
1239 for (i = 0; i <= max_nodes; i++)
1240 {
1241 values[0] = CStringGetTextDatum(ent->key);
1242 values[1] = Int32GetDatum(i);
1244
1245 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1246 values, nulls);
1247 }
1248
1249 /* The last entry is used for pages without a NUMA node. */
1250 nulls[1] = true;
1251 values[0] = CStringGetTextDatum(ent->key);
1253
1254 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1255 values, nulls);
1256 }
1257
1259 firstNumaTouch = false;
1260
1261 return (Datum) 0;
1262}
#define TYPEALIGN(ALIGNVAL, LEN)
Definition c.h:889
#define UINT64_FORMAT
Definition c.h:635
uint64_t uint64
Definition c.h:625
#define TYPEALIGN_DOWN(ALIGNVAL, LEN)
Definition c.h:901
#define DEBUG1
Definition elog.h:31
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_array(type, count)
Definition fe_memutils.h:92
int i
Definition isn.c:77
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
PGDLLIMPORT int pg_numa_get_max_node(void)
Definition pg_numa.c:138
#define pg_numa_touch_mem_if_required(ptr)
Definition pg_numa.h:37
PGDLLIMPORT int pg_numa_query_pages(int pid, unsigned long count, void **pages, int *status)
Definition pg_numa.c:132
PGDLLIMPORT int pg_numa_init(void)
Definition pg_numa.c:125
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
Size pg_get_shmem_pagesize(void)
Definition shmem.c:1273
#define PG_GET_SHMEM_NUMA_SIZES_COLS
static bool firstNumaTouch
Definition shmem.c:274

References CHECK_FOR_INTERRUPTS, CStringGetTextDatum, DEBUG1, elog, ERROR, fb(), firstNumaTouch, hash_seq_init(), hash_seq_search(), i, InitMaterializedSRF(), Int32GetDatum(), Int64GetDatum(), LW_SHARED, LWLockAcquire(), LWLockRelease(), palloc0_array, palloc_array, PG_GET_SHMEM_NUMA_SIZES_COLS, pg_get_shmem_pagesize(), pg_numa_get_max_node(), pg_numa_init(), pg_numa_query_pages(), pg_numa_touch_mem_if_required, ShmemIndex, ShmemIndexLock, ShmemSegHdr, PGShmemHeader::totalsize, tuplestore_putvalues(), TYPEALIGN, TYPEALIGN_DOWN, UINT64_FORMAT, and values.

◆ pg_get_shmem_pagesize()

Size pg_get_shmem_pagesize ( void  )

Definition at line 1273 of file shmem.c.

1274{
1276#ifdef WIN32
1278
1280 os_page_size = sysinfo.dwPageSize;
1281#else
1283#endif
1284
1287
1290
1291 return os_page_size;
1292}
int huge_pages_status
Definition guc_tables.c:610
@ HUGE_PAGES_UNKNOWN
Definition pg_shmem.h:56
@ HUGE_PAGES_ON
Definition pg_shmem.h:54
void GetHugePageSize(Size *hugepagesize, int *mmap_flags)
Definition sysv_shmem.c:480

References Assert, fb(), GetHugePageSize(), HUGE_PAGES_ON, huge_pages_status, HUGE_PAGES_UNKNOWN, and IsUnderPostmaster.

Referenced by pg_buffercache_os_pages_internal(), and pg_get_shmem_allocations_numa().

◆ pg_numa_available()

Datum pg_numa_available ( PG_FUNCTION_ARGS  )

Definition at line 1295 of file shmem.c.

1296{
1298}
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360

References pg_numa_init(), and PG_RETURN_BOOL.

◆ RegisterShmemCallbacks()

void RegisterShmemCallbacks ( const ShmemCallbacks callbacks)

Definition at line 873 of file shmem.c.

874{
876 {
877 /*
878 * After-startup initialization or attachment. Call the appropriate
879 * callbacks immediately.
880 */
881 if ((callbacks->flags & SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP) == 0)
882 elog(ERROR, "cannot request shared memory at this time");
883
885 }
886 else
887 {
888 /* Remember the callbacks for later */
890 (void *) callbacks);
891 }
892}
List * lappend(List *list, void *datum)
Definition list.c:339
static List * registered_shmem_callbacks
Definition shmem.c:157
static void CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
Definition shmem.c:898
#define SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP
Definition shmem.h:167

References CallShmemCallbacksAfterStartup(), elog, ERROR, ShmemCallbacks::flags, IsUnderPostmaster, lappend(), registered_shmem_callbacks, SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP, and SRS_DONE.

Referenced by _PG_init().

◆ ResetShmemAllocator()

void ResetShmemAllocator ( void  )

Definition at line 742 of file shmem.c.

743{
746
748
749 /*
750 * Note that we don't clear the registered callbacks. We will need to
751 * call them again as we restart
752 */
753}

References Assert, IsUnderPostmaster, NIL, pending_shmem_requests, and SRS_INITIAL.

Referenced by PostmasterStateMachine().

◆ ShmemAddrIsValid()

bool ShmemAddrIsValid ( const void addr)

Definition at line 849 of file shmem.c.

850{
851 return (addr >= ShmemBase) && (addr < ShmemEnd);
852}

References ShmemBase, and ShmemEnd.

Referenced by ReleasePredXact().

◆ ShmemAlloc()

void * ShmemAlloc ( Size  size)

Definition at line 763 of file shmem.c.

764{
765 void *newSpace;
766 Size allocated_size;
767
768 newSpace = ShmemAllocRaw(size, 0, &allocated_size);
769 if (!newSpace)
772 errmsg("out of shared memory (%zu bytes requested)",
773 size)));
774 return newSpace;
775}

References ereport, errcode(), errmsg, ERROR, fb(), and ShmemAllocRaw().

Referenced by InitShmemAllocator().

◆ ShmemAllocNoError()

void * ShmemAllocNoError ( Size  size)

Definition at line 783 of file shmem.c.

784{
785 Size allocated_size;
786
787 return ShmemAllocRaw(size, 0, &allocated_size);
788}

References ShmemAllocRaw().

◆ ShmemAllocRaw()

static void * ShmemAllocRaw ( Size  size,
Size  alignment,
Size allocated_size 
)
static

Definition at line 797 of file shmem.c.

798{
802 void *newSpace;
803
804 /*
805 * Ensure all space is adequately aligned. We used to only MAXALIGN this
806 * space but experience has proved that on modern systems that is not good
807 * enough. Many parts of the system are very sensitive to critical data
808 * structures getting split across cache line boundaries. To avoid that,
809 * attempt to align the beginning of the allocation to a cache line
810 * boundary. The calling code will still need to be careful about how it
811 * uses the allocated space - e.g. by padding each element in an array of
812 * structures out to a power-of-two size - but without this, even that
813 * won't be sufficient.
814 */
815 if (alignment < PG_CACHE_LINE_SIZE)
816 alignment = PG_CACHE_LINE_SIZE;
817
819
821
823 newStart = TYPEALIGN(alignment, rawStart);
824
825 newFree = newStart + size;
826 if (newFree <= ShmemSegHdr->totalsize)
827 {
828 newSpace = (char *) ShmemBase + newStart;
830 }
831 else
832 newSpace = NULL;
833
835
836 /* note this assert is okay with newSpace == NULL */
837 Assert(newSpace == (void *) TYPEALIGN(alignment, newSpace));
838
839 *allocated_size = newFree - rawStart;
840 return newSpace;
841}
#define PG_CACHE_LINE_SIZE
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56

References Assert, fb(), ShmemAllocatorData::free_offset, PG_CACHE_LINE_SIZE, ShmemAllocatorData::shmem_lock, ShmemAllocator, ShmemBase, ShmemSegHdr, SpinLockAcquire(), SpinLockRelease(), and TYPEALIGN.

Referenced by InitShmemIndexEntry(), ShmemAlloc(), and ShmemAllocNoError().

◆ ShmemCallRequestCallbacks()

void ShmemCallRequestCallbacks ( void  )

Definition at line 978 of file shmem.c.

979{
980 ListCell *lc;
981
984
986 {
987 const ShmemCallbacks *callbacks = (const ShmemCallbacks *) lfirst(lc);
988
989 if (callbacks->request_fn)
990 callbacks->request_fn(callbacks->opaque_arg);
991 }
992}
#define lfirst(lc)
Definition pg_list.h:172

References Assert, fb(), lfirst, ShmemCallbacks::opaque_arg, registered_shmem_callbacks, ShmemCallbacks::request_fn, SRS_INITIAL, and SRS_REQUESTING.

Referenced by BootstrapModeMain(), PostgresSingleUserMain(), PostmasterMain(), and PostmasterStateMachine().

◆ ShmemGetRequestedSize()

size_t ShmemGetRequestedSize ( void  )

Definition at line 391 of file shmem.c.

392{
393 size_t size;
394
395 /* memory needed for the ShmemIndex */
397 sizeof(ShmemIndexEnt));
398 size = CACHELINEALIGN(size);
399
400 /* memory needed for all the requested areas */
402 {
403 size_t alignment = request->options->alignment;
404
405 /* pad the start address for alignment like ShmemAllocRaw() does */
406 if (alignment < PG_CACHE_LINE_SIZE)
407 alignment = PG_CACHE_LINE_SIZE;
408 size = TYPEALIGN(alignment, size);
409
410 size = add_size(size, request->options->size);
411 }
412
413 return size;
414}
Size add_size(Size s1, Size s2)
Definition mcxt.c:1733

References add_size(), CACHELINEALIGN, fb(), foreach_ptr, hash_estimate_size(), list_length(), pending_shmem_requests, PG_CACHE_LINE_SIZE, SHMEM_INDEX_ADDITIONAL_SIZE, and TYPEALIGN.

Referenced by CalculateShmemSize().

◆ ShmemInitRequested()

void ShmemInitRequested ( void  )

Definition at line 424 of file shmem.c.

425{
426 /* should be called only by the postmaster or a standalone backend */
429
430 /*
431 * Initialize the ShmemIndex entries and perform basic initialization of
432 * all the requested memory areas. There are no concurrent processes yet,
433 * so no need for locking.
434 */
436 {
438 pfree(request->options);
439 }
442
443 /*
444 * Call the subsystem-specific init callbacks to finish initialization of
445 * all the areas.
446 */
448 {
449 if (callbacks->init_fn)
450 callbacks->init_fn(callbacks->opaque_arg);
451 }
452
454}

References Assert, fb(), foreach_ptr, InitShmemIndexEntry(), IsUnderPostmaster, list_free_deep(), NIL, pending_shmem_requests, pfree(), registered_shmem_callbacks, SRS_DONE, and SRS_INITIALIZING.

Referenced by CreateSharedMemoryAndSemaphores().

◆ ShmemInitStruct()

void * ShmemInitStruct ( const char name,
Size  size,
bool foundPtr 
)

Definition at line 1010 of file shmem.c.

1011{
1012 void *ptr = NULL;
1014 .name = name,
1015 .size = size,
1016 .ptr = &ptr,
1017 };
1019
1023
1025
1026 /*
1027 * During postmaster startup, look up the existing entry if any.
1028 */
1029 *foundPtr = false;
1032
1033 /* Initialize it if not found */
1034 if (!*foundPtr)
1036
1038
1039 Assert(ptr != NULL);
1040 return ptr;
1041}

References Assert, AttachShmemIndexEntry(), fb(), InitShmemIndexEntry(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), name, SHMEM_KIND_STRUCT, ShmemIndexLock, SRS_DONE, SRS_INITIALIZING, and SRS_REQUESTING.

Referenced by ShmemInitHash().

◆ ShmemRequestInternal()

void ShmemRequestInternal ( ShmemStructOpts options,
ShmemRequestKind  kind 
)

Definition at line 336 of file shmem.c.

337{
339
340 /* Check the options */
341 if (options->name == NULL)
342 elog(ERROR, "shared memory request is missing 'name' option");
343
345 {
346 if (options->size <= 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
347 elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
348 options->size, options->name);
349 }
350 else
351 {
353 elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
354 if (options->size <= 0)
355 elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
356 options->size, options->name);
357 }
358
359 if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment)
360 elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"",
361 options->alignment, options->name);
362
363 /* Check that we're in the right state */
365 elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
366
367 /* Check that it's not already registered in this process */
369 {
370 if (strcmp(existing->options->name, options->name) == 0)
372 (errmsg("shared memory struct \"%s\" is already registered",
373 options->name)));
374 }
375
376 /* Request looks valid, remember it */
377 request = palloc(sizeof(ShmemRequest));
378 request->options = options;
379 request->kind = kind;
381}
void * palloc(Size size)
Definition mcxt.c:1390
#define pg_nextpower2_size_t

References elog, ereport, errmsg, ERROR, fb(), foreach_ptr, IsUnderPostmaster, lappend(), palloc(), pending_shmem_requests, pg_nextpower2_size_t, SHMEM_ATTACH_UNKNOWN_SIZE, and SRS_REQUESTING.

Referenced by ShmemRequestHashWithOpts(), ShmemRequestStructWithOpts(), and SimpleLruRequestWithOpts().

◆ ShmemRequestStructWithOpts()

void ShmemRequestStructWithOpts ( const ShmemStructOpts options)

Definition at line 315 of file shmem.c.

316{
318
320 sizeof(ShmemStructOpts));
322
324}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1235
MemoryContext TopMemoryContext
Definition mcxt.c:167
void ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
Definition shmem.c:336

References fb(), memcpy(), MemoryContextAlloc(), SHMEM_KIND_STRUCT, ShmemRequestInternal(), and TopMemoryContext.

Variable Documentation

◆ firstNumaTouch

bool firstNumaTouch = true
static

Definition at line 274 of file shmem.c.

Referenced by pg_get_shmem_allocations_numa().

◆ pending_shmem_requests

◆ registered_shmem_callbacks

List* registered_shmem_callbacks
static

Definition at line 157 of file shmem.c.

Referenced by RegisterShmemCallbacks(), ShmemCallRequestCallbacks(), and ShmemInitRequested().

◆ shmem_request_state

Definition at line 214 of file shmem.c.

◆ ShmemAllocator

ShmemAllocatorData* ShmemAllocator
static

Definition at line 246 of file shmem.c.

Referenced by InitShmemAllocator(), pg_get_shmem_allocations(), and ShmemAllocRaw().

◆ ShmemBase

void* ShmemBase
static

Definition at line 243 of file shmem.c.

Referenced by InitShmemAllocator(), ShmemAddrIsValid(), and ShmemAllocRaw().

◆ ShmemEnd

void* ShmemEnd
static

Definition at line 244 of file shmem.c.

Referenced by InitShmemAllocator(), and ShmemAddrIsValid().

◆ ShmemIndex

◆ ShmemSegHdr

PGShmemHeader* ShmemSegHdr
static