SmartAudio/package/allwinner/liballwinner_tina/liballwinner/LIBRARY/DEMUX/BASE/CdxMessage.c

520 lines
12 KiB
C
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* Copyright (c) 2008-2016 Allwinner Technology Co. Ltd.
* All rights reserved.
*
* File : CdxMessage.c
* Description : Message
* History :
*
*/
#include <CdxMessage.h>
#include <CdxMemory.h>
#include <CdxLock.h>
//#include <CdxBaseErrno.h>
#include <CdxAtomic.h>
#include <CdxList.h>
#include <CdxQueue.h>
#include <unistd.h>
struct CdxEventS
{
struct CdxMessageS *msg;
struct CdxDeliverS *deliver;
CdxListNodeT deliverListNode;
CdxListNodeT timerListNode;
cdx_uint32 timeout; /*100 millisecond*/
};
struct CdxDeliverTimerCtxS
{
CdxListT timeoutList;
CdxMutexT timeoutListMutex;
pthread_t timeoutProcPid;
cdx_bool threadExit;
};
struct CdxDeliverTimerCtxS *gDeliverTimerHdr;
/*<2A>ö<EFBFBD><C3B6>д洢<D0B4><E6B4A2>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD>д֮<D0B4><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
static cdx_void *DeliverTimerProcess(cdx_void *arg)
{
struct CdxDeliverTimerCtxS *ctx = (struct CdxDeliverTimerCtxS *)arg;
struct CdxEventS *posEvent, *nextEvent;
while(!ctx->threadExit)
{
usleep(100000);
CdxMutexLock(&ctx->timeoutListMutex); /*lock*/
CdxListForEachEntrySafe(posEvent, nextEvent, &ctx->timeoutList, timerListNode)
{
if (--posEvent->timeout == 0)
{
CdxListDel(&posEvent->deliverListNode);
CdxListDel(&posEvent->timerListNode);
CdxDeliverPostUs(posEvent->deliver, posEvent->msg, 0);
Pfree(NULL, posEvent);
}
}
CdxMutexUnlock(&ctx->timeoutListMutex); /*lock*/
}
return NULL;
}
//static cdx_void DeliverTimerInit(cdx_void) __attribute__((constructor));
cdx_void DeliverTimerInit(cdx_void)
{
cdx_int32 ret;
gDeliverTimerHdr = Palloc(NULL, sizeof(*gDeliverTimerHdr));
CDX_FORCE_CHECK(gDeliverTimerHdr);
memset(gDeliverTimerHdr, 0x00, sizeof(*gDeliverTimerHdr));
CdxMutexInit(&gDeliverTimerHdr->timeoutListMutex);
CdxListInit(&gDeliverTimerHdr->timeoutList);
gDeliverTimerHdr->threadExit = CDX_FALSE;
ret = pthread_create(&gDeliverTimerHdr->timeoutProcPid, NULL,
DeliverTimerProcess, gDeliverTimerHdr);
CDX_FORCE_CHECK(ret == 0);
return ;
}
//static cdx_void DeliverTimerExit(cdx_void) __attribute__((destructor));
cdx_void DeliverTimerExit(cdx_void)
{
struct CdxEventS *posEvent, *nextEvent;
gDeliverTimerHdr->threadExit = CDX_TRUE;
pthread_join(gDeliverTimerHdr->timeoutProcPid, NULL);
CdxListForEachEntrySafe(posEvent, nextEvent, &gDeliverTimerHdr->timeoutList, timerListNode)
{
CdxListDel(&posEvent->timerListNode);
CdxMessageDestroy(posEvent->msg);
Pfree(NULL, posEvent);
}
CdxMutexDestroy(&gDeliverTimerHdr->timeoutListMutex);
Pfree(NULL, gDeliverTimerHdr);
gDeliverTimerHdr = NULL;
return ;
}
struct CdxDeliverImplS
{
CdxDeliverT base;
CdxQueueT *eventQueue;
CdxListT timeoutList;
pthread_t pid;
CdxMutexT mutex;
CdxCondT cond;
volatile cdx_bool threadExit;
AwPoolT *pool; /*<2A><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣߳<DFB3><CCA3>ö<EFBFBD><C3B6><EFBFBD><EFBFBD><EFBFBD>pool*/
};
CdxDeliverT *globalDeliver = NULL;
static cdx_int32 __CdxDeliverPostUS(CdxDeliverT *deliver, CdxMessageT *msg,
cdx_uint64 timeout)
{
struct CdxDeliverImplS *impl;
impl = CdxContainerOf(deliver, struct CdxDeliverImplS, base);
if (timeout == 0LL)
{
CdxQueuePush(impl->eventQueue, msg);
CdxMutexLock(&impl->mutex); /*lock*/
CdxCondSignal(&impl->cond);
CdxMutexUnlock(&impl->mutex); /*unlock*/
}
else
{
struct CdxEventS *event;
if (!gDeliverTimerHdr)
{
DeliverTimerInit();
}
event = Palloc(0, sizeof(*event));
CDX_FORCE_CHECK(event);
event->msg = msg;
event->timeout = timeout/100000;
event->deliver = deliver;
CdxListAdd(&event->deliverListNode, &impl->timeoutList);
CdxMutexLock(&gDeliverTimerHdr->timeoutListMutex); /*lock*/
CdxListAddTail(&event->timerListNode, &gDeliverTimerHdr->timeoutList);
CdxMutexUnlock(&gDeliverTimerHdr->timeoutListMutex); /*lock*/
}
return CDX_SUCCESS;
}
struct CdxDeliverOpsS deliverOps =
{
.postUS = __CdxDeliverPostUS
};
/*<2A>ö<EFBFBD><C3B6>д洢<D0B4><E6B4A2>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD>д֮<D0B4><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
static cdx_void *DeliverProcess(cdx_void *arg)
{
struct CdxDeliverImplS *impl = (struct CdxDeliverImplS *)arg;
CdxMessageT *msg;
// CDX_LOGD("DeliverProcess (%d)", gettid());
for (;;)
{
if (CdxQueueEmpty(impl->eventQueue))
{
if (impl->threadExit)
{
break;
}
struct timespec abstime;
abstime.tv_sec = time(0) + 1;
abstime.tv_nsec = 0;
CdxMutexLock(&impl->mutex); /*lock*/
CdxCondTimedwait(&impl->cond, &impl->mutex, &abstime);
CdxMutexUnlock(&impl->mutex); /*unlock*/
}
if (impl->threadExit)
{
break;
}
while (!CdxQueueEmpty(impl->eventQueue))
{
msg = CdxQueuePop(impl->eventQueue);
CDX_CHECK(msg);
if (msg)
{
CdxMessageDeliver(msg);
CdxMessageDestroy(msg);
}
}
if (impl->threadExit)
{
break;
}
}
pthread_exit(NULL);
return NULL;
}
CdxDeliverT *CdxDeliverCreate(AwPoolT *pool)
{
cdx_int32 ret;
AwPoolT *selfPool = NULL;
struct CdxDeliverImplS *impl;
selfPool = AwPoolCreate(pool); /*create self pool will fast deliver*/
impl = Palloc(selfPool, sizeof(*impl));
CDX_FORCE_CHECK(impl);
memset(impl, 0x00, sizeof(*impl));
impl->pool = selfPool;
impl->base.ops = &deliverOps;
CdxMutexInit(&impl->mutex);
CdxCondInit(&impl->cond);
CdxListInit(&impl->timeoutList);
impl->eventQueue = CdxQueueCreate(impl->pool);
impl->threadExit = CDX_FALSE;
ret = pthread_create(&impl->pid, NULL, DeliverProcess, impl);
CDX_LOGD("deliver process, pid(%ld)", (unsigned long)impl->pid);
CDX_FORCE_CHECK(ret == 0);
return &impl->base;
}
cdx_void CdxDeliverClearMsg(CdxDeliverT *deliver)
{
struct CdxDeliverImplS *impl;
struct CdxEventS *event, *nEvent;
CdxMessageT *msg;
impl = CdxContainerOf(deliver, struct CdxDeliverImplS, base);
CdxListForEachEntrySafe(event, nEvent, &impl->timeoutList, deliverListNode)
{
CdxListDel(&event->timerListNode);
CdxListDel(&event->deliverListNode);
CdxMessageDestroy(event->msg);
Pfree(0, event);
}
while (!CdxQueueEmpty(impl->eventQueue))
{
msg = CdxQueuePop(impl->eventQueue);
CdxMessageDestroy(msg);
}
return ;
}
cdx_void CdxDeliverDestroy(CdxDeliverT *deliver)
{
struct CdxDeliverImplS *impl;
AwPoolT *selfPool;
impl = CdxContainerOf(deliver, struct CdxDeliverImplS, base);
CdxDeliverClearMsg(deliver);
selfPool = impl->pool;
impl->threadExit = CDX_TRUE;
CdxMutexLock(&impl->mutex); /*lock*/
CdxCondBroadcast(&impl->cond);
CdxMutexUnlock(&impl->mutex); /*unlock*/
CDX_LOGD("wait thread, pid(%ld)", (unsigned long)impl->pid);
pthread_join(impl->pid, NULL);
CdxDeliverClearMsg(deliver);
CDX_CHECK(CdxQueueEmpty(impl->eventQueue));
CdxDeliverClearMsg(deliver);
CdxQueueDestroy(impl->eventQueue);
CdxMutexDestroy(&impl->mutex);
CdxCondDestroy(&impl->cond);
Pfree(impl->pool, impl);
AwPoolDestroy(selfPool);
return ;
}
cdx_void CdxDeliverReset(cdx_void)
{
if (globalDeliver)
{
CdxDeliverDestroy(globalDeliver);
globalDeliver = NULL;
}
else
{
CDX_LOGW("global deliver not initinal...");
}
DeliverTimerExit();
}
/**************************message impl*********************************/
struct CdxMessageImplS
{
struct CdxMessageS base;
CdxMetaT *meta;
AwPoolT *pool;
CdxHandlerT *handler;
cdx_int32 what;
cdx_atomic_t ref;
};
static struct CdxMessageS *__CdxMessageIncRef(struct CdxMessageS *msg)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
CdxAtomicInc(&impl->ref);
return msg;
}
static cdx_void __CdxMessageDecRef(struct CdxMessageS *msg)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
if (CdxAtomicDec(&impl->ref) == 0)
{
CdxMetaDestroy(impl->meta);
Pfree(impl->pool, impl);
}
return ;
}
static cdx_void __CdxMessageDeliver(CdxMessageT *msg)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
CdxHandlerMsgRecv(impl->handler, msg);
return ;
}
static CdxMetaT *__CdxMessageGetMeta(CdxMessageT *msg)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
return impl->meta;
}
static cdx_int32 __CdxMessageWhat(CdxMessageT *msg)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
return impl->what;
}
static cdx_err __CdxMessagePostUs(struct CdxMessageS *msg, cdx_uint64 timeout)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
return CdxHandlerPostUs(impl->handler, msg, timeout);
}
static CdxMessageT *__CdxMessageDup(CdxMessageT *msg)
{
struct CdxMessageImplS *impl, *newImpl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
newImpl = Palloc(impl->pool, sizeof(struct CdxMessageImplS));
CDX_FORCE_CHECK(newImpl);
memset(newImpl, 0x00, sizeof(struct CdxMessageImplS));
newImpl->meta = CdxMetaDup(impl->meta);
newImpl->what = impl->what;
newImpl->handler = impl->handler;
CdxAtomicSet(&newImpl->ref, 1);
newImpl->base.ops = impl->base.ops;
return &newImpl->base;
}
struct CdxMessageOpsS messageOps =
{
.incRef = __CdxMessageIncRef,
.decRef = __CdxMessageDecRef,
.getMeta = __CdxMessageGetMeta,
.what = __CdxMessageWhat,
.postUs = __CdxMessagePostUs,
.dup = __CdxMessageDup,
.deliver = __CdxMessageDeliver
};
CdxMessageT *__CdxMessageCreate(AwPoolT *pool, cdx_int32 waht, CdxHandlerT *handler,
char *file, int line)
{
struct CdxMessageImplS *impl;
char *callFrom = file;
#ifdef MEMORY_LEAK_CHK
callFrom = malloc(512);
sprintf(callFrom, "%s:%s", file, __FUNCTION__);
#endif
impl = AwPalloc(pool, sizeof(struct CdxMessageImplS), callFrom, line);
CDX_FORCE_CHECK(impl);
memset(impl, 0x00, sizeof(struct CdxMessageImplS));
CDX_CHECK(handler);
impl->pool = pool;
impl->meta = CdxMetaCreate(impl->pool);
impl->what = waht;
impl->handler = handler;
CdxAtomicSet(&impl->ref, 1);
impl->base.ops = &messageOps;
return &impl->base;
}
cdx_void CdxMessageDestroy(CdxMessageT *msg)
{
struct CdxMessageImplS *impl;
CDX_CHECK(msg);
impl = CdxContainerOf(msg, struct CdxMessageImplS, base);
CDX_CHECK(CdxAtomicRead(&impl->ref) == 1);
__CdxMessageDecRef(msg);
return ;
}
/*-----------------------------msg handler-----------------------------*/
struct CdxHandlerImplS
{
struct CdxHandlerS base;
CdxDeliverT *deliver;
CdxHandlerItfT *itf;
AwPoolT *pool;
};
cdx_int32 __CdxHandlerPostUS(CdxHandlerT *hdr, CdxMessageT *msg, cdx_uint64 timeUs)
{
struct CdxHandlerImplS *impl;
impl = CdxContainerOf(hdr, struct CdxHandlerImplS, base);
return CdxDeliverPostUs(impl->deliver, msg, timeUs);
}
cdx_void __CdxHandlerMsgRecv(CdxHandlerT *hdr, CdxMessageT *msg)
{
struct CdxHandlerImplS *impl;
impl = CdxContainerOf(hdr, struct CdxHandlerImplS, base);
impl->itf->ops->msgRecv(impl->itf, msg);
return ;
}
struct CdxHandlerOpsS handlerOps =
{
.postUs = __CdxHandlerPostUS,
.msgRecv = __CdxHandlerMsgRecv
};
CdxHandlerT *CdxHandlerCreate(AwPoolT *pool, CdxHandlerItfT *itf, CdxDeliverT *deliver)
{
struct CdxHandlerImplS *impl;
impl = Palloc(pool, sizeof(*impl));
impl->pool = pool;
impl->base.ops = &handlerOps;
impl->itf = itf;
if (deliver)
{
impl->deliver = deliver;
}
else
{
if (!globalDeliver)
{
globalDeliver = CdxDeliverCreate(NULL);
}
impl->deliver = globalDeliver;
}
return &impl->base;
}
cdx_void CdxHandlerDestroy(CdxHandlerT *hdr)
{
struct CdxHandlerImplS *impl;
impl = CdxContainerOf(hdr, struct CdxHandlerImplS, base);
Pfree(impl->pool, impl);
return ;
}
/*--------------------------msg handler end----------------------------*/