#pragma once #include "Baselib_ErrorState.h" #include "Internal/Baselib_EnumSizeCheck.h" #ifdef __cplusplus BASELIB_C_INTERFACE { #endif // Max alignment that can be passed to Baselib_Memory_AlignedAlloc and Baselib_Memory_AlignedReallocate functions static const size_t Baselib_Memory_MaxAlignment = 64 * 1024; // We can't handle platform varying constants in the C# bindings right now. #if !defined(BASELIB_BINDING_GENERATION) // Minimum guaranteed alignment for Baselib_Memory_Allocate/Baselib_Memory_AlignedAlloc in bytes. // // Guaranteed to be at least 8. // Note that on some platforms it is possible to overwrite the internally used allocator in which case this guarantee may no longer be upheld. static const size_t Baselib_Memory_MinGuaranteedAlignment = PLATFORM_MEMORY_MALLOC_MIN_ALIGNMENT; #else // Minimum guaranteed alignment for Baselib_Memory_Allocate/Baselib_Memory_AlignedAlloc in bytes. // // Guaranteed to be at least 8. // Note that on some platforms it is possible to overwrite the internally used allocator in which case this guarantee may no longer be upheld. static const size_t Baselib_Memory_MinGuaranteedAlignment = 8; #endif // !defined(BASELIB_BINDING_GENERATION) // Information about available pages sizes. // // Page sizes do not reflect necessarily hardware ("physical") page sizes, but rather "virtual" page sizes that the OS is dealing with. // I.e. a virtual page may refer to several hardware pages, but the OS exposes only a single state for this group of pages. typedef struct Baselib_Memory_PageSizeInfo { // Commonly used page size on this platform. uint64_t defaultPageSize; // pageSizesLen valid page sizes, ordered from small to large. uint64_t pageSizes[6]; uint64_t pageSizesLen; } Baselib_Memory_PageSizeInfo; typedef struct Baselib_Memory_PageAllocation { void* ptr; uint64_t pageSize; uint64_t pageCount; } Baselib_Memory_PageAllocation; static const Baselib_Memory_PageAllocation Baselib_Memory_PageAllocation_Invalid = {0, 0, 0}; // Fills out a Baselib_Memory_PageSizeInfo struct. // // \param outPagesSizeInfo: Pointer to page size info struct. Passing 'nullptr' will return immediately. BASELIB_API void Baselib_Memory_GetPageSizeInfo(Baselib_Memory_PageSizeInfo* outPagesSizeInfo); // Allocates memory using a system allocator like malloc. // // Allocation failures or invalid alignments will trigger process abort. // // \param size Size of the allocation. Zero is valid. // \returns Unique pointer to allocation. At least aligned to by Baselib_Memory_MinGuaranteedAlignment bytes. // This is true for zero sized allocations as well. BASELIB_API void* Baselib_Memory_Allocate(size_t size); // Reallocates memory previously allocated by Baselib_Memory_Allocate or Baselib_Memory_Reallocate. // // Allocation failures or invalid alignments will trigger process abort. // // \param ptr Pointer previously returned by Baselib_Memory_Allocate or Baselib_Memory_Reallocate. // Reallocating an already freed pointer or a pointer that was not previously allocated by Baselib_Memory_Allocate or // Baselib_Memory_Reallocate leads to undefined behavior. // Passing `nullptr` yield the same result as calling Baselib_Memory_Allocate. // \param size Size of the allocation. No special restrictions apply, zero is valid. // \returns Unique pointer to allocation. At least aligned to by Baselib_Memory_MinGuaranteedAlignment bytes. // This is true for zero sized allocations as well. BASELIB_API void* Baselib_Memory_Reallocate(void* ptr, size_t newSize); // Frees memory allocated by Baselib_Memory_Allocate Baselib_Memory_Reallocate. // // \param ptr Pointer previously returned by Baselib_Memory_Allocate or Baselib_Memory_Reallocate. // Freeing an already freed pointer or a pointer that was not previously allocated by Baselib_Memory_Allocate or Baselib_Memory_Reallocate leads to undefined behavior. // Passing `nullptr` result in a no-op. BASELIB_API void Baselib_Memory_Free(void* ptr); // Allocates memory using a system allocator like malloc and guarantees that the returned pointer is aligned to the specified alignment. // // Allocation failures or invalid alignments will trigger process abort. // // \param size Size of the allocation. No special restrictions (like multiples of alignment) apply, zero is valid. // \param alignment Needs to be a power of two which is also a multiple of of pointer size (i.e. sizeof(void*)) but less or equal to Baselib_Memory_MaxAlignment. // Any alignment smaller than Baselib_Memory_MinGuaranteedAlignment, will be clamped to Baselib_Memory_MinGuaranteedAlignment. // \returns Unique pointer to aligned allocation. This is true for zero sized allocations as well. BASELIB_API void* Baselib_Memory_AlignedAllocate(size_t size, size_t alignment); // Reallocates memory previously allocated by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate. // // Allocation failures or invalid alignments will trigger process abort. // // \param ptr Pointer previously returned by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate. // Reallocating an already freed pointer or a pointer that was not previously allocated by Baselib_Memory_AlignedAllocate or // Baselib_Memory_AlignedReallocate leads to undefined behavior. // Passing `nullptr` yield the same result as calling Baselib_Memory_AlignedAllocate. // \param size Size of the allocation. No special restrictions apply, zero is valid. // \param alignment Needs to be a power of two which is also a multiple of of pointer size (i.e. sizeof(void*)) but less or equal to Baselib_Memory_MaxAlignment. // Any alignment smaller than Baselib_Memory_MinGuaranteedAlignment, will be clamped to Baselib_Memory_MinGuaranteedAlignment. // \returns Unique pointer to aligned allocation. This is true for zero sized allocations as well. BASELIB_API void* Baselib_Memory_AlignedReallocate(void* ptr, size_t newSize, size_t alignment); // Frees memory allocated by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate. // // \param ptr Pointer previously returned by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate. // Freeing an already freed pointer or a pointer that was not previously allocated by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate leads to undefined behavior. // Passing `nullptr` result in a no-op. BASELIB_API void Baselib_Memory_AlignedFree(void* ptr); // Page state options typedef enum Baselib_Memory_PageState { // The page are in a reserved state and any access will cause a seg-fault/access violation. // On some platforms that support this state this may be just a hint to the OS and there is no guarantee pages in this state behave differently from Baselib_Memory_PageState_NoAccess. // The Baselib implementation does a best effort and tries to ensure as best as possible that pages in this state are not commited. Baselib_Memory_PageState_Reserved = 0x00, // This is a no access page and will cause a seg-fault/access violation when accessed. Baselib_Memory_PageState_NoAccess = 0x01, // The memory can only be read. Baselib_Memory_PageState_ReadOnly = 0x02, // The memory can be read and written. Baselib_Memory_PageState_ReadWrite = 0x04, // The memory can be used to execute code and can be read. Baselib_Memory_PageState_ReadOnly_Executable = 0x10 | Baselib_Memory_PageState_ReadOnly, // The memory can be used to execute code and can be both read and written. Baselib_Memory_PageState_ReadWrite_Executable = 0x10 | Baselib_Memory_PageState_ReadWrite, } Baselib_Memory_PageState; BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_Memory_PageState); // Allocates a given number of memory pages and guarantees that the returned pointer is aligned to specified multiple of the page size. // // Large alignments may lead to a significantly higher use of virtual address space than the amount of memory requested. // This may result in an aligned page allocation to fail where a less/non-aligned allocation would succeed. // Note that this is especially common in 32bit applications but a platform may impose additional restrictions on the size of its virtual address space. // Whether a page allocation is pure virtual address space or already commited memory depends on the platform and passed page state flag. // // \param pageCount Number of pages requested (each will have pageSize size) // \param alignmentInMultipleOfPageSize Specified alignment in multiple of page sizes (a value of 1 implies alignment to page size). // Value needs to be larger than zero and a power of two, otherwise UnsupportedAlignment will be raised. // \param pageState: In which state the pages should be. Certain values may raise UnsupportedPageState on certain platforms. // // Possible error codes: // - Baselib_ErrorCode_InvalidPageSize: Page size doesn't match any of the available page sizes (see Baselib_Memory_GetPageSizeInfo). // - Baselib_ErrorCode_InvalidPageCount: Requested number of pages is zero. // - Baselib_ErrorCode_UnsupportedAlignment: Requested alignment is invalid. // - Baselib_ErrorCode_UnsupportedPageState: The underlying system doesn't support the requested page state (see Baselib_Memory_PageState). // - Baselib_ErrorCode_OutOfMemory: If there is not enough continuous address space available, or physical memory space when acquiring committed memory. // // \returns Page allocation info or Baselib_Memory_PageAllocation_Invalid in case of an error. BASELIB_API Baselib_Memory_PageAllocation Baselib_Memory_AllocatePages(uint64_t pageSize, uint64_t pageCount, uint64_t alignmentInMultipleOfPageSize, Baselib_Memory_PageState pageState, Baselib_ErrorState* errorState); // Releases the previously allocated pages (using either Baselib_Memory_AllocatePages) // // A single call of ReleasePages must encompass all pages that were originally allocated with a single call of AllocatePages. // Passing Baselib_Memory_PageAllocation with a nullptr or a zero page count result in a no-op. // // Possible error codes: // - Baselib_ErrorCode_InvalidAddressRange: Address range was detected to not match a valid allocation. // CAUTION: Not all platforms are able to detect this and may either raise an error or cause undefined behavior. // Note to implementors: Raising the error is strongly preferred as it helps identifying issues in user code. // - Baselib_ErrorCode_InvalidPageSize: If page size doesn't match a previous allocation at `pageAllocation.ptr`. // // Implementation note: // We could be able to allow granular ReleasePages call, but even then only in the _allocation granularity_ which might be different from the page size. // (e.g. windows page size 4k allocation granularity 64k) BASELIB_API void Baselib_Memory_ReleasePages(Baselib_Memory_PageAllocation pageAllocation, Baselib_ErrorState* errorState); // Modifies the page state property of an already allocated virtual address range. // // It is possible to modify only some of the pages allocated by Baselib_Memory_AllocatePages. // Passing `nullptr` or a zero page count result in a no-op. // // Possible error codes: // - Baselib_ErrorCode_InvalidAddressRange: Address range is not covered by a valid allocation. // Platforms that emulate page allocations (e.g. Emscripten) are not able to present this error and will pass the function call silently. // - Baselib_ErrorCode_InvalidPageSize: If page size doesn't match the previous allocation at `addressOfFirstPage`. // - Baselib_ErrorCode_UnsupportedPageState: The underlying system doesn't support the requested page state (see Baselib_Memory_PageState). BASELIB_API void Baselib_Memory_SetPageState(void* addressOfFirstPage, uint64_t pageSize, uint64_t pageCount, Baselib_Memory_PageState pageState, Baselib_ErrorState* errorState); #ifdef __cplusplus } // BASELIB_C_INTERFACE #endif