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 import xdc.runtime.Memory;
41 import xdc.runtime.Error;
42
43 /*!
44 * ======== HeapMem ========
45 * Variable size buffer heap manager
46 *
47 * HeapMem manager provides functions to allocate and free storage from a
48 * heap of type HeapMem which inherits from IHeap.
49 *
50 * In addition to allowing multiple static HeapMem instances to be created
51 * who's buffer placements and sizes are defined by their instance
52 * configuration parameters,
53 * HeapMem allows one Heap instance to be defined who's heap
54 * memory is defined by buffer start and end symbols in the linker command
55 * file. This singular Heap instance is referred to as the 'Primary Heap'.
56 *
57 * see {@link #primaryHeapBaseAddr}, {@link #primaryHeapEndAddr},
58 * and {@link #usePrimaryHeap}
59 *
60 * @p(html)
61 * <h3> HeapMem Gate </h3>
62 * A HeapMem instance will use the HeapMem module Gate to protect any accesses
63 * to its list of free memory blocks. The HeapMem instance will enter and
64 * leave the module Gate when allocating blocks, freeing blocks, and
65 * retrieving statistics about the HeapMem.
66 *
67 * By default, the Gate is of type GateMutex.
68 *
69 * A different Gate can be specified using the common$.gate parameter.
70 * For example, to use a GateTask to protect HeapMem:
71 * HeapMem.common$.gate = GateTask.create();
72 *
73 * To save on overhead, HeapMem does not create additional Gate instances on a
74 * per-instance basis; there is only one Gate instance shared across all of
75 * the HeapMem instances. Therefore, the HeapMem.common$.gateParams parameter
76 * (used for configuring per-instance Gates) is ignored.
77 *
78 * The type of Gate used should be chosen based on the type of threads (Hwi,
79 * Swi, Task, etc.) using the heap. It should also consider the
80 * non-deterministic nature of the HeapMem. A call to alloc or free will
81 * traverse a list of free blocks, so a GateHwi, for example, is likely an
82 * inappropriate Gate for HeapMem.
83 *
84 * @p(html)
85 * <h3> Calling Context </h3>
86 * <table border="1" cellpadding="3">
87 * <colgroup span="1"></colgroup> <colgroup span="5" align="center">
88 * </colgroup>
89 *
90 * <tr><th> Function </th><th> Hwi </th><th> Swi </th>
91 * <th> Task </th><th> Main </th><th> Startup </th></tr>
92 * <!-- -->
93 * <tr><td> Params_init </td><td> Y </td><td> Y </td>
94 * <td> Y </td><td> Y </td><td> Y </td></tr>
95 * <tr><td> alloc </td><td> N** </td><td> N** </td>
96 * <td> Y** </td><td> Y </td><td> N </td></tr>
97 * <tr><td> construct </td><td> Y </td><td> Y </td>
98 * <td> Y </td><td> Y </td><td> N </td></tr>
99 * <tr><td> create </td><td> N* </td><td> N* </td>
100 * <td> Y </td><td> Y </td><td> N </td></tr>
101 * <tr><td> delete </td><td> N* </td><td> N* </td>
102 * <td> Y </td><td> Y </td><td> N </td></tr>
103 * <tr><td> destruct </td><td> Y </td><td> Y </td>
104 * <td> Y </td><td> Y </td><td> N </td></tr>
105 * <tr><td> free </td><td> N** </td><td> N** </td>
106 * <td> Y** </td><td> Y </td><td> N </td></tr>
107 * <tr><td> getExtendedStats </td><td> Y </td><td> Y </td>
108 * <td> Y </td><td> Y </td><td> N </td></tr>
109 * <tr><td> getStats </td><td> N** </td><td> N** </td>
110 * <td> Y** </td><td> Y </td><td> N </td></tr>
111 * <tr><td> isBlocking </td><td> Y </td><td> Y </td>
112 * <td> Y </td><td> Y </td><td> N </td></tr>
113 * <tr><td> restore </td><td> Y+ </td><td> Y+ </td>
114 * <td> Y+ </td><td> Y </td><td> N </td></tr>
115 * <tr><td colspan="6"> Definitions: <br />
116 * <ul>
117 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
118 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
119 * <li> <b>Task</b>: API is callable from a Task thread. </li>
120 * <li> <b>Main</b>: API is callable during any of these phases: </li>
121 * <ul>
122 * <li> In your module startup after this module is started
123 * (e.g. HeapMem_Module_startupDone() returns TRUE). </li>
124 * <li> During xdc.runtime.Startup.lastFxns. </li>
125 * <li> During main().</li>
126 * <li> During BIOS.startupFxns.</li>
127 * </ul>
128 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
129 * <ul>
130 * <li> During xdc.runtime.Startup.firstFxns.</li>
131 * <li> In your module startup before this module is started
132 * (e.g. HeapMem_Module_startupDone() returns FALSE).</li>
133 * </ul>
134 * <li> <b>*</b> : Assuming blocking Heap is used for creation. </li>
135 * <li> <b>**</b>: Assuming GateMutex is used as HeapMem's Gate. </li>
136 * <li> <b>+</b> : Cannot use HeapMem object while it is being
137 * restored. </li>
138 * </ul>
139 * </td></tr>
140 *
141 * </table>
142 * @p
143 */
144 @Gated
145 module HeapMem inherits xdc.runtime.IHeap {
146
147 /*! @_nodoc */
148 @XmlDtd
149 metaonly struct BasicView {
150 String label;
151 Ptr buf;
152 SizeT minBlockAlign;
153 String sectionName;
154 }
155
156 /*! @_nodoc */
157 @XmlDtd
158 metaonly struct DetailedView {
159 String label;
160 Ptr buf;
161 SizeT minBlockAlign;
162 String sectionName;
163 Memory.Size totalSize;
164 Memory.Size totalFreeSize;
165 Memory.Size largestFreeSize;
166 }
167
168 /*!
169 * ======== FreeBlockView ========
170 * @_nodoc
171 */
172 metaonly struct FreeBlockView {
173 String Address;
174 String size;
175 String next;
176 String status;
177 }
178
179 /*! @_nodoc */
180 @Facet
181 metaonly config ViewInfo.Instance rovViewInfo =
182 ViewInfo.create({
183 viewMap: [
184 [
185 'Basic',
186 {
187 type: ViewInfo.INSTANCE,
188 viewInitFxn: 'viewInitBasic',
189 structName: 'BasicView'
190 }
191 ],
192 [
193 'Detailed',
194 {
195 type: ViewInfo.INSTANCE,
196 viewInitFxn: 'viewInitDetailed',
197 structName: 'DetailedView'
198 }
199 ],
200 [
201 'FreeList',
202 {
203 type: ViewInfo.INSTANCE_DATA,
204 viewInitFxn: 'viewInitData',
205 structName: 'FreeBlockView'
206 }
207 ]
208 ]
209 });
210
211
212 /*!
213 * ======== ExtendedStats ========
214 * Stat structure for the HeapMem_getExtendedStats function
215 *
216 * @field(buf) Base address of the internal buffer.
217 * This may be different from the original buf
218 * parameter due to alignment requirements.
219 * @field(size) Size of the internal buffer.
220 * This may be different from the original size
221 * parameter due to alignment requirements.
222 */
223 struct ExtendedStats {
224 Ptr buf;
225 SizeT size;
226 }
227
228 /*!
229 * ======== A_zeroBlock ========
230 * Assert raised when a block of size 0 is requested
231 *
232 * This error can also be raised if the requested size wraps
233 * the contents of a SizeT type when it is adjusted for a minimum
234 * alignment. For example, when SizeT is 16-bits and a size request
235 * is made for 0xFFFB.
236 */
237 config xdc.runtime.Assert.Id A_zeroBlock =
238 {msg: "A_zeroBlock: Cannot allocate size 0"};
239
240 /*!
241 * ======== A_heapSize ========
242 * Assert raised when the requested heap size is too small
243 */
244 config xdc.runtime.Assert.Id A_heapSize =
245 {msg: "A_heapSize: Requested heap size is too small"};
246
247 /*!
248 * ======== A_align ========
249 * Assert raised when the requested alignment is not a power of 2
250 */
251 config xdc.runtime.Assert.Id A_align =
252 {msg: "A_align: Requested align is not a power of 2"};
253
254 /*!
255 * ======== E_memory ========
256 * Raised when requested size exceeds largest free block
257 */
258 config Error.Id E_memory = {msg: "out of memory: handle=0x%x, size=%u"};
259
260 /*!
261 * ======== A_invalidFree ========
262 * Assert raised when the free detects that an invalid addr or size
263 *
264 * This could arise when multiple frees are done on the same buffer or
265 * if corruption occurred.
266 *
267 * This also could occur when an alloc is made with size N and the
268 * free for this buffer specifies size M where M > N. Note: not every
269 * case is detectable.
270 *
271 * This assert can also be caused when passing an invalid addr to free
272 * or if the size is causing the end of the buffer to be
273 * out of the expected range.
274 */
275 config xdc.runtime.Assert.Id A_invalidFree =
276 {msg: "A_invalidFree: Invalid free"};
277
278 /*!
279 * ======== primaryHeapBaseAddr ========
280 * Base address of the 'Primary Heap' buffer.
281 *
282 * HeapMem allows one Heap instance to be defined who's heap
283 * memory is defined by symbols in the linker command file.
284 * This singular Heap instance is referred to as the 'Primary Heap'.
285 *
286 * see {@link #primaryHeapEndAddr}
287 * see {@link #usePrimaryHeap}
288 *
289 * The following example will create a HeapMem instance whose
290 * size and buffer will be determined at runtime based on the
291 * values of the symbols `__primary_heap_start__` and
292 * `__primary_heap_end__`. It is assumed the user will define these
293 * symbols in their linker command file.
294 *
295 * @p(code)
296 * var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
297 *
298 * HeapMem.primaryHeapBaseAddr = "&__primary_heap_start__";
299 * HeapMem.primaryHeapEndAddr = "&__primary_heap_end__";
300 *
301 * var heapMemParams = new HeapMem.Params;
302 * heapMemParams.usePrimaryHeap = true;
303 *
304 * var heap0 = HeapMem.create(heapMemParams);
305 * @p
306 */
307 config Char *primaryHeapBaseAddr = null;
308
309 /*!
310 * ======== primaryHeapEndAddr ========
311 * End address of the 'Primary Heap' buffer, plus one.
312 *
313 * see {@link #primaryHeapBaseAddr}
314 * see {@link #usePrimaryHeap}
315 *
316 * @p(code)
317 * HeapMem.primaryHeapEndAddr = "&__primary_heap_end__";
318 * @p
319 */
320 config Char *primaryHeapEndAddr = null;
321
322 /*!
323 * ======== enter ========
324 * @_nodoc
325 * Enter the module's gate. This is needed to support
326 * the legacy MEM module. It allows MEM to use the same
327 * gate for thread-safety.
328 */
329 IArg enter();
330
331 /*!
332 * ======== leave ========
333 * @_nodoc
334 * Leave the module's gate. This is needed to support
335 * the legacy MEM module. It allows MEM to use the same
336 * gate for thread-safety.
337 */
338 Void leave(IArg key);
339
340 instance:
341
342 /*!
343 * ======== usePrimaryHeap ========
344 * Use {@link #primaryHeapBaseAddr} and {@link #primaryHeapEndAddr}
345 * to define the Heap buffer managed by this static instance.
346 *
347 * @a(warning)
348 * This instance parameter only exists for statically defined
349 * HeapMem objects and can only be set to true in the creation
350 * of one static HeapMem object!
351 */
352 metaonly config Bool usePrimaryHeap = false;
353
354 /*!
355 * ======== align ========
356 * Alignment of the buffer being managed by this heap instance
357 *
358 * In the static HeapMem.create() call, the buffer allocated for the
359 * HeapMem instance will have the alignment specified by this parameter.
360 *
361 * In the dynamic case, the client must supply the buffer, so it is the
362 * client's responsibility to manage the buffer's alignment, and there is
363 * no 'align' parameter.
364 *
365 * The specified alignment must be a power of 2.
366 *
367 * HeapMem requires that the buffer be aligned on a target-specific minimum
368 * alignment, and will adjust (round up) the requested alignment as
369 * necessary to satisfy this requirement.
370 *
371 * The default alignment is 0.
372 */
373 metaonly config SizeT align = 0;
374
375 /*!
376 * ======== minBlockAlign ========
377 * Minimum alignment for each block allocated
378 *
379 * This parameter dictates the minimum alignment for each
380 * block that is allocated. If an alignment request of greater than
381 * minBlockAlign is made in the alloc, it will be honored. If an
382 * alignment request of less than minBlockAlign is made, the request will
383 * be ignored and minBlockAlign will be used.
384 *
385 * @p(code)
386 * HeapMem_Params_init(&prms);
387 * prms.minBlockAlign = 32;
388 * handle = HeapMem_create(&prms, &eb);
389 * ...
390 * // buf will be aligned on a 32 MAU boundary
391 * buf = Memory_alloc(HeapMem_Handle_upCast(handle), SIZE, 8, &eb);
392 *
393 * // buf will be aligned on a 64 MAU boundary
394 * buf = Memory_alloc(HeapMem_Handle_upCast(handle), SIZE, 64, &eb);
395 * @p
396 *
397 * The default alignment is 0 (which means this parameter is ignored).
398 */
399 config SizeT minBlockAlign = 0;
400
401 /*!
402 * ======== sectionName ========
403 * Section name for the buffer managed by the instance
404 *
405 * The default section is the 'dataSection' in the platform.
406 */
407 metaonly config String sectionName = null;
408
409 /*!
410 * ======== buf ========
411 * Buffer being managed by this heap instance
412 *
413 * This parameter is ignored in the static HeapMem.create() call. It is a
414 * required parameter in the dynamic HeapMem_create() call.
415 *
416 * HeapMem requires that the buffer be aligned on a target-specific minimum
417 * alignment, and will adjust the buffer's start address and size as
418 * necessary to satisfy this requirement.
419 */
420 config Ptr buf = 0;
421
422 /*!
423 * ======== size ========
424 * Size of buffer being managed by this heap instance
425 *
426 * The usable size may be smaller depending on alignment requirements.
427 */
428 config Memory.Size size = 0;
429
430 /*!
431 * ======== alloc ========
432 *
433 * @HeapMem
434 * The actual block returned may be larger than requested to satisfy
435 * alignment requirements, and its size will always be a multiple of
436 * the size of the HeapMem_Header data structure (usually 8 bytes)
437 *
438 * HeapMem_alloc() will lock the heap using the HeapMem Gate while it
439 * traverses the list of free blocks to find a large enough block for
440 * the request.
441 *
442 * HeapMem_alloc() should not be called directly. Application code
443 * should use Memory_alloc() with a HeapMem_Handle as the first
444 * parameter. Among other things, Memory_alloc() makes sure that the
445 * alignment parameter is greater than or equal to the minimum alignment
446 * required for the HeapMem_Header data structure for a given C compiler
447 * (8 bytes in most cases). HeapMem_alloc() may crash if you pass a
448 * smaller alignment.
449 *
450 * Guidelines for using large heaps and multiple alloc() calls.
451 * @p(blist)
452 * - If possible, allocate larger blocks first. Previous
453 * allocations of small memory blocks can reduce the size
454 * of the blocks available for larger memory allocations.
455 * - Realize that alloc() can fail even if the heap contains a
456 * sufficient absolute amount of unallocated space. This is
457 * because the largest free memory block may be smaller than
458 * total amount of unallocated memory.
459 * @p
460 *
461 * @param(size) Requested size
462 * @param(align) Requested alignment
463 * @param(eb) Error_Block used to denote location in case of a failure
464 *
465 * @b(returns) allocated block or NULL is request cannot be honored
466 */
467 override Ptr alloc(SizeT size, SizeT align, xdc.runtime.Error.Block *eb);
468
469 /*!
470 * ======== allocUnprotected ========
471 *
472 * @HeapMem
473 * The actual block returned may be larger than requested to satisfy
474 * alignment requirements
475 *
476 * HeapMem_allocUnprotected() will
477 * traverses the list of free blocks to find a large enough block for
478 * the request.
479 *
480 * The caller of this API must provider the thread-safety
481 * of this call.
482 *
483 * Guidelines for using large heaps and multiple alloc() calls.
484 * @p(blist)
485 * - If possible, allocate larger blocks first. Previous
486 * allocations of small memory blocks can reduce the size
487 * of the blocks available for larger memory allocations.
488 * - Realize that alloc() can fail even if the heap contains a
489 * sufficient absolute amount of unallocated space. This is
490 * because the largest free memory block may be smaller than
491 * total amount of unallocated memory.
492 * @p
493 *
494 * @param(size) Requested size
495 * @param(align) Requested alignment
496 *
497 * @b(returns) allocated block or NULL is request cannot be honored
498 */
499 Ptr allocUnprotected(SizeT size, SizeT align);
500
501 /*!
502 * ======== free ========
503 *
504 * @HeapMem
505 * free() places the memory block specified by addr and size back into the
506 * free pool of the heap specified. The newly freed block is combined with
507 * any adjacent free blocks. The space is then available for further
508 * allocation by alloc().
509 *
510 * free() will lock the heap using the HeapMem Gate, if one is specified
511 * using 'HeapMem.common$.gate'.
512 *
513 * @param(block) Block to be freed
514 * @param(size) Size of block to free
515 */
516 override Void free(Ptr block, SizeT size);
517
518 /*!
519 * ======== freeUnprotected ========
520 *
521 * @HeapMem
522 * freeNoGate() places the memory block specified by addr and size back into the
523 * free pool of the heap specified. The newly freed block is combined with
524 * any adjacent free blocks. The space is then available for further
525 * allocation by alloc().
526 *
527 * The caller of this API must provider the thread-safety
528 * of this call.
529 *
530 * @param(block) Block to be freed
531 * @param(size) Size of block to free
532 */
533 Void freeUnprotected(Ptr block, SizeT size);
534
535 /*!
536 * ======== isBlocking ========
537 *
538 * @HeapMem
539 * This function queries the gate (as specified by 'HeapMem.common$.gate')
540 * to determine if the alloc/free can be blocking.
541 */
542 override Bool isBlocking();
543
544 /*!
545 * ======== getStats ========
546 *
547 * @HeapMem
548 * getStats() will lock the heap using the HeapMem Gate while it retrieves
549 * the HeapMem's statistics.
550 *
551 * The returned totalSize reflects the usable size of the buffer, not
552 * necessarily the size specified during create.
553 */
554 override Void getStats(xdc.runtime.Memory.Stats *stats);
555
556
557 /*!
558 * ======== restore ========
559 * Restores an instance to its original created state
560 *
561 * This function restores a static or dynamically created instance to
562 * its original created state. Any memory previously allocated from the
563 * heap is no longer valid after this API is called. This function
564 * does not check whether there is allocated memory or not.
565 */
566 Void restore();
567
568 /*!
569 * ======== getExtendedStats ========
570 * Retrieves the extended statistics for a HeapMem instance
571 *
572 * This function retrieves the extended statistics for a HeapMem instance.
573 * It does not retrieve the standard xdc.runtime.Memory.Stats information.
574 *
575 * @param(stats) Location for the returned extended statistics.
576 */
577 Void getExtendedStats(ExtendedStats *stats);
578
579
580 internal:
581
582 /*!
583 * ======== init ========
584 * Initialize instance at runtime
585 *
586 * This function is plugged as a Startup.firstFxn so that the
587 * HeapMem objects are ready and usable by malloc() and
588 * Memory_alloc() by the time the module startup functions
589 * get called so that any calls to atexit(), which in some targets
590 * invokes malloc(), will be handled cleanly.
591 */
592 Void init();
593
594 /*!
595 * ======== initPrimary ========
596 * Initialize instance at runtime
597 *
598 * Same as 'init' but supports the use of 'HeapMem.primaryHeapBaseAddress'.
599 */
600 Void initPrimary();
601
602
603 config SizeT reqAlign;
604
605
606 struct Header {
607 Header *next;
608 Memory.Size size;
609 };
610
611 struct Instance_State {
612 xdc.runtime.Memory.Size align;
613 Char buf[];
614 Header head; 615 616 617
618 SizeT minBlockAlign;
619 };
620 }
621