1    /*
     2     * Copyright (c) 2013, 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     *  ======== HeapMultiBuf.xdc ========
    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     /* Instance_init may throw an error */
   248    @InstanceFinalize      /* to destruct HeapBufs */
   249    @ModuleStartup         /* to determine buffer addresses */
   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:   /* not for client use */
   390    
   391        /*
   392         *  ======== AddrPair ========
   393         *  Used to sort bufs by address
   394         *
   395         *  A dynamically created HeapMultiBuf may have multiple AddrPairs
   396         *  per HeapBuf because of merging.
   397         */
   398        struct AddrPair {
   399            HeapBuf.Handle      heapBuf;  /* The heapBuf that manages lastAddr */
   400            Ptr                 lastAddr; /* The last address in the buffer */
   401        }
   402    
   403        /*
   404         *  ======== addrPairCompare ========
   405         */
   406        Int addrPairCompare(const Void *a, const Void *b);
   407    
   408        /*
   409         *  ======== sizeAlignCompare ========
   410         */
   411        Int sizeAlignCompare(const Void *a, const Void *b);
   412    
   413        /*
   414         *  ======== moveToEnd ========
   415         */
   416        Void moveToEnd(HeapBuf.Handle *heapBufs, UInt numHeapBufs, UInt index);
   417        
   418        /*
   419         *  ======== borrowBlock ========
   420         */
   421        Void *borrowBlock(HeapMultiBuf.Object *obj, SizeT size, SizeT align,
   422                          Int startIndex);
   423        /*
   424         *  ======== Instance_State ========
   425         * The bufsBySize array has length numHeapBufs and is used for alloc.
   426         * The bufsyByAddr array has length numBufs and is used for free.
   427         */
   428        struct Instance_State {        
   429            Bool              blockBorrow;  /* Enable/Disable block borrowing */
   430            Int               numHeapBufs;  /* Number of HeapBuf instances    */
   431            HeapBuf.Handle    bufsBySize[]; /* HeapBufs, sorted by size       */
   432            Int               numBufs;      /* Number of memory buffers       */
   433            AddrPair          bufsByAddr[]; /* HeapBufs, sorted by address    */
   434        };
   435    }