1    /*
     2     * Copyright (c) 2014-2020, 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     *  ======== Semaphore.xdc ========
    34     *
    35     */
    36    
    37    package ti.sysbios.knl;
    38    
    39    import xdc.rov.ViewInfo;
    40    
    41    import xdc.runtime.Diags;
    42    import xdc.runtime.Log;
    43    import xdc.runtime.Assert;
    44    import xdc.runtime.Error;
    45    
    46    import ti.sysbios.knl.Queue;
    47    import ti.sysbios.knl.Task;
    48    import ti.sysbios.knl.Clock;
    49    
    50    /*!
    51     *  ======== Semaphore ========
    52     *  Semaphore Manager
    53     *
    54     *  The Semaphore manager makes available a set of functions that manipulate
    55     *  semaphore objects. Semaphores can be used for task synchronization and
    56     *  mutual exclusion.
    57     *
    58     *  Semaphores can be counting semaphores or binary semaphores. Counting
    59     *  semaphores keep track of the number of times the semaphore has been posted
    60     *  with post(). This is useful, for example, if you have a group of resources
    61     *  that are shared between tasks. Such tasks might call pend() to see if a
    62     *  resource is available before using one.
    63     *
    64     *  Binary semaphores can have only two states: available (count = 1) and
    65     *  unavailable (count = 0). They can be used to share a single resource
    66     *  between tasks. They can also be used for a basic signaling mechanism,
    67     *  where the semaphore can be posted multiple times. Binary semaphores do
    68     *  not keep track of the count; they simply track whether the semaphore has
    69     *  been posted or not.
    70     *
    71     *  See {@link #getCount Semaphore_getCount()} for more details of the 'count'
    72     *  behavior.
    73     *
    74     *  The Mailbox module uses a counting semaphore internally to manage the
    75     *  count of free (or full) mailbox elements. Another example of a counting
    76     *  semaphore is an ISR that might fill multiple buffers of data for
    77     *  consumption by a task. After filling each buffer, the ISR puts the buffer on
    78     *  a queue and calls post(). The task waiting for the data calls pend(), which
    79     *  simply decrements the semaphore count and returns or blocks if the count is
    80     *  0. The semaphore count thus tracks the number of full buffers available for
    81     *  the task.
    82     *
    83     *  pend() is used to wait for a semaphore. The timeout parameter allows the
    84     *  task to wait until a timeout, wait indefinitely, or not wait at all. The
    85     *  return value is used to indicate if the semaphore was signaled successfully.
    86     *
    87     *  post() is used to signal a semaphore. If a task is waiting for the
    88     *  semaphore, post() removes the task from the semaphore queue and puts it on
    89     *  the ready queue. If no tasks are waiting, post() simply increments the
    90     *  semaphore count and returns.  For a binary semaphore the count is always
    91     *  set to one.
    92     *
    93     *  @p(html)
    94     *  <h3> Calling Context </h3>
    95     *  <table border="1" cellpadding="3">
    96     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
    97     *    </colgroup>
    98     *
    99     *    <tr><th> Function               </th><th>  Hwi   </th><th>  Swi   </th>
   100     *    <th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
   101     *    <!--                                                                  -->
   102     *    <tr><td> {@link #Params_init}   </td><td>   Y    </td><td>   Y    </td>
   103     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   104     *    <tr><td> {@link #construct}     </td><td>   N    </td><td>   N    </td>
   105     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   106     *    <tr><td> {@link #create}        </td><td>   N    </td><td>   N    </td>
   107     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   108     *    <tr><td> {@link #delete}        </td><td>   N    </td><td>   N    </td>
   109     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   110     *    <tr><td> {@link #destruct}      </td><td>   N    </td><td>   N    </td>
   111     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   112     *    <tr><td> {@link #getCount}      </td><td>   Y    </td><td>   Y    </td>
   113     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   114     *    <tr><td> {@link #pend}          </td><td>   N*   </td><td>   N*   </td>
   115     *    <td>   Y    </td><td>   N*   </td><td>   N    </td></tr>
   116     *    <tr><td> {@link #post}          </td><td>   Y    </td><td>   Y    </td>
   117     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   118     *    <tr><td> {@link #registerEvent} </td><td>   N    </td><td>   N    </td>
   119     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
   120     *    <tr><td> {@link #reset}         </td><td>   N    </td><td>   N    </td>
   121     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   122     *    <tr><td colspan="6"> Definitions: (N* means OK to call iff the timeout
   123     *           parameter is set to '0'.)<br />
   124     *       <ul>
   125     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   126     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   127     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   128     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   129     *           <ul>
   130     *             <li> In your module startup after this module is started
   131     *    (e.g. Semaphore_Module_startupDone() returns TRUE). </li>
   132     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   133     *             <li> During main().</li>
   134     *             <li> During BIOS.startupFxns.</li>
   135     *           </ul>
   136     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   137     *           <ul>
   138     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   139     *             <li> In your module startup before this module is started
   140     *    (e.g. Semaphore_Module_startupDone() returns FALSE).</li>
   141     *           </ul>
   142     *       </ul>
   143     *    </td></tr>
   144     *
   145     *  </table>
   146     *  @p
   147     */
   148    
   149    @CustomHeader
   150    @DirectCall
   151    /* REQ_TAG(SYSBIOS-501) */
   152    @InstanceFinalize       /* to destruct queue */
   153    @InstanceInitStatic     /* Construct/Destruct CAN becalled at runtime */
   154    
   155    /* REQ_TAG(SYSBIOS-500) */
   156    module Semaphore
   157    {
   158        /*!
   159         *  Semaphore types.
   160         *
   161         *  These enumerations specify the type of semaphore.
   162         *
   163         *  Tasks wait for the semaphore in FIFO order unless the PRIORITY
   164         *  option is chosen.
   165         *
   166         *  For PRIORITY semaphores, the pending task will be
   167         *  inserted in the waiting list before the first task that has
   168         *  lower priority.  This ensures that tasks of equal priority will
   169         *  pend in FIFO order.
   170         *
   171         *  @a(WARNING)
   172         *  PRIORITY semaphores have a potential to increase the interrupt
   173         *  latency in the system since interrupts are disabled while the list of
   174         *  tasks waiting on the  semaphore is scanned for the proper insertion
   175         *  point.  This is typically about a dozen instructions per waiting task.
   176         *  For example, if you have 10 tasks of higher priority waiting, then all
   177         *  10 will be checked with interrupts disabled before the new task is
   178         *  entered onto the list.
   179         */
   180        enum Mode {
   181            Mode_COUNTING = 0x0,           /*! Counting (FIFO) */
   182            Mode_BINARY = 0x1,             /*! Binary (FIFO) */
   183            Mode_COUNTING_PRIORITY = 0x2,  /*! Counting (priority-based) */
   184            Mode_BINARY_PRIORITY = 0x3     /*! Binary (priority-based) */
   185        };
   186    
   187        /*!
   188         *  ======== BasicView ========
   189         *  @_nodoc
   190         */
   191        metaonly struct BasicView {
   192            String          label;
   193            String          event;
   194            String          eventId;
   195            String          mode;
   196            Int             count;
   197            String          pendedTasks[];
   198        };
   199    
   200        /*!
   201         *  ======== rovViewInfo ========
   202         *  @_nodoc
   203         */
   204        @Facet
   205        metaonly config ViewInfo.Instance rovViewInfo =
   206            ViewInfo.create({
   207                viewMap: [
   208                    ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}]
   209                ]
   210            });
   211    
   212        // -------- Module Parameters --------
   213    
   214        /*!
   215         *  ======== LM_post ========
   216         *  Logged on calls to Semaphore_post()
   217         */
   218        config Log.Event LM_post = {
   219            mask: Diags.USER1 | Diags.USER2,
   220            msg: "LM_post: sem: 0x%x, count: %d"
   221        };
   222    
   223        /*!
   224         *  ======== LM_pend ========
   225         *  Logged on calls to Semaphore_pend()
   226         */
   227        config Log.Event LM_pend = {
   228            mask: Diags.USER1 | Diags.USER2,
   229            msg: "LM_pend: sem: 0x%x, count: %d, timeout: %d"
   230        };
   231    
   232        /*!
   233         *  ======== A_noEvents ========
   234         *  Assert raised if application uses Event but it's not supported
   235         *
   236         *  This assertion is triggered by {@link #create} if
   237         *  {@link #supportsEvents} is false and an {@link ti.sysbios.knl.Event}
   238         *  object is passed to {@link #create}.
   239         */
   240        config Assert.Id A_noEvents = {
   241            msg: "A_noEvents: The Event.supportsEvents flag is disabled."
   242        };
   243    
   244        /*!
   245         *  ======== A_invTimeout ========
   246         *  @_nodoc
   247         *  This assertion is no longer used
   248         */
   249        config Assert.Id A_invTimeout = {
   250            msg: "A_invTimeout: Can't use BIOS_EVENT_ACQUIRED with this Semaphore."
   251        };
   252    
   253        /*!
   254         *  ======== A_badContext ========
   255         *  Assert raised if an operation is invalid in the current calling context
   256         *
   257         *  Asserted when {@link #pend} is called with non-zero timeout from
   258         *  other than a Task context.
   259         */
   260        config Assert.Id A_badContext = {
   261            msg: "A_badContext: bad calling context. Must be called from a Task."
   262        };
   263    
   264        /*!
   265         *  ======== A_overflow ========
   266         *  Assert raised if the semaphore count is incremented past 65535
   267         *
   268         *  Asserted when Semaphore_post() has been called when the 16 bit
   269         *  semaphore count is at its maximum value of 65535.
   270         */
   271        config Assert.Id A_overflow = {
   272            msg: "A_overflow: Count has exceeded 65535 and rolled over."
   273        };
   274    
   275        /*!
   276         *  ======== A_pendTaskDisabled ========
   277         *  Asserted in Sempahore_pend()
   278         *
   279         *  Assert raised if Semaphore_pend() is called with the Task or
   280         *  Swi scheduler disabled.
   281         */
   282        config Assert.Id A_pendTaskDisabled = {
   283            msg: "A_pendTaskDisabled: Cannot call Semaphore_pend() while the Task or Swi scheduler is disabled."
   284        };
   285    
   286        // Errors
   287    
   288        /*!
   289         *  Error raised when BIOS.mpeEnabled is TRUE and Semaphore object passed to
   290         *  Semaphore_construct() is not in Kernel address space. This can happen if
   291         *  a user Task passes a Semaphore object that resides in unprivileged
   292         *  memory to Semaphore_construct().
   293         */
   294        config Error.Id E_objectNotInKernelSpace = {
   295            msg: "E_objectNotInKernelSpace: Semaphore object passed not in Kernel address space."
   296        };
   297    
   298        /*!
   299         *  ======== supportsEvents ========
   300         *  Support Semaphores with Events?
   301         *
   302         *  The default for this parameter is false.
   303         */
   304        config Bool supportsEvents = false;
   305    
   306        /*!
   307         *  ======== supportsPriority ========
   308         *  Support Task priority pend queuing?
   309         *
   310         *  The default for this parameter is true.
   311         */
   312        config Bool supportsPriority = true;
   313    
   314        /*!
   315         *  ======== testStaticInlines ========
   316         *  @_nodoc
   317         *  Used for code coverage testing.
   318         */
   319        Void testStaticInlines();
   320    
   321    instance:
   322    
   323        /*!
   324         *  ======== create ========
   325         *  Create a Semaphore object
   326         *
   327         *  This function creates a new Semaphore object which is initialized to
   328         *  count.
   329         *
   330         *  @param(count)   initial semaphore count
   331         *
   332         *  @a(NOTE)
   333         *  The "count" argument should not be a negative number as the Semaphore
   334         *  count is stored as a 16-bit unsigned integer inside the Semaphore
   335         *  object.
   336         */
   337        create(Int count);
   338    
   339        /* REQ_TAG(SYSBIOS-502) */
   340        /*!
   341         *  ======== event ========
   342         *  Event instance to use if non-NULL
   343         *
   344         *  The default value of this parameter is null.  If event is non-null:
   345         *  @p(blist)
   346         *      - Event_post(sem->event, sem->eventId) will be invoked when
   347         *        Semaphore_post() is called.
   348         *
   349         *      - Event_pend(sem->event, 0, sem->eventId, timeout) will be
   350         *        invoked when Semaphore_pend() is called.
   351         *  @p
   352         *
   353         *  @a(CONSTRAINT)
   354         *  The 'event' parameter is ignored if
   355         *  {@link #supportsEvents Semaphore.supportsEvents}
   356         *  is set to false.
   357         */
   358        config Event.Handle event = null;
   359    
   360        /*!
   361         *  ======== eventId ========
   362         *  eventId if using Events
   363         *
   364         *  The default for this parameters is 1.
   365         *
   366         *  @a(CONSTRAINT)
   367         *  The 'eventId' parameter is ignored if
   368         *  {@link #supportsEvents Semaphore.supportsEvents}
   369         *  is set to false.
   370         */
   371        config UInt eventId = 1;
   372    
   373        /*!
   374         *  ======== mode ========
   375         *  Semaphore mode
   376         *
   377         *  When mode is BINARY, the semaphore has only two states, available
   378         *  and unavailable. When mode is COUNTING, the semaphore keeps track of
   379         *  number of times a semaphore is posted.
   380         *
   381         *  The default for this parameter is COUNTING.
   382         */
   383        config Mode mode = Mode_COUNTING;
   384    
   385        /*!
   386         *  ======== getCount ========
   387         *  Get current semaphore count
   388         *
   389         *  This function returns the current value of the semaphore specified by
   390         *  the handle.
   391         *
   392         *  A semaphore's count is incremented when Semaphore_post() is called.
   393         *  If configured as a binary semaphore, the count will not increment past
   394         *  1. If configured as a counting semaphore, the count will continue
   395         *  incrementing and will rollover to zero after reaching a count of
   396         *  65,535. Care must be taken in applications to avoid the rollover
   397         *  situation as a count of zero will always be interpreted as an empty
   398         *  semaphore.
   399         *
   400         *  A semaphore's count is decremented, if non-zero, when Semaphore_pend()
   401         *  is called. A task will block on a semaphore if the count is zero when
   402         *  Semaphore_pend() is called. An empty semaphore will always have a
   403         *  count of zero regardless of the number of tasks that are blocked on
   404         *  it.
   405         *
   406         *  @b(returns)             current semaphore count
   407         */
   408        /* REQ_TAG(SYSBIOS-508) */
   409        Int getCount();
   410    
   411        /*!
   412         *  ======== pend ========
   413         *  Wait for a semaphore
   414         *
   415         *  If the semaphore count is greater than zero (available), this function
   416         *  decrements the count and returns TRUE. If the semaphore count is zero
   417         *  (unavailable), this function suspends execution of the current task
   418         *  (leaving the count equal to zero) until post() is called or the
   419         *  timeout expires.
   420         *
   421         *  A timeout value of
   422         *  {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER} causes
   423         *  the task to wait indefinitely for its semaphore to be posted.
   424         *
   425         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT BIOS_NO_WAIT}
   426         *  causes Semaphore_pend to return immediately.
   427         *
   428         *  @a(Event Object Note)
   429         *  If the Semaphore object has been configured with an embedded Event
   430         *  object, then prior to returning from this function, the Event object's
   431         *  state is updated to reflect the new value of 'count'.
   432         *  If 'count' is zero, then the configured Event_Id is cleared in the
   433         *  Event object. If 'count' is non-zero, then the configured Event_Id
   434         *  is set in the Event object.
   435         *
   436         *  @param(timeout)     return after this many system time units
   437         *
   438         *  @b(returns)         TRUE if successful, FALSE if timeout
   439         *
   440         *  @a(CONSTRAINT)
   441         *  It is a fatal error to invoke Semaphore_pend() with a non-zero timeout
   442         *  while the Task scheduler is disabled.
   443         *  See {@link ti.sysbios.knl.Task#disable Task_disable} for more details.
   444         */
   445        /* REQ_TAG(SYSBIOS-504) */
   446        Bool pend(UInt32 timeout);
   447    
   448        /*!
   449         *  ======== post ========
   450         *  Signal a semaphore.
   451         *
   452         *  If any tasks are waiting on the semaphore, this function readies
   453         *  the first task waiting for the semaphore without incrementing
   454         *  the count. If no task is waiting, this function simply increments
   455         *  the semaphore count and returns. In the case of a binary semaphore,
   456         *  the count has a maximum value of one.
   457         */
   458        /* REQ_TAG(SYSBIOS-503) */
   459        Void post();
   460    
   461        /*!
   462         *  ======== registerEvent ========
   463         *  Register an Event Object with a semaphore
   464         *
   465         *  Ordinarily, an Event object and eventId are configured at
   466         *  Semaphore create time.
   467         *
   468         *  This API is provided so that Semaphore-using middleware
   469         *  can support implicit Event posting without having to be
   470         *  retrofitted.
   471         *
   472         *  After the Event object and eventId are registered with the
   473         *  Semaphore:
   474    
   475         *  Event_post(event, eventId) will be invoked when
   476         *  Semaphore_post(sem) is called.
   477         *
   478         *  Event_pend(event, eventId, 0, timeout) will be invoked when
   479         *  Semaphore_pend(sem, timeout) is called.
   480         *
   481         *  @param(event)                     Ptr to Event Object
   482         *  @param(eventId)                   Event ID
   483         *
   484         */
   485        Void registerEvent(Event.Handle event, UInt eventId);
   486    
   487        /*!
   488         *  ======== reset ========
   489         *  Reset semaphore count
   490         *
   491         *  Resets the semaphore count to count.
   492         *  No task switch occurs when calling SEM_reset.
   493         *
   494         *  @a(constraints)
   495         *  count must be greater than or equal to 0.
   496         *
   497         *  No tasks should be waiting on the semaphore when
   498         *  Semaphore_reset is called.
   499         *
   500         *  Semaphore_reset cannot be called by a Hwi or a Swi.
   501         *
   502         *  @param(count)                   semaphore count
   503         *
   504         */
   505        Void reset(Int count);
   506    
   507    internal:
   508    
   509        /*
   510         * Event module function pointers. Used to decouple
   511         * Semaphore from Event when supportsEvents is false
   512         */
   513        config Void (*eventPost)(Event.Handle, UInt);
   514    
   515        config Void (*eventSync)(Event.Handle, UInt, UInt);
   516    
   517        /*!
   518         *  ======== pendTimeout ========
   519         *  This function is the clock event handler for pend
   520         */
   521        Void pendTimeout(UArg arg);
   522    
   523        /* pendQ Element PendStates */
   524        enum PendState {
   525            PendState_TIMEOUT = 0,          /* Clock timeout */
   526            PendState_POSTED = 1,           /* posted by post */
   527            PendState_CLOCK_WAIT = 2,       /* in Clock queue */
   528            PendState_WAIT_FOREVER = 3      /* not in Clock queue */
   529        };
   530    
   531        /* Semaphore pendQ Element */
   532        struct PendElem {
   533            Task.PendElem           tpElem;
   534            PendState               pendState;
   535        };
   536    
   537        struct Instance_State {
   538            Event.Handle            event;
   539            UInt                    eventId;
   540            Mode                    mode;   /* binary or counting */
   541            volatile UInt16         count;  /* curr semaphore count */
   542            Queue.Object            pendQ;  /* queue of PendElems */
   543        };
   544    }