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
22AWS_EXTERN_C_BEGIN
23
24/* Allocator structure. An instance of this will be passed around for anything needing memory allocation */
25struct 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 */
38AWS_COMMON_API
39bool aws_allocator_is_valid(const struct aws_allocator *alloc);
40
41AWS_COMMON_API
42struct aws_allocator *aws_default_allocator(void);
43
44#ifdef __MACH__
45/* Avoid pulling in CoreFoundation headers in a header file. */
46struct __CFAllocator;
47typedef 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 */
54AWS_COMMON_API
55CFAllocatorRef aws_wrapped_cf_allocator_new(struct aws_allocator *allocator);
56
57/**
58 * Cleans up any resources alloced in aws_wrapped_cf_allocator_new.
59 */
60AWS_COMMON_API
61void 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 */
67AWS_COMMON_API
68void *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 */
74AWS_COMMON_API
75void *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 */
86AWS_COMMON_API
87void *aws_mem_acquire_many(struct aws_allocator *allocator, size_t count, ...);
88
89/**
90 * Releases ptr back to whatever allocated it.
91 */
92AWS_COMMON_API
93void 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 */
103AWS_COMMON_API
104int 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
113enum 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 */
129AWS_COMMON_API
130struct 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 */
140AWS_COMMON_API
141struct 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 */
148AWS_COMMON_API
149void aws_mem_tracer_dump(struct aws_allocator *trace_allocator);
150
151/*
152 * Returns the current number of bytes in outstanding allocations
153 */
154AWS_COMMON_API
155size_t aws_mem_tracer_bytes(struct aws_allocator *trace_allocator);
156
157/*
158 * Returns the current number of outstanding allocations
159 */
160AWS_COMMON_API
161size_t aws_mem_tracer_count(struct aws_allocator *trace_allocator);
162
163AWS_EXTERN_C_END
164
165#endif /* AWS_COMMON_ALLOCATOR_H */
166