1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32 33 34 35
36
37 package ti.sysbios.heaps;
38
39 import xdc.rov.ViewInfo;
40
41 /*!
42 * ======== HeapMultiBuf ========
43 * Multiple fixed size buffer heap manager
44 *
45 * The HeapMultiBuf manager provides functions to allocate and free storage
46 * from a heap of type HeapMultiBuf which inherits from IHeap. HeapMultiBuf
47 * manages multiple fixed-size memory buffers. Each buffer contains a fixed
48 * number of allocable memory 'blocks' of the same size. Simply put, a
49 * HeapMultiBuf instance manages a collection of HeapBuf instances.
50 * HeapMultiBuf is intended as a fast and deterministic memory manager which
51 * can service requests for blocks of arbitrary size.
52 *
53 * An example HeapMultiBuf instance might have sixteen 32-byte blocks in one
54 * buffer, and four 128-byte blocks in another buffer. A request for memory
55 * will be serviced by the smallest possible block, so a request for 100
56 * bytes would receive a 128-byte block in our example.
57 *
58 * Allocating from HeapMultiBuf will try to return a block from the first
59 * buffer which has:
60 *
61 * 1. A block size that is >= to the requested size
62 *
63 * AND
64 *
65 * 2. An alignment that is >= to the requested alignment
66 *
67 * If the first matching buffer is empty, HeapMultiBuf will only continue
68 * searching for a block if 'block borrowing' is enabled (see Block
69 * Borrowing).
70 *
71 * @p(html)
72 * <h4>HeapMultiBuf and HeapBuf</h4>
73 * The HeapMultiBuf module is built on top of the HeapBuf module. Each buffer
74 * in a HeapMultiBuf is in fact managed by a HeapBuf instance. Configuration
75 * of a HeapMultiBuf is done by providing an array of configured HeapBuf
76 * parameter structures. Refer to the HeapBuf documentation for information on
77 * the buffer parameters. All of the documentation and parameters for HeapBuf
78 * apply equally to HeapMultiBuf.
79 * Another consequence of this is that configuration checking is left to the
80 * HeapBuf module. If a buffer in a HeapMultiBuf has been incorrectly
81 * configured (with blockSize = 0, for example), HeapBuf, not HeapMultiBuf,
82 * will raise an Assert.
83 * Since HeapMultiBuf is built on HeapBuf, it simply performs the logic to
84 * determine which HeapBuf to allocate a block from or which HeapBuf to free
85 * a block to.
86 *
87 * @p(html)
88 * <h4>Configuration Example</h4>
89 * The following configuration code creates a HeapMultiBuf instance which
90 * manages 3 pools of 10 blocks each, with block sizes of 64, 128 and 256.
91 *
92 * @p(code)
93 * var HeapMultiBuf = xdc.useModule('ti.sysbios.heaps.HeapMultiBuf');
94 * var HeapBuf = xdc.useModule('ti.sysbios.heaps.HeapBuf');
95 *
96 * // Create parameter structure for HeapMultiBuf instance.
97 * var hmbParams = new HeapMultiBuf.Params();
98 * hmbParams.numBufs = 3;
99 *
100 * // Create the parameter structures for each of the three
101 * // HeapBufs to be managed by the HeapMultiBuf instance.
102 * hmbParams.bufParams.$add(new HeapBuf.Params());
103 * hmbParams.bufParams[0].blockSize = 64;
104 * hmbParams.bufParams[0].numBlocks = 10;
105 *
106 * hmbParams.bufParams.$add(new HeapBuf.Params());
107 * hmbParams.bufParams[1].blockSize = 128;
108 * hmbParams.bufParams[1].numBlocks = 10;
109 *
110 * hmbParams.bufParams.$add(new HeapBuf.Params());
111 * hmbParams.bufParams[2].blockSize = 256;
112 * hmbParams.bufParams[2].numBlocks = 10;
113 *
114 *
115 * // Create the HeapMultiBuf instance, and assign the global handle
116 * // 'multiBufHeap' to it. Add '#include <xdc/cfg/global.h>' to your
117 * // .c file to reference the instance by this handle.
118 * Program.global.multiBufHeap = HeapMultiBuf.create(hmbParams);
119 * @p
120 *
121 * @p(html)
122 * <h4>Block Borrowing</h4>
123 * HeapMultiBuf can support "block borrowing". With this feature turned on,
124 * if a request is made for a 32-byte block and none are available,
125 * HeapMultiBuf will continue looking for an available block in other buffers.
126 * When a borrowed block is freed, it will be returned back to its original
127 * buffer. Enabling Block Borrowing changes the determinism of alloc, since it
128 * may have to check any number of buffers to find an available block.
129 *
130 * Block borrowing may also occur, even if it is disabled, if a block of a
131 * particular size is requested with an alignment that is greater than the
132 * configured alignment for that block size. For example, a HeapMultiBuf is
133 * configured with a buffer of 32-byte blocks with an alignment of 8, and
134 * a buffer of 64-byte blocks with an alignment of 16. If a request is made
135 * for a 32-byte block with an alignment of 16, it will be serviced by the
136 * buffer of 64-byte blocks.
137 *
138 * <h4>Static vs. Dynamic Creation</h4>
139 * As with HeapBuf, a statically created HeapMultiBuf instance will ignore the
140 * bufSize and buf parameters. Dynamic creates require all of the parameters.
141 *
142 * It should be noted that static creates are ideal if code space is a
143 * concern; dynamically creating a HeapMultiBuf requires a relatively large
144 * amount of initialization code to be pulled in to the executable.
145 *
146 * <h4>Block Sizes and Alignment</h4>
147 * @p(blist)
148 * - A buffer with a requested alignment of 0 will receive the target-
149 * specific minimum alignment.
150 * - The actual block sizes will be a multiple of the alignment. For
151 * example, if a buffer is configured to have 56-byte blocks with an
152 * alignment of 32, HeapMultiBuf will actually create 64-byte blocks.
153 * When providing the buffer for a dynamic create, make sure it is
154 * large enough to take this into account.
155 * - Multiple buffers with the same block size ARE allowed. This may
156 * occur, for example, if sizeof is used to specify the block sizes.
157 * - If any buffers have both the same block size and alignment, they
158 * will be merged. If this is a problem, consider managing these buffers
159 * directly with HeapBuf objects.
160 * @p
161 *
162 * @p(html)
163 * <h4>Real-Time Concerns</h4>
164 * Allocation from and freeing to a HeapMultiBuf instance is non-blocking.
165 *
166 * HeapMultiBuf is deterministic:
167 * @p(blist)
168 * - A call to alloc will always take the same amount of time for a given
169 * block size (with block borrowing disabled).
170 * - The worst case call to free is constant and proportional to the number
171 * of buffers managed.
172 * @p
173 *
174 * @p(html)
175 * <h4>Restrictions</h4>
176 * @p(blist)
177 * - Align parameters must be a power of 2.
178 * - The buffers passed to dynamically create a HeapMultiBuf must be aligned
179 * according to the alignment parameter, and must be large enough to account
180 * for the actual block size after it has been rounded up to a multiple of
181 * the alignment.
182 * - Buffers must be provided to dynamically create a HeapMultiBuf, and cannot
183 * be provided to statically create a HeapMultiBuf.
184 * @p
185 *
186 * @p(html)
187 * <h4>Unconstrained Functions</h4>
188 * All functions
189 *
190 * @p(html)
191 * <h3> Calling Context </h3>
192 * <table border="1" cellpadding="3">
193 * <colgroup span="1"></colgroup> <colgroup span="5" align="center">
194 * </colgroup>
195 *
196 * <tr><th> Function </th><th> Hwi </th><th> Swi </th>
197 * <th> Task </th><th> Main </th><th> Startup </th></tr>
198 * <!-- -->
199 * <tr><td> Params_init </td><td> Y </td><td> Y </td>
200 * <td> Y </td><td> Y </td><td> Y </td></tr>
201 * <tr><td> alloc </td><td> Y </td><td> Y </td>
202 * <td> Y </td><td> Y </td><td> N </td></tr>
203 * <tr><td> construct </td><td> N* </td><td> N* </td>
204 * <td> Y </td><td> Y </td><td> N </td></tr>
205 * <tr><td> create </td><td> N* </td><td> N* </td>
206 * <td> Y </td><td> Y </td><td> N </td></tr>
207 * <tr><td> delete </td><td> N* </td><td> N* </td>
208 * <td> Y </td><td> Y </td><td> N </td></tr>
209 * <tr><td> destruct </td><td> N* </td><td> N* </td>
210 * <td> Y </td><td> Y </td><td> N </td></tr>
211 * <tr><td> free </td><td> Y </td><td> Y </td>
212 * <td> Y </td><td> Y </td><td> N </td></tr>
213 * <tr><td> getStats </td><td> Y </td><td> Y </td>
214 * <td> Y </td><td> Y </td><td> N </td></tr>
215 * <tr><td> isBlocking </td><td> Y </td><td> Y </td>
216 * <td> Y </td><td> Y </td><td> N </td></tr>
217 * <tr><td colspan="6"> Definitions: <br />
218 * <ul>
219 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
220 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
221 * <li> <b>Task</b>: API is callable from a Task thread. </li>
222 * <li> <b>Main</b>: API is callable during any of these phases: </li>
223 * <ul>
224 * <li> In your module startup after this module is started
225 * (e.g. HeapMultiBuf_Module_startupDone() returns TRUE). </li>
226 * <li> During xdc.runtime.Startup.lastFxns. </li>
227 * <li> During main().</li>
228 * <li> During BIOS.startupFxns.</li>
229 * </ul>
230 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
231 * <ul>
232 * <li> During xdc.runtime.Startup.firstFxns.</li>
233 * <li> In your module startup before this module is started
234 * (e.g. HeapMultiBuf_Module_startupDone() returns FALSE).</li>
235 * </ul>
236 * <li> <b>*</b>: Assuming blocking Heap is used for creation. </li>
237 * <li> <b>**</b>: Assuming GateMutex is used as HeapMem's Gate. </li>
238 * <li> <b>+</b> : Cannot use HeapMem object while it is being
239 * restored. </li>
240 * </ul>
241 * </td></tr>
242 *
243 * </table>
244 * @p
245 */
246
247 @InstanceInitError
248 @InstanceFinalize
249 @ModuleStartup
250
251 module HeapMultiBuf inherits xdc.runtime.IHeap {
252
253 /*!
254 * ======== BasicView ========
255 * @_nodoc
256 */
257 metaonly struct BasicView {
258 String label;
259 Bool blockBorrow;
260 Int numHeapBufs;
261 }
262
263 /*!
264 * ======== DetailedView ========
265 * @_nodoc
266 */
267 metaonly struct DetailedView {
268 String label;
269 Bool blockBorrow;
270 Int numHeapBufs;
271 String HeapBufHandles[];
272 }
273
274
275 /*! @_nodoc */
276 @Facet
277 metaonly config ViewInfo.Instance rovViewInfo =
278 ViewInfo.create({
279 viewMap: [
280 [
281 'Basic',
282 {
283 type: ViewInfo.INSTANCE,
284 viewInitFxn: 'viewInitBasic',
285 structName: 'BasicView'
286 }
287 ],
288 [
289 'Detailed',
290 {
291 type: ViewInfo.INSTANCE,
292 viewInitFxn: 'viewInitDetailed',
293 structName: 'DetailedView'
294 }
295 ],
296 ]
297 });
298
299 /*!
300 * ======== A_blockNotFreed ========
301 * Invalid block pointer
302 *
303 * This Assert is raised if a call to free does not successfully
304 * free the block back to any of the buffers. Indicates that the
305 * block pointer is invalid, or that the HeapMultiBuf state has been
306 * corrupted.
307 */
308 config xdc.runtime.Assert.Id A_blockNotFreed =
309 {msg: "Invalid block address on the free. Failed to free block back to heap."};
310
311 /*!
312 * ======== E_size ========
313 * Raised when requested size exceeds all blockSizes
314 */
315 config xdc.runtime.Error.Id E_size =
316 {msg: "requested size is too big: handle=0x%x, size=%u"};
317
318 instance:
319
320 /*!
321 * ======== numBufs ========
322 * Number of memory buffers
323 *
324 * The number of different fixed size memory buffers that are managed
325 * by the heap instance. The bufParams array has length numBufs.
326 *
327 * The default number of buffers is 0.
328 */
329 config Int numBufs = 0;
330
331 /*!
332 * ======== blockBorrow ========
333 * Turn block borrowing on (true) or off (false)
334 *
335 * With block borrowing on, if there are no blocks available of the
336 * requested size, then alloc will look for a larger block to return.
337 * Calls to alloc which borrow blocks will be slower, and will cause
338 * internal fragmentation of the heap (until the block is freed), so it
339 * is ideal to configure a HeapMultiBuf such that block borrowing is not
340 * needed.
341 */
342 config Bool blockBorrow = false;
343
344 /*!
345 * ======== bufParams ========
346 * Config parameters for each buffer
347 *
348 * Each buffer in a HeapMultiBuf is in fact managed by a HeapBuf instance.
349 * Configuration of a HeapMultiBuf is done by providing an array of
350 * configured HeapBuf parameter structures. Refer to the HeapBuf
351 * documentation for information on the buffer parameters. All of the
352 * documentation and parameters for HeapBuf apply to HeapMultiBuf.
353 * If a buffer is configured incorrectly, HeapBuf, not HeapMultiBuf,
354 * will raise an Assert.
355 */
356 config HeapBuf.Params bufParams[];
357
358 /*!
359 * ======== alloc ========
360 *
361 * @HeapMultiBuf
362 * HeapMultiBuf will return a block that is >= 'size' with
363 * an alignment that is >= 'align'.
364 * The HeapMultiBuf will attempt to service a request for any size; the
365 * specified size does not need to match the configured block sizes of
366 * the buffers.
367 */
368 override Ptr alloc(SizeT size, SizeT align, xdc.runtime.Error.Block *eb);
369
370 /*!
371 * ======== free ========
372 *
373 * @HeapMultiBuf
374 * HeapMultiBuf ignores the 'size' parameter to free. It
375 * determines the correct buffer to free the block to by comparing
376 * addresses.
377 */
378 override Void free(Ptr block, SizeT size);
379
380 /*!
381 * ======== isBlocking ========
382 *
383 * @HeapMultiBuf
384 * This function always returns FALSE since the alloc/free
385 * never block on a resource.
386 */
387 override Bool isBlocking();
388
389 internal:
390
391 392 393 394 395 396 397
398 struct AddrPair {
399 HeapBuf.Handle heapBuf;
400 Ptr lastAddr;
401 }
402
403 404 405
406 Int addrPairCompare(const Void *a, const Void *b);
407
408 409 410
411 Int sizeAlignCompare(const Void *a, const Void *b);
412
413 414 415
416 Void moveToEnd(HeapBuf.Handle *heapBufs, UInt numHeapBufs, UInt index);
417
418 419 420
421 Void *borrowBlock(HeapMultiBuf.Object *obj, SizeT size, SizeT align,
422 Int startIndex);
423 424 425 426 427
428 struct Instance_State {
429 Bool blockBorrow;
430 Int numHeapBufs;
431 HeapBuf.Handle bufsBySize[];
432 Int numBufs;
433 AddrPair bufsByAddr[];
434 };
435 }