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     *  ======== GateMutexPri.xdc ========
    34     *
    35     */
    36    package ti.sysbios.gates;
    37    
    38    import xdc.rov.ViewInfo;
    39    import xdc.runtime.Assert;
    40    import ti.sysbios.knl.Queue;
    41    import ti.sysbios.knl.Task;
    42    
    43    /*!
    44     *  ======== GateMutexPri ========
    45     *  Mutex Gate with priority inheritance.
    46     *
    47     *  GateMutexPri is a mutex gate (it can only be held by one thread at a time)
    48     *  which implements priority inheritance in order to prevent priority
    49     *  inversion. Priority inversion occurs when a high priority task has its
    50     *  priority effectively 'inverted' because it is waiting on a gate held by a
    51     *  low priority task.
    52     *
    53     *  When multiple tasks wait on this gate, they will receive the gate in order
    54     *  of priority (higher priority tasks will receive the gate first). This is
    55     *  because the queue of tasks waiting on a GateMutexPri is sorted by priority,
    56     *  not FIFO.
    57     *
    58     *  @p(html)
    59     *  <h3> Problem: Priority Inversion </h3>
    60     *  The following example demonstrates priority inversion.
    61     *  A system has three tasks, Low, Med, and High, each with the priority
    62     *  suggested by its name. Task Low runs first and acquires the gate. Task High
    63     *  is scheduled and preempts Low. Task High tries to acquire the gate, and
    64     *  waits on it. Next, task Med is scheduled and preempts task Low. Now task
    65     *  High must wait for both task Med and task Low to finish before it can
    66     *  continue. In this situation, task Low has in effect lowered task High's
    67     *  priority to that of Low.
    68     *
    69     *  <h3> Solution: Priority Inheritance </h3>
    70     *  To guard against priority inversion, GateMutexPri implements priority
    71     *  inheritance: when task High tries to acquire a gate that is owned by task
    72     *  Low, task Low's priority will be temporarily raised to that of High, as
    73     *  long as High is waiting on the gate. Task High will "donate" its priority
    74     *  to task Low.
    75     *
    76     *  When multiple tasks wait on the gate, the gate owner will receive the
    77     *  highest priority of any of the tasks waiting on the gate.
    78     *
    79     *  <h3> Caveats </h3>
    80     *  Priority inheritance is not a complete guard against priority inversion.
    81     *  Tasks only donate priority on the call to gate, so if a task has its
    82     *  priority raised while waiting on a gate, that priority will not carry
    83     *  through to the gate owner.
    84     *  This can occur in situations involving multiple gates. A system has four
    85     *  tasks: VeryLow, Low, Med, and High, each with the priority suggested by its
    86     *  name. Task VeryLow runs first and acquires gate A. Task Low runs next and
    87     *  acquires gate B, then waits on gate A. Task High runs and waits on gate B.
    88     *  Task High has donated its priority to task Low, but Low is blocked on
    89     *  VeryLow, so priority inversion occurs despite the use of the gate.
    90     *  The solution to this problem is to design around it. If gate A may be
    91     *  needed by a high-priority, time-critical task, then it should be a design
    92     *  rule that no task holds this gate for a long time, or blocks while holding
    93     *  this gate.
    94     *
    95     *  <h3> Miscellaneous </h3>
    96     *  Calls to enter() may block, so this gate can only be used in the task
    97     *  context.
    98     *
    99     *  GateMutexPri is non-deterministic on calls to gate because it keeps the
   100     *  queue of waiting tasks sorted by priority.
   101     *
   102     *  @p(html)
   103     *  <h3> Calling Context </h3>
   104     *  <table border="1" cellpadding="3">
   105     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
   106     *  </colgroup>
   107     *
   108     *    <tr><th> Function </th><th>  Hwi   </th><th>  Swi   </th><th>  Task  </th>
   109     *  <th>  Main  </th><th>  Startup  </th></tr>
   110     *    <!--                                                          -->
   111     *    <tr><td> {@link #Params_init} </td><td>   Y    </td><td>   Y    </td>
   112     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   113     *    <tr><td> {@link #query}       </td><td>   Y    </td><td>   Y    </td>
   114     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   115     *    <tr><td> {@link #construct}   </td><td>   Y    </td><td>   Y    </td>
   116     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   117     *    <tr><td> {@link #create}      </td><td>   N*   </td><td>   N*   </td>
   118     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   119     *    <tr><td> {@link #delete}      </td><td>   N*   </td><td>   N*   </td>
   120     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   121     *    <tr><td> {@link #destruct}    </td><td>   Y    </td><td>   Y    </td>
   122     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   123     *    <tr><td> {@link #enter}       </td><td>   N    </td><td>   N    </td>
   124     *    <td>   Y    </td><td>   Y**  </td><td>   N    </td></tr>
   125     *    <tr><td> {@link #leave}       </td><td>   N    </td><td>   N    </td>
   126     *    <td>   Y    </td><td>   Y**  </td><td>   N    </td></tr>
   127     *    <tr><td colspan="6"> Definitions: <br />
   128     *       <ul>
   129     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   130     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   131     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   132     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   133     *           <ul>
   134     *             <li> In your module startup after this module is started
   135     *    (e.g. GateMutexPri_Module_startupDone() returns TRUE). </li>
   136     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   137     *             <li> During main().</li>
   138     *             <li> During BIOS.startupFxns.</li>
   139     *           </ul>
   140     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   141     *           <ul>
   142     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   143     *             <li> In your module startup before this module is started
   144     *    (e.g. GateMutexPri_Module_startupDone() returns FALSE).</li>
   145     *           </ul>
   146     *       <li> <b>*</b>:  Assuming blocking Heap is used for creation. </li>
   147     *       <li> <b>**</b>: Must be used in enter/leave pairs. </li>
   148     *       </ul>
   149     *    </td></tr>
   150     *
   151     *  </table>
   152     *  @p
   153     */
   154    
   155    @InstanceFinalize       /* To deconstruct the Queue */
   156    
   157    module GateMutexPri inherits xdc.runtime.IGateProvider
   158    {
   159    
   160        /*!
   161         *  ======== BasicView ========
   162         *  @_nodoc
   163         */
   164        metaonly struct BasicView {
   165            String     status;
   166            String     label;
   167            UInt       mutexCnt;
   168            String     owner;
   169            Int        ownerOrigPri;
   170            Int        ownerCurrPri;
   171        }
   172    
   173        /*!
   174         *  ======== DetailedView ========
   175         *  @_nodoc
   176         */
   177        metaonly struct DetailedView {
   178            String     status;
   179            String     label;
   180            UInt       mutexCnt;
   181            String     owner;
   182            Int        ownerOrigPri;
   183            Int        ownerCurrPri;
   184            String     pendedTasks[];
   185        }
   186    
   187        /*!
   188         *  ======== rovViewInfo ========
   189         *  @_nodoc
   190         */
   191        @Facet
   192        metaonly config ViewInfo.Instance rovViewInfo =
   193            ViewInfo.create({
   194                viewMap: [
   195                    ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}],
   196                    ['Detailed', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitDetailed', structName: 'DetailedView'}],
   197                ]
   198            });
   199    
   200        /*!
   201         *  Assert when GateMutexPri_enter() is not called from correct context.
   202         *  GateMutexPri_enter() can only be called from main() or Task context (not
   203         *  Hwi or Swi).
   204         *
   205         *  Common causes and workarounds for hitting this Assert:
   206         *
   207         *  - Calling printf() from a Hwi or Swi thread.
   208         *  @p(blist)
   209         *          - Use xdc.runtime.System_printf (with SysMin) instead.
   210         *  @p
   211         *  - Calling System_printf() from a Hwi or Swi thread when using SysStd.
   212         *  @p(blist)
   213         *          - Use xdc.runtime.SysMin instead of xdc.runtume.SysStd.
   214         *          - Use a different type of Gate for
   215         *            {@link ti.sysbios.BIOS#rtsGateType BIOS.rtsGateType}
   216         *            (ie {@link ti.sysbios.BIOS#GateHwi BIOS.GateHwi}
   217         *            or {@link ti.sysbios.BIOS#GateSwi BIOS.GateSwi})
   218         *  @p
   219         *  - Calling Memory_alloc() from a Hwi or Swi thread.
   220         *  @p(blist)
   221         *          - Use a different Heap manager
   222         *  @p
   223         */
   224        config Assert.Id A_badContext = {
   225            msg: "A_badContext: bad calling context. See GateMutexPri API doc for details."
   226        };
   227    
   228        /*!
   229         *  ======== A_enterTaskDisabled ========
   230         *  Asserted in GateMutexPri_enter()
   231         *
   232         *  Assert raised if GateMutexPri_enter() is called with the Task or
   233         *  Swi scheduler disabled.
   234         */
   235        config Assert.Id A_enterTaskDisabled = {
   236            msg: "A_enterTaskDisabled: Cannot call GateMutexPri_enter() while the Task or Swi scheduler is disabled."
   237        };
   238    
   239    instance:
   240    
   241        override IArg enter();
   242    
   243        override Void leave(IArg key);
   244    
   245    internal:
   246    
   247        Void insertPri(ti.sysbios.knl.Queue.Object *queue,
   248                       ti.sysbios.knl.Queue.Elem *newElem,
   249                       Int newPri);
   250    
   251        /* instance object */
   252        struct Instance_State {
   253            volatile UInt           mutexCnt;       /* The mutex, 0 or 1 */
   254            volatile Int            ownerOrigPri;   /* Owner's original pri */
   255            volatile Task.Handle    owner;          /* Gate owner */
   256            Queue.Object            pendQ;          /* Q of pending tasks */
   257        };
   258    }