1 #ifndef AWS_COMMON_ALLOCATOR_H 2 #define AWS_COMMON_ALLOCATOR_H 3 /** 4 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 * SPDX-License-Identifier: Apache-2.0. 6 */ 7 8 #include <aws/common/macros.h> 9 #include <aws/common/stdbool.h> 10 #include <aws/common/stdint.h> 11 12 AWS_EXTERN_C_BEGIN 13 14 /* Allocator structure. An instance of this will be passed around for anything needing memory allocation */ 15 struct aws_allocator { 16 void *(*mem_acquire)(struct aws_allocator *allocator, size_t size); 17 void (*mem_release)(struct aws_allocator *allocator, void *ptr); 18 /* Optional method; if not supported, this pointer must be NULL */ 19 void *(*mem_realloc)(struct aws_allocator *allocator, void *oldptr, size_t oldsize, size_t newsize); 20 /* Optional method; if not supported, this pointer must be NULL */ 21 void *(*mem_calloc)(struct aws_allocator *allocator, size_t num, size_t size); 22 void *impl; 23 }; 24 25 /** 26 * Inexpensive (constant time) check of data-structure invariants. 27 */ 28 AWS_COMMON_API 29 bool aws_allocator_is_valid(const struct aws_allocator *alloc); 30 31 AWS_COMMON_API 32 struct aws_allocator *aws_default_allocator(void); 33 34 #ifdef __MACH__ 35 /* Avoid pulling in CoreFoundation headers in a header file. */ 36 struct __CFAllocator; 37 typedef const struct __CFAllocator *CFAllocatorRef; 38 39 /** 40 * Wraps a CFAllocator around aws_allocator. For Mac only. Use this anytime you need a CFAllocatorRef for interacting 41 * with Apple Frameworks. Unfortunately, it allocates memory so we can't make it static file scope, be sure to call 42 * aws_wrapped_cf_allocator_destroy when finished. 43 */ 44 AWS_COMMON_API 45 CFAllocatorRef aws_wrapped_cf_allocator_new(struct aws_allocator *allocator); 46 47 /** 48 * Cleans up any resources alloced in aws_wrapped_cf_allocator_new. 49 */ 50 AWS_COMMON_API 51 void aws_wrapped_cf_allocator_destroy(CFAllocatorRef allocator); 52 #endif 53 54 /** 55 * Returns at least `size` of memory ready for usage. In versions v0.6.8 and prior, this function was allowed to return 56 * NULL. In later versions, if allocator->mem_acquire() returns NULL, this function will assert and exit. To handle 57 * conditions where OOM is not a fatal error, allocator->mem_acquire() is responsible for finding/reclaiming/running a 58 * GC etc...before returning. 59 */ 60 AWS_COMMON_API 61 void *aws_mem_acquire(struct aws_allocator *allocator, size_t size); 62 63 /** 64 * Allocates a block of memory for an array of num elements, each of them size bytes long, and initializes all its bits 65 * to zero. In versions v0.6.8 and prior, this function was allowed to return NULL. 66 * In later versions, if allocator->mem_calloc() returns NULL, this function will assert and exit. To handle 67 * conditions where OOM is not a fatal error, allocator->mem_calloc() is responsible for finding/reclaiming/running a 68 * GC etc...before returning. 69 */ 70 AWS_COMMON_API 71 void *aws_mem_calloc(struct aws_allocator *allocator, size_t num, size_t size); 72 73 /** 74 * Allocates many chunks of bytes into a single block. Expects to be called with alternating void ** (dest), size_t 75 * (size). The first void ** will be set to the root of the allocation. Alignment is assumed to be sizeof(intmax_t). 76 * 77 * This is useful for allocating structs using the pimpl pattern, as you may allocate the public object and impl object 78 * in the same contiguous block of memory. 79 * 80 * Returns a pointer to the allocation. 81 * 82 * In versions v0.6.8 and prior, this function was allowed to return 83 * NULL. In later versions, if allocator->mem_acquire() returns NULL, this function will assert and exit. To handle 84 * conditions where OOM is not a fatal error, allocator->mem_acquire() is responsible for finding/reclaiming/running a 85 * GC etc...before returning. 86 */ 87 AWS_COMMON_API 88 void *aws_mem_acquire_many(struct aws_allocator *allocator, size_t count, ...); 89 90 /** 91 * Releases ptr back to whatever allocated it. 92 * Nothing happens if ptr is NULL. 93 */ 94 AWS_COMMON_API 95 void aws_mem_release(struct aws_allocator *allocator, void *ptr); 96 97 /** 98 * Attempts to adjust the size of the pointed-to memory buffer from oldsize to 99 * newsize. The pointer (*ptr) may be changed if the memory needs to be 100 * reallocated. 101 * 102 * In versions v0.6.8 and prior, this function was allowed to return 103 * NULL. In later versions, if allocator->mem_realloc() returns NULL, this function will assert and exit. To handle 104 * conditions where OOM is not a fatal error, allocator->mem_realloc() is responsible for finding/reclaiming/running a 105 * GC etc...before returning. 106 */ 107 AWS_COMMON_API 108 int aws_mem_realloc(struct aws_allocator *allocator, void **ptr, size_t oldsize, size_t newsize); 109 /* 110 * Maintainer note: The above function doesn't return the pointer (as with 111 * standard C realloc) as this pattern becomes error-prone when OOMs occur. 112 * In particular, we want to avoid losing the old pointer when an OOM condition 113 * occurs, so we prefer to take the old pointer as an in/out reference argument 114 * that we can leave unchanged on failure. 115 */ 116 117 enum aws_mem_trace_level { 118 AWS_MEMTRACE_NONE = 0, /* no tracing */ 119 AWS_MEMTRACE_BYTES = 1, /* just track allocation sizes and total allocated */ 120 AWS_MEMTRACE_STACKS = 2, /* capture callstacks for each allocation */ 121 }; 122 123 /* 124 * Wraps an allocator and tracks all external allocations. If aws_mem_trace_dump() is called 125 * and there are still allocations active, they will be reported to the aws_logger at TRACE level. 126 * allocator - The allocator to wrap 127 * deprecated - Deprecated arg, ignored. 128 * level - The level to track allocations at 129 * frames_per_stack is how many frames to store per callstack if AWS_MEMTRACE_STACKS is in use, 130 * otherwise it is ignored. 8 tends to be a pretty good number balancing storage space vs useful stacks. 131 * Returns the tracer allocator, which should be used for all allocations that should be tracked. 132 */ 133 AWS_COMMON_API 134 struct aws_allocator *aws_mem_tracer_new( 135 struct aws_allocator *allocator, 136 struct aws_allocator *deprecated, 137 enum aws_mem_trace_level level, 138 size_t frames_per_stack); 139 140 /* 141 * Unwraps the traced allocator and cleans up the tracer. 142 * Returns the original allocator 143 */ 144 AWS_COMMON_API 145 struct aws_allocator *aws_mem_tracer_destroy(struct aws_allocator *trace_allocator); 146 147 /* 148 * If there are outstanding allocations, dumps them to log, along with any information gathered 149 * based on the trace level set when aws_mem_trace() was called. 150 * Should be passed the tracer allocator returned from aws_mem_trace(). 151 */ 152 AWS_COMMON_API 153 void aws_mem_tracer_dump(struct aws_allocator *trace_allocator); 154 155 /* 156 * Returns the current number of bytes in outstanding allocations 157 */ 158 AWS_COMMON_API 159 size_t aws_mem_tracer_bytes(struct aws_allocator *trace_allocator); 160 161 /* 162 * Returns the current number of outstanding allocations 163 */ 164 AWS_COMMON_API 165 size_t aws_mem_tracer_count(struct aws_allocator *trace_allocator); 166 167 /* 168 * Creates a new Small Block Allocator which fronts the supplied parent allocator. The SBA will intercept 169 * and handle small allocs, and will forward anything larger to the parent allocator. 170 * If multi_threaded is true, the internal allocator will protect its internal data structures with a mutex 171 */ 172 AWS_COMMON_API 173 struct aws_allocator *aws_small_block_allocator_new(struct aws_allocator *allocator, bool multi_threaded); 174 175 /* 176 * Destroys a Small Block Allocator instance and frees its memory to the parent allocator. The parent 177 * allocator will otherwise be unaffected. 178 */ 179 AWS_COMMON_API 180 void aws_small_block_allocator_destroy(struct aws_allocator *sba_allocator); 181 182 /* 183 * Returns the number of bytes currently active in the SBA 184 */ 185 AWS_COMMON_API 186 size_t aws_small_block_allocator_bytes_active(struct aws_allocator *sba_allocator); 187 188 /* 189 * Returns the number of bytes reserved in pages/bins inside the SBA, e.g. the 190 * current system memory used by the SBA 191 */ 192 AWS_COMMON_API 193 size_t aws_small_block_allocator_bytes_reserved(struct aws_allocator *sba_allocator); 194 195 /* 196 * Returns the page size that the SBA is using 197 */ 198 AWS_COMMON_API 199 size_t aws_small_block_allocator_page_size(struct aws_allocator *sba_allocator); 200 201 AWS_EXTERN_C_END 202 203 #endif /* AWS_COMMON_ALLOCATOR_H */ 204