Home | History | Annotate | Download | only in utils
      1 /*
      2  * queue.c
      3  *
      4  * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  *  * Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *  * Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *  * Neither the name Texas Instruments nor the names of its
     18  *    contributors may be used to endorse or promote products derived
     19  *    from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 
     35 
     36 /** \file   queue.c
     37  *  \brief  This module provides generic queueing services, including enqueue, dequeue
     38  *            and requeue of any object that contains TQueNodeHdr in its structure.
     39  *
     40  *  \see    queue.h
     41  */
     42 
     43 
     44 
     45 #define __FILE_ID__  FILE_ID_130
     46 #include "report.h"
     47 #include "queue.h"
     48 
     49 
     50 /* Queue structure */
     51 typedef struct
     52 {
     53     TQueNodeHdr tHead;          /* The queue first node */
     54     TI_UINT32   uCount;         /* Current number of nodes in queue */
     55     TI_UINT32   uLimit;         /* Upper limit of nodes in queue */
     56     TI_UINT32   uMaxCount;      /* Maximum uCount value (for debug) */
     57     TI_UINT32   uOverflow;      /* Number of overflow occurences - couldn't insert node (for debug) */
     58     TI_UINT32   uNodeHeaderOffset; /* Offset of NodeHeader field from the entry of the queued item */
     59 	TI_HANDLE   hOs;
     60 	TI_HANDLE   hReport;
     61 } TQueue;
     62 
     63 
     64 
     65 /*
     66  *              INTERNAL  FUNCTIONS
     67  *        ===============================
     68  */
     69 
     70 
     71 /*
     72  *  InsertNode():  Insert new node between pPrev and pNext
     73  */
     74 static INLINE void InsertNode( TQueNodeHdr *pNode, TQueNodeHdr *pPrev, TQueNodeHdr *pNext)
     75 {
     76 	pNext->pPrev = pNode;
     77 	pNode->pNext = pNext;
     78 	pNode->pPrev = pPrev;
     79 	pPrev->pNext = pNode;
     80 }
     81 
     82 /*
     83  *  RemoveNode():  Remove node from between pPrev and pNext
     84  */
     85 static INLINE void RemoveNode( TQueNodeHdr *pPrev, TQueNodeHdr *pNext)
     86 {
     87 	pNext->pPrev = pPrev;
     88 	pPrev->pNext = pNext;
     89 }
     90 
     91 /*
     92  *  AddToHead():  Add node to queue head (last in queue)
     93  */
     94 static INLINE void AddToHead( TQueNodeHdr *pNode, TQueNodeHdr *pListHead)
     95 {
     96 	InsertNode (pNode, pListHead, pListHead->pNext);
     97 }
     98 
     99 /*
    100  *  AddToTail():  Add node to queue tail (first in queue)
    101  */
    102 static INLINE void AddToTail( TQueNodeHdr *pNode, TQueNodeHdr *pListHead)
    103 {
    104 	InsertNode( pNode, pListHead->pPrev, pListHead );
    105 }
    106 
    107 /*
    108  *  DelFromTail():  Delete node from queue tail (first in queue)
    109  */
    110 static INLINE void DelFromTail (TQueNodeHdr *pNode)
    111 {
    112 	RemoveNode (pNode->pPrev, pNode->pNext);
    113 }
    114 
    115 
    116 
    117 /*
    118  *              EXTERNAL  FUNCTIONS
    119  *        ===============================
    120  */
    121 
    122 
    123 /**
    124  * \fn     que_Create
    125  * \brief  Create a queue.
    126  *
    127  * Allocate and init a queue object.
    128  *
    129  * \note
    130  * \param  hOs               - Handle to Os Abstraction Layer
    131  * \param  hReport           - Handle to report module
    132  * \param  uLimit            - Maximum items to store in queue
    133  * \param  uNodeHeaderOffset - Offset of NodeHeader field from the entry of the queued item.
    134  * \return Handle to the allocated queue
    135  * \sa     que_Destroy
    136  */
    137 TI_HANDLE que_Create (TI_HANDLE hOs, TI_HANDLE hReport, TI_UINT32 uLimit, TI_UINT32 uNodeHeaderOffset)
    138 {
    139 	TQueue *pQue;
    140 
    141 	/* allocate queue module */
    142 	pQue = os_memoryAlloc (hOs, sizeof(TQueue));
    143 
    144 	if (!pQue)
    145 	{
    146 		WLAN_OS_REPORT (("Error allocating the Queue Module\n"));
    147 		return NULL;
    148 	}
    149 
    150     os_memoryZero (hOs, pQue, sizeof(TQueue));
    151 
    152 	/* Intialize the queue header */
    153     pQue->tHead.pNext = pQue->tHead.pPrev = &pQue->tHead;
    154 
    155 	/* Set the Queue parameters */
    156     pQue->hOs               = hOs;
    157     pQue->hReport           = hReport;
    158 	pQue->uLimit            = uLimit;
    159 	pQue->uNodeHeaderOffset = uNodeHeaderOffset;
    160 
    161 	return (TI_HANDLE)pQue;
    162 }
    163 
    164 
    165 /**
    166  * \fn     que_Destroy
    167  * \brief  Destroy the queue.
    168  *
    169  * Free the queue memory.
    170  *
    171  * \note   The queue's owner should first free the queued items!
    172  * \param  hQue - The queue object
    173  * \return TI_OK on success or TI_NOK on failure
    174  * \sa     que_Create
    175  */
    176 TI_STATUS que_Destroy (TI_HANDLE hQue)
    177 {
    178     TQueue *pQue = (TQueue *)hQue;
    179 
    180     if (pQue)
    181 	{
    182         /* Alert if the queue is unloaded before it was cleared from items */
    183         if (pQue->uCount)
    184         {
    185             TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING, "que_Destroy() Queue Not Empty!!");
    186         }
    187         /* free Queue object */
    188         os_memoryFree (pQue->hOs, pQue, sizeof(TQueue));
    189     }
    190 
    191     return TI_OK;
    192 }
    193 
    194 
    195 /**
    196  * \fn     que_Init
    197  * \brief  Init required handles
    198  *
    199  * Init required handles.
    200  *
    201  * \note
    202  * \param  hQue      - The queue object
    203  * \param  hOs       - Handle to Os Abstraction Layer
    204  * \param  hReport   - Handle to report module
    205  * \return TI_OK on success or TI_NOK on failure
    206  * \sa
    207  */
    208 TI_STATUS que_Init (TI_HANDLE hQue, TI_HANDLE hOs, TI_HANDLE hReport)
    209 {
    210 	TQueue *pQue = (TQueue *)hQue;
    211 
    212     pQue->hOs = hOs;
    213     pQue->hReport = hReport;
    214 
    215 	return TI_OK;
    216 }
    217 
    218 
    219 /**
    220  * \fn     que_Enqueue
    221  * \brief  Enqueue an item
    222  *
    223  * Enqueue an item at the queue's head (last in queue).
    224  *
    225  * \note
    226  * \param  hQue   - The queue object
    227  * \param  hItem  - Handle to queued item
    228  * \return TI_OK if item was queued, or TI_NOK if not queued due to overflow
    229  * \sa     que_Dequeue, que_Requeue
    230  */
    231 TI_STATUS que_Enqueue (TI_HANDLE hQue, TI_HANDLE hItem)
    232 {
    233 	TQueue      *pQue = (TQueue *)hQue;
    234     TQueNodeHdr *pQueNodeHdr;  /* the Node-Header in the given item */
    235 
    236     if (pQue)
    237 	{
    238             /* Check queue limit */
    239             if(pQue->uCount < pQue->uLimit)
    240             {
    241                 /* Find NodeHeader in the given item */
    242                 pQueNodeHdr = (TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset);
    243 
    244                 /* Verify that pNext is NULL --> Sanity check that this item is not already linked to a queue */
    245                 if (pQueNodeHdr->pNext)
    246                 {
    247                     /* Not an error since we have a case where a timer may expire twice in a row (in TxDataQueue) */
    248                     TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING, "que_Enqueue(): Trying to enqueue an item that is already enqueued!!");
    249                     return TI_NOK;
    250                 }
    251 
    252                 /* Enqueue item and increment items counter */
    253                 AddToHead (pQueNodeHdr, &pQue->tHead);
    254                 pQue->uCount++;
    255 
    256 #ifdef TI_DBG
    257                     if (pQue->uCount > pQue->uMaxCount)
    258                     {
    259                         pQue->uMaxCount = pQue->uCount;
    260                     }
    261                     TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Enqueue(): Enqueued Successfully\n");
    262 #endif
    263 
    264                 return TI_OK;
    265             }
    266 
    267         /*
    268          *  Queue is overflowed, return TI_NOK.
    269          */
    270 #ifdef TI_DBG
    271         pQue->uOverflow++;
    272         TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING , "que_Enqueue(): Queue Overflow\n");
    273 #endif
    274     }
    275 	return TI_NOK;
    276 }
    277 
    278 
    279 /**
    280  * \fn     que_Dequeue
    281  * \brief  Dequeue an item
    282  *
    283  * Dequeue an item from the queue's tail (first in queue).
    284  *
    285  * \note
    286  * \param  hQue - The queue object
    287  * \return pointer to dequeued item or NULL if queue is empty
    288  * \sa     que_Enqueue, que_Requeue
    289  */
    290 TI_HANDLE que_Dequeue (TI_HANDLE hQue)
    291 {
    292     TQueue   *pQue = (TQueue *)hQue;
    293 	TI_HANDLE hItem;
    294 
    295     if (pQue)
    296     {
    297         if (pQue->uCount)
    298         {
    299             /* Queue is not empty, take packet from the queue tail */
    300 
    301             /* find pointer to the node entry */
    302             hItem = (TI_HANDLE)((TI_UINT8*)pQue->tHead.pPrev - pQue->uNodeHeaderOffset);
    303 
    304             DelFromTail (pQue->tHead.pPrev);    /* remove node from the queue */
    305             pQue->uCount--;
    306 
    307 #ifdef TI_DBG
    308             /* Clear the pNext so we can do a sanity check when enqueuing this structre in the future */
    309             ((TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset))->pNext = NULL;
    310 #endif
    311 
    312             return (hItem);
    313         }
    314     }
    315 
    316 	/* Queue is empty */
    317     TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Dequeue(): Queue is empty\n");
    318     return NULL;
    319 }
    320 
    321 
    322 /**
    323  * \fn     que_Requeue
    324  * \brief  Requeue an item
    325  *
    326  * Requeue an item at the queue's tail (first in queue).
    327  *
    328  * \note
    329  * \param  hQue   - The queue object
    330  * \param  hItem  - Handle to queued item
    331  * \return TI_OK if item was queued, or TI_NOK if not queued due to overflow
    332  * \sa     que_Enqueue, que_Dequeue
    333  */
    334 TI_STATUS que_Requeue (TI_HANDLE hQue, TI_HANDLE hItem)
    335 {
    336     TQueue      *pQue = (TQueue *)hQue;
    337     TQueNodeHdr *pQueNodeHdr;  /* the NodeHeader in the given item */
    338 
    339     /*
    340 	 *  If queue's limits not exceeded add the packet to queue's tail and return TI_OK
    341 	 */
    342     if (pQue->uCount < pQue->uLimit)
    343 	{
    344         /* Find NodeHeader in the given item */
    345         pQueNodeHdr = (TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset);
    346 
    347         /* Verify that pNext is NULL --> Sanity check that this item is not already linked to a queue */
    348         if (pQueNodeHdr->pNext)
    349         {
    350             TRACE0(pQue->hReport, REPORT_SEVERITY_ERROR, "que_Requeue(): Trying to Requeue an item that is already enqueued!!");
    351             return TI_NOK;
    352         }
    353 
    354         /* Enqueue item and increment items counter */
    355 		AddToTail (pQueNodeHdr, &pQue->tHead);
    356 		pQue->uCount++;
    357 
    358 #ifdef TI_DBG
    359 		if (pQue->uCount > pQue->uMaxCount)
    360 			pQue->uMaxCount = pQue->uCount;
    361 TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Requeue(): Requeued successfully\n");
    362 #endif
    363 
    364 		return TI_OK;
    365     }
    366 
    367 
    368 	/*
    369 	 *  Queue is overflowed, return TI_NOK.
    370 	 *  Note: This is not expected in the current design, since Tx packet may be requeued
    371 	 *          only right after it was dequeued in the same context so the queue can't be full.
    372 	 */
    373 #ifdef TI_DBG
    374     pQue->uOverflow++;
    375 TRACE0(pQue->hReport, REPORT_SEVERITY_ERROR , "que_Requeue(): Queue Overflow\n");
    376 #endif
    377 
    378     return TI_NOK;
    379 }
    380 
    381 
    382 /**
    383  * \fn     que_Size
    384  * \brief  Return queue size
    385  *
    386  * Return number of items in queue.
    387  *
    388  * \note
    389  * \param  hQue - The queue object
    390  * \return TI_UINT32 - the items count
    391  * \sa
    392  */
    393 TI_UINT32 que_Size (TI_HANDLE hQue)
    394 {
    395     TQueue *pQue = (TQueue *)hQue;
    396 
    397     return (pQue->uCount);
    398 }
    399 
    400 
    401 /**
    402  * \fn     que_Print
    403  * \brief  Print queue status
    404  *
    405  * Print the queue's parameters (not the content).
    406  *
    407  * \note
    408  * \param  hQue - The queue object
    409  * \return void
    410  * \sa
    411  */
    412 
    413 #ifdef TI_DBG
    414 
    415 void que_Print(TI_HANDLE hQue)
    416 {
    417 #ifdef REPORT_LOG
    418     TQueue *pQue = (TQueue *)hQue;
    419 
    420     WLAN_OS_REPORT(("que_Print: Count=%u MaxCount=%u Limit=%u Overflow=%u NodeHeaderOffset=%u Next=0x%x Prev=0x%x\n",
    421                     pQue->uCount, pQue->uMaxCount, pQue->uLimit, pQue->uOverflow,
    422                     pQue->uNodeHeaderOffset, pQue->tHead.pNext, pQue->tHead.pPrev));
    423 #endif
    424 }
    425 
    426 #endif /* TI_DBG */
    427