www.pudn.com > r&s1.10°æ±¾£«Îĵµ.rar > msgq.c
/*
===============================================================================
| Copyright (C) 2004 RuanHaiShen, All rights reserved.
| SUMMARY:
| Message queue implementation
|
| DESCRIPTION:
| See http://www.01s.org for documentation, latest information, license
| and contact details.
| email:ruanhaishen@01s.org
=============================================================================*/
/*===========================================================================*/
#include "arch/arch.h"
#include "inc/queue.h"
#include "inc/kernel.h"
#include "inc/memory.h"
#include "inc/ipc.h"
#include "inc/kapi.h"
#if CFG_MSGQ_EN > 0
#define __msgq_take_head(msgq, buf) \
do { \
__memcpy(buf, msgq->phead, msgq->msgsz); \
msgq->phead += msgq->msgsz; \
if (msgq->phead == msgq->pend) { \
msgq->phead = msgq->pstart; \
} \
} while (0)
#define __msgq_take_tail(msgq, buf) \
do { \
if (msgq->ptail == msgq->pstart) { \
msgq->ptail = msgq->pend; \
} \
msgq->ptail -= msgq->msgsz; \
__memcpy(buf, msgq->ptail, msgq->msgsz); \
} while (0)
err_t msgq_init(msgq_t* msgq, u16 size, u16 entries, u8 opt)
{
__ASSERT(msgq != NULL);
__ASSERT(size > 0);
__ASSERT(entries > 0);
msgq->pstart = kmalloc(size * entries);
if (msgq->pstart == NULL) {
return ENULL;
}
msgq->phead =
msgq->ptail = msgq->pstart;
msgq->pend = msgq->pstart + size * entries;
msgq->msgsz = size;
msgq->entries = entries;
msgq->opt = opt;
msgq->avail = 0;
__queue_init(msgq->tasks);
return EOK;
}
err_t msgq_send(msgq_t* msgq, const void* buf)
{
__ASSERT(msgq != NULL);
__ASSERT(buf != NULL);
CRITICAL_ENTER;
if (msgq->avail < msgq->entries) {
__memcpy(msgq->ptail, buf, msgq->msgsz);
msgq->ptail += msgq->msgsz;
if (msgq->ptail == msgq->pend) {
msgq->ptail = msgq->pstart;
}
if (msgq->avail++ == 0) {
__ipc_resume(&msgq->tasks);
CRITICAL_EXIT;
__schedule();
} else {
CRITICAL_EXIT;
}
return EOK;
} else {
CRITICAL_EXIT;
return EFULL;
}
}
err_t msgq_receive(msgq_t* msgq, void* buf)
{
__ASSERT(msgq != NULL);
__ASSERT(buf != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
while (true) {
CRITICAL_ENTER;
if (msgq->avail > 0) {
msgq->avail--;
if (msgq->opt == MSG_FIFO) {
__msgq_take_head(msgq, buf);
} else {
__msgq_take_tail(msgq, buf);
}
CRITICAL_EXIT;
return EOK;
}
__ipc_block(&msgq->tasks, 0);
CRITICAL_EXIT;
__schedule();
}
}
#if CFG_IPC_TIMEOUT_EN > 0
err_t msgq_timereceive(msgq_t* msgq, void* buf, tick_t ticks)
{
register u8 current;
__ASSERT(msgq != NULL);
__ASSERT(buf != NULL);
#if CFG_ARG_CHK > 0
if (_sched_lock > 0) {
return ELOCK;
}
#else
__ASSERT(_sched_lock == 0);
#endif
while (true) {
CRITICAL_ENTER;
if (msgq->avail > 0) {
msgq->avail--;
if (msgq->opt == MSG_FIFO) {
__msgq_take_head(msgq, buf);
} else {
__msgq_take_tail(msgq, buf);
}
CRITICAL_EXIT;
return EOK;
}
__ipc_block(&msgq->tasks, ticks);
CRITICAL_EXIT;
__schedule();
CRITICAL_ENTER;
current = _current_prio;
if (_tasks[current].state & STATE_BLOCKED) {
__ipc_timeout(&msgq->tasks);
CRITICAL_EXIT;
return ETIMEOUT;
}
__adjust_delay(current, ticks);
CRITICAL_EXIT;
}
}
#endif
err_t msgq_flush(msgq_t* msgq)
{
__ASSERT(msgq != NULL);
CRITICAL_ENTER;
msgq->phead =
msgq->ptail = msgq->pstart;
msgq->avail = 0;
CRITICAL_EXIT;
return EOK;
}
err_t msgq_destroy(msgq_t* msgq)
{
__ASSERT(msgq != NULL);
CRITICAL_ENTER;
if (__ipc_resume(&msgq->tasks) != NULL_PRIO) {
CRITICAL_EXIT;
return EEXIST;
}
CRITICAL_EXIT;
CRITICAL_ENTER;
if (msgq->pstart != NULL) {
kfree(msgq->pstart);
msgq->pstart = NULL;
}
CRITICAL_EXIT;
return EOK;
}
#endif
/*===========================================================================*/