LCOV - code coverage report
Current view: top level - src/backend/storage/ipc - shmem.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 71.7 % 318 228
Test Date: 2026-09-02 16:15:49 Functions: 85.7 % 21 18
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.0 % 240 120

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * shmem.c
       4                 :             :  *    create shared memory and initialize shared memory data structures.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    src/backend/storage/ipc/shmem.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : /*
      16                 :             :  * POSTGRES processes share one or more regions of shared memory.
      17                 :             :  * The shared memory is created by a postmaster and is inherited
      18                 :             :  * by each backend via fork() (or, in some ports, via other OS-specific
      19                 :             :  * methods).  The routines in this file are used for allocating and
      20                 :             :  * binding to shared memory data structures.
      21                 :             :  *
      22                 :             :  * This module provides facilities to allocate fixed-size structures in shared
      23                 :             :  * memory, for things like variables shared between all backend processes.
      24                 :             :  * Each such structure has a string name to identify it, specified when it is
      25                 :             :  * requested.  shmem_hash.c provides a shared hash table implementation on top
      26                 :             :  * of that.
      27                 :             :  *
      28                 :             :  * Shared memory areas should usually not be allocated after postmaster
      29                 :             :  * startup, although we do allow small allocations later for the benefit of
      30                 :             :  * extension modules that are loaded after startup.  Despite that allowance,
      31                 :             :  * extensions that need shared memory should be added in
      32                 :             :  * shared_preload_libraries, because the allowance is quite small and there is
      33                 :             :  * no guarantee that any memory is available after startup.
      34                 :             :  *
      35                 :             :  * Nowadays, there is also another way to allocate shared memory called
      36                 :             :  * Dynamic Shared Memory.  See dsm.c for that facility.  One big difference
      37                 :             :  * between traditional shared memory handled by shmem.c and dynamic shared
      38                 :             :  * memory is that traditional shared memory areas are mapped to the same
      39                 :             :  * address in all processes, so you can use normal pointers in shared memory
      40                 :             :  * structs.  With Dynamic Shared Memory, you must use offsets or DSA pointers
      41                 :             :  * instead.
      42                 :             :  *
      43                 :             :  * Shared memory managed by shmem.c can never be freed, once allocated.  Each
      44                 :             :  * hash table has its own free list, so hash buckets can be reused when an
      45                 :             :  * item is deleted.
      46                 :             :  *
      47                 :             :  * Usage
      48                 :             :  * -----
      49                 :             :  *
      50                 :             :  * To allocate shared memory, you need to register a set of callback functions
      51                 :             :  * which handle the lifecycle of the allocation.  In the request_fn callback,
      52                 :             :  * call ShmemRequestStruct() with the desired name and size.  When the area is
      53                 :             :  * later allocated or attached to, the global variable pointed to by the .ptr
      54                 :             :  * option is set to the shared memory location of the allocation.  The init_fn
      55                 :             :  * callback can perform additional initialization.
      56                 :             :  *
      57                 :             :  *  typedef struct MyShmemData {
      58                 :             :  *      ...
      59                 :             :  *  } MyShmemData;
      60                 :             :  *
      61                 :             :  *  static MyShmemData *MyShmem;
      62                 :             :  *
      63                 :             :  *  static void my_shmem_request(void *arg);
      64                 :             :  *  static void my_shmem_init(void *arg);
      65                 :             :  *
      66                 :             :  *  const ShmemCallbacks MyShmemCallbacks = {
      67                 :             :  *      .request_fn = my_shmem_request,
      68                 :             :  *      .init_fn = my_shmem_init,
      69                 :             :  *  };
      70                 :             :  *
      71                 :             :  *  static void
      72                 :             :  *  my_shmem_request(void *arg)
      73                 :             :  *  {
      74                 :             :  *      ShmemRequestStruct(.name = "My shmem area",
      75                 :             :  *                         .size = sizeof(MyShmemData),
      76                 :             :  *                         .ptr = (void **) &MyShmem,
      77                 :             :  *          );
      78                 :             :  *  }
      79                 :             :  *
      80                 :             :  * In builtin PostgreSQL code, add the callbacks to the list in
      81                 :             :  * src/include/storage/subsystemlist.h.  In an add-in module, you can register
      82                 :             :  * the callbacks by calling RegisterShmemCallbacks(&MyShmemCallbacks) in the
      83                 :             :  * extension's _PG_init() function.
      84                 :             :  *
      85                 :             :  * Lifecycle
      86                 :             :  * ---------
      87                 :             :  *
      88                 :             :  * Initializing shared memory happens in multiple phases.  In the first phase,
      89                 :             :  * during postmaster startup, all the request_fn callbacks are called.  Only
      90                 :             :  * after all the request_fn callbacks have been called and all the shmem areas
      91                 :             :  * have been requested by the ShmemRequestStruct() calls we know how much
      92                 :             :  * shared memory we need in total.  After that, postmaster allocates global
      93                 :             :  * shared memory segment, and calls all the init_fn callbacks to initialize
      94                 :             :  * all the requested shmem areas.
      95                 :             :  *
      96                 :             :  * In standard Unix-ish environments, individual backends do not need to
      97                 :             :  * re-establish their local pointers into shared memory, because they inherit
      98                 :             :  * correct values of those variables via fork() from the postmaster.  However,
      99                 :             :  * this does not work in the EXEC_BACKEND case.  In ports using EXEC_BACKEND,
     100                 :             :  * backend startup also calls the shmem_request callbacks to re-establish the
     101                 :             :  * knowledge about each shared memory area, sets the pointer variables
     102                 :             :  * (*options->ptr), and calls the attach_fn callback, if any, for additional
     103                 :             :  * per-backend setup.
     104                 :             :  *
     105                 :             :  * Legacy ShmemInitStruct()/ShmemInitHash() functions
     106                 :             :  * --------------------------------------------------
     107                 :             :  *
     108                 :             :  * ShmemInitStruct()/ShmemInitHash() is another way of registering shmem
     109                 :             :  * areas.  It pre-dates the ShmemRequestStruct()/ShmemRequestHash() functions,
     110                 :             :  * and should not be used in new code, but as of this writing it is still
     111                 :             :  * widely used in extensions.
     112                 :             :  *
     113                 :             :  * To allocate a shmem area with ShmemInitStruct(), you need to separately
     114                 :             :  * register the size needed for the area by calling RequestAddinShmemSpace()
     115                 :             :  * from the extension's shmem_request_hook, and allocate the area by calling
     116                 :             :  * ShmemInitStruct() from the extension's shmem_startup_hook.  There are no
     117                 :             :  * init/attach callbacks.  Instead, the caller of ShmemInitStruct() must check
     118                 :             :  * the return status of ShmemInitStruct() and initialize the struct if it was
     119                 :             :  * not previously initialized.
     120                 :             :  *
     121                 :             :  * Calling ShmemAlloc() directly
     122                 :             :  * -----------------------------
     123                 :             :  *
     124                 :             :  * There's a more low-level way of allocating shared memory too: you can call
     125                 :             :  * ShmemAlloc() directly.  It's used to implement the higher level mechanisms,
     126                 :             :  * and should generally not be called directly.
     127                 :             :  */
     128                 :             : 
     129                 :             : #include "postgres.h"
     130                 :             : 
     131                 :             : #include <unistd.h>
     132                 :             : 
     133                 :             : #include "access/slru.h"
     134                 :             : #include "fmgr.h"
     135                 :             : #include "funcapi.h"
     136                 :             : #include "miscadmin.h"
     137                 :             : #include "port/pg_bitutils.h"
     138                 :             : #include "port/pg_numa.h"
     139                 :             : #include "storage/lwlock.h"
     140                 :             : #include "storage/pg_shmem.h"
     141                 :             : #include "storage/shmem.h"
     142                 :             : #include "storage/shmem_internal.h"
     143                 :             : #include "storage/spin.h"
     144                 :             : #include "utils/builtins.h"
     145                 :             : #include "utils/tuplestore.h"
     146                 :             : 
     147                 :             : typedef struct ShmemIndexEnt ShmemIndexEnt;
     148                 :             : 
     149                 :             : /*
     150                 :             :  * Registered callbacks.
     151                 :             :  *
     152                 :             :  * During postmaster startup, we accumulate the callbacks from all subsystems
     153                 :             :  * in this list.
     154                 :             :  *
     155                 :             :  * This is in process private memory, although on Unix-like systems, we expect
     156                 :             :  * all the registrations to happen at postmaster startup time and be inherited
     157                 :             :  * by all the child processes via fork().
     158                 :             :  */
     159                 :             : static List *registered_shmem_callbacks;
     160                 :             : 
     161                 :             : /*
     162                 :             :  * In the shmem request phase, all the shmem areas requested with the
     163                 :             :  * ShmemRequest*() functions are accumulated in the 'pending_shmem_requests'
     164                 :             :  * list.  The List, the ShmemRequest structs, and the 'options' are all
     165                 :             :  * allocated in TopMemoryContext.
     166                 :             :  */
     167                 :             : typedef struct
     168                 :             : {
     169                 :             :     ShmemStructOpts *options;
     170                 :             :     ShmemRequestKind kind;
     171                 :             : 
     172                 :             :     /* InitShmemIndexEntry() sets this pointer when the area is allocated */
     173                 :             :     ShmemIndexEnt *index_entry;
     174                 :             : } ShmemRequest;
     175                 :             : 
     176                 :             : static List *pending_shmem_requests;    /* List of ShmemRequests */
     177                 :             : 
     178                 :             : /*
     179                 :             :  * Per-process state machine, for sanity checking that we do things in the
     180                 :             :  * right order.
     181                 :             :  *
     182                 :             :  * Postmaster:
     183                 :             :  *   INITIAL -> REQUESTING -> INITIALIZING -> DONE
     184                 :             :  *
     185                 :             :  * Backends in EXEC_BACKEND mode:
     186                 :             :  *   INITIAL -> REQUESTING -> ATTACHING -> DONE
     187                 :             :  *
     188                 :             :  * Late request:
     189                 :             :  *   DONE -> REQUESTING -> AFTER_STARTUP_ATTACH_OR_INIT -> DONE
     190                 :             :  */
     191                 :             : enum shmem_request_state
     192                 :             : {
     193                 :             :     /* Initial state */
     194                 :             :     SRS_INITIAL,
     195                 :             : 
     196                 :             :     /*
     197                 :             :      * When we start calling the shmem_request callbacks, we enter the
     198                 :             :      * SRS_REQUESTING phase.  All ShmemRequestStruct calls happen in this
     199                 :             :      * state.
     200                 :             :      */
     201                 :             :     SRS_REQUESTING,
     202                 :             : 
     203                 :             :     /*
     204                 :             :      * Postmaster has finished all shmem requests, and is now initializing the
     205                 :             :      * shared memory segment.  init_fn callbacks are called in this state.
     206                 :             :      */
     207                 :             :     SRS_INITIALIZING,
     208                 :             : 
     209                 :             :     /*
     210                 :             :      * A postmaster child process is starting up.  attach_fn callbacks are
     211                 :             :      * called in this state.
     212                 :             :      */
     213                 :             :     SRS_ATTACHING,
     214                 :             : 
     215                 :             :     /* An after-startup allocation or attachment is in progress */
     216                 :             :     SRS_AFTER_STARTUP_ATTACH_OR_INIT,
     217                 :             : 
     218                 :             :     /* Normal state after shmem initialization / attachment */
     219                 :             :     SRS_DONE,
     220                 :             : };
     221                 :             : static enum shmem_request_state shmem_request_state = SRS_INITIAL;
     222                 :             : 
     223                 :             : /*
     224                 :             :  * This is the first data structure stored in the shared memory segment, at
     225                 :             :  * the offset that PGShmemHeader->content_offset points to.  Allocations by
     226                 :             :  * ShmemAlloc() are carved out of the space after this.
     227                 :             :  *
     228                 :             :  * For the base pointer and the total size of the shmem segment, we rely on
     229                 :             :  * the PGShmemHeader.
     230                 :             :  */
     231                 :             : typedef struct ShmemAllocatorData
     232                 :             : {
     233                 :             :     Size        free_offset;    /* offset to first free space from ShmemBase */
     234                 :             : 
     235                 :             :     /* protects 'free_offset' */
     236                 :             :     slock_t     shmem_lock;
     237                 :             : 
     238                 :             :     HASHHDR    *index;          /* location of ShmemIndex */
     239                 :             :     size_t      index_size;     /* size of shmem region holding ShmemIndex */
     240                 :             :     LWLock      index_lock;     /* protects ShmemIndex */
     241                 :             : } ShmemAllocatorData;
     242                 :             : 
     243                 :             : #define ShmemIndexLock (&ShmemAllocator->index_lock)
     244                 :             : 
     245                 :             : static void *ShmemAllocRaw(Size size, Size alignment, Size *allocated_size);
     246                 :             : 
     247                 :             : /* shared memory global variables */
     248                 :             : 
     249                 :             : static PGShmemHeader *ShmemSegHdr;  /* shared mem segment header */
     250                 :             : static void *ShmemBase;         /* start address of shared memory */
     251                 :             : static void *ShmemEnd;          /* end+1 address of shared memory */
     252                 :             : 
     253                 :             : static ShmemAllocatorData *ShmemAllocator;
     254                 :             : 
     255                 :             : /*
     256                 :             :  * ShmemIndex is a global directory of shmem areas, itself also stored in the
     257                 :             :  * shared memory.
     258                 :             :  */
     259                 :             : static HTAB *ShmemIndex;
     260                 :             : 
     261                 :             :  /* max size of data structure string name */
     262                 :             : #define SHMEM_INDEX_KEYSIZE      (48)
     263                 :             : 
     264                 :             : /*
     265                 :             :  * # of additional entries to reserve in the shmem index table, for
     266                 :             :  * allocations after postmaster startup.  (This is not a hard limit, the hash
     267                 :             :  * table can grow larger than that if there is shared memory available)
     268                 :             :  */
     269                 :             : #define SHMEM_INDEX_ADDITIONAL_SIZE      (128)
     270                 :             : 
     271                 :             : /* this is a hash bucket in the shmem index table */
     272                 :             : typedef struct ShmemIndexEnt
     273                 :             : {
     274                 :             :     char        key[SHMEM_INDEX_KEYSIZE];   /* string name */
     275                 :             :     void       *location;       /* location in shared mem */
     276                 :             :     Size        size;           /* # bytes requested for the structure */
     277                 :             :     Size        allocated_size; /* # bytes actually allocated */
     278                 :             :     bool        initialized;    /* has the init callback been run? */
     279                 :             : } ShmemIndexEnt;
     280                 :             : 
     281                 :             : /* To get reliable results for NUMA inquiry we need to "touch pages" once */
     282                 :             : static bool firstNumaTouch = true;
     283                 :             : 
     284                 :             : static void CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks);
     285                 :             : static void ProcessShmemRequestsAfterStartup(const ShmemCallbacks *callbacks);
     286                 :             : static void InitShmemIndexEntry(ShmemRequest *request);
     287                 :             : static bool AttachShmemIndexEntry(ShmemRequest *request, bool missing_ok);
     288                 :             : 
     289                 :             : Datum       pg_numa_available(PG_FUNCTION_ARGS);
     290                 :             : 
     291                 :             : /*
     292                 :             :  *  ShmemRequestStruct() --- request a named shared memory area
     293                 :             :  *
     294                 :             :  * Subsystems call this to register their shared memory needs.  This is
     295                 :             :  * usually done early in postmaster startup, before the shared memory segment
     296                 :             :  * has been created, so that the size can be included in the estimate for
     297                 :             :  * total amount of shared memory needed.  We set aside a small amount of
     298                 :             :  * memory for allocations that happen later, for the benefit of non-preloaded
     299                 :             :  * extensions, but that should not be relied upon.
     300                 :             :  *
     301                 :             :  * This does not yet allocate the memory, but merely registers the need for
     302                 :             :  * it.  The actual allocation happens later in the postmaster startup
     303                 :             :  * sequence.
     304                 :             :  *
     305                 :             :  * This must be called from a shmem_request callback function, registered with
     306                 :             :  * RegisterShmemCallbacks().  This enforces a coding pattern that works the
     307                 :             :  * same in normal Unix systems and with EXEC_BACKEND.  On Unix systems, the
     308                 :             :  * shmem_request callbacks are called once, early in postmaster startup, and
     309                 :             :  * the child processes inherit the struct descriptors and any other
     310                 :             :  * per-process state from the postmaster.  In EXEC_BACKEND mode, shmem_request
     311                 :             :  * callbacks are *also* called in each backend, at backend startup, to
     312                 :             :  * re-establish the struct descriptors.  By calling the same function in both
     313                 :             :  * cases, we ensure that all the shmem areas are registered the same way in
     314                 :             :  * all processes.
     315                 :             :  *
     316                 :             :  * 'options' defines the name and size of the area, and any other optional
     317                 :             :  * features.  Leave unused options as zeros.  The options are copied to
     318                 :             :  * longer-lived memory, so it doesn't need to live after the
     319                 :             :  * ShmemRequestStruct() call and can point to a local variable in the calling
     320                 :             :  * function.  The 'name' must point to a long-lived string though, only the
     321                 :             :  * pointer to it is copied.
     322                 :             :  */
     323                 :             : void
     324                 :       80643 : ShmemRequestStructWithOpts(const ShmemStructOpts *options)
     325                 :             : {
     326                 :             :     ShmemStructOpts *options_copy;
     327                 :             : 
     328                 :       80643 :     options_copy = MemoryContextAlloc(TopMemoryContext,
     329                 :             :                                       sizeof(ShmemStructOpts));
     330                 :       80643 :     memcpy(options_copy, options, sizeof(ShmemStructOpts));
     331                 :             : 
     332                 :       80643 :     ShmemRequestInternal(options_copy, SHMEM_KIND_STRUCT);
     333                 :       80643 : }
     334                 :             : 
     335                 :             : /*
     336                 :             :  * Internal workhorse of ShmemRequestStruct() and ShmemRequestHash().
     337                 :             :  *
     338                 :             :  * Note: Unlike in the public ShmemRequestStruct() and ShmemRequestHash()
     339                 :             :  * functions, 'options' is *not* copied.  It must be allocated in
     340                 :             :  * TopMemoryContext by the caller, and will be freed after the init/attach
     341                 :             :  * callbacks have been called.  This allows ShmemRequestHash() to pass a
     342                 :             :  * pointer to the extended ShmemHashOpts struct instead.
     343                 :             :  */
     344                 :             : void
     345                 :       99858 : ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
     346                 :             : {
     347                 :             :     MemoryContext oldcontext;
     348                 :             :     ShmemRequest *request;
     349                 :             : 
     350                 :             :     /* Check the options */
     351         [ -  + ]:       99858 :     if (options->name == NULL)
     352         [ #  # ]:           0 :         elog(ERROR, "shared memory request is missing 'name' option");
     353                 :             : 
     354         [ +  + ]:       99858 :     if (IsUnderPostmaster)
     355                 :             :     {
     356   [ -  +  -  - ]:           7 :         if (options->size <= 0 && options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
     357         [ #  # ]:           0 :             elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
     358                 :             :                  options->size, options->name);
     359                 :             :     }
     360                 :             :     else
     361                 :             :     {
     362         [ -  + ]:       99851 :         if (options->size == SHMEM_ATTACH_UNKNOWN_SIZE)
     363         [ #  # ]:           0 :             elog(ERROR, "SHMEM_ATTACH_UNKNOWN_SIZE cannot be used during startup");
     364         [ -  + ]:       99851 :         if (options->size <= 0)
     365         [ #  # ]:           0 :             elog(ERROR, "invalid size %zd for shared memory request for \"%s\"",
     366                 :             :                  options->size, options->name);
     367                 :             :     }
     368                 :             : 
     369   [ +  +  -  + ]:       99858 :     if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment)
     370         [ #  # ]:           0 :         elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"",
     371                 :             :              options->alignment, options->name);
     372                 :             : 
     373                 :             :     /* Check that we're in the right state */
     374         [ -  + ]:       99858 :     if (shmem_request_state != SRS_REQUESTING)
     375         [ #  # ]:           0 :         elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
     376                 :             : 
     377                 :             :     /* Check that it's not already registered in this process */
     378   [ +  +  +  +  :     4044383 :     foreach_ptr(ShmemRequest, existing, pending_shmem_requests)
                   +  + ]
     379                 :             :     {
     380         [ -  + ]:     3844667 :         if (strcmp(existing->options->name, options->name) == 0)
     381         [ #  # ]:           0 :             ereport(ERROR,
     382                 :             :                     (errmsg("shared memory struct \"%s\" is already registered",
     383                 :             :                             options->name)));
     384                 :             :     }
     385                 :             : 
     386                 :             :     /* Request looks valid, remember it */
     387                 :       99858 :     oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     388                 :       99858 :     request = palloc_object(ShmemRequest);
     389                 :       99858 :     request->options = options;
     390                 :       99858 :     request->kind = kind;
     391                 :       99858 :     request->index_entry = NULL;
     392                 :       99858 :     pending_shmem_requests = lappend(pending_shmem_requests, request);
     393                 :       99858 :     MemoryContextSwitchTo(oldcontext);
     394                 :       99858 : }
     395                 :             : 
     396                 :             : /*
     397                 :             :  *  ShmemGetRequestedSize() --- estimate the total size of all registered shared
     398                 :             :  *                              memory structures.
     399                 :             :  *
     400                 :             :  * This is called at postmaster startup, before the shared memory segment has
     401                 :             :  * been created.
     402                 :             :  */
     403                 :             : size_t
     404                 :        2386 : ShmemGetRequestedSize(void)
     405                 :             : {
     406                 :             :     size_t      size;
     407                 :             : 
     408                 :             :     /* memory needed for the ShmemIndex */
     409                 :        2386 :     size = hash_estimate_size(list_length(pending_shmem_requests) + SHMEM_INDEX_ADDITIONAL_SIZE,
     410                 :             :                               sizeof(ShmemIndexEnt));
     411                 :        2386 :     size = CACHELINEALIGN(size);
     412                 :             : 
     413                 :             :     /* memory needed for all the requested areas */
     414   [ +  -  +  +  :      190902 :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
     415                 :             :     {
     416                 :      186130 :         size_t      alignment = request->options->alignment;
     417                 :             : 
     418                 :             :         /* pad the start address for alignment like ShmemAllocRaw() does */
     419         [ +  + ]:      186130 :         if (alignment < PG_CACHE_LINE_SIZE)
     420                 :      178972 :             alignment = PG_CACHE_LINE_SIZE;
     421                 :      186130 :         size = TYPEALIGN(alignment, size);
     422                 :             : 
     423                 :      186130 :         size = add_size(size, request->options->size);
     424                 :             :     }
     425                 :             : 
     426                 :        2386 :     return size;
     427                 :             : }
     428                 :             : 
     429                 :             : /*
     430                 :             :  *  ShmemInitRequested() --- allocate and initialize requested shared memory
     431                 :             :  *                            structures.
     432                 :             :  *
     433                 :             :  * This is called once at postmaster startup, after the shared memory segment
     434                 :             :  * has been created.
     435                 :             :  */
     436                 :             : void
     437                 :        1277 : ShmemInitRequested(void)
     438                 :             : {
     439                 :             :     /* should be called only by the postmaster or a standalone backend */
     440                 :             :     Assert(!IsUnderPostmaster);
     441                 :             :     Assert(shmem_request_state == SRS_INITIALIZING);
     442                 :             : 
     443                 :             :     /*
     444                 :             :      * Initialize the ShmemIndex entries and perform basic initialization of
     445                 :             :      * all the requested memory areas.  There are no concurrent processes yet,
     446                 :             :      * so no need for locking.
     447                 :             :      */
     448   [ +  -  +  +  :      102170 :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
     449                 :             :     {
     450                 :       99616 :         InitShmemIndexEntry(request);
     451                 :             :     }
     452                 :             : 
     453                 :             :     /*
     454                 :             :      * Call the subsystem-specific init callbacks to finish initialization of
     455                 :             :      * all the areas.
     456                 :             :      */
     457   [ +  -  +  +  :       58768 :     foreach_ptr(const ShmemCallbacks, callbacks, registered_shmem_callbacks)
                   +  + ]
     458                 :             :     {
     459         [ +  + ]:       56214 :         if (callbacks->init_fn)
     460                 :       51102 :             callbacks->init_fn(callbacks->opaque_arg);
     461                 :             :     }
     462                 :             : 
     463                 :             :     /* Now we can mark all the areas as initialized and free the requests */
     464   [ +  -  +  +  :      102170 :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
     465                 :             :     {
     466                 :       99616 :         request->index_entry->initialized = true;
     467                 :       99616 :         pfree(request->options);
     468                 :             :     }
     469                 :        1277 :     list_free_deep(pending_shmem_requests);
     470                 :        1277 :     pending_shmem_requests = NIL;
     471                 :             : 
     472                 :        1277 :     shmem_request_state = SRS_DONE;
     473                 :        1277 : }
     474                 :             : 
     475                 :             : /*
     476                 :             :  * Re-establish process private state related to shmem areas.
     477                 :             :  *
     478                 :             :  * This is called at backend startup in EXEC_BACKEND mode, in every backend.
     479                 :             :  */
     480                 :             : #ifdef EXEC_BACKEND
     481                 :             : void
     482                 :             : ShmemAttachRequested(void)
     483                 :             : {
     484                 :             :     ListCell   *lc;
     485                 :             : 
     486                 :             :     /* Must be initializing a (non-standalone) backend */
     487                 :             :     Assert(IsUnderPostmaster);
     488                 :             :     Assert(ShmemAllocator->index != NULL);
     489                 :             :     Assert(shmem_request_state == SRS_REQUESTING);
     490                 :             :     shmem_request_state = SRS_ATTACHING;
     491                 :             : 
     492                 :             :     LWLockAcquire(ShmemIndexLock, LW_SHARED);
     493                 :             : 
     494                 :             :     /*
     495                 :             :      * Attach to all the requested memory areas.
     496                 :             :      */
     497                 :             :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
     498                 :             :     {
     499                 :             :         AttachShmemIndexEntry(request, false);
     500                 :             :         pfree(request->options);
     501                 :             :     }
     502                 :             :     list_free_deep(pending_shmem_requests);
     503                 :             :     pending_shmem_requests = NIL;
     504                 :             : 
     505                 :             :     /* Call attach callbacks */
     506                 :             :     foreach(lc, registered_shmem_callbacks)
     507                 :             :     {
     508                 :             :         const ShmemCallbacks *callbacks = (const ShmemCallbacks *) lfirst(lc);
     509                 :             : 
     510                 :             :         if (callbacks->attach_fn)
     511                 :             :             callbacks->attach_fn(callbacks->opaque_arg);
     512                 :             :     }
     513                 :             : 
     514                 :             :     LWLockRelease(ShmemIndexLock);
     515                 :             : 
     516                 :             :     shmem_request_state = SRS_DONE;
     517                 :             : }
     518                 :             : #endif
     519                 :             : 
     520                 :             : /*
     521                 :             :  * Insert requested shmem area into the shared memory index and initialize it.
     522                 :             :  *
     523                 :             :  * Note that this only does performs basic initialization depending on
     524                 :             :  * ShmemRequestKind, like setting the global pointer variable to the area for
     525                 :             :  * SHMEM_KIND_STRUCT or setting up the backend-private HTAB control struct.
     526                 :             :  * This does *not* call the subsystem-specific init callbacks.  That's done
     527                 :             :  * later after all the shmem areas have been initialized or attached to.
     528                 :             :  */
     529                 :             : static void
     530                 :       99622 : InitShmemIndexEntry(ShmemRequest *request)
     531                 :             : {
     532                 :       99622 :     const char *name = request->options->name;
     533                 :             :     ShmemIndexEnt *index_entry;
     534                 :             :     bool        found;
     535                 :             :     size_t      allocated_size;
     536                 :             :     void       *structPtr;
     537                 :             : 
     538                 :             :     /* look it up in the shmem index */
     539                 :             :     index_entry = (ShmemIndexEnt *)
     540                 :       99622 :         hash_search(ShmemIndex, name, HASH_ENTER_NULL, &found);
     541         [ -  + ]:       99622 :     if (found)
     542         [ #  # ]:           0 :         elog(ERROR, "shared memory struct \"%s\" is already initialized", name);
     543         [ -  + ]:       99622 :     if (!index_entry)
     544                 :             :     {
     545                 :             :         /* tried to add it to the hash table, but there was no space */
     546         [ #  # ]:           0 :         ereport(ERROR,
     547                 :             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     548                 :             :                  errmsg("could not create ShmemIndex entry for data structure \"%s\"",
     549                 :             :                         name)));
     550                 :             :     }
     551                 :             : 
     552                 :             :     /*
     553                 :             :      * We inserted the entry to the shared memory index.  Allocate requested
     554                 :             :      * amount of shared memory for it, and initialize the index entry.
     555                 :             :      */
     556                 :       99622 :     structPtr = ShmemAllocRaw(request->options->size,
     557                 :       99622 :                               request->options->alignment,
     558                 :             :                               &allocated_size);
     559         [ +  + ]:       99622 :     if (structPtr == NULL)
     560                 :             :     {
     561                 :             :         /* out of memory; remove the failed ShmemIndex entry */
     562                 :           1 :         hash_search(ShmemIndex, name, HASH_REMOVE, NULL);
     563         [ +  - ]:           1 :         ereport(ERROR,
     564                 :             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     565                 :             :                  errmsg("not enough shared memory for data structure"
     566                 :             :                         " \"%s\" (%zd bytes requested)",
     567                 :             :                         name, request->options->size)));
     568                 :             :     }
     569                 :       99621 :     index_entry->size = request->options->size;
     570                 :       99621 :     index_entry->allocated_size = allocated_size;
     571                 :       99621 :     index_entry->location = structPtr;
     572                 :             : 
     573                 :             :     /*
     574                 :             :      * The area is considered fully initialized only after the subsystem's
     575                 :             :      * init callback has been called.  For now, perform only basic
     576                 :             :      * initialization based on the kind of shmem area it is.
     577                 :             :      */
     578                 :       99621 :     index_entry->initialized = false;
     579   [ +  +  +  - ]:       99621 :     switch (request->kind)
     580                 :             :     {
     581                 :       80451 :         case SHMEM_KIND_STRUCT:
     582         [ +  - ]:       80451 :             if (request->options->ptr)
     583                 :       80451 :                 *(request->options->ptr) = index_entry->location;
     584                 :       80451 :             break;
     585                 :       10227 :         case SHMEM_KIND_HASH:
     586                 :       10227 :             shmem_hash_init(structPtr, request->options);
     587                 :       10227 :             break;
     588                 :        8943 :         case SHMEM_KIND_SLRU:
     589                 :        8943 :             shmem_slru_init(structPtr, request->options);
     590                 :        8943 :             break;
     591                 :             :     }
     592                 :             : 
     593                 :             :     /* return the pointer to the entry to the caller */
     594                 :       99621 :     request->index_entry = index_entry;
     595                 :       99621 : }
     596                 :             : 
     597                 :             : /*
     598                 :             :  * Look up a named shmem area in the shared memory index and attach to it.
     599                 :             :  *
     600                 :             :  * Note that this only performs the basic attachment actions depending on
     601                 :             :  * ShmemRequestKind, like setting the global pointer variable to the area for
     602                 :             :  * SHMEM_KIND_STRUCT or setting up the backend-private HTAB control struct.
     603                 :             :  * This does *not* call the subsystem-specific attach callbacks.  That's done
     604                 :             :  * later after all the shmem areas have been initialized or attached to.
     605                 :             :  */
     606                 :             : static bool
     607                 :           1 : AttachShmemIndexEntry(ShmemRequest *request, bool missing_ok)
     608                 :             : {
     609                 :           1 :     const char *name = request->options->name;
     610                 :             :     ShmemIndexEnt *index_entry;
     611                 :             : 
     612                 :             :     /* Look it up in the shmem index */
     613                 :             :     index_entry = (ShmemIndexEnt *)
     614                 :           1 :         hash_search(ShmemIndex, name, HASH_FIND, NULL);
     615         [ -  + ]:           1 :     if (!index_entry)
     616                 :             :     {
     617         [ #  # ]:           0 :         if (!missing_ok)
     618         [ #  # ]:           0 :             ereport(ERROR,
     619                 :             :                     (errmsg("could not find ShmemIndex entry for data structure \"%s\"",
     620                 :             :                             request->options->name)));
     621                 :           0 :         return false;
     622                 :             :     }
     623                 :             : 
     624                 :             :     /*
     625                 :             :      * If it was previously allocated but not fully initialized, error out.
     626                 :             :      * There is currently no way of retrying or cleaning up an uninitialized
     627                 :             :      * entry, it just lingers until the server is shut down.  But this can
     628                 :             :      * only happen when allocating areas after postmaster startup, and it's
     629                 :             :      * unlikely that you could successfully retry anyway.  The most likely
     630                 :             :      * reason for failed initialization is that you are out of shared memory
     631                 :             :      * and retrying won't help with that.
     632                 :             :      */
     633         [ -  + ]:           1 :     if (!index_entry->initialized)
     634         [ #  # ]:           0 :         ereport(ERROR,
     635                 :             :                 (errmsg("cannot attach to shared memory struct \"%s\" because it was not fully initialized",
     636                 :             :                         request->options->name)));
     637                 :             : 
     638                 :             :     /* Check that the size in the index matches the request */
     639         [ -  + ]:           1 :     if (index_entry->size != request->options->size &&
     640         [ #  # ]:           0 :         request->options->size != SHMEM_ATTACH_UNKNOWN_SIZE)
     641                 :             :     {
     642         [ #  # ]:           0 :         ereport(ERROR,
     643                 :             :                 (errmsg("shared memory struct \"%s\" was created with"
     644                 :             :                         " different size: existing %zu, requested %zd",
     645                 :             :                         name, index_entry->size, request->options->size)));
     646                 :             :     }
     647                 :             : 
     648                 :             :     /*
     649                 :             :      * Re-establish the caller's pointer variable, or do other actions to
     650                 :             :      * attach depending on the kind of shmem area it is.
     651                 :             :      */
     652   [ +  -  -  - ]:           1 :     switch (request->kind)
     653                 :             :     {
     654                 :           1 :         case SHMEM_KIND_STRUCT:
     655         [ +  - ]:           1 :             if (request->options->ptr)
     656                 :           1 :                 *(request->options->ptr) = index_entry->location;
     657                 :           1 :             break;
     658                 :           0 :         case SHMEM_KIND_HASH:
     659                 :           0 :             shmem_hash_attach(index_entry->location, request->options);
     660                 :           0 :             break;
     661                 :           0 :         case SHMEM_KIND_SLRU:
     662                 :           0 :             shmem_slru_attach(index_entry->location, request->options);
     663                 :           0 :             break;
     664                 :             :     }
     665                 :             : 
     666                 :           1 :     request->index_entry = index_entry;
     667                 :             : 
     668                 :           1 :     return true;
     669                 :             : }
     670                 :             : 
     671                 :             : /*
     672                 :             :  *  InitShmemAllocator() --- set up basic pointers to shared memory.
     673                 :             :  *
     674                 :             :  * Called at postmaster or stand-alone backend startup, to initialize the
     675                 :             :  * allocator's data structure in the shared memory segment.  In EXEC_BACKEND,
     676                 :             :  * this is also called at backend startup, to set up pointers to the
     677                 :             :  * already-initialized data structure.
     678                 :             :  */
     679                 :             : void
     680                 :        1277 : InitShmemAllocator(PGShmemHeader *seghdr)
     681                 :             : {
     682                 :             :     Size        offset;
     683                 :             :     int64       hash_nelems;
     684                 :             :     HASHCTL     info;
     685                 :             :     int         hash_flags;
     686                 :             : 
     687                 :             : #ifndef EXEC_BACKEND
     688                 :             :     Assert(!IsUnderPostmaster);
     689                 :             : #endif
     690                 :             :     Assert(seghdr != NULL);
     691                 :             : 
     692         [ +  - ]:        1277 :     if (IsUnderPostmaster)
     693                 :             :     {
     694                 :             :         Assert(shmem_request_state == SRS_INITIAL);
     695                 :             :     }
     696                 :             :     else
     697                 :             :     {
     698                 :             :         Assert(shmem_request_state == SRS_REQUESTING);
     699                 :        1277 :         shmem_request_state = SRS_INITIALIZING;
     700                 :             :     }
     701                 :             : 
     702                 :             :     /*
     703                 :             :      * We assume the pointer and offset are MAXALIGN.  Not a hard requirement,
     704                 :             :      * but it's true today and keeps the math below simpler.
     705                 :             :      */
     706                 :             :     Assert(seghdr == (void *) MAXALIGN(seghdr));
     707                 :             :     Assert(seghdr->content_offset == MAXALIGN(seghdr->content_offset));
     708                 :             : 
     709                 :             :     /*
     710                 :             :      * Allocations after this point should go through ShmemAlloc, which
     711                 :             :      * expects to allocate everything on cache line boundaries.  Make sure the
     712                 :             :      * first allocation begins on a cache line boundary.
     713                 :             :      */
     714                 :        1277 :     offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
     715         [ -  + ]:        1277 :     if (offset > seghdr->totalsize)
     716         [ #  # ]:           0 :         ereport(ERROR,
     717                 :             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     718                 :             :                  errmsg("out of shared memory (%zu bytes requested)",
     719                 :             :                         offset)));
     720                 :             : 
     721                 :             :     /*
     722                 :             :      * In postmaster or stand-alone backend, initialize the shared memory
     723                 :             :      * allocator so that we can allocate shared memory for ShmemIndex using
     724                 :             :      * ShmemAlloc().  In a regular backend just set up the pointers required
     725                 :             :      * by ShmemAlloc().
     726                 :             :      */
     727                 :        1277 :     ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
     728         [ +  - ]:        1277 :     if (!IsUnderPostmaster)
     729                 :             :     {
     730                 :        1277 :         SpinLockInit(&ShmemAllocator->shmem_lock);
     731                 :        1277 :         ShmemAllocator->free_offset = offset;
     732                 :        1277 :         LWLockInitialize(&ShmemAllocator->index_lock, LWTRANCHE_SHMEM_INDEX);
     733                 :             :     }
     734                 :             : 
     735                 :        1277 :     ShmemSegHdr = seghdr;
     736                 :        1277 :     ShmemBase = seghdr;
     737                 :        1277 :     ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
     738                 :             : 
     739                 :             :     /*
     740                 :             :      * Create (or attach to) the shared memory index of shmem areas.
     741                 :             :      *
     742                 :             :      * This is the same initialization as ShmemInitHash() does, but we cannot
     743                 :             :      * use ShmemInitHash() here because it relies on ShmemIndex being already
     744                 :             :      * initialized.
     745                 :             :      */
     746                 :        1277 :     hash_nelems = list_length(pending_shmem_requests) + SHMEM_INDEX_ADDITIONAL_SIZE;
     747                 :             : 
     748                 :        1277 :     info.keysize = SHMEM_INDEX_KEYSIZE;
     749                 :        1277 :     info.entrysize = sizeof(ShmemIndexEnt);
     750                 :        1277 :     hash_flags = HASH_ELEM | HASH_STRINGS | HASH_FIXED_SIZE;
     751                 :             : 
     752         [ +  - ]:        1277 :     if (!IsUnderPostmaster)
     753                 :             :     {
     754                 :        1277 :         ShmemAllocator->index_size = hash_estimate_size(hash_nelems, info.entrysize);
     755                 :        1277 :         ShmemAllocator->index = (HASHHDR *) ShmemAlloc(ShmemAllocator->index_size);
     756                 :             :     }
     757                 :        2554 :     ShmemIndex = shmem_hash_create(ShmemAllocator->index,
     758                 :        1277 :                                    ShmemAllocator->index_size,
     759                 :             :                                    IsUnderPostmaster,
     760                 :             :                                    "ShmemIndex", hash_nelems,
     761                 :             :                                    &info, hash_flags);
     762                 :             :     Assert(ShmemIndex != NULL);
     763                 :             : 
     764                 :             :     /*
     765                 :             :      * Add an entry for ShmemIndex itself into ShmemIndex, so that it's
     766                 :             :      * visible in the pg_shmem_allocations view
     767                 :             :      */
     768         [ +  - ]:        1277 :     if (!IsUnderPostmaster)
     769                 :             :     {
     770                 :             :         bool        found;
     771                 :             :         ShmemIndexEnt *result = (ShmemIndexEnt *)
     772                 :        1277 :             hash_search(ShmemIndex, "ShmemIndex", HASH_ENTER, &found);
     773                 :             : 
     774                 :             :         Assert(!found);
     775                 :        1277 :         result->size = ShmemAllocator->index_size;
     776                 :        1277 :         result->allocated_size = ShmemAllocator->index_size;
     777                 :        1277 :         result->location = ShmemAllocator->index;
     778                 :        1277 :         result->initialized = true;
     779                 :             :     }
     780                 :        1277 : }
     781                 :             : 
     782                 :             : /*
     783                 :             :  * Reset state on postmaster crash restart.
     784                 :             :  */
     785                 :             : void
     786                 :           5 : ResetShmemAllocator(void)
     787                 :             : {
     788                 :             :     Assert(!IsUnderPostmaster);
     789                 :           5 :     shmem_request_state = SRS_INITIAL;
     790                 :             : 
     791                 :           5 :     pending_shmem_requests = NIL;
     792                 :             : 
     793                 :             :     /*
     794                 :             :      * Note that we don't clear the registered callbacks.  We will need to
     795                 :             :      * call them again as we restart
     796                 :             :      */
     797                 :           5 : }
     798                 :             : 
     799                 :             : /*
     800                 :             :  * ShmemAlloc -- allocate max-aligned chunk from shared memory
     801                 :             :  *
     802                 :             :  * Throws error if request cannot be satisfied.
     803                 :             :  *
     804                 :             :  * Assumes ShmemSegHdr is initialized.
     805                 :             :  */
     806                 :             : void *
     807                 :        1277 : ShmemAlloc(Size size)
     808                 :             : {
     809                 :             :     void       *newSpace;
     810                 :             :     Size        allocated_size;
     811                 :             : 
     812                 :        1277 :     newSpace = ShmemAllocRaw(size, 0, &allocated_size);
     813         [ -  + ]:        1277 :     if (!newSpace)
     814         [ #  # ]:           0 :         ereport(ERROR,
     815                 :             :                 (errcode(ERRCODE_OUT_OF_MEMORY),
     816                 :             :                  errmsg("out of shared memory (%zu bytes requested)",
     817                 :             :                         size)));
     818                 :        1277 :     return newSpace;
     819                 :             : }
     820                 :             : 
     821                 :             : /*
     822                 :             :  * ShmemAllocNoError -- allocate max-aligned chunk from shared memory
     823                 :             :  *
     824                 :             :  * As ShmemAlloc, but returns NULL if out of space, rather than erroring.
     825                 :             :  */
     826                 :             : void *
     827                 :           0 : ShmemAllocNoError(Size size)
     828                 :             : {
     829                 :             :     Size        allocated_size;
     830                 :             : 
     831                 :           0 :     return ShmemAllocRaw(size, 0, &allocated_size);
     832                 :             : }
     833                 :             : 
     834                 :             : /*
     835                 :             :  * ShmemAllocRaw -- allocate align chunk and return allocated size
     836                 :             :  *
     837                 :             :  * Also sets *allocated_size to the number of bytes allocated, which will
     838                 :             :  * be equal to the number requested plus any padding we choose to add.
     839                 :             :  */
     840                 :             : static void *
     841                 :      100899 : ShmemAllocRaw(Size size, Size alignment, Size *allocated_size)
     842                 :             : {
     843                 :             :     Size        rawStart;
     844                 :             :     Size        newStart;
     845                 :             :     Size        newFree;
     846                 :             :     void       *newSpace;
     847                 :             : 
     848                 :             :     /*
     849                 :             :      * Ensure all space is adequately aligned.  We used to only MAXALIGN this
     850                 :             :      * space but experience has proved that on modern systems that is not good
     851                 :             :      * enough.  Many parts of the system are very sensitive to critical data
     852                 :             :      * structures getting split across cache line boundaries.  To avoid that,
     853                 :             :      * attempt to align the beginning of the allocation to a cache line
     854                 :             :      * boundary.  The calling code will still need to be careful about how it
     855                 :             :      * uses the allocated space - e.g. by padding each element in an array of
     856                 :             :      * structures out to a power-of-two size - but without this, even that
     857                 :             :      * won't be sufficient.
     858                 :             :      */
     859         [ +  + ]:      100899 :     if (alignment < PG_CACHE_LINE_SIZE)
     860                 :       97068 :         alignment = PG_CACHE_LINE_SIZE;
     861                 :             : 
     862                 :             :     Assert(ShmemSegHdr != NULL);
     863                 :             : 
     864                 :      100899 :     SpinLockAcquire(&ShmemAllocator->shmem_lock);
     865                 :             : 
     866                 :      100899 :     rawStart = ShmemAllocator->free_offset;
     867                 :      100899 :     newStart = TYPEALIGN(alignment, rawStart);
     868                 :             : 
     869                 :      100899 :     newFree = newStart + size;
     870         [ +  + ]:      100899 :     if (newFree <= ShmemSegHdr->totalsize)
     871                 :             :     {
     872                 :      100898 :         newSpace = (char *) ShmemBase + newStart;
     873                 :      100898 :         ShmemAllocator->free_offset = newFree;
     874                 :             :     }
     875                 :             :     else
     876                 :           1 :         newSpace = NULL;
     877                 :             : 
     878                 :      100899 :     SpinLockRelease(&ShmemAllocator->shmem_lock);
     879                 :             : 
     880                 :             :     /* note this assert is okay with newSpace == NULL */
     881                 :             :     Assert(newSpace == (void *) TYPEALIGN(alignment, newSpace));
     882                 :             : 
     883                 :      100899 :     *allocated_size = newFree - rawStart;
     884                 :      100899 :     return newSpace;
     885                 :             : }
     886                 :             : 
     887                 :             : /*
     888                 :             :  * ShmemAddrIsValid -- test if an address refers to shared memory
     889                 :             :  *
     890                 :             :  * Returns true if the pointer points within the shared memory segment.
     891                 :             :  */
     892                 :             : bool
     893                 :           0 : ShmemAddrIsValid(const void *addr)
     894                 :             : {
     895   [ #  #  #  # ]:           0 :     return (addr >= ShmemBase) && (addr < ShmemEnd);
     896                 :             : }
     897                 :             : 
     898                 :             : /*
     899                 :             :  * Register callbacks that define a shared memory area (or multiple areas).
     900                 :             :  *
     901                 :             :  * The system will call the callbacks at different stages of postmaster or
     902                 :             :  * backend startup, to allocate and initialize the area.
     903                 :             :  *
     904                 :             :  * This is normally called early during postmaster startup, but if the
     905                 :             :  * SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP is set, this can also be used after
     906                 :             :  * startup, although after startup there's no guarantee that there's enough
     907                 :             :  * shared memory available.  When called after startup, this immediately calls
     908                 :             :  * the right callbacks depending on whether another backend had already
     909                 :             :  * initialized the area.
     910                 :             :  *
     911                 :             :  * Note: In EXEC_BACKEND mode, this needs to be called in every backend
     912                 :             :  * process.  That's needed because we cannot pass down the callback function
     913                 :             :  * pointers from the postmaster process, because different processes may have
     914                 :             :  * loaded libraries to different addresses.
     915                 :             :  */
     916                 :             : void
     917                 :       56704 : RegisterShmemCallbacks(const ShmemCallbacks *callbacks)
     918                 :             : {
     919         [ +  + ]:       56704 :     if (shmem_request_state == SRS_DONE)
     920                 :             :     {
     921                 :             :         /*
     922                 :             :          * After-startup initialization or attachment.  Call the appropriate
     923                 :             :          * callbacks immediately.
     924                 :             :          *
     925                 :             :          * This is not allowed from the postmaster, because the postmaster
     926                 :             :          * cannot acquire locks.
     927                 :             :          */
     928         [ -  + ]:           8 :         if ((callbacks->flags & SHMEM_CALLBACKS_ALLOW_AFTER_STARTUP) == 0)
     929         [ #  # ]:           0 :             elog(ERROR, "cannot request shared memory at this time");
     930                 :             :         Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
     931                 :             : 
     932                 :           8 :         CallShmemCallbacksAfterStartup(callbacks);
     933                 :             :     }
     934         [ +  - ]:       56696 :     else if (shmem_request_state == SRS_INITIAL)
     935                 :             :     {
     936                 :             :         /* Remember the callbacks for later */
     937                 :       56696 :         registered_shmem_callbacks = lappend(registered_shmem_callbacks,
     938                 :             :                                              (void *) callbacks);
     939                 :             :     }
     940                 :             :     else
     941         [ #  # ]:           0 :         elog(ERROR, "cannot request shared memory at this time");
     942                 :       56701 : }
     943                 :             : 
     944                 :             : /*
     945                 :             :  * Register a shmem area (or multiple areas) after startup.
     946                 :             :  */
     947                 :             : static void
     948                 :           8 : CallShmemCallbacksAfterStartup(const ShmemCallbacks *callbacks)
     949                 :             : {
     950                 :             :     Assert(shmem_request_state == SRS_DONE);
     951                 :             :     Assert(pending_shmem_requests == NIL);
     952                 :             : 
     953         [ +  + ]:           8 :     PG_TRY();
     954                 :             :     {
     955                 :           8 :         shmem_request_state = SRS_REQUESTING;
     956                 :             : 
     957                 :             :         /*
     958                 :             :          * Call the request callback first.  The callback makes
     959                 :             :          * ShmemRequest*() calls for each shmem area, adding them to
     960                 :             :          * pending_shmem_requests.
     961                 :             :          */
     962         [ +  - ]:           8 :         if (callbacks->request_fn)
     963                 :           8 :             callbacks->request_fn(callbacks->opaque_arg);
     964                 :             : 
     965                 :             :         /* Process all the requests */
     966                 :           8 :         shmem_request_state = SRS_AFTER_STARTUP_ATTACH_OR_INIT;
     967         [ +  - ]:           8 :         if (pending_shmem_requests != NIL)
     968                 :           8 :             ProcessShmemRequestsAfterStartup(callbacks);
     969                 :             :     }
     970                 :           3 :     PG_FINALLY();
     971                 :             :     {
     972   [ +  -  +  +  :          24 :         foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
     973                 :           8 :             pfree(request->options);
     974                 :           8 :         list_free_deep(pending_shmem_requests);
     975                 :           8 :         pending_shmem_requests = NIL;
     976                 :             : 
     977                 :           8 :         shmem_request_state = SRS_DONE;
     978                 :             :     }
     979         [ +  + ]:           8 :     PG_END_TRY();
     980                 :           5 : }
     981                 :             : 
     982                 :             : static void
     983                 :           8 : ProcessShmemRequestsAfterStartup(const ShmemCallbacks *callbacks)
     984                 :             : {
     985                 :             :     bool        found_any;
     986                 :             :     bool        notfound_any;
     987                 :             : 
     988                 :             :     /* There should be some requests to process */
     989                 :             :     Assert(pending_shmem_requests != NIL);
     990                 :             : 
     991                 :             :     /* Caller manages the global state variable */
     992                 :             :     Assert(shmem_request_state == SRS_AFTER_STARTUP_ATTACH_OR_INIT);
     993                 :             : 
     994                 :             :     /*
     995                 :             :      * Hold ShmemIndexLock while we allocate all the shmem entries and run all
     996                 :             :      * the initializers.
     997                 :             :      */
     998                 :           8 :     LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
     999                 :             : 
    1000                 :             :     /*
    1001                 :             :      * Check if the requested shared memory areas have already been
    1002                 :             :      * initialized.  We assume all the areas requested by the request callback
    1003                 :             :      * to form a coherent unit such that they're all already initialized or
    1004                 :             :      * none.  Otherwise it would be ambiguous which callback, init or attach,
    1005                 :             :      * to callback afterwards.
    1006                 :             :      */
    1007                 :           8 :     found_any = notfound_any = false;
    1008   [ +  -  +  +  :          22 :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
    1009                 :             :     {
    1010                 :             :         ShmemIndexEnt *index_entry;
    1011                 :             : 
    1012                 :             :         index_entry = (ShmemIndexEnt *)
    1013                 :           8 :             hash_search(ShmemIndex, request->options->name, HASH_FIND, NULL);
    1014         [ +  + ]:           8 :         if (index_entry)
    1015                 :             :         {
    1016                 :             :             /*
    1017                 :             :              * Check for a half-initialized area.  (See also similar check in
    1018                 :             :              * AttachShmemIndexEntry())
    1019                 :             :              */
    1020         [ +  + ]:           2 :             if (!index_entry->initialized)
    1021         [ +  - ]:           1 :                 ereport(ERROR,
    1022                 :             :                         (errmsg("cannot attach to shared memory struct \"%s\" because it was not fully initialized",
    1023                 :             :                                 request->options->name)));
    1024                 :           1 :             found_any = true;
    1025                 :             :         }
    1026                 :             :         else
    1027                 :           6 :             notfound_any = true;
    1028                 :             :     }
    1029   [ +  +  -  + ]:           7 :     if (found_any && notfound_any)
    1030         [ #  # ]:           0 :         elog(ERROR, "some of the requested shmem areas have already been initialized");
    1031                 :             : 
    1032                 :             :     /*
    1033                 :             :      * Allocate or attach all the shmem areas requested by the request_fn
    1034                 :             :      * callback.
    1035                 :             :      */
    1036   [ +  -  +  +  :          19 :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
    1037                 :             :     {
    1038         [ +  + ]:           7 :         if (found_any)
    1039                 :           1 :             AttachShmemIndexEntry(request, false);
    1040                 :             :         else
    1041                 :           6 :             InitShmemIndexEntry(request);
    1042                 :             :     }
    1043                 :             : 
    1044                 :             :     /* Finish by calling the appropriate subsystem-specific callback */
    1045         [ +  + ]:           6 :     if (found_any)
    1046                 :             :     {
    1047         [ +  - ]:           1 :         if (callbacks->attach_fn)
    1048                 :           1 :             callbacks->attach_fn(callbacks->opaque_arg);
    1049                 :             :     }
    1050                 :             :     else
    1051                 :             :     {
    1052         [ +  - ]:           5 :         if (callbacks->init_fn)
    1053                 :           5 :             callbacks->init_fn(callbacks->opaque_arg);
    1054                 :             :     }
    1055                 :             : 
    1056   [ +  -  +  +  :          15 :     foreach_ptr(ShmemRequest, request, pending_shmem_requests)
                   +  + ]
    1057                 :             :     {
    1058                 :           5 :         request->index_entry->initialized = true;
    1059                 :             :     }
    1060                 :             : 
    1061                 :           5 :     LWLockRelease(ShmemIndexLock);
    1062                 :           5 : }
    1063                 :             : 
    1064                 :             : /*
    1065                 :             :  * Call all shmem request callbacks.
    1066                 :             :  */
    1067                 :             : void
    1068                 :        1280 : ShmemCallRequestCallbacks(void)
    1069                 :             : {
    1070                 :             :     ListCell   *lc;
    1071                 :             : 
    1072                 :             :     Assert(shmem_request_state == SRS_INITIAL);
    1073                 :        1280 :     shmem_request_state = SRS_REQUESTING;
    1074                 :             : 
    1075   [ +  -  +  +  :       57626 :     foreach(lc, registered_shmem_callbacks)
                   +  + ]
    1076                 :             :     {
    1077                 :       56346 :         const ShmemCallbacks *callbacks = (const ShmemCallbacks *) lfirst(lc);
    1078                 :             : 
    1079         [ +  - ]:       56346 :         if (callbacks->request_fn)
    1080                 :       56346 :             callbacks->request_fn(callbacks->opaque_arg);
    1081                 :             :     }
    1082                 :        1280 : }
    1083                 :             : 
    1084                 :             : /*
    1085                 :             :  * ShmemInitStruct -- Create/attach to a structure in shared memory.
    1086                 :             :  *
    1087                 :             :  *      This is called during initialization to find or allocate
    1088                 :             :  *      a data structure in shared memory.  If no other process
    1089                 :             :  *      has created the structure, this routine allocates space
    1090                 :             :  *      for it.  If it exists already, a pointer to the existing
    1091                 :             :  *      structure is returned.
    1092                 :             :  *
    1093                 :             :  *  Returns: pointer to the object.  *foundPtr is set true if the object was
    1094                 :             :  *      already in the shmem index (hence, already initialized).
    1095                 :             :  *
    1096                 :             :  * Note: This is a legacy interface, kept for backwards compatibility with
    1097                 :             :  * extensions.  Use ShmemRequestStruct() in new code!
    1098                 :             :  */
    1099                 :             : void *
    1100                 :           0 : ShmemInitStruct(const char *name, Size size, bool *foundPtr)
    1101                 :             : {
    1102                 :           0 :     void       *ptr = NULL;
    1103                 :           0 :     ShmemStructOpts options = {
    1104                 :             :         .name = name,
    1105                 :             :         .size = size,
    1106                 :             :         .ptr = &ptr,
    1107                 :             :     };
    1108                 :           0 :     ShmemRequest request = {&options, SHMEM_KIND_STRUCT};
    1109                 :             : 
    1110                 :             :     Assert(shmem_request_state == SRS_DONE ||
    1111                 :             :            shmem_request_state == SRS_INITIALIZING ||
    1112                 :             :            shmem_request_state == SRS_REQUESTING);
    1113                 :             : 
    1114                 :           0 :     LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
    1115                 :             : 
    1116                 :             :     /*
    1117                 :             :      * During postmaster startup, look up the existing entry if any.
    1118                 :             :      */
    1119                 :           0 :     *foundPtr = false;
    1120         [ #  # ]:           0 :     if (IsUnderPostmaster)
    1121                 :           0 :         *foundPtr = AttachShmemIndexEntry(&request, true);
    1122                 :             : 
    1123                 :             :     /* Initialize it if not found */
    1124         [ #  # ]:           0 :     if (!*foundPtr)
    1125                 :             :     {
    1126                 :           0 :         InitShmemIndexEntry(&request);
    1127                 :             :         /* no additional initialization needed */
    1128                 :           0 :         request.index_entry->initialized = true;
    1129                 :             :     }
    1130                 :             : 
    1131                 :           0 :     LWLockRelease(ShmemIndexLock);
    1132                 :             : 
    1133                 :             :     Assert(ptr != NULL);
    1134                 :           0 :     return ptr;
    1135                 :             : }
    1136                 :             : 
    1137                 :             : /* SQL SRF showing allocated shared memory */
    1138                 :             : Datum
    1139                 :           4 : pg_get_shmem_allocations(PG_FUNCTION_ARGS)
    1140                 :             : {
    1141                 :             : #define PG_GET_SHMEM_SIZES_COLS 4
    1142                 :           4 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1143                 :             :     HASH_SEQ_STATUS hstat;
    1144                 :             :     ShmemIndexEnt *ent;
    1145                 :           4 :     Size        named_allocated = 0;
    1146                 :             :     Datum       values[PG_GET_SHMEM_SIZES_COLS];
    1147                 :             :     bool        nulls[PG_GET_SHMEM_SIZES_COLS];
    1148                 :             : 
    1149                 :           4 :     InitMaterializedSRF(fcinfo, 0);
    1150                 :             : 
    1151                 :           4 :     LWLockAcquire(ShmemIndexLock, LW_SHARED);
    1152                 :             : 
    1153                 :           4 :     hash_seq_init(&hstat, ShmemIndex);
    1154                 :             : 
    1155                 :             :     /* output all allocated entries */
    1156                 :           4 :     memset(nulls, 0, sizeof(nulls));
    1157         [ +  + ]:         322 :     while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
    1158                 :             :     {
    1159                 :         318 :         values[0] = CStringGetTextDatum(ent->key);
    1160                 :         318 :         values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr);
    1161                 :         318 :         values[2] = Int64GetDatum(ent->size);
    1162                 :         318 :         values[3] = Int64GetDatum(ent->allocated_size);
    1163                 :         318 :         named_allocated += ent->allocated_size;
    1164                 :             : 
    1165                 :         318 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
    1166                 :             :                              values, nulls);
    1167                 :             :     }
    1168                 :             : 
    1169                 :             :     /* output shared memory allocated but not counted via the shmem index */
    1170                 :           4 :     values[0] = CStringGetTextDatum("<anonymous>");
    1171                 :           4 :     nulls[1] = true;
    1172                 :           4 :     values[2] = Int64GetDatum(ShmemAllocator->free_offset - named_allocated);
    1173                 :           4 :     values[3] = values[2];
    1174                 :           4 :     tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    1175                 :             : 
    1176                 :             :     /* output as-of-yet unused shared memory */
    1177                 :           4 :     nulls[0] = true;
    1178                 :           4 :     values[1] = Int64GetDatum(ShmemAllocator->free_offset);
    1179                 :           4 :     nulls[1] = false;
    1180                 :           4 :     values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemAllocator->free_offset);
    1181                 :           4 :     values[3] = values[2];
    1182                 :           4 :     tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    1183                 :             : 
    1184                 :           4 :     LWLockRelease(ShmemIndexLock);
    1185                 :             : 
    1186                 :           4 :     return (Datum) 0;
    1187                 :             : }
    1188                 :             : 
    1189                 :             : /*
    1190                 :             :  * SQL SRF showing NUMA memory nodes for allocated shared memory
    1191                 :             :  *
    1192                 :             :  * Compared to pg_get_shmem_allocations(), this function does not return
    1193                 :             :  * information about shared anonymous allocations and unused shared memory.
    1194                 :             :  */
    1195                 :             : Datum
    1196                 :           4 : pg_get_shmem_allocations_numa(PG_FUNCTION_ARGS)
    1197                 :             : {
    1198                 :             : #define PG_GET_SHMEM_NUMA_SIZES_COLS 3
    1199                 :           4 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    1200                 :             :     HASH_SEQ_STATUS hstat;
    1201                 :             :     ShmemIndexEnt *ent;
    1202                 :             :     Datum       values[PG_GET_SHMEM_NUMA_SIZES_COLS];
    1203                 :             :     bool        nulls[PG_GET_SHMEM_NUMA_SIZES_COLS];
    1204                 :             :     Size        os_page_size;
    1205                 :             :     void      **page_ptrs;
    1206                 :             :     int        *pages_status;
    1207                 :             :     uint64      shm_total_page_count,
    1208                 :             :                 shm_ent_page_count,
    1209                 :             :                 max_nodes;
    1210                 :             :     Size       *nodes;
    1211                 :             : 
    1212         [ +  - ]:           4 :     if (pg_numa_init() == -1)
    1213         [ +  - ]:           4 :         elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
    1214                 :             : 
    1215                 :           0 :     InitMaterializedSRF(fcinfo, 0);
    1216                 :             : 
    1217                 :           0 :     max_nodes = pg_numa_get_max_node();
    1218                 :           0 :     nodes = palloc_array(Size, max_nodes + 2);
    1219                 :             : 
    1220                 :             :     /*
    1221                 :             :      * Shared memory allocations can vary in size and may not align with OS
    1222                 :             :      * memory page boundaries, while NUMA queries work on pages.
    1223                 :             :      *
    1224                 :             :      * To correctly map each allocation to NUMA nodes, we need to: 1.
    1225                 :             :      * Determine the OS memory page size. 2. Align each allocation's start/end
    1226                 :             :      * addresses to page boundaries. 3. Query NUMA node information for all
    1227                 :             :      * pages spanning the allocation.
    1228                 :             :      */
    1229                 :           0 :     os_page_size = pg_get_shmem_pagesize();
    1230                 :             : 
    1231                 :             :     /*
    1232                 :             :      * Allocate memory for page pointers and status based on total shared
    1233                 :             :      * memory size. This simplified approach allocates enough space for all
    1234                 :             :      * pages in shared memory rather than calculating the exact requirements
    1235                 :             :      * for each segment.
    1236                 :             :      *
    1237                 :             :      * Add 1, because we don't know how exactly the segments align to OS
    1238                 :             :      * pages, so the allocation might use one more memory page. In practice
    1239                 :             :      * this is not very likely, and moreover we have more entries, each of
    1240                 :             :      * them using only fraction of the total pages.
    1241                 :             :      */
    1242                 :           0 :     shm_total_page_count = (ShmemSegHdr->totalsize / os_page_size) + 1;
    1243                 :           0 :     page_ptrs = palloc0_array(void *, shm_total_page_count);
    1244                 :           0 :     pages_status = palloc_array(int, shm_total_page_count);
    1245                 :             : 
    1246         [ #  # ]:           0 :     if (firstNumaTouch)
    1247         [ #  # ]:           0 :         elog(DEBUG1, "NUMA: page-faulting shared memory segments for proper NUMA readouts");
    1248                 :             : 
    1249                 :           0 :     LWLockAcquire(ShmemIndexLock, LW_SHARED);
    1250                 :             : 
    1251                 :           0 :     hash_seq_init(&hstat, ShmemIndex);
    1252                 :             : 
    1253                 :             :     /* output all allocated entries */
    1254         [ #  # ]:           0 :     while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL)
    1255                 :             :     {
    1256                 :             :         char       *startptr,
    1257                 :             :                    *endptr;
    1258                 :             :         Size        total_len;
    1259                 :             : 
    1260                 :             :         /*
    1261                 :             :          * Calculate the range of OS pages used by this segment. The segment
    1262                 :             :          * may start / end half-way through a page, we want to count these
    1263                 :             :          * pages too. So we align the start/end pointers down/up, and then
    1264                 :             :          * calculate the number of pages from that.
    1265                 :             :          */
    1266                 :           0 :         startptr = (char *) TYPEALIGN_DOWN(os_page_size, ent->location);
    1267                 :           0 :         endptr = (char *) TYPEALIGN(os_page_size,
    1268                 :             :                                     (char *) ent->location + ent->allocated_size);
    1269                 :           0 :         total_len = (endptr - startptr);
    1270                 :             : 
    1271                 :           0 :         shm_ent_page_count = total_len / os_page_size;
    1272                 :             : 
    1273                 :             :         /*
    1274                 :             :          * If we ever get 0xff (-1) back from kernel inquiry, then we probably
    1275                 :             :          * have a bug in mapping buffers to OS pages.
    1276                 :             :          */
    1277                 :           0 :         memset(pages_status, 0xff, sizeof(int) * shm_ent_page_count);
    1278                 :             : 
    1279                 :             :         /*
    1280                 :             :          * Setup page_ptrs[] with pointers to all OS pages for this segment,
    1281                 :             :          * and get the NUMA status using pg_numa_query_pages.
    1282                 :             :          *
    1283                 :             :          * In order to get reliable results we also need to touch memory
    1284                 :             :          * pages, so that inquiry about NUMA memory node doesn't return -2
    1285                 :             :          * (ENOENT, which indicates unmapped/unallocated pages).
    1286                 :             :          */
    1287         [ #  # ]:           0 :         for (uint64 i = 0; i < shm_ent_page_count; i++)
    1288                 :             :         {
    1289                 :           0 :             page_ptrs[i] = startptr + (i * os_page_size);
    1290                 :             : 
    1291                 :           0 :             if (firstNumaTouch)
    1292                 :             :                 pg_numa_touch_mem_if_required(page_ptrs[i]);
    1293                 :             : 
    1294         [ #  # ]:           0 :             CHECK_FOR_INTERRUPTS();
    1295                 :             :         }
    1296                 :             : 
    1297         [ #  # ]:           0 :         if (pg_numa_query_pages(0, shm_ent_page_count, page_ptrs, pages_status) == -1)
    1298         [ #  # ]:           0 :             elog(ERROR, "failed NUMA pages inquiry status: %m");
    1299                 :             : 
    1300                 :             :         /* Count number of NUMA nodes used for this shared memory entry */
    1301                 :           0 :         memset(nodes, 0, sizeof(Size) * (max_nodes + 2));
    1302                 :             : 
    1303         [ #  # ]:           0 :         for (uint64 i = 0; i < shm_ent_page_count; i++)
    1304                 :             :         {
    1305                 :           0 :             int         s = pages_status[i];
    1306                 :             : 
    1307                 :             :             /* Ensure we are adding only valid index to the array */
    1308   [ #  #  #  # ]:           0 :             if (s >= 0 && s <= max_nodes)
    1309                 :             :             {
    1310                 :             :                 /* valid NUMA node */
    1311                 :           0 :                 nodes[s]++;
    1312                 :           0 :                 continue;
    1313                 :             :             }
    1314         [ #  # ]:           0 :             else if (s == -2)
    1315                 :             :             {
    1316                 :             :                 /* -2 means ENOENT (e.g. page was moved to swap) */
    1317                 :           0 :                 nodes[max_nodes + 1]++;
    1318                 :           0 :                 continue;
    1319                 :             :             }
    1320                 :             : 
    1321         [ #  # ]:           0 :             elog(ERROR, "invalid NUMA node id outside of allowed range "
    1322                 :             :                  "[0, " UINT64_FORMAT "]: %d", max_nodes, s);
    1323                 :             :         }
    1324                 :             : 
    1325                 :             :         /* no NULLs for regular nodes */
    1326                 :           0 :         memset(nulls, 0, sizeof(nulls));
    1327                 :             : 
    1328                 :             :         /*
    1329                 :             :          * Add one entry for each NUMA node, including those without allocated
    1330                 :             :          * memory for this segment.
    1331                 :             :          */
    1332         [ #  # ]:           0 :         for (uint64 i = 0; i <= max_nodes; i++)
    1333                 :             :         {
    1334                 :           0 :             values[0] = CStringGetTextDatum(ent->key);
    1335                 :           0 :             values[1] = Int32GetDatum(i);
    1336                 :           0 :             values[2] = Int64GetDatum(nodes[i] * os_page_size);
    1337                 :             : 
    1338                 :           0 :             tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
    1339                 :             :                                  values, nulls);
    1340                 :             :         }
    1341                 :             : 
    1342                 :             :         /* The last entry is used for pages without a NUMA node. */
    1343                 :           0 :         nulls[1] = true;
    1344                 :           0 :         values[0] = CStringGetTextDatum(ent->key);
    1345                 :           0 :         values[2] = Int64GetDatum(nodes[max_nodes + 1] * os_page_size);
    1346                 :             : 
    1347                 :           0 :         tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
    1348                 :             :                              values, nulls);
    1349                 :             :     }
    1350                 :             : 
    1351                 :           0 :     LWLockRelease(ShmemIndexLock);
    1352                 :           0 :     firstNumaTouch = false;
    1353                 :             : 
    1354                 :           0 :     return (Datum) 0;
    1355                 :             : }
    1356                 :             : 
    1357                 :             : /*
    1358                 :             :  * Determine the memory page size used for the shared memory segment.
    1359                 :             :  *
    1360                 :             :  * If the shared segment was allocated using huge pages, returns the size of
    1361                 :             :  * a huge page. Otherwise returns the size of regular memory page.
    1362                 :             :  *
    1363                 :             :  * This should be used only after the server is started.
    1364                 :             :  */
    1365                 :             : Size
    1366                 :           2 : pg_get_shmem_pagesize(void)
    1367                 :             : {
    1368                 :             :     Size        os_page_size;
    1369                 :             : #ifdef WIN32
    1370                 :             :     SYSTEM_INFO sysinfo;
    1371                 :             : 
    1372                 :             :     GetSystemInfo(&sysinfo);
    1373                 :             :     os_page_size = sysinfo.dwPageSize;
    1374                 :             : #else
    1375                 :           2 :     os_page_size = sysconf(_SC_PAGESIZE);
    1376                 :             : #endif
    1377                 :             : 
    1378                 :             :     Assert(IsUnderPostmaster);
    1379                 :             :     Assert(huge_pages_status != HUGE_PAGES_UNKNOWN);
    1380                 :             : 
    1381         [ -  + ]:           2 :     if (huge_pages_status == HUGE_PAGES_ON)
    1382                 :           0 :         GetHugePageSize(&os_page_size, NULL);
    1383                 :             : 
    1384                 :           2 :     return os_page_size;
    1385                 :             : }
    1386                 :             : 
    1387                 :             : Datum
    1388                 :           5 : pg_numa_available(PG_FUNCTION_ARGS)
    1389                 :             : {
    1390                 :           5 :     PG_RETURN_BOOL(pg_numa_init() != -1);
    1391                 :             : }
        

Generated by: LCOV version 2.0-1