1    /*
     2     * Copyright (c) 2013-2019, 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     *  ======== Queue.xdc ========
    34     *
    35     */
    36    package ti.sysbios.knl;
    37    
    38    import xdc.rov.ViewInfo;
    39    
    40    /*!
    41     *  ======== Queue ========
    42     *  Queue manager.
    43     *
    44     *  The Queue module makes available a set of functions that manipulate
    45     *  queue objects accessed through handles of type Queue_Handle.
    46     *  Each queue contains a linked sequence of zero or more elements
    47     *  referenced through variables of type Queue_Elem, which are
    48     *  embedded as the first field within a structure.
    49     *
    50     *  In the Queue API descriptions, the APIs which disable interrupts before 
    51     *  modifying the Queue are noted as "atomic", while APIs that do not disable
    52     *  interrupts are "non-atomic".
    53     *
    54     *  Queues are represented as doubly-linked lists, so calls to Queue_next 
    55     *  or Queue_prev can loop continuously over the Queue. The following code
    56     *  demonstrates one way to iterate over a Queue once from beginning to end.
    57     *  In this example, 'myQ' is a Queue_Handle. 
    58     *  
    59     *  @p(code)
    60     *  Queue_Elem *elem;
    61     *
    62     *  for (elem = Queue_head(myQ); 
    63     *      elem != (Queue_Elem *)myQ; 
    64     *      elem = Queue_next(elem)) {
    65     *      ...
    66     *  }
    67     *  @p
    68     * 
    69     *  Below is a simple example of how to create a Queue, enqueue two elements,
    70     *  and dequeue the elements until the queue is empty:
    71     *
    72     *  @p(code)
    73     *  #include <xdc/std.h>
    74     *  #include <xdc/runtime/System.h>
    75     *  
    76     *  #include <ti/sysbios/knl/Queue.h>
    77     *  
    78     *  typedef struct Rec {
    79     *      Queue_Elem _elem;
    80     *      Int data;
    81     *  } Rec;
    82     *  
    83     *  Int main(Int argc, Char *argv[])
    84     *  {
    85     *      Queue_Handle q;
    86     *      Rec r1, r2;
    87     *      Rec* rp;
    88     *  
    89     *      r1.data = 100;
    90     *      r2.data = 200;
    91     *  
    92     *  
    93     *      // create a Queue instance 'q'
    94     *      q = Queue_create(NULL, NULL);
    95     *  
    96     *  
    97     *      // enQ a couple of records
    98     *      Queue_enqueue(q, &r1._elem);
    99     *      Queue_enqueue(q, &r2._elem);
   100     *  
   101     *  
   102     *      // deQ the records and print their data values until Q is empty
   103     *      while (!Queue_empty(q)) {
   104     *          rp = Queue_dequeue(q);
   105     *          System_printf("rec: %d\n", rp->data);
   106     *      }
   107     *  
   108     *      System_exit(0);
   109     *      return (0);
   110     *  }
   111     *  @p
   112     *
   113     *
   114     *
   115     *  Unconstrained Functions
   116     *  All functions are unconstrained
   117     *
   118     *  @p(html)
   119     *  <h3> Calling Context </h3>
   120     *  <table border="1" cellpadding="3">
   121     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
   122     *    </colgroup>
   123     *
   124     *    <tr><th> Function                 </th><th>  Hwi   </th><th>  Swi   </th>
   125     *    <th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
   126     *    <!--                                                        -->
   127     *    <tr><td> {@link #create}          </td><td>   N    </td><td>   N    </td>
   128     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   129     *    <tr><td> {@link #insert}          </td><td>   Y    </td><td>   Y    </td>
   130     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   131     *    <tr><td> {@link #next}            </td><td>   Y    </td><td>   Y    </td>
   132     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   133     *    <tr><td> {@link #Params_init}     </td><td>   Y    </td><td>   Y    </td>
   134     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   135     *    <tr><td> {@link #prev}            </td><td>   Y    </td><td>   Y    </td>
   136     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   137     *    <tr><td> {@link #remove}          </td><td>   Y    </td><td>   Y    </td>
   138     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   139     *    <tr><td> {@link #construct}       </td><td>   Y    </td><td>   Y    </td>
   140     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   141     *    <tr><td> {@link #delete}          </td><td>   N    </td><td>   N    </td>
   142     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   143     *    <tr><td> {@link #dequeue}         </td><td>   Y    </td><td>   Y    </td>
   144     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   145     *    <tr><td> {@link #destruct}        </td><td>   Y    </td><td>   Y    </td>
   146     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   147     *    <tr><td> {@link #empty}           </td><td>   Y    </td><td>   Y    </td>
   148     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   149     *    <tr><td> {@link #enqueue}         </td><td>   Y    </td><td>   Y    </td>
   150     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   151     *    <tr><td> {@link #get}                     </td><td>   Y    </td><td>   Y    </td>
   152     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   153     *    <tr><td> {@link #head}            </td><td>   Y    </td><td>   Y    </td>
   154     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   155     *    <tr><td> {@link #put}                     </td><td>   Y    </td><td>   Y    </td>
   156     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   157     *    <tr><td colspan="6"> Definitions: <br />
   158     *       <ul>
   159     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   160     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   161     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   162     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   163     *           <ul>
   164     *             <li> In your module startup after this module is started 
   165     *    (e.g. Queue_Module_startupDone() returns TRUE). </li>
   166     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   167     *             <li> During main().</li>
   168     *             <li> During BIOS.startupFxns.</li>
   169     *           </ul>
   170     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   171     *           <ul>
   172     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   173     *             <li> In your module startup before this module is started 
   174     *    (e.g. Queue_Module_startupDone() returns FALSE).</li>
   175     *           </ul>
   176     *       </ul>
   177     *    </td></tr>
   178     *
   179     *  </table>
   180     *  @p
   181     */
   182    
   183    @DirectCall
   184    /* REQ_TAG(SYSBIOS-485) */
   185    @InstanceInitStatic /* Construct/Destruct CAN be called at runtime */
   186    module Queue
   187    {
   188    
   189        /*!
   190         *  ======== BasicView ========
   191         *  @_nodoc
   192         */
   193        metaonly struct BasicView {
   194            String  label;
   195            Ptr     elems[];
   196        }
   197        
   198        /*!
   199         *  ======== rovViewInfo ========
   200         *  @_nodoc
   201         */
   202        @Facet
   203        metaonly config ViewInfo.Instance rovViewInfo = 
   204            ViewInfo.create({
   205                viewMap: [
   206                    ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitInstance', structName: 'BasicView'}]
   207                ]
   208            });
   209        
   210        /*!
   211         *  ======== Elem ========
   212         *  Opaque queue element.
   213         *
   214         *  A field of this type is placed at the head of client structs.
   215         */
   216        /* REQ_TAG(SYSBIOS-487) */
   217        struct Elem {
   218            Elem *volatile next;
   219            Elem *volatile prev;
   220        };
   221    
   222        /*!
   223         *  @_nodoc
   224         *  ======== elemClear ========
   225         *  Clears a Queue element's pointers so that if isQueued() is called on
   226         *  the element it will return FALSE. When a Queue element is dequeued or
   227         *  removed from a Queue, this API must be called on the element for 
   228         *  isQueued() to return FALSE.     
   229         *
   230         *  To be clear, this API is not for removing elements from a queue, and
   231         *  should never be called on an element in a queue--only on dequeued 
   232         *  elements.
   233         *
   234         *  @param(qelem)           element to be cleared
   235         */
   236        Void elemClear(Elem *qelem); 
   237    
   238        /*!
   239         *  ======== elemClearMeta ========
   240         *  @_nodoc
   241         *  Clears a Queue element's pointers so that if isQueued() is called on
   242         *  the element it will return FALSE. When a Queue element is dequeued or
   243         *  removed from a Queue, this API must be called on the element for 
   244         *  isQueued() to return FALSE.     
   245         *
   246         *  To be clear, this API is not for removing elements from a queue, and
   247         *  should never be called on an element in a queue--only on dequeued 
   248         *  elements.
   249         *
   250         *  @param(qelem)           element to be cleared
   251         */
   252        metaonly Void elemClearMeta(Elem *qelem); 
   253    
   254        /*!
   255         *  ======== insert ========
   256         *  Insert `elem` in the queue in front of `qelem`.
   257         *
   258         *  @param(qelem)           element already in queue
   259         *
   260         *  @param(elem)            element to be inserted in queue
   261         */
   262        /* REQ_TAG(SYSBIOS-497) */
   263        Void insert(Elem *qelem, Elem *elem); 
   264    
   265        /*!
   266         *  ======== insertMeta ========
   267         *  @_nodoc
   268         *  Insert `elem` in the queue in front of `qelem`.
   269         *
   270         *  @param(qelem)           element already in queue
   271         *
   272         *  @param(elem)            element to be inserted in queue
   273         */
   274        metaonly Void insertMeta(Elem *qelem, Elem *elem); 
   275    
   276        /*!
   277         *  ======== next ========
   278         *  Return next element in queue (non-atomically).
   279         *
   280         *  This function returns a pointer to an Elem object in the queue 
   281         *  after `qelem`. A Queue is represented internally as a doubly-linked
   282         *  list, so 'next' can be called in a continuous loop over the queue.
   283         *  See the module description for an example of iterating once over a
   284         *  Queue.
   285         *
   286         *  @param(qelem)           element in queue
   287         *
   288         *  @b(returns)             next element in queue
   289         */
   290        /* REQ_TAG(SYSBIOS-498) */
   291        Ptr next(Elem *qelem);
   292    
   293        /*!
   294         *  ======== prev ========
   295         *  Return previous element in queue (non-atomically).
   296         *
   297         *  This function returns a pointer to an Elem object in the queue 
   298         *  before `qelem`. A Queue is represented internally as a doubly-linked
   299         *  list, so 'prev' can be called in a continuous loop over the queue.
   300         *  See the module description for an example of iterating once over a
   301         *  Queue.
   302         *
   303         *  @param(qelem)           element in queue
   304         *
   305         *  @b(returns)             previous element in queue
   306         */
   307        /* REQ_TAG(SYSBIOS-499) */
   308        Ptr prev(Elem *qelem);
   309    
   310        /*!
   311         *  ======== remove ========
   312         *  Remove qelem from middle of queue (non-atomically).
   313         *
   314         *  The `qelem` parameter is a pointer to an existing element to be removed
   315         *  from the Queue.
   316         *
   317         *  @param(qelem)           element in queue
   318         */
   319        Void remove (Elem *qelem);
   320    
   321        /*!
   322         *  @_nodoc
   323         *  ======== isQueued ========
   324         *  Check if the elem is on any queue. 
   325         *  
   326         *  In order for this API to return false on an element that has been
   327         *  dequeued or removed from a Queue, elemClear must have been called on
   328         *  the element.
   329         *
   330         *  @param(qelem)           element in queue
   331         */
   332        Bool isQueued (Elem *qelem);
   333    
   334    instance:
   335        /* REQ_TAG(SYSBIOS-486) */
   336    
   337        /*!
   338         *  @_nodoc
   339         *  Added to get the Grace instance view to work.
   340         */
   341        metaonly config UInt dummy = 0;
   342    
   343        /*!
   344         *  ======== create ========
   345         *  Create a Queue object
   346         */
   347        create();
   348    
   349        /*!
   350         *  ======== dequeue ========
   351         *  Remove the element from the front of queue and return elem
   352         *  (non-atomically).
   353         *
   354         *  This function removes an element from the front of a queue and returns
   355         *  it.
   356         *
   357         *  If called with an empty queue, this function will return a pointer to
   358         *  the queue itself.
   359         *
   360         *  @a(note) As this function is non-atomic, the method for detecting an
   361         *  empty Queue as shown in {@link #get Queue_get()} isn't reliable in
   362         *  a multi-threaded system. Thread safety can be achieved as shown below:
   363         *
   364         *  @p(code)
   365         *  key = Hwi_disable();
   366         *
   367         *  if ((Queue_Handle)(elem = Queue_dequeue(q)) != q) {
   368         *      ` process elem `
   369         *  }
   370         *
   371         *  Hwi_restore(key);
   372         *  @p
   373         *
   374         *  @b(returns)             pointer to former first element
   375         */
   376        /* REQ_TAG(SYSBIOS-488) */
   377        Ptr dequeue();
   378    
   379        /*!
   380         *  ======== empty ========
   381         *  Test for an empty queue.
   382         *
   383         *  @b(returns)             TRUE if this queue is empty
   384         */
   385        /* REQ_TAG(SYSBIOS-494) */
   386        Bool empty();
   387    
   388        /*!
   389         *  ======== enqueue ========
   390         *  Insert at end of queue (non-atomically).
   391         *
   392         *  @param(elem)            pointer to an element
   393         */
   394        /* REQ_TAG(SYSBIOS-492) */
   395        Void enqueue(Elem *elem);
   396    
   397        /*!
   398         *  ======== get ========
   399         *  Get element from front of queue (atomically).
   400         *
   401         *  This function removes an element from the front of a queue and returns
   402         *  it.
   403         *
   404         *  If called with an empty queue, this function will return a pointer to
   405         *  the queue itself.
   406         *  This provides a means for using a single atomic action to check if a
   407         *  queue is empty, and to remove and return the first element if it is
   408         *  not empty:
   409         *
   410         *  @p(code)
   411         *  if ((Queue_Handle)(elem = Queue_get(q)) != q) {
   412         *      ` process elem `
   413         *  }
   414         *  @p
   415         *
   416         *  @b(returns)             pointer to former first element
   417         */
   418        /* REQ_TAG(SYSBIOS-489) */
   419        Ptr get();
   420    
   421        /*!
   422         *  ======== getTail ========
   423         *  Get the element at the end of the queue (atomically).
   424         *
   425         *  This function removes the element at the end of a queue and returns
   426         *  a pointer to it.  
   427         *  If called with an empty queue, this function will return a pointer to
   428         *  the queue itself.
   429         *  This provides a means for using a single atomic action to check if a
   430         *  queue is empty, and to remove and return the last element if it is
   431         *  not empty:
   432         *
   433         *  @p(code)
   434         *  if ((Queue_Handle)(elem = Queue_getTail(q)) != q) {
   435         *      `process elem`
   436         *  }
   437         *  @p
   438         *
   439         *  @b(returns)             pointer to former end element
   440         */
   441        /* REQ_TAG(SYSBIOS-496) */
   442        Ptr getTail();
   443    
   444        /*!
   445         *  ======== head ========
   446         *  Return element at front of queue. (atomically)
   447         *
   448         *  This function returns a pointer to the element at the front of a queue.
   449         *  The element is not removed from the queue.
   450         *  If called with an empty queue, this function will return a pointer to
   451         *  the queue itself.
   452         *  This provides a means for using a single atomic action to check if a queue
   453         *  is empty, and to return a pointer to the first element if it is not empty:
   454         *
   455         *  @p(code)
   456         *  if ((Queue_Handle)(elem = Queue_head(q)) != q) {
   457         *      `process elem`
   458         *  @p
   459         *
   460         *  @b(returns)             pointer to first element
   461         */
   462        Ptr head();
   463    
   464        /*!
   465         *  ======== headMeta ========
   466         *  @_nodoc
   467         *  Return element at front of queue. Returns null if queue is empty.
   468         *
   469         *  This function returns a pointer to the element at the front of queue.
   470         *  The element is not removed from the queue.
   471         *
   472         *  @b(returns)             pointer to first element
   473         */
   474        metaonly Ptr headMeta();
   475    
   476        /*!
   477         *  ======== put ========
   478         *  Put element at end of queue (atomically).
   479         *
   480         *  @param(elem)            pointer to new queue element
   481         */
   482        /* REQ_TAG(SYSBIOS-493) */
   483        Void put(Elem *elem);
   484        
   485        /*!
   486         *  ======== putMeta ========
   487         *  @_nodoc
   488         *  Put element at end of queue.
   489         *
   490         *  @param(elem)            pointer to new queue element
   491         */
   492        metaonly Void putMeta(Elem* elem);
   493    
   494        /*!
   495         *  ======== putHead ========
   496         *  Put element at the front of the queue (atomically).
   497         *
   498         *  @param(elem)            pointer to new queue element
   499         */
   500        /* REQ_TAG(SYSBIOS-491) */
   501        Void putHead(Elem *elem);
   502    
   503        /*!
   504         *  ======== nextMeta ========
   505         *  @_nodoc
   506         *  Return next element in queue. Returns null if end of queue.
   507         *
   508         *  This function returns a pointer to an Elem object in the queue 
   509         *  after `qelem`.
   510         *
   511         *  @param(qelem)           element in queue
   512         *
   513         *  @b(returns)             next element in queue
   514         */
   515        metaonly Ptr nextMeta(Elem *qelem);
   516    
   517    internal:   // not for client use
   518    
   519        // instance object
   520        struct Instance_State {
   521                Elem elem;
   522        };
   523    }