Baselib_Memory.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #pragma once
  2. #include "Baselib_ErrorState.h"
  3. #include "Internal/Baselib_EnumSizeCheck.h"
  4. #ifdef __cplusplus
  5. BASELIB_C_INTERFACE
  6. {
  7. #endif
  8. // Max alignment that can be passed to Baselib_Memory_AlignedAlloc and Baselib_Memory_AlignedReallocate functions
  9. static const size_t Baselib_Memory_MaxAlignment = 64 * 1024;
  10. // We can't handle platform varying constants in the C# bindings right now.
  11. #if !defined(BASELIB_BINDING_GENERATION)
  12. // Minimum guaranteed alignment for Baselib_Memory_Allocate/Baselib_Memory_AlignedAlloc in bytes.
  13. //
  14. // Guaranteed to be at least 8.
  15. // Note that on some platforms it is possible to overwrite the internally used allocator in which case this guarantee may no longer be upheld.
  16. static const size_t Baselib_Memory_MinGuaranteedAlignment = PLATFORM_MEMORY_MALLOC_MIN_ALIGNMENT;
  17. #else
  18. // Minimum guaranteed alignment for Baselib_Memory_Allocate/Baselib_Memory_AlignedAlloc in bytes.
  19. //
  20. // Guaranteed to be at least 8.
  21. // Note that on some platforms it is possible to overwrite the internally used allocator in which case this guarantee may no longer be upheld.
  22. static const size_t Baselib_Memory_MinGuaranteedAlignment = 8;
  23. #endif // !defined(BASELIB_BINDING_GENERATION)
  24. // Information about available pages sizes.
  25. //
  26. // Page sizes do not reflect necessarily hardware ("physical") page sizes, but rather "virtual" page sizes that the OS is dealing with.
  27. // I.e. a virtual page may refer to several hardware pages, but the OS exposes only a single state for this group of pages.
  28. typedef struct Baselib_Memory_PageSizeInfo
  29. {
  30. // Commonly used page size on this platform.
  31. uint64_t defaultPageSize;
  32. // pageSizesLen valid page sizes, ordered from small to large.
  33. uint64_t pageSizes[6];
  34. uint64_t pageSizesLen;
  35. } Baselib_Memory_PageSizeInfo;
  36. typedef struct Baselib_Memory_PageAllocation
  37. {
  38. void* ptr;
  39. uint64_t pageSize;
  40. uint64_t pageCount;
  41. } Baselib_Memory_PageAllocation;
  42. static const Baselib_Memory_PageAllocation Baselib_Memory_PageAllocation_Invalid = {0, 0, 0};
  43. // Fills out a Baselib_Memory_PageSizeInfo struct.
  44. //
  45. // \param outPagesSizeInfo: Pointer to page size info struct. Passing 'nullptr' will return immediately.
  46. BASELIB_API void Baselib_Memory_GetPageSizeInfo(Baselib_Memory_PageSizeInfo* outPagesSizeInfo);
  47. // Allocates memory using a system allocator like malloc.
  48. //
  49. // Allocation failures or invalid alignments will trigger process abort.
  50. //
  51. // \param size Size of the allocation. Zero is valid.
  52. // \returns Unique pointer to allocation. At least aligned to by Baselib_Memory_MinGuaranteedAlignment bytes.
  53. // This is true for zero sized allocations as well.
  54. BASELIB_API void* Baselib_Memory_Allocate(size_t size);
  55. // Reallocates memory previously allocated by Baselib_Memory_Allocate or Baselib_Memory_Reallocate.
  56. //
  57. // Allocation failures or invalid alignments will trigger process abort.
  58. //
  59. // \param ptr Pointer previously returned by Baselib_Memory_Allocate or Baselib_Memory_Reallocate.
  60. // Reallocating an already freed pointer or a pointer that was not previously allocated by Baselib_Memory_Allocate or
  61. // Baselib_Memory_Reallocate leads to undefined behavior.
  62. // Passing `nullptr` yield the same result as calling Baselib_Memory_Allocate.
  63. // \param size Size of the allocation. No special restrictions apply, zero is valid.
  64. // \returns Unique pointer to allocation. At least aligned to by Baselib_Memory_MinGuaranteedAlignment bytes.
  65. // This is true for zero sized allocations as well.
  66. BASELIB_API void* Baselib_Memory_Reallocate(void* ptr, size_t newSize);
  67. // Frees memory allocated by Baselib_Memory_Allocate Baselib_Memory_Reallocate.
  68. //
  69. // \param ptr Pointer previously returned by Baselib_Memory_Allocate or Baselib_Memory_Reallocate.
  70. // 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.
  71. // Passing `nullptr` result in a no-op.
  72. BASELIB_API void Baselib_Memory_Free(void* ptr);
  73. // Allocates memory using a system allocator like malloc and guarantees that the returned pointer is aligned to the specified alignment.
  74. //
  75. // Allocation failures or invalid alignments will trigger process abort.
  76. //
  77. // \param size Size of the allocation. No special restrictions (like multiples of alignment) apply, zero is valid.
  78. // \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.
  79. // Any alignment smaller than Baselib_Memory_MinGuaranteedAlignment, will be clamped to Baselib_Memory_MinGuaranteedAlignment.
  80. // \returns Unique pointer to aligned allocation. This is true for zero sized allocations as well.
  81. BASELIB_API void* Baselib_Memory_AlignedAllocate(size_t size, size_t alignment);
  82. // Reallocates memory previously allocated by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate.
  83. //
  84. // Allocation failures or invalid alignments will trigger process abort.
  85. //
  86. // \param ptr Pointer previously returned by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate.
  87. // Reallocating an already freed pointer or a pointer that was not previously allocated by Baselib_Memory_AlignedAllocate or
  88. // Baselib_Memory_AlignedReallocate leads to undefined behavior.
  89. // Passing `nullptr` yield the same result as calling Baselib_Memory_AlignedAllocate.
  90. // \param size Size of the allocation. No special restrictions apply, zero is valid.
  91. // \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.
  92. // Any alignment smaller than Baselib_Memory_MinGuaranteedAlignment, will be clamped to Baselib_Memory_MinGuaranteedAlignment.
  93. // \returns Unique pointer to aligned allocation. This is true for zero sized allocations as well.
  94. BASELIB_API void* Baselib_Memory_AlignedReallocate(void* ptr, size_t newSize, size_t alignment);
  95. // Frees memory allocated by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate.
  96. //
  97. // \param ptr Pointer previously returned by Baselib_Memory_AlignedAllocate or Baselib_Memory_AlignedReallocate.
  98. // 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.
  99. // Passing `nullptr` result in a no-op.
  100. BASELIB_API void Baselib_Memory_AlignedFree(void* ptr);
  101. // Page state options
  102. typedef enum Baselib_Memory_PageState
  103. {
  104. // The page are in a reserved state and any access will cause a seg-fault/access violation.
  105. // 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.
  106. // The Baselib implementation does a best effort and tries to ensure as best as possible that pages in this state are not commited.
  107. Baselib_Memory_PageState_Reserved = 0x00,
  108. // This is a no access page and will cause a seg-fault/access violation when accessed.
  109. Baselib_Memory_PageState_NoAccess = 0x01,
  110. // The memory can only be read.
  111. Baselib_Memory_PageState_ReadOnly = 0x02,
  112. // The memory can be read and written.
  113. Baselib_Memory_PageState_ReadWrite = 0x04,
  114. // The memory can be used to execute code and can be read.
  115. Baselib_Memory_PageState_ReadOnly_Executable = 0x10 | Baselib_Memory_PageState_ReadOnly,
  116. // The memory can be used to execute code and can be both read and written.
  117. Baselib_Memory_PageState_ReadWrite_Executable = 0x10 | Baselib_Memory_PageState_ReadWrite,
  118. } Baselib_Memory_PageState;
  119. BASELIB_ENUM_ENSURE_ABI_COMPATIBILITY(Baselib_Memory_PageState);
  120. // Allocates a given number of memory pages and guarantees that the returned pointer is aligned to specified multiple of the page size.
  121. //
  122. // Large alignments may lead to a significantly higher use of virtual address space than the amount of memory requested.
  123. // This may result in an aligned page allocation to fail where a less/non-aligned allocation would succeed.
  124. // Note that this is especially common in 32bit applications but a platform may impose additional restrictions on the size of its virtual address space.
  125. // Whether a page allocation is pure virtual address space or already commited memory depends on the platform and passed page state flag.
  126. //
  127. // \param pageCount Number of pages requested (each will have pageSize size)
  128. // \param alignmentInMultipleOfPageSize Specified alignment in multiple of page sizes (a value of 1 implies alignment to page size).
  129. // Value needs to be larger than zero and a power of two, otherwise UnsupportedAlignment will be raised.
  130. // \param pageState: In which state the pages should be. Certain values may raise UnsupportedPageState on certain platforms.
  131. //
  132. // Possible error codes:
  133. // - Baselib_ErrorCode_InvalidPageSize: Page size doesn't match any of the available page sizes (see Baselib_Memory_GetPageSizeInfo).
  134. // - Baselib_ErrorCode_InvalidPageCount: Requested number of pages is zero.
  135. // - Baselib_ErrorCode_UnsupportedAlignment: Requested alignment is invalid.
  136. // - Baselib_ErrorCode_UnsupportedPageState: The underlying system doesn't support the requested page state (see Baselib_Memory_PageState).
  137. // - Baselib_ErrorCode_OutOfMemory: If there is not enough continuous address space available, or physical memory space when acquiring committed memory.
  138. //
  139. // \returns Page allocation info or Baselib_Memory_PageAllocation_Invalid in case of an error.
  140. BASELIB_API Baselib_Memory_PageAllocation Baselib_Memory_AllocatePages(uint64_t pageSize, uint64_t pageCount, uint64_t alignmentInMultipleOfPageSize, Baselib_Memory_PageState pageState, Baselib_ErrorState* errorState);
  141. // Releases the previously allocated pages (using either Baselib_Memory_AllocatePages)
  142. //
  143. // A single call of ReleasePages must encompass all pages that were originally allocated with a single call of AllocatePages.
  144. // Passing Baselib_Memory_PageAllocation with a nullptr or a zero page count result in a no-op.
  145. //
  146. // Possible error codes:
  147. // - Baselib_ErrorCode_InvalidAddressRange: Address range was detected to not match a valid allocation.
  148. // CAUTION: Not all platforms are able to detect this and may either raise an error or cause undefined behavior.
  149. // Note to implementors: Raising the error is strongly preferred as it helps identifying issues in user code.
  150. // - Baselib_ErrorCode_InvalidPageSize: If page size doesn't match a previous allocation at `pageAllocation.ptr`.
  151. //
  152. // Implementation note:
  153. // 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.
  154. // (e.g. windows page size 4k allocation granularity 64k)
  155. BASELIB_API void Baselib_Memory_ReleasePages(Baselib_Memory_PageAllocation pageAllocation, Baselib_ErrorState* errorState);
  156. // Modifies the page state property of an already allocated virtual address range.
  157. //
  158. // It is possible to modify only some of the pages allocated by Baselib_Memory_AllocatePages.
  159. // Passing `nullptr` or a zero page count result in a no-op.
  160. //
  161. // Possible error codes:
  162. // - Baselib_ErrorCode_InvalidAddressRange: Address range is not covered by a valid allocation.
  163. // Platforms that emulate page allocations (e.g. Emscripten) are not able to present this error and will pass the function call silently.
  164. // - Baselib_ErrorCode_InvalidPageSize: If page size doesn't match the previous allocation at `addressOfFirstPage`.
  165. // - Baselib_ErrorCode_UnsupportedPageState: The underlying system doesn't support the requested page state (see Baselib_Memory_PageState).
  166. BASELIB_API void Baselib_Memory_SetPageState(void* addressOfFirstPage, uint64_t pageSize, uint64_t pageCount, Baselib_Memory_PageState pageState, Baselib_ErrorState* errorState);
  167. #ifdef __cplusplus
  168. } // BASELIB_C_INTERFACE
  169. #endif