182 lines
4.1 KiB
C
182 lines
4.1 KiB
C
|
/*
|
|||
|
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
|
|||
|
* All rights reserved.
|
|||
|
*
|
|||
|
* File : CdxQueue.c
|
|||
|
* Description : Queue
|
|||
|
* History :
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
#include <CdxTypes.h>
|
|||
|
#include <CdxAtomic.h>
|
|||
|
#include <CdxMemory.h>
|
|||
|
//#include <CdxBaseErrno.h>
|
|||
|
#include <CdxLog.h>
|
|||
|
|
|||
|
#include <CdxQueue.h>
|
|||
|
|
|||
|
#define CdxAtomicBoolCAS(ptr, oldVal, newVal) \
|
|||
|
__sync_bool_compare_and_swap(ptr, oldVal, newVal)
|
|||
|
|
|||
|
struct CdxQueueImplS
|
|||
|
{
|
|||
|
struct CdxQueueS base;
|
|||
|
struct CdxQueueNodeEntityS *front;
|
|||
|
struct CdxQueueNodeEntityS *rear;
|
|||
|
cdx_bool enablePop;
|
|||
|
cdx_bool enablePush;
|
|||
|
AwPoolT *pool;
|
|||
|
};
|
|||
|
|
|||
|
struct CdxQueueNodeEntityS
|
|||
|
{
|
|||
|
struct CdxQueueNodeEntityS *next;
|
|||
|
cdx_atomic_t ref;
|
|||
|
CdxQueueDataT data;
|
|||
|
};
|
|||
|
|
|||
|
static inline struct CdxQueueNodeEntityS *
|
|||
|
QueueNodeEntityIncRef(struct CdxQueueNodeEntityS *entity)
|
|||
|
{
|
|||
|
CdxAtomicInc(&entity->ref);
|
|||
|
return entity;
|
|||
|
}
|
|||
|
|
|||
|
static inline cdx_void QueueNodeEntityDecRef(AwPoolT *pool, struct CdxQueueNodeEntityS *entity)
|
|||
|
{
|
|||
|
if (CdxAtomicDec(&entity->ref) == 0)
|
|||
|
{
|
|||
|
Pfree(pool, entity);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static CdxQueueDataT __CdxQueuePop(CdxQueueT *queue)
|
|||
|
{
|
|||
|
struct CdxQueueImplS *impl;
|
|||
|
struct CdxQueueNodeEntityS *entity = NULL;
|
|||
|
CdxQueueDataT data;
|
|||
|
CDX_CHECK(queue);
|
|||
|
impl = CdxContainerOf(queue, struct CdxQueueImplS, base);
|
|||
|
|
|||
|
if (!impl->enablePop)
|
|||
|
{
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
if (entity)
|
|||
|
{
|
|||
|
QueueNodeEntityDecRef(impl->pool, entity);
|
|||
|
}
|
|||
|
entity = QueueNodeEntityIncRef(impl->front);
|
|||
|
if (entity->next == NULL) /* it's only a dummy node */
|
|||
|
{
|
|||
|
QueueNodeEntityDecRef(impl->pool, entity);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
data = entity->next->data;
|
|||
|
/*
|
|||
|
*<EFBFBD>Ȱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
*<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>entity֮<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>next<EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
*/
|
|||
|
}
|
|||
|
while (!CdxAtomicBoolCAS(&impl->front, entity, entity->next));
|
|||
|
QueueNodeEntityDecRef(impl->pool, entity); /*<2A><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>ȡentity<74><79>ʱ<EFBFBD><CAB1>+1*/
|
|||
|
QueueNodeEntityDecRef(impl->pool, entity); /*<2A><>-1 <20><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>ڴ<EFBFBD>*/
|
|||
|
|
|||
|
return data;
|
|||
|
}
|
|||
|
|
|||
|
static cdx_err __CdxQueuePush(CdxQueueT *queue, CdxQueueDataT data)
|
|||
|
{
|
|||
|
struct CdxQueueImplS *impl;
|
|||
|
struct CdxQueueNodeEntityS *entity, *tmpEntity;
|
|||
|
cdx_bool ret;
|
|||
|
|
|||
|
CDX_CHECK(queue);
|
|||
|
impl = CdxContainerOf(queue, struct CdxQueueImplS, base);
|
|||
|
|
|||
|
if (!impl->enablePush)
|
|||
|
{
|
|||
|
return -1;
|
|||
|
}
|
|||
|
entity = Palloc(impl->pool, sizeof(*entity));
|
|||
|
CDX_FORCE_CHECK(entity);
|
|||
|
CDX_CHECK(data);/*<2A><>ϣ<EFBFBD><CFA3><EFBFBD><EFBFBD>Ϊ0<CEAA><30>data*/
|
|||
|
entity->data = data;
|
|||
|
entity->next = NULL;
|
|||
|
CdxAtomicSet(&entity->ref, 1);
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
tmpEntity = impl->rear;
|
|||
|
}
|
|||
|
while (!CdxAtomicBoolCAS(&tmpEntity->next, NULL, entity));
|
|||
|
|
|||
|
ret = CdxAtomicBoolCAS(&impl->rear, tmpEntity, entity);
|
|||
|
CDX_CHECK(CDX_TRUE == ret);
|
|||
|
|
|||
|
return CDX_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
static cdx_bool __CdxQueueEmpty(CdxQueueT *queue)
|
|||
|
{
|
|||
|
struct CdxQueueImplS *impl;
|
|||
|
|
|||
|
CDX_CHECK(queue);
|
|||
|
impl = CdxContainerOf(queue, struct CdxQueueImplS, base);
|
|||
|
|
|||
|
return impl->front == impl->rear;
|
|||
|
}
|
|||
|
|
|||
|
static struct CdxQueueOpsS gQueueOps =
|
|||
|
{
|
|||
|
.pop = __CdxQueuePop,
|
|||
|
.push = __CdxQueuePush,
|
|||
|
.empty = __CdxQueueEmpty
|
|||
|
};
|
|||
|
|
|||
|
CdxQueueT *CdxQueueCreate(AwPoolT *pool)
|
|||
|
{
|
|||
|
struct CdxQueueImplS *impl;
|
|||
|
struct CdxQueueNodeEntityS *dummy;
|
|||
|
impl = Palloc(pool, sizeof(struct CdxQueueImplS));
|
|||
|
CDX_FORCE_CHECK(impl);
|
|||
|
memset(impl, 0x00, sizeof(struct CdxQueueImplS));
|
|||
|
|
|||
|
impl->pool = pool;
|
|||
|
dummy = Palloc(impl->pool, sizeof(struct CdxQueueNodeEntityS));
|
|||
|
CDX_FORCE_CHECK(dummy);
|
|||
|
dummy->next = NULL;
|
|||
|
dummy->data = NULL;
|
|||
|
CdxAtomicSet(&dummy->ref, 1);
|
|||
|
|
|||
|
impl->front = dummy;
|
|||
|
impl->rear = dummy;
|
|||
|
impl->base.ops = &gQueueOps;
|
|||
|
impl->enablePop = CDX_TRUE;
|
|||
|
impl->enablePush = CDX_TRUE;
|
|||
|
return &impl->base;
|
|||
|
}
|
|||
|
|
|||
|
cdx_void CdxQueueDestroy(CdxQueueT *queue)
|
|||
|
{
|
|||
|
struct CdxQueueImplS *impl;
|
|||
|
// struct CdxQueueNodeEntityS *dummy;
|
|||
|
|
|||
|
CDX_CHECK(queue);
|
|||
|
impl = CdxContainerOf(queue, struct CdxQueueImplS, base);
|
|||
|
|
|||
|
impl->enablePush = CDX_FALSE;
|
|||
|
|
|||
|
impl->enablePop = CDX_FALSE;
|
|||
|
CDX_LOG_CHECK(impl->front == impl->rear, "queue not empty");
|
|||
|
|
|||
|
QueueNodeEntityDecRef(impl->pool, impl->front);
|
|||
|
Pfree(impl->pool, impl);
|
|||
|
|
|||
|
return ;
|
|||
|
}
|