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