📄 os_q.c
字号:
/*
*********************************************************************************************************
* uC/OS-II 实时内核
* 消息队列管理
*
* (c) 版权 1992-2002, 所有版权归Jean J. Labrosse, Weston, FL 所有
*
*
* 文件名称 : OS_Q.C
* 程序作者 : Jean J. Labrosse
*********************************************************************************************************
*/
#ifndef OS_MASTER_FILE
#include "includes.h"
#endif
#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
/*
*********************************************************************************************************
* 从队列中获取消息
*
* 函数描述: 该函数检查队列看消息是否有效。不象 OSMboxPend(),如果消息无效,函数OSMboxAccept()不会挂起
* 调用的函数。
*
* 输入参数 : pevent 指向ECB的指针
*
* 返回值 : != (void *)0 如果有效是在队列中的消息。OSQAccept() 再次被调用则队列清零队列为空。
* == (void *)0 队列为空,
* 'pevent' 是空指针,
* 没有传递适当的事件指针
*********************************************************************************************************
*/
#if OS_Q_ACCEPT_EN > 0
void *OSQAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配存储变量 */
OS_CPU_SR cpu_sr;
#endif
void *msg;
OS_Q *pq;
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0)
{ /* 无效的 'pevent' */
return ((void *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q)
{ /* 无效的事件块类型 */
return ((void *)0);
}
#endif
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr; /* 指向QCB */
if (pq->OSQEntries > 0) /* 看队列中是否有消息? */
{
msg = *pq->OSQOut++; /* 是,提取最先进入的消息 */
pq->OSQEntries--; /* 更新队列中的消息数 */
if (pq->OSQOut == pq->OSQEnd) /* 进行边界检查 */
{
pq->OSQOut = pq->OSQStart;
}
}
else
{
msg = (void *)0; /* 队列中的消息为空 */
}
OS_EXIT_CRITICAL();
return (msg); /* 返回接收的消息 (或空指针) */
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* 建立一个消息队列
*
* 函数描述: 如果空余ECB有效,该函数创建消息队列。
*
* 输入参数: start 指向消息队列存储区基址的指针。存储区必须声明指向空的指针阵列,如下:
*
* void *MessageStorage[size]
*
* size 存储区的单元数
*
* 返回值: != (OS_EVENT *)0 指向带有已创建的队列的ECB的指针
* == (OS_EVENT *)0 ECB无效或出错
*********************************************************************************************************
*/
OS_EVENT *OSQCreate (void **start, INT16U size)
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配存储变量 */
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
OS_Q *pq;
if (OSIntNesting > 0)
{ /* 看调用是否来自ISR ... */
return ((OS_EVENT *)0); /* ... 从 ISR中不能创建 */
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; /* 得到空余的ECB */
if (OSEventFreeList != (OS_EVENT *)0) /* 看空余ECB池是否为空? */
{
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0)
{ /* 看是否有一个ECB? */
OS_ENTER_CRITICAL();
pq = OSQFreeList; /* 得到一个队列控制块 */
if (pq != (OS_Q *)0) /* 队列控制块是否为空 ? */
{
OSQFreeList = OSQFreeList->OSQPtr; /* 不为空, 得到QCB */
OS_EXIT_CRITICAL();
pq->OSQStart = start; /* 初始化队列 */
pq->OSQEnd = &start[size];
pq->OSQIn = start;
pq->OSQOut = start;
pq->OSQSize = size;
pq->OSQEntries = 0;
pevent->OSEventType = OS_EVENT_TYPE_Q;
pevent->OSEventCnt = 0;
pevent->OSEventPtr = pq;
OS_EventWaitListInit(pevent); /* 初始化任务等待列表 */
}
else
{
pevent->OSEventPtr = (void *)OSEventFreeList; /* 空, 返回ECB出错 */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
pevent = (OS_EVENT *)0;
}
}
return (pevent);
}
/*$PAGE*/
/*
*********************************************************************************************************
* 删除一个消息队列
*
* 函数描述: 该函数删除一个消息队列和就绪等待消息队列的所有任务。
*
* 输入参数 : pevent 指向带有期望消息队列的ECB的指针
*
* opt 决定删除的选项如下:
* opt == OS_DEL_NO_PEND 只在无任务等待时,才删除队列
* opt == OS_DEL_ALWAYS 即使有任务等待,也要删除队列
* 该种情况下,所有等待任务将就绪.
*
* err 指向下列值之一的出错代码的指针:
* OS_NO_ERR 调用成功,队列被删除
* OS_ERR_DEL_ISR 从 ISR中删除队列
* OS_ERR_INVALID_OPT 指定选项无效
* OS_ERR_TASK_WAITING 一个或更多的任务正等待队列
* OS_ERR_EVENT_TYPE 没有传递一个指向队列的指针
* OS_ERR_PEVENT_NULL 'pevent' 是一个空指针
*
* 返回值 : pevent upon error
* (OS_EVENT *)0 队列成功删除.
*
* 注释 : 1) 该函数使用时要小心。期望消息队列的任务一定要检查OSQPend()的返回值。
* 2) OSQAccept() 的调用函数将不会知道消息邮箱已被删除,除非检查'pevent'是一个空指针。
* 3) 这种调用潜在的关闭中断很长时间。中断关闭时间直接正比于等待消息队列的任务的数量。
* 4) 由于所有等待消息队列的任务将被就绪。所以,必须小心处理队列用在互斥上,因为资源不再受队列保护。
* 5) 如果消息队列的存储动态分配(如使用 malloc() 调用),那么,应用程序必须使用相配的动态释放存储区。
* 如果存储区静态创建,存储能重用。
*********************************************************************************************************
*/
#if OS_Q_DEL_EN > 0
OS_EVENT *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配存储变量 */
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
OS_Q *pq;
if (OSIntNesting > 0)
{ /* 如果调用来自 ISR ... */
*err = OS_ERR_DEL_ISR; /* ... 从ISR中不能删除 */
return ((OS_EVENT *)0);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0)
{ /* 无效的 'pevent' */
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q)
{ /* 无效的事件块类型 */
*err = OS_ERR_EVENT_TYPE;
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00)
{ /* 看是否有任务在等待消息队列? */
tasks_waiting = TRUE; /* 是 */
}
else
{
tasks_waiting = FALSE; /* 否 */
}
switch (opt)
{
case OS_DEL_NO_PEND: /* 只在无任务等待时,才删除队列 */
if (tasks_waiting == FALSE)
{
pq = (OS_Q *)pevent->OSEventPtr; /* 返回 OS_Q 空余列表 */
pq->OSQPtr = OSQFreeList;
OSQFreeList = pq;
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 返回ECB到空余链表中 */
OSEventFreeList = pevent; /* 加入空余链表中 */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* 消息队列被删除 */
}
else
{
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING;
return (pevent);
}
case OS_DEL_ALWAYS: /* 即使有任务等待,也要删除队列 */
while (pevent->OSEventGrp != 0x00)
{
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q); /* 就绪所有等待消息队列的任务 */
}
pq = (OS_Q *)pevent->OSEventPtr; /* 返回 OS_Q 空余列表 */
pq->OSQPtr = OSQFreeList;
OSQFreeList = pq;
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 返回ECB到空余链表中 */
OSEventFreeList = pevent; /* 加入空余链表中 */
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE)
{ /* 如果任务等待重新调度 */
OS_Sched(); /* 寻找最高优先级任务就绪运行 */
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* 消息队列被删除 */
default:
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT;
return (pevent);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -