1    /*
     2     * Copyright (c) 2014, Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     */
    32    /*
    33     *  ======== HeapMem.xdc ========
    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:   /* not for client use */
   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        /* Required alignment. Must be a power of 2 */
   468        config SizeT reqAlign;
   469    
   470        /* Header maintained at the lower address of every free block */
   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[];      /* The heap used by HeapMem. */
   479            Header                  head;       /* First free block pointer.
   480                                                 * The size field will be used
   481                                                 * to store original heap size.
   482                                                 */
   483            SizeT                   minBlockAlign;
   484        };
   485    }
   486