forked from xuos/xiuos
Adjust directory structure
This commit is contained in:
496
Ubiquitous/XiUOS/kernel/thread/msgqueue.c
Normal file
496
Ubiquitous/XiUOS/kernel/thread/msgqueue.c
Normal file
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file: msgqueue.c
|
||||
* @brief: msgqueue file
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include <xiuos.h>
|
||||
#include <xs_delay.h>
|
||||
|
||||
DECLARE_ID_MANAGER(k_mq_id_manager, ID_NUM_MAX);
|
||||
DoubleLinklistType k_mq_list = {&k_mq_list, &k_mq_list};
|
||||
|
||||
struct MqMessage
|
||||
{
|
||||
struct MqMessage *next;
|
||||
};
|
||||
|
||||
static struct MsgQueue *GetMsgQueueById(int32 id)
|
||||
{
|
||||
x_base lock = 0;
|
||||
struct MsgQueue *mq = NONE;
|
||||
struct IdNode *idnode = NONE;
|
||||
|
||||
if (id < 0 )
|
||||
return NONE;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
idnode = IdGetObj(&k_mq_id_manager, id);
|
||||
if (idnode == NONE){
|
||||
CriticalAreaUnLock(lock);
|
||||
return NONE;
|
||||
}
|
||||
mq = CONTAINER_OF(idnode, struct MsgQueue, id);
|
||||
CriticalAreaUnLock(lock);
|
||||
return mq;
|
||||
}
|
||||
|
||||
static x_err_t _InitMsgQueue( struct MsgQueue *mq ,x_size_t msg_size,
|
||||
x_size_t max_msgs )
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
|
||||
mq->max_msgs = max_msgs;
|
||||
mq->num_msgs = 0;
|
||||
mq->each_len = ALIGN_MEN_UP(msg_size, MEM_ALIGN_SIZE);
|
||||
mq->index = 0;
|
||||
|
||||
InitDoubleLinkList(&mq->send_pend_list);
|
||||
InitDoubleLinkList(&(mq->recv_pend_list));
|
||||
|
||||
mq->msg_buf = x_malloc( mq->each_len * mq->max_msgs);
|
||||
if (mq->msg_buf == NONE) {
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListRmNode(&(mq->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
KERNEL_FREE(mq);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueSend(struct MsgQueue *mq,
|
||||
const void *buffer,
|
||||
x_size_t size,
|
||||
int32 msec)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
uint32 tick_delta = 0;
|
||||
int32 timeout = 0;
|
||||
uint8 *msg = NONE;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
if (size > mq->each_len)
|
||||
return -ERROR;
|
||||
|
||||
tick_delta = 0;
|
||||
task = GetKTaskDescriptor();
|
||||
timeout = CalculteTickFromTimeMs(msec);
|
||||
lock = CriticalAreaLock();
|
||||
if (mq->num_msgs >= mq->max_msgs && timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -EFULL;
|
||||
}
|
||||
|
||||
while(mq->num_msgs >= mq->max_msgs ) {
|
||||
|
||||
task->exstatus = EOK;
|
||||
if (timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -EFULL;
|
||||
}
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
LinklistSuspend(&(mq->send_pend_list), task, LINKLIST_FLAG_FIFO);
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain();
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("mq_send_wait: start timer of task:%s\n",
|
||||
task->task_base_info.name));
|
||||
KTaskSetDelay(task,timeout);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
if (task->exstatus != EOK) {
|
||||
return task->exstatus;
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain() - tick_delta;
|
||||
timeout -= tick_delta;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
msg = mq->msg_buf + ( ( mq->index + mq->num_msgs ) % mq->max_msgs ) * mq->each_len ;
|
||||
memcpy(msg, buffer, size);
|
||||
mq->num_msgs ++;
|
||||
if (!IsDoubleLinkListEmpty(&mq->recv_pend_list)) {
|
||||
LinklistResume(&(mq->recv_pend_list));
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueUrgentSend(struct MsgQueue *mq, const void *buffer, x_size_t size)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
uint8 *msg = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
if (size > mq->each_len)
|
||||
return -ERROR;
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
if (mq->num_msgs >= mq->max_msgs) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -EFULL;
|
||||
}
|
||||
|
||||
mq->index --;
|
||||
if (mq->index < 0)
|
||||
mq->index += mq->max_msgs;
|
||||
|
||||
msg = mq->msg_buf + ( ( mq->index + mq->num_msgs ) % mq->max_msgs ) * mq->each_len ;
|
||||
memcpy(msg , buffer, size);
|
||||
mq->num_msgs ++;
|
||||
if (!IsDoubleLinkListEmpty(&mq->send_pend_list)) {
|
||||
LinklistResume(&(mq->send_pend_list));
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueRecv(struct MsgQueue *mq,
|
||||
void *buffer,
|
||||
x_size_t size,
|
||||
int32 msec)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
uint32 tick_delta = 0;
|
||||
int32 timeout = 0;
|
||||
struct MqMessage *msg = NONE;
|
||||
struct TaskDescriptor *task = NONE;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
NULL_PARAM_CHECK(buffer);
|
||||
|
||||
tick_delta = 0;
|
||||
task = GetKTaskDescriptor();
|
||||
timeout = CalculteTickFromTimeMs(msec);
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (mq->index == 0 && timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
return -ETIMEOUT;
|
||||
}
|
||||
|
||||
for( ; mq->num_msgs <= 0 ; ) {
|
||||
KDEBUG_IN_KTASK_CONTEXT;
|
||||
|
||||
task->exstatus = EOK;
|
||||
if (timeout == 0) {
|
||||
CriticalAreaUnLock(lock);
|
||||
task->exstatus = -ETIMEOUT;
|
||||
return -ETIMEOUT;
|
||||
}
|
||||
|
||||
LinklistSuspend(&(mq->recv_pend_list),
|
||||
task,
|
||||
LINKLIST_FLAG_FIFO);
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain();
|
||||
SYS_KDEBUG_LOG(KDBG_IPC, ("set task:%s to timer list\n",
|
||||
task->task_base_info.name));
|
||||
KTaskSetDelay(task,timeout);
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
if (task->exstatus != EOK) {
|
||||
return task->exstatus;
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
if (timeout > 0) {
|
||||
tick_delta = CurrentTicksGain() - tick_delta;
|
||||
timeout -= tick_delta;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
msg = mq->msg_buf + mq->index * mq->each_len;
|
||||
mq->index = (mq->index + 1) % mq->max_msgs;
|
||||
memcpy(buffer, msg , size > mq->each_len ? mq->each_len : size);
|
||||
mq->num_msgs --;
|
||||
|
||||
if (!IsDoubleLinkListEmpty(&(mq->send_pend_list))) {
|
||||
LinklistResume(&(mq->send_pend_list));
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
DO_KTASK_ASSIGN;
|
||||
return EOK;
|
||||
}
|
||||
|
||||
CriticalAreaUnLock(lock);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _MsgQueueReinit(struct MsgQueue *mq)
|
||||
{
|
||||
x_ubase lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
|
||||
LinklistResumeAll(&mq->send_pend_list);
|
||||
LinklistResumeAll(&(mq->recv_pend_list));
|
||||
mq->index = 0;
|
||||
mq->num_msgs = 0;
|
||||
CriticalAreaUnLock(lock);
|
||||
DO_KTASK_ASSIGN;
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static x_err_t _DeleteMsgQueue(struct MsgQueue *mq)
|
||||
{
|
||||
x_base lock = 0;
|
||||
|
||||
NULL_PARAM_CHECK(mq);
|
||||
|
||||
LinklistResumeAll(&(mq->send_pend_list));
|
||||
LinklistResumeAll(&(mq->recv_pend_list));
|
||||
KERNEL_FREE(mq->msg_buf);
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListRmNode(&(mq->link));
|
||||
CriticalAreaUnLock(lock);
|
||||
KERNEL_FREE(mq);
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static struct MsgQueueDone Done = {
|
||||
.init = _InitMsgQueue ,
|
||||
.urgensend = _MsgQueueUrgentSend,
|
||||
.send = _MsgQueueSend,
|
||||
.recv = _MsgQueueRecv,
|
||||
.reinit = _MsgQueueReinit,
|
||||
.Delete = _DeleteMsgQueue
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will create a msg queue.
|
||||
*
|
||||
* @param msg_size the length of the msg queue.
|
||||
* @param max_msgs the max length of the msg queue.
|
||||
*
|
||||
* @return id on success;ENOMEMORY/ERROR on failure
|
||||
*/
|
||||
int32 KCreateMsgQueue(x_size_t msg_size,
|
||||
x_size_t max_msgs)
|
||||
{
|
||||
int32 id = 0;
|
||||
x_base temp = 0;
|
||||
x_base lock = 0;
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
mq = (struct MsgQueue *)x_malloc(sizeof(struct MsgQueue));
|
||||
if (mq == NONE)
|
||||
return -ENOMEMORY;
|
||||
memset(mq,0x0,sizeof(struct MsgQueue));
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
id = IdInsertObj(&k_mq_id_manager, &mq->id);
|
||||
CriticalAreaUnLock(lock);
|
||||
if (id < 0) {
|
||||
x_free(mq);
|
||||
return -ENOMEMORY;
|
||||
}
|
||||
|
||||
lock = CriticalAreaLock();
|
||||
DoubleLinkListInsertNodeAfter(&k_mq_list, &mq->link);
|
||||
CriticalAreaUnLock(lock);
|
||||
mq->Done = &Done;
|
||||
if( mq->Done->init(mq, msg_size,max_msgs) == EOK )
|
||||
return mq->id.id;
|
||||
else
|
||||
return -ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will reset a event.
|
||||
*
|
||||
* @param id the id number of event.
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*/
|
||||
x_err_t KMsgQueueReinit(int32 id)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->reinit(mq);
|
||||
else
|
||||
return -EINVALED;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* receive message with some waiting time
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
* @param timeout time needed waiting
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueRecv(int32 id,
|
||||
void *buffer,
|
||||
x_size_t size,
|
||||
int32 timeout)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->recv(mq,buffer,size,timeout);
|
||||
else
|
||||
return -EINVALED;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* a dynamic messagequeue will be deleted from the manage list
|
||||
*
|
||||
* @param id the message id
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KDeleteMsgQueue(int32 id)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->Delete(mq);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
|
||||
/**
|
||||
* send urgent message without waiting time, this message will be inserted to the head of the queue
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueUrgentSend(int32 id, const void *buffer, x_size_t size)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->urgensend(mq,buffer,size);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
|
||||
/**
|
||||
* send message without waiting time,current suspend task will be resumed
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueSend(int32 id, const void *buffer, x_size_t size)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->send(mq,buffer,size,0);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
/**
|
||||
* send message with waiting time,current suspend task will be resumed
|
||||
*
|
||||
* @param id the message id
|
||||
* @param buffer message info
|
||||
* @param size the size of buffer
|
||||
* @param timeout waiting time
|
||||
*
|
||||
* @return EOK on success;EINVALED on failure
|
||||
*
|
||||
*/
|
||||
x_err_t KMsgQueueSendwait(int32 id, const void *buffer, x_size_t size,int32 timeout)
|
||||
{
|
||||
struct MsgQueue *mq = NONE;
|
||||
|
||||
if (id < 0)
|
||||
return -EINVALED;
|
||||
|
||||
mq = GetMsgQueueById(id);
|
||||
if (mq != NONE)
|
||||
return mq->Done->send(mq,buffer,size,timeout);
|
||||
else
|
||||
return -EINVALED;
|
||||
}
|
||||
Reference in New Issue
Block a user