1    /* 
     2     * Copyright (c) 2009
     3     * Texas Instruments
     4     *
     5     *  All rights reserved.  Property of Texas Instruments
     6     *  Restricted rights to use, duplicate or disclose this code are
     7     *  granted through contract.
     8     * 
     9     * */
    10    /*
    11     *  ======== Semaphore.xdc ========
    12     *
    13     */
    14    
    15    package ti.sysbios.ipc;
    16    
    17    import xdc.rov.ViewInfo;
    18    
    19    import xdc.runtime.Diags;
    20    import xdc.runtime.Log;
    21    import xdc.runtime.Assert;
    22    
    23    import ti.sysbios.misc.Queue;
    24    import ti.sysbios.knl.Task;
    25    import ti.sysbios.knl.Clock;
    26    
    27    /*!
    28     *  ======== Semaphore ========
    29     *  Semaphore Manager.
    30     *
    31     *  The Semaphore manager makes available a set of functions that manipulate 
    32     *  semaphore objects. Semaphores can be used for task synchronization and 
    33     *  mutual exclusion.
    34     *
    35     *  Semaphores can be counting semaphores or binary semaphores. Counting 
    36     *  semaphores keep track of the number of times the semaphore has been posted 
    37     *  with post(). This is useful, for example, if you have a group of resources 
    38     *  that are shared between tasks. Such tasks might call pend() to see if a 
    39     *  resource is available before using one. 
    40     *
    41     *  Binary semaphores can have only two states: available (count = 1) and 
    42     *  unavailable (count = 0). They can be used to share a single resource between 
    43     *  tasks. They can also be used for a basic signaling mechanism, where the 
    44     *  semaphore can be posted multiple times. Binary semaphores do not keep track 
    45     *  of the count; they simply track whether the semaphore has been posted or not.
    46     *
    47     *  The Mailbox module uses a counting semaphore internally to manage the
    48     *  count of free (or full) mailbox elements. Another example of a counting
    49     *  semaphore is an ISR that might fill multiple buffers of data for
    50     *  consumption by a task. After filling each buffer, the ISR puts the buffer on
    51     *  a queue and calls post(). The task waiting for the data calls pend(), which
    52     *  simply decrements the semaphore count and returns or blocks if the count is
    53     *  0. The semaphore count thus tracks the number of full buffers available for
    54     *  the task. 
    55     *
    56     *  pend() is used to wait for a semaphore. The timeout parameter allows the 
    57     *  task to wait until a timeout, wait indefinitely, or not wait at all. The 
    58     *  return value is used to indicate if the semaphore was signaled successfully.
    59     *
    60     *  post() is used to signal a semaphore. If a task is waiting for the 
    61     *  semaphore, post() removes the task from the semaphore queue and puts it on 
    62     *  the ready queue. If no tasks are waiting, post() simply increments the 
    63     *  semaphore count and returns.  For a binary semaphore the count is always
    64     *  set to one.
    65     *
    66     *  @p(html)
    67     *  <h3> Calling Context </h3>
    68     *  <table border="1" cellpadding="3">
    69     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center"></colgroup>
    70     *    
    71     *    <tr><th> Function               </th><th>  Hwi   </th><th>  Swi   </th><th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
    72     *    <!--                                                                                                                        -->
    73     *    <tr><td> {@link #Params_init}   </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    74     *    <tr><td> {@link #construct}     </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    75     *    <tr><td> {@link #create}        </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    76     *    <tr><td> {@link #delete}        </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    77     *    <tr><td> {@link #destruct}      </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    78     *    <tr><td> {@link #getCount}      </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    79     *    <tr><td> {@link #pend}          </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   N    </td><td>   N    </td></tr>
    80     *    <tr><td> {@link #post}          </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    81     *    <tr><td> {@link #registerEvent} </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    82     *    <tr><td colspan="6"> Definitions: <br />
    83     *       <ul>
    84     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
    85     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
    86     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
    87     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
    88     *           <ul>
    89     *             <li> In your module startup after this module is started (e.g. Semaphore_Module_startupDone() returns TRUE). </li>
    90     *             <li> During xdc.runtime.Startup.lastFxns. </li>
    91     *             <li> During main().</li>
    92     *             <li> During BIOS.startupFxns.</li>
    93     *           </ul>
    94     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
    95     *           <ul>
    96     *             <li> During xdc.runtime.Startup.firstFxns.</li>
    97     *             <li> In your module startup before this module is started (e.g. Semaphore_Module_startupDone() returns FALSE).</li>
    98     *           </ul>
    99     *       </ul>
   100     *    </td></tr>
   101     *  
   102     *  </table>
   103     *  @p
   104     */
   105    
   106    @InstanceFinalize       /* to destruct queue */
   107    
   108    module Semaphore
   109    {
   110        /*! Types of semaphores. */
   111        enum Mode {
   112            Mode_COUNTING,  /*! Counting semaphore. */
   113            Mode_BINARY     /*! Binary Semaphore. */
   114        };
   115     
   116        metaonly struct BasicView {
   117            String          label;
   118            String          event;
   119            String          eventId;
   120            String          mode;
   121            Int             count;
   122            String          pendedTasks[];
   123        };
   124        
   125        @Facet
   126        metaonly config ViewInfo.Instance rovViewInfo = 
   127            ViewInfo.create({
   128                viewMap: [
   129                    ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}]
   130                ]
   131            });
   132        
   133        // -------- Module Parameters --------
   134    
   135        // Logs
   136    
   137        /*! Logged on calls to Semaphore_post() */
   138        config Log.Event LM_post = {
   139            mask: Diags.USER1 | Diags.USER2,
   140            msg: "LM_post: sem: 0x%x, count: %d"
   141        };
   142    
   143        /*! Logged on calls to Semaphore_pend() */
   144        config Log.Event LM_pend = {
   145            mask: Diags.USER1 | Diags.USER2,
   146            msg: "LM_pend: sem: 0x%x, count: %d, timeout: %d"
   147        };
   148    
   149        // Asserts
   150    
   151        /*! 
   152         *  Generated by {@link #create} if {@link #supportsEvents} is false
   153         *  and an {@link ti.sysbios.ipc.Event} object is passed to 
   154         *  {@link #create}.
   155         */
   156        config Assert.Id A_noEvents = {
   157            msg: "A_noEvents: The Event.supportsEvents flag is disabled."
   158        };
   159    
   160        /*! 
   161         *  Generated by {@link #pend} if BIOS_EVENT_ACQUIRED timeout is used
   162         *  with a Semaphore that has not been configured with an Event object
   163         */
   164        config Assert.Id A_invTimeout = {
   165            msg: "A_invTimeout: Can't use BIOS_EVENT_ACQUIRED with this Semaphore."
   166        };
   167    
   168        /*!
   169         * Asserted when {@link #pend} is called with non-zero timeout from other
   170         * than a Task context.
   171         */
   172        config Assert.Id A_badContext = {
   173            msg: "A_badContext: bad calling context. Must be called from a Task."
   174        };
   175    
   176        /*! Support Semaphores with Events? Default is false. */
   177        config Bool supportsEvents = false;
   178    
   179    instance:
   180    
   181        /*!
   182         *  ======== create ========
   183         *  Create a Semaphore object.
   184         *
   185         *  This function creates a new Semaphore object which is initialized to
   186         *  count.
   187         *
   188         *  @param(count)                   initial semaphore count
   189         */
   190        create(Int count);
   191    
   192        /*!
   193         *  ======== event ========
   194         *  event if using Events. Default is null.
   195         *
   196         *  If event is non-null:
   197         * 
   198         *  Event_post(sem->event, sem->eventId) will be invoked when 
   199         *  Semaphore_post() is called.
   200         *
   201         *  Event_pend(sem->event, 0, sem->eventId, timeout) will be 
   202         *  invoked when Semaphore_pend() is called.
   203         */
   204        config Event.Handle event = null;
   205    
   206        /*!
   207         *  ======== eventId ========
   208         *  eventId if using Events. Default is 1.
   209         */
   210        config UInt eventId = 1;
   211    
   212        /*! 
   213         *  ======== mode ========
   214         *  Semaphore mode. Default is COUNTING.
   215         *
   216         *  When mode is BINARY , the semaphore has only two states, available
   217         *  and unavailable. When mode is COUNTING, the semaphore keeps track of
   218         *  number of times a semaphore is posted.
   219         */
   220        config Mode mode = Mode_COUNTING;
   221    
   222        /*!
   223         *  ======== getCount ========
   224         *  Get current semaphore count.
   225         *
   226         *  This function returns the current value of the semaphore specified by
   227         *  the handle.
   228         *
   229         *  @b(returns)             current semaphore count
   230         */
   231        Int getCount();
   232    
   233        /*!
   234         *  ======== pend ========
   235         *  Wait for a semaphore.
   236         *
   237         *  If the semaphore count is greater than zero (available), this function
   238         *  decrements the count and returns TRUE. If the semaphore count is zero
   239         *  (unavailable), this function suspends execution of the current task 
   240         *  until post() is called or the timeout expires.
   241         *
   242         *  A timeout value of 
   243         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   244         *  the task to wait indefinitely for its semaphore to be posted. 
   245         *
   246         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   247         *  causes Semaphore_pend to return immediately. 
   248         *
   249         *  @param(timeout)                 return after this many system time units
   250         *
   251         *  @b(returns)                     TRUE if successful, FALSE if timeout
   252         */
   253        Bool pend(UInt timeout);
   254    
   255        /*!
   256         *  ======== post ========
   257         *  Signal a semaphore.
   258         *
   259         *  Readies the first task waiting for the semaphore. If no task is
   260         *  waiting, This function simply increments the semaphore count and returns
   261         *  In case of binary semaphore the count has a maximum value of one.
   262         */
   263        Void post();
   264    
   265        /*!
   266         *  ======== registerEvent ========
   267         *  Register an Event Object with a semaphore.
   268         *
   269         *  Ordinarily, an Event object and eventId are configured at 
   270         *  Semaphore create time.
   271         *
   272         *  This API is provided so that Semaphore-using middleware
   273         *  can support implicit Event posting without having to be
   274         *  retrofitted.
   275         *
   276         *  After the Event object and eventId are registered with the
   277         *  Semaphore:
   278    
   279         *  Event_post(event, eventId) will be invoked when 
   280         *  Semaphore_post(sem) is called.
   281         *
   282         *  Event_pend(event, eventId, 0, timeout) will be invoked when 
   283         *  Semaphore_pend(sem, timeout) is called.
   284         *
   285         *  @param(event)                     Ptr to Event Object
   286         *  @param(eventId)                   Event ID
   287         *
   288         */
   289        Void registerEvent(Event.Handle event, UInt eventId);
   290    
   291        /*!
   292         *  ======== reset ========
   293         *  @_nodoc
   294         *  Reset semaphore count.
   295         *
   296         *  Resets the semaphore count to count.
   297         *
   298         *  @param(count)                   semaphore count
   299         *
   300         */
   301        Void reset(Int count);
   302    
   303    internal:
   304    
   305        /* 
   306         * Event module function pointers. Used to decouple
   307         * Semaphore from Event when supportsEvents is false
   308         */
   309        config Void (*eventPost)(Event.Handle, UInt);
   310    
   311        config Void (*eventSync)(Event.Handle, UInt, UInt);
   312    
   313        /*!
   314         *  ======== pendTimeout ========
   315         *  This function is the clock event handler for pend
   316         */
   317        Void pendTimeout(UArg arg);
   318    
   319        /* pendQ Element PendStates */
   320        enum PendState {
   321            PendState_TIMEOUT = 0,          /* Clock timeout */
   322            PendState_POSTED = 1,           /* posted by post */
   323            PendState_CLOCK_WAIT = 2,       /* in Clock queue */
   324            PendState_WAIT_FOREVER = 3      /* not in Clock queue */
   325        };
   326        
   327        /* Semaphore pendQ Element */
   328        struct PendElem {
   329            Queue.Elem              qElem;
   330            Task.Handle             task;
   331            PendState               pendState;
   332            Clock.Handle            clock;
   333        };
   334    
   335        struct Instance_State {
   336            Event.Handle            event;
   337            UInt                    eventId;
   338            Mode                    mode;   /* binary or counting */
   339            volatile UInt16         count;  /* curr semaphore count */
   340            Queue.Object            pendQ;  /* queue of PendElems */
   341        };
   342    }
   343    /*
   344     *  @(#) ti.sysbios.ipc; 2, 0, 0, 0,348; 12-18-2009 15:13:00; /db/vtree/library/trees/avala/avala-m19x/src/
   345     */
   346