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