From: Heikki Linnakangas Date: Sun, 5 Apr 2026 23:13:06 +0000 (+0300) Subject: Add alignment option to ShmemRequestStruct() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dacfe81a0de513308e6753fe3d9b4f3e4811da69;p=thirdparty%2Fpostgresql.git Add alignment option to ShmemRequestStruct() The buffer blocks, converted to use ShmemRequestStruct() in the next commit, are IO-aligned. This might come handy in other places too, so make it an explicit feature of ShmemRequestStruct(). Reviewed-by: Ashutosh Bapat Reviewed-by: Matthias van de Meent Reviewed-by: Daniel Gustafsson Discussion: https://www.postgresql.org/message-id/CAExHW5vM1bneLYfg0wGeAa=52UiJ3z4vKd3AJ72X8Fw6k3KKrg@mail.gmail.com --- diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index e60dfb4272c..92c96257588 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -135,6 +135,7 @@ #include "fmgr.h" #include "funcapi.h" #include "miscadmin.h" +#include "port/pg_bitutils.h" #include "port/pg_numa.h" #include "storage/lwlock.h" #include "storage/pg_shmem.h" @@ -235,7 +236,7 @@ typedef struct ShmemAllocatorData #define ShmemIndexLock (&ShmemAllocator->index_lock) -static void *ShmemAllocRaw(Size size, Size *allocated_size); +static void *ShmemAllocRaw(Size size, Size alignment, Size *allocated_size); /* shared memory global variables */ @@ -336,6 +337,7 @@ ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind) { ShmemRequest *request; + /* Check the options */ if (options->name == NULL) elog(ERROR, "shared memory request is missing 'name' option"); @@ -354,6 +356,11 @@ ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind) options->size, options->name); } + if (options->alignment != 0 && pg_nextpower2_size_t(options->alignment) != options->alignment) + elog(ERROR, "invalid alignment %zu for shared memory request for \"%s\"", + options->alignment, options->name); + + /* Check that we're in the right state */ if (shmem_request_state != SRS_REQUESTING) elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback"); @@ -393,9 +400,14 @@ ShmemGetRequestedSize(void) /* memory needed for all the requested areas */ foreach_ptr(ShmemRequest, request, pending_shmem_requests) { + size_t alignment = request->options->alignment; + + /* pad the start address for alignment like ShmemAllocRaw() does */ + if (alignment < PG_CACHE_LINE_SIZE) + alignment = PG_CACHE_LINE_SIZE; + size = TYPEALIGN(alignment, size); + size = add_size(size, request->options->size); - /* calculate alignment padding like ShmemAllocRaw() does */ - size = CACHELINEALIGN(size); } return size; @@ -520,7 +532,9 @@ InitShmemIndexEntry(ShmemRequest *request) * We inserted the entry to the shared memory index. Allocate requested * amount of shared memory for it, and initialize the index entry. */ - structPtr = ShmemAllocRaw(request->options->size, &allocated_size); + structPtr = ShmemAllocRaw(request->options->size, + request->options->alignment, + &allocated_size); if (structPtr == NULL) { /* out of memory; remove the failed ShmemIndex entry */ @@ -749,7 +763,7 @@ ShmemAlloc(Size size) void *newSpace; Size allocated_size; - newSpace = ShmemAllocRaw(size, &allocated_size); + newSpace = ShmemAllocRaw(size, 0, &allocated_size); if (!newSpace) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -768,7 +782,7 @@ ShmemAllocNoError(Size size) { Size allocated_size; - return ShmemAllocRaw(size, &allocated_size); + return ShmemAllocRaw(size, 0, &allocated_size); } /* @@ -778,8 +792,9 @@ ShmemAllocNoError(Size size) * be equal to the number requested plus any padding we choose to add. */ static void * -ShmemAllocRaw(Size size, Size *allocated_size) +ShmemAllocRaw(Size size, Size alignment, Size *allocated_size) { + Size rawStart; Size newStart; Size newFree; void *newSpace; @@ -795,14 +810,15 @@ ShmemAllocRaw(Size size, Size *allocated_size) * structures out to a power-of-two size - but without this, even that * won't be sufficient. */ - size = CACHELINEALIGN(size); - *allocated_size = size; + if (alignment < PG_CACHE_LINE_SIZE) + alignment = PG_CACHE_LINE_SIZE; Assert(ShmemSegHdr != NULL); SpinLockAcquire(&ShmemAllocator->shmem_lock); - newStart = ShmemAllocator->free_offset; + rawStart = ShmemAllocator->free_offset; + newStart = TYPEALIGN(alignment, rawStart); newFree = newStart + size; if (newFree <= ShmemSegHdr->totalsize) @@ -816,8 +832,9 @@ ShmemAllocRaw(Size size, Size *allocated_size) SpinLockRelease(&ShmemAllocator->shmem_lock); /* note this assert is okay with newSpace == NULL */ - Assert(newSpace == (void *) CACHELINEALIGN(newSpace)); + Assert(newSpace == (void *) TYPEALIGN(alignment, newSpace)); + *allocated_size = newFree - rawStart; return newSpace; } diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h index 1680712498f..af7fe893bc4 100644 --- a/src/include/storage/shmem.h +++ b/src/include/storage/shmem.h @@ -51,6 +51,12 @@ typedef struct ShmemStructOpts */ ssize_t size; + /* + * Alignment of the starting address. If not set, defaults to cacheline + * boundary. Must be a power of two. + */ + size_t alignment; + /* * When the shmem area is initialized or attached to, pointer to it is * stored in *ptr. It usually points to a global variable, used to access