Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2021 Project CHIP Authors
4 : * 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 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file defines heap memory allocation APIs for CHIP.
22 : *
23 : */
24 :
25 : #pragma once
26 :
27 : #include <lib/core/CHIPError.h>
28 : #include <stdlib.h>
29 :
30 : #include <memory>
31 : #include <new>
32 : #include <utility>
33 :
34 : namespace chip {
35 : namespace Platform {
36 :
37 : #define CHIP_ZERO_AT(value) \
38 : do \
39 : { \
40 : memset(&value, 0, sizeof(value)); \
41 : } while (0)
42 :
43 : /**
44 : * This function is called by CHIP layer to initialize memory and resources
45 : * required for proper functionality of the CHIP memory allocator.
46 : * This function is platform specific and might be empty in certain cases.
47 : * For example, this function is doing nothing when the C Standard Library malloc()
48 : * and free() functions are used for memory allocation.
49 : *
50 : * @param[in] buf A pointer to a dedicated memory buffer, which should be used as
51 : * a memory pool for CHIP memory allocation.
52 : * This input is optional (defaults to NULL) and shouldn't be used
53 : * if a dedicated memory buffer is not used.
54 : *
55 : * @param[in] bufSize Size of a dedicated memory buffer. This input is optional (defaults to 0)
56 : * and shouldn't be used if dedicated memory buffer is not used.
57 : * When a dedicated memory buffer is used the function checks and
58 : * generates an error if buffer size is not big enough to support
59 : * CHIP use cases.
60 : *
61 : * @retval #CHIP_ERROR_BUFFER_TOO_SMALL If dedicated input buffer size is not sufficient
62 : * to support CHIP use cases.
63 : * @retval #CHIP_NO_ERROR On success.
64 : * @retval other An error generated by platform-specific memory
65 : * initialization function.
66 : *
67 : */
68 : extern CHIP_ERROR MemoryInit(void * buf = nullptr, size_t bufSize = 0);
69 :
70 : /**
71 : * This function is called by the CHIP layer to releases all resources that were allocated
72 : * by MemoryInit() function.
73 : * This function can be an empty call if there is no need to release resources. For example,
74 : * this is the case when the C Standard Library malloc() and free() functions are used
75 : * for memory allocation.
76 : *
77 : */
78 : extern void MemoryShutdown();
79 :
80 : /**
81 : * This function is called by the CHIP layer to allocate a block of memory of "size" bytes.
82 : *
83 : * @param[in] size Specifies requested memory size in bytes.
84 : *
85 : * @retval Pointer to a memory block in case of success.
86 : * @retval NULL-pointer if memory allocation fails.
87 : *
88 : */
89 : extern void * MemoryAlloc(size_t size);
90 :
91 : /**
92 : * This function is called by the CHIP layer to allocate a block of memory for an array of num
93 : * elements, each of them size bytes long, and initializes all its bits to zero.
94 : * The effective result is the allocation of a zero-initialized memory block of (num*size) bytes.
95 : *
96 : * @param[in] num Specifies number of elements to allocate.
97 : * @param[in] size Specifies size of each element in bytes.
98 : *
99 : * @retval Pointer to a memory block in case of success.
100 : * @retval NULL-pointer if memory allocation fails.
101 : *
102 : */
103 : extern void * MemoryCalloc(size_t num, size_t size);
104 :
105 : /**
106 : * This function is called by the Chip layer to change the size of the memory block pointed to by p.
107 : * The function may move the memory block to a new location (whose address is returned by the function).
108 : * The content of the memory block is preserved up to the lesser of the new and old sizes, even if the
109 : * block is moved to a new location. If the new size is larger, the value of the newly allocated portion
110 : * is indeterminate.
111 :
112 : * In case that p is a null pointer, the function behaves like malloc, assigning a new block of size bytes
113 : * and returning a pointer to its beginning.
114 : *
115 : * @param[in] p Pointer to a memory block previously allocated with MemoryAlloc, MemoryCalloc
116 : * or MemoryRealloc.
117 : * @param[in] size Specifies new size for the memory block, in bytes..
118 : *
119 : * @retval Pointer to a memory block in case of success.
120 : * @retval NULL-pointer if memory allocation fails.
121 : *
122 : */
123 : extern void * MemoryRealloc(void * p, size_t size);
124 :
125 : /**
126 : * This function is called by the Chip layer to release a memory block allocated by
127 : * the MemoryAlloc(), MemoryCalloc or MemoryRealloc.
128 : * @param[in] p Pointer to a memory block that should be released.
129 : *
130 : */
131 : extern void MemoryFree(void * p);
132 :
133 : /**
134 : * This function wraps the operator `new` with placement-new using MemoryAlloc().
135 : * Instead of
136 : * p = new T(arguments)
137 : * use
138 : * p = New<T>(arguments)
139 : * In a few cases it may be necessary to add explicit casts to arguments, notably
140 : * when passing integer constants to smaller integer parameters.
141 : */
142 : template <typename T, typename... Args>
143 12454873 : inline T * New(Args &&... args)
144 : {
145 12454873 : void * p = MemoryAlloc(sizeof(T));
146 12454873 : if (p != nullptr)
147 : {
148 12454873 : return new (p) T(std::forward<Args>(args)...);
149 : }
150 0 : return nullptr;
151 : }
152 :
153 : /**
154 : * This function wraps the operator `delete` with using MemoryFree().
155 : * Instead of
156 : * delete p
157 : * use
158 : * Delete(p)
159 : */
160 : template <typename T>
161 9343497 : inline void Delete(T * p)
162 : {
163 9343497 : if (p == nullptr)
164 : {
165 0 : return;
166 : }
167 :
168 9343497 : p->~T();
169 9343497 : MemoryFree(p);
170 : }
171 :
172 : template <typename T>
173 : struct Deleter
174 : {
175 354 : void operator()(T * p) { Delete(p); }
176 : };
177 :
178 : template <typename T>
179 : using UniquePtr = std::unique_ptr<T, Deleter<T>>;
180 :
181 : template <typename T, typename... Args>
182 4 : inline UniquePtr<T> MakeUnique(Args &&... args)
183 : {
184 4 : return UniquePtr<T>(New<T>(std::forward<Args>(args)...));
185 : }
186 :
187 : template <typename T>
188 : using SharedPtr = std::shared_ptr<T>;
189 :
190 : template <typename T, typename... Args>
191 14 : inline SharedPtr<T> MakeShared(Args &&... args)
192 : {
193 14 : return SharedPtr<T>(New<T>(std::forward<Args>(args)...), Deleter<T>());
194 : }
195 :
196 : template <typename T>
197 : using WeakPtr = std::weak_ptr<T>;
198 :
199 : // See MemoryDebugCheckPointer().
200 : extern bool MemoryInternalCheckPointer(const void * p, size_t min_size);
201 :
202 : /**
203 : * In debug builds, test the validity of a pointer obtained from a chip::Platform memory allocation.
204 : *
205 : * @param[in] p Pointer to a memory block previously allocated with MemoryAlloc, MemoryCalloc,
206 : * MemoryRealloc, or New, and not freed.
207 : * @param[in] min_size Gives a size that the allocated block is expected to be able to hold.
208 : *
209 : * @e Unless configured with #CHIP_CONFIG_MEMORY_DEBUG_CHECKS, this function returns `true` without performing
210 : * any check, inlined with the expectation that the compiler can remove any associated failure code.
211 : *
212 : * With #CHIP_CONFIG_MEMORY_DEBUG_CHECKS enabled:
213 : *
214 : * This function is guaranteed to return `false` if \a p is `nullptr`. The function returns `true` if \a p is a valid
215 : * pointer to an allocation *and* the implementation memory manager is in a fully functioning state.
216 : *
217 : * @note For non-null \a p, the function *may* return `true` even if the pointer is invalid. That is, a particular
218 : * implementation or configuration is not guaranteed to catch any particular faulty state.
219 : * @note For non-null \a p, the function return value *may* be incorrect if the memory manager is in a faulty state
220 : * (e.g. corrupt heap), even if the faulty state does not directly involve \a p.
221 : * @note For non-null \a p, the function *may* abort the program rather than return at all if the memory manager is in
222 : * a faulty state, even if \a p is valid.
223 : * @note For a non-null \a p, checking *may* be slow.
224 : *
225 : *
226 : * @return An implementation- and configuration-defined estimate of whether \a p is a valid allocated pointer.
227 : */
228 13719979 : inline bool MemoryDebugCheckPointer(const void * p, size_t min_size = 0)
229 : {
230 : #if CHIP_CONFIG_MEMORY_DEBUG_CHECKS
231 : return MemoryInternalCheckPointer(p, min_size);
232 : #else // CHIP_CONFIG_MEMORY_DEBUG_CHECKS
233 13719979 : return true;
234 : #endif // CHIP_CONFIG_MEMORY_DEBUG_CHECKS
235 : }
236 :
237 : } // namespace Platform
238 : } // namespace chip
|