1 | #ifndef AWS_COMMON_ALLOCATOR_H |
2 | #define AWS_COMMON_ALLOCATOR_H |
3 | /* |
4 | * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
5 | * |
6 | * Licensed under the Apache License, Version 2.0 (the "License"). |
7 | * You may not use this file except in compliance with the License. |
8 | * A copy of the License is located at |
9 | * |
10 | * http://aws.amazon.com/apache2.0 |
11 | * |
12 | * or in the "license" file accompanying this file. This file is distributed |
13 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
14 | * express or implied. See the License for the specific language governing |
15 | * permissions and limitations under the License. |
16 | */ |
17 | |
18 | #include <aws/common/macros.h> |
19 | #include <aws/common/stdbool.h> |
20 | #include <aws/common/stdint.h> |
21 | |
22 | AWS_EXTERN_C_BEGIN |
23 | |
24 | /* Allocator structure. An instance of this will be passed around for anything needing memory allocation */ |
25 | struct aws_allocator { |
26 | void *(*mem_acquire)(struct aws_allocator *allocator, size_t size); |
27 | void (*mem_release)(struct aws_allocator *allocator, void *ptr); |
28 | /* Optional method; if not supported, this pointer must be NULL */ |
29 | void *(*mem_realloc)(struct aws_allocator *allocator, void *oldptr, size_t oldsize, size_t newsize); |
30 | /* Optional method; if not supported, this pointer must be NULL */ |
31 | void *(*mem_calloc)(struct aws_allocator *allocator, size_t num, size_t size); |
32 | void *impl; |
33 | }; |
34 | |
35 | /** |
36 | * Inexpensive (constant time) check of data-structure invariants. |
37 | */ |
38 | AWS_COMMON_API |
39 | bool aws_allocator_is_valid(const struct aws_allocator *alloc); |
40 | |
41 | AWS_COMMON_API |
42 | struct aws_allocator *aws_default_allocator(void); |
43 | |
44 | #ifdef __MACH__ |
45 | /* Avoid pulling in CoreFoundation headers in a header file. */ |
46 | struct __CFAllocator; |
47 | typedef const struct __CFAllocator *CFAllocatorRef; |
48 | |
49 | /** |
50 | * Wraps a CFAllocator around aws_allocator. For Mac only. Use this anytime you need a CFAllocatorRef for interacting |
51 | * with Apple Frameworks. Unfortunately, it allocates memory so we can't make it static file scope, be sure to call |
52 | * aws_wrapped_cf_allocator_destroy when finished. |
53 | */ |
54 | AWS_COMMON_API |
55 | CFAllocatorRef aws_wrapped_cf_allocator_new(struct aws_allocator *allocator); |
56 | |
57 | /** |
58 | * Cleans up any resources alloced in aws_wrapped_cf_allocator_new. |
59 | */ |
60 | AWS_COMMON_API |
61 | void aws_wrapped_cf_allocator_destroy(CFAllocatorRef allocator); |
62 | #endif |
63 | |
64 | /** |
65 | * Returns at least `size` of memory ready for usage or returns NULL on failure. |
66 | */ |
67 | AWS_COMMON_API |
68 | void *aws_mem_acquire(struct aws_allocator *allocator, size_t size); |
69 | |
70 | /** |
71 | * Allocates a block of memory for an array of num elements, each of them size bytes long, and initializes all its bits |
72 | * to zero. Returns null on failure. |
73 | */ |
74 | AWS_COMMON_API |
75 | void *aws_mem_calloc(struct aws_allocator *allocator, size_t num, size_t size); |
76 | |
77 | /** |
78 | * Allocates many chunks of bytes into a single block. Expects to be called with alternating void ** (dest), size_t |
79 | * (size). The first void ** will be set to the root of the allocation. Alignment is assumed to be sizeof(intmax_t). |
80 | * |
81 | * This is useful for allocating structs using the pimpl pattern, as you may allocate the public object and impl object |
82 | * in the same contiguous block of memory. |
83 | * |
84 | * Returns a pointer to the allocation. |
85 | */ |
86 | AWS_COMMON_API |
87 | void *aws_mem_acquire_many(struct aws_allocator *allocator, size_t count, ...); |
88 | |
89 | /** |
90 | * Releases ptr back to whatever allocated it. |
91 | */ |
92 | AWS_COMMON_API |
93 | void aws_mem_release(struct aws_allocator *allocator, void *ptr); |
94 | |
95 | /* |
96 | * Attempts to adjust the size of the pointed-to memory buffer from oldsize to |
97 | * newsize. The pointer (*ptr) may be changed if the memory needs to be |
98 | * reallocated. |
99 | * |
100 | * If reallocation fails, *ptr is unchanged, and this method raises an |
101 | * AWS_ERROR_OOM error. |
102 | */ |
103 | AWS_COMMON_API |
104 | int aws_mem_realloc(struct aws_allocator *allocator, void **ptr, size_t oldsize, size_t newsize); |
105 | /* |
106 | * Maintainer note: The above function doesn't return the pointer (as with |
107 | * standard C realloc) as this pattern becomes error-prone when OOMs occur. |
108 | * In particular, we want to avoid losing the old pointer when an OOM condition |
109 | * occurs, so we prefer to take the old pointer as an in/out reference argument |
110 | * that we can leave unchanged on failure. |
111 | */ |
112 | |
113 | enum aws_mem_trace_level { |
114 | AWS_MEMTRACE_NONE = 0, /* no tracing */ |
115 | AWS_MEMTRACE_BYTES = 1, /* just track allocation sizes and total allocated */ |
116 | AWS_MEMTRACE_STACKS = 2, /* capture callstacks for each allocation */ |
117 | }; |
118 | |
119 | /* |
120 | * Wraps an allocator and tracks all external allocations. If aws_mem_trace_dump() is called |
121 | * and there are still allocations active, they will be reported to the aws_logger at TRACE level. |
122 | * allocator - The allocator to wrap |
123 | * system_allocator - The allocator to allocate bookkeeping data from, or NULL to use the default |
124 | * level - The level to track allocations at |
125 | * frames_per_stack is how many frames to store per callstack if AWS_MEMTRACE_STACKS is in use, |
126 | * otherwise it is ignored. 8 tends to be a pretty good number balancing storage space vs useful stacks. |
127 | * Returns the tracer allocator, which should be used for all allocations that should be tracked. |
128 | */ |
129 | AWS_COMMON_API |
130 | struct aws_allocator *aws_mem_tracer_new( |
131 | struct aws_allocator *allocator, |
132 | struct aws_allocator *system_allocator, |
133 | enum aws_mem_trace_level level, |
134 | size_t frames_per_stack); |
135 | |
136 | /* |
137 | * Unwraps the traced allocator and cleans up the tracer. |
138 | * Returns the original allocator |
139 | */ |
140 | AWS_COMMON_API |
141 | struct aws_allocator *aws_mem_tracer_destroy(struct aws_allocator *trace_allocator); |
142 | |
143 | /* |
144 | * If there are outstanding allocations, dumps them to log, along with any information gathered |
145 | * based on the trace level set when aws_mem_trace() was called. |
146 | * Should be passed the tracer allocator returned from aws_mem_trace(). |
147 | */ |
148 | AWS_COMMON_API |
149 | void aws_mem_tracer_dump(struct aws_allocator *trace_allocator); |
150 | |
151 | /* |
152 | * Returns the current number of bytes in outstanding allocations |
153 | */ |
154 | AWS_COMMON_API |
155 | size_t aws_mem_tracer_bytes(struct aws_allocator *trace_allocator); |
156 | |
157 | /* |
158 | * Returns the current number of outstanding allocations |
159 | */ |
160 | AWS_COMMON_API |
161 | size_t aws_mem_tracer_count(struct aws_allocator *trace_allocator); |
162 | |
163 | AWS_EXTERN_C_END |
164 | |
165 | #endif /* AWS_COMMON_ALLOCATOR_H */ |
166 | |