对比新文件 |
| | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \file wsf_queue.c |
| | | * |
| | | * \brief General purpose queue service. |
| | | * |
| | | * Copyright (c) 2009-2018 Arm Ltd. All Rights Reserved. |
| | | * |
| | | * Copyright (c) 2019-2020 Packetcraft, Inc. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | |
| | | #include "wsf_types.h" |
| | | #include "wsf_queue.h" |
| | | |
| | | #include "wsf_assert.h" |
| | | #include "wsf_cs.h" |
| | | |
| | | /************************************************************************************************** |
| | | Macros |
| | | **************************************************************************************************/ |
| | | |
| | | /* Get next queue element */ |
| | | #define WSF_QUEUE_NEXT(p) (((wsfQueueElem_t *)(p))->pNext) |
| | | |
| | | /************************************************************************************************** |
| | | Data Types |
| | | **************************************************************************************************/ |
| | | |
| | | /* Queue element */ |
| | | typedef struct wsfQueueElem_tag |
| | | { |
| | | struct wsfQueueElem_tag *pNext; /* pointer to next element */ |
| | | } wsfQueueElem_t; |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Enqueue and element to the tail of a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * \param pElem Pointer to element. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | void WsfQueueEnq(wsfQueue_t *pQueue, void *pElem) |
| | | { |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | WSF_ASSERT(pElem != NULL); |
| | | |
| | | /* initialize next pointer */ |
| | | WSF_QUEUE_NEXT(pElem) = NULL; |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | /* if queue empty */ |
| | | if (pQueue->pHead == NULL) |
| | | { |
| | | pQueue->pHead = pElem; |
| | | pQueue->pTail = pElem; |
| | | } |
| | | /* else enqueue element to the tail of queue */ |
| | | else |
| | | { |
| | | WSF_QUEUE_NEXT(pQueue->pTail) = pElem; |
| | | pQueue->pTail = pElem; |
| | | } |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Peek the head of a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * |
| | | * \return Pointer to element that has been dequeued or NULL if queue is empty. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | void *WsfQueuePeek(wsfQueue_t *pQueue) |
| | | { |
| | | wsfQueueElem_t *pElem; |
| | | |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | pElem = pQueue->pHead; |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | |
| | | return pElem; |
| | | } |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Dequeue and element from the head of a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * |
| | | * \return Pointer to element that has been dequeued or NULL if queue is empty. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | void *WsfQueueDeq(wsfQueue_t *pQueue) |
| | | { |
| | | wsfQueueElem_t *pElem; |
| | | |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | pElem = pQueue->pHead; |
| | | |
| | | /* if queue is not empty */ |
| | | if (pElem != NULL) |
| | | { |
| | | /* set head to next element in queue */ |
| | | pQueue->pHead = WSF_QUEUE_NEXT(pElem); |
| | | |
| | | /* check for empty queue */ |
| | | if (pQueue->pHead == NULL) |
| | | { |
| | | pQueue->pTail = NULL; |
| | | } |
| | | } |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | |
| | | return pElem; |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Push an element to the head of a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * \param pElem Pointer to element. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | void WsfQueuePush(wsfQueue_t *pQueue, void *pElem) |
| | | { |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | WSF_ASSERT(pElem != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | /* else push element to head of queue */ |
| | | WSF_QUEUE_NEXT(pElem) = pQueue->pHead; |
| | | |
| | | /* if queue was empty set tail */ |
| | | if (pQueue->pHead == NULL) |
| | | { |
| | | pQueue->pTail = pElem; |
| | | } |
| | | |
| | | /* set head */ |
| | | pQueue->pHead = pElem; |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Insert an element into a queue. This function is typically used when iterating |
| | | * over a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * \param pElem Pointer to element to be inserted. |
| | | * \param pPrev Pointer to previous element in the queue before element to be inserted. |
| | | * Note: set pPrev to NULL if pElem is first element in queue. |
| | | * \return None. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | void WsfQueueInsert(wsfQueue_t *pQueue, void *pElem, void *pPrev) |
| | | { |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | WSF_ASSERT(pElem != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | /* if queue empty or inserting at tail */ |
| | | if (pQueue->pHead == NULL || pPrev == pQueue->pTail) |
| | | { |
| | | /* queue as normal */ |
| | | WsfQueueEnq(pQueue, pElem); |
| | | } |
| | | /* else if inserting at head */ |
| | | else if (pPrev == NULL) |
| | | { |
| | | /* push to head */ |
| | | WsfQueuePush(pQueue, pElem); |
| | | } |
| | | else |
| | | { |
| | | /* insert in middle of queue */ |
| | | WSF_QUEUE_NEXT(pElem) = WSF_QUEUE_NEXT(pPrev); |
| | | WSF_QUEUE_NEXT(pPrev) = pElem; |
| | | } |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Remove an element from a queue. This function is typically used when iterating |
| | | * over a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * \param pElem Pointer to element to be removed. |
| | | * \param pPrev Pointer to previous element in the queue before element to be removed. |
| | | * Note: set pPrev to NULL if pElem is first element in queue. |
| | | * \return None. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | void WsfQueueRemove(wsfQueue_t *pQueue, void *pElem, void *pPrev) |
| | | { |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | WSF_ASSERT(pQueue->pHead != NULL); |
| | | WSF_ASSERT(pElem != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | /* if first element */ |
| | | if (pElem == pQueue->pHead) |
| | | { |
| | | /* remove from head of queue */ |
| | | pQueue->pHead = WSF_QUEUE_NEXT(pElem); |
| | | } |
| | | else if (pPrev) |
| | | { |
| | | /* remove from middle of queue, pPrev will never be null */ |
| | | WSF_QUEUE_NEXT(pPrev) = WSF_QUEUE_NEXT(pElem); |
| | | } |
| | | |
| | | /* if last element */ |
| | | if (pElem == pQueue->pTail) |
| | | { |
| | | /* update tail */ |
| | | pQueue->pTail = pPrev; |
| | | } |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Count the number of elements in a queue. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * |
| | | * \return Number of elements in queue. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | uint16_t WsfQueueCount(wsfQueue_t *pQueue) |
| | | { |
| | | wsfQueueElem_t *pElem; |
| | | uint16_t count = 0; |
| | | |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | pElem = pQueue->pHead; |
| | | |
| | | /* iterate over queue */ |
| | | while (pElem != NULL) |
| | | { |
| | | count++; |
| | | pElem = pElem->pNext; |
| | | } |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | |
| | | return count; |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Return TRUE if queue is empty. |
| | | * |
| | | * \param pQueue Pointer to queue. |
| | | * |
| | | * \return TRUE if queue is empty, FALSE otherwise. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | bool_t WsfQueueEmpty(wsfQueue_t *pQueue) |
| | | { |
| | | bool_t empty; |
| | | |
| | | WSF_CS_INIT(cs); |
| | | |
| | | WSF_ASSERT(pQueue != NULL); |
| | | |
| | | /* enter critical section */ |
| | | uint32_t lock = WSF_CS_ENTER(); |
| | | |
| | | empty = (pQueue->pHead == NULL); |
| | | |
| | | /* exit critical section */ |
| | | WSF_CS_EXIT(lock); |
| | | |
| | | return empty; |
| | | } |
| | | |
| | | /*************************************************************************************************/ |
| | | /*! |
| | | * \brief Check for a queue depth of 1 element. |
| | | * |
| | | * \param pQueue Queue. |
| | | * |
| | | * \return TRUE if Queue only has 1 element, FALSE otherwise. |
| | | */ |
| | | /*************************************************************************************************/ |
| | | bool_t WsfIsQueueDepthOne(wsfQueue_t *pQueue) |
| | | { |
| | | return pQueue->pHead == pQueue->pTail; |
| | | } |