📄 os_q.c
字号:
BOOLEAN tasks_waiting;
OS_Q *pq;
if (OSIntNesting > 0) { /* See if called from ISR ... */
*err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
return ((OS_EVENT *)0);
}//不能在中断服务程序中删除
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
*err = OS_ERR_PEVENT_NULL;
return (pevent);//pevent不合理
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
*err = OS_ERR_EVENT_TYPE;
return (pevent);//非法的事件块模式
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* See if any tasks waiting on queue */
//如果有任务在队列中等待
tasks_waiting = TRUE; /* Yes */
} else {
tasks_waiting = FALSE; /* No */
}
switch (opt) {
case OS_DEL_NO_PEND: /* Delete queue only if no task waiting */
//如果只在无任务等待的情况下删除
if (tasks_waiting == FALSE) {//无任务等待
pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */
pq->OSQPtr = OSQFreeList;
OSQFreeList = pq;//将它加入了空闲链表
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;//标记未用
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
OSEventFreeList = pevent; /* Get next free event control block *///将事件控制块放入空闲链表中
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;//无错
return ((OS_EVENT *)0); /* Queue has been deleted */
} else {//有任务等待
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING;
return (pevent);
}
case OS_DEL_ALWAYS: /* Always delete the queue */
//始终要删除队列
while (pevent->OSEventGrp != 0x00) { /* Ready ALL tasks waiting for queue */
//真有任务等待
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q);//将挂起的任务就绪
}
pq = (OS_Q *)pevent->OSEventPtr; /* Return OS_Q to free list */
pq->OSQPtr = OSQFreeList;
OSQFreeList = pq;//同上,将队列控制块放入空闲链表
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;//标记为未用
pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
OSEventFreeList = pevent; /* Get next free event control block */
//将事件控制块放入空闲链表
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE) { /* Reschedule only if task(s) were waiting */
OS_Sched(); /* Find highest priority task ready to run */
//因为新任务就绪,所以要重新调度
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* Queue has been deleted */
default://其它异常情况
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT;
return (pevent);
}
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* FLUSH QUEUE
*
* Description : This function is used to flush the contents of the message queue.
*
* Arguments : none
*
* Returns : OS_NO_ERR upon success
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a queue
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
清空消息队列
描述:清空消息队列中内容
参数:无
返回:
OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 没有传递指针给队列
* OS_ERR_PEVENT_NULL 如果'pevent' 是一个空指针
*********************************************************************************************************
*/
#if OS_Q_FLUSH_EN > 0
INT8U OSQFlush (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
OS_Q *pq;
#if OS_ARG_CHK_EN > 0//允许参数检验
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
return (OS_ERR_PEVENT_NULL);
}//不合理的参数pevent
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}//不是事件块类型
#endif
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue storage structure */
//保存结构指针
pq->OSQIn = pq->OSQStart;
pq->OSQOut = pq->OSQStart;//将队列的插入指针IN和取出指针OUT复位
pq->OSQEntries = 0;//初始化入口为零
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* PEND ON A QUEUE FOR A MESSAGE
*
* Description: This function waits for a message to be sent to a queue
*
* Arguments : pevent is a pointer to the event control block associated with the desired queue
*
* timeout is an optional timeout period (in clock ticks). If non-zero, your task will
* wait for a message to arrive at the queue up to the amount of time
* specified by this argument. If you specify 0, however, your task will wait
* forever at the specified queue or, until a message arrives.
*
* err is a pointer to where an error message will be deposited. Possible error
* messages are:
*
* OS_NO_ERR The call was successful and your task received a
* message.
* OS_TIMEOUT A message was not received within the specified timeout
* OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
* would lead to a suspension.
*
* Returns : != (void *)0 is a pointer to the message received
* == (void *)0 if no message was received or,
* if 'pevent' is a NULL pointer or,
* if you didn't pass a pointer to a queue.
等待消息队列中的消息
描述:等待消息中的队列
参数:pevent:指向事件控制块结合目标队列的指针
timeout:超时时间选项(按时钟节拍来),如果非零,任务将按照此
参数的定时在队列中等待消息到来,如果设置为零,任务将在目标
队列中永远等待,直到消息到来。
err:指向可能的错误消息的指针,可能为:
* OS_NO_ERR 调用成功,任务接收到消息
* OS_TIMEOUT 定时时间内消息没有来
* OS_ERR_EVENT_TYPE 你没有传递指针到队列
* OS_ERR_PEVENT_NULL 如果 'pevent' 是一个空指针
* OS_ERR_PEND_ISR 如果从ISR中调用,结果将出现异常
*********************************************************************************************************
*/
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
void *msg;
OS_Q *pq;
if (OSIntNesting > 0) { /* See if called from ISR ... */
*err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
return ((void *)0);//不能在ISR中挂起
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
*err = OS_ERR_PEVENT_NULL;
return ((void *)0);//不合理的pevent
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
*err = OS_ERR_EVENT_TYPE;
return ((void *)0);//不是事件块类型
}
#endif
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
//取出队列控制块指针
if (pq->OSQEntries > 0) { /* See if any messages in the queue */
//大于零,表示有消息可以用。此时,OSQPend得到事件控制块的.OSQOut域所指
//向的消息,将指向消息的指针复制到msg变量中,并让.OSQOut指针指向
//队列中的下个单元
msg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */
pq->OSQEntries--; /* Update the number of entries in the queue */
// 队列中有效消息减一
if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */
pq->OSQOut = pq->OSQStart;
}//消息队列是一个循环缓冲区,如果超出了队列中最末一个单元,发生
//这种越界时,就要将.OSQOut重新调整到指向队列的起始单元
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (msg); /* Return message received *///返回接收到的消息
}
OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */
//设置任务的TCB状态标志,以表明等待消息队列消息的任务被挂起
OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */
//装载定时器到TCB
OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
//挂起任务直到消息到来或者超时。在用户进程中,调用此函数的任务
//并不知道消息没有到来之前自己被挂起,队列接收到一则消息或者超时
//时,此函数就会调用调度函数恢复运行。
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next highest priority task ready to run */
//挂起后要进行任务调度。
OS_ENTER_CRITICAL();
msg = OSTCBCur->OSTCBMsg;//任务调度后,任务会检查此函数是不是将消息放到了
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -