summaryrefslogtreecommitdiff
path: root/src/backend/utils/mmgr/alignedalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/mmgr/alignedalloc.c')
-rw-r--r--src/backend/utils/mmgr/alignedalloc.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/backend/utils/mmgr/alignedalloc.c b/src/backend/utils/mmgr/alignedalloc.c
new file mode 100644
index 00000000000..62f9dbfe89a
--- /dev/null
+++ b/src/backend/utils/mmgr/alignedalloc.c
@@ -0,0 +1,132 @@
+/*-------------------------------------------------------------------------
+ *
+ * alignedalloc.c
+ * Allocator functions to implement palloc_aligned
+ *
+ * This is not a fully-fledged MemoryContext type as there is no means to
+ * create a MemoryContext of this type. The code here only serves to allow
+ * operations such as pfree() and repalloc() to work correctly on a memory
+ * chunk that was allocated by palloc_aligned().
+ *
+ * Portions Copyright (c) 2022, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/utils/mmgr/alignedalloc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "utils/memdebug.h"
+#include "utils/memutils_memorychunk.h"
+
+/*
+ * AlignedAllocFree
+* Frees allocated memory; memory is removed from its owning context.
+*/
+void
+AlignedAllocFree(void *pointer)
+{
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
+ void *unaligned;
+
+ Assert(!MemoryChunkIsExternal(chunk));
+
+ /* obtain the original (unaligned) allocated pointer */
+ unaligned = MemoryChunkGetBlock(chunk);
+
+#ifdef MEMORY_CONTEXT_CHECKING
+ /* Test for someone scribbling on unused space in chunk */
+ if (!sentinel_ok(pointer, chunk->requested_size))
+ elog(WARNING, "detected write past chunk end in %s %p",
+ GetMemoryChunkContext(unaligned)->name, chunk);
+#endif
+
+ pfree(unaligned);
+}
+
+/*
+ * AlignedAllocRealloc
+ * Change the allocated size of a chunk and return possibly a different
+ * pointer to a memory address aligned to the same boundary as the
+ * originally requested alignment. The contents of 'pointer' will be
+ * copied into the returned pointer up until 'size'. Any additional
+ * memory will be uninitialized.
+ */
+void *
+AlignedAllocRealloc(void *pointer, Size size)
+{
+ MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
+ Size alignto = MemoryChunkGetValue(redirchunk);
+ void *unaligned = MemoryChunkGetBlock(redirchunk);
+ MemoryContext ctx;
+ Size old_size;
+ void *newptr;
+
+ /* sanity check this is a power of 2 value */
+ Assert((alignto & (alignto - 1)) == 0);
+
+ /*
+ * Determine the size of the original allocation. We can't determine this
+ * exactly as GetMemoryChunkSpace() returns the total space used for the
+ * allocation, which for contexts like aset includes rounding up to the
+ * next power of 2. However, this value is just used to memcpy() the old
+ * data into the new allocation, so we only need to concern ourselves with
+ * not reading beyond the end of the original allocation's memory. The
+ * drawback here is that we may copy more bytes than we need to, which
+ * only amounts to wasted effort. We can safely subtract the extra bytes
+ * that we requested to allow us to align the pointer. We must also
+ * subtract the space for the unaligned pointer's MemoryChunk since
+ * GetMemoryChunkSpace should have included that. This does assume that
+ * all context types use MemoryChunk as a chunk header.
+ */
+ old_size = GetMemoryChunkSpace(unaligned) -
+ PallocAlignedExtraBytes(alignto) - sizeof(MemoryChunk);
+
+#ifdef MEMORY_CONTEXT_CHECKING
+ /* check that GetMemoryChunkSpace returned something realistic */
+ Assert(old_size >= redirchunk->requested_size);
+#endif
+
+ ctx = GetMemoryChunkContext(unaligned);
+ newptr = MemoryContextAllocAligned(ctx, size, alignto, 0);
+
+ /*
+ * We may memcpy beyond the end of the original allocation request size,
+ * so we must mark the entire allocation as defined.
+ */
+ VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
+ memcpy(newptr, pointer, Min(size, old_size));
+ pfree(unaligned);
+
+ return newptr;
+}
+
+/*
+ * AlignedAllocGetChunkContext
+ * Return the MemoryContext that 'pointer' belongs to.
+ */
+MemoryContext
+AlignedAllocGetChunkContext(void *pointer)
+{
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
+
+ Assert(!MemoryChunkIsExternal(chunk));
+
+ return GetMemoryChunkContext(MemoryChunkGetBlock(chunk));
+}
+
+/*
+ * AlignedAllocGetChunkSpace
+ * Given a currently-allocated chunk, determine the total space
+ * it occupies (including all memory-allocation overhead).
+ */
+Size
+AlignedAllocGetChunkSpace(void *pointer)
+{
+ MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
+ void *unaligned = MemoryChunkGetBlock(redirchunk);
+
+ return GetMemoryChunkSpace(unaligned);
+}