Ucos源码分析
1.Ucos源码分析------任务控制块与任务调度
2.Ucos源码分析------事件控制块与事件控制
3.Ucos源码分析------信号量
4.Ucos源码分析------邮箱与队列
5.Ucos源码分析------事件标志组
6.Ucos源码分析------内存管理
7.Ucos源码分析------临界区与中断管理
8.Ucos源码分析------OS启动
9.Ucos总结
邮箱与队列----OS_Q.C
邮箱和队列都是用来进行消息传递的,他们的区别是:
邮箱只能传递一个消息, 队列可以传递多个消息。
1.消息队列控制块与环形队列
消息队列控制块的基本成员如下
控制块成员 | 成员类型 | |
---|---|---|
struct os_q *OSQPtr | 队列控制块指针 | 队列控制块连接下一个控制块 |
void **OSQEnd | 指向地址的指针 | 队列起始的地址 |
void **OSQStart | 指向地址的指针 | 队列终止的地址 |
void **OSQIn | 指向地址的指针 | 队列要插入的地址 |
void **OSQOut | 指向地址的指针 | 队列要输出的地址 |
OSQSize | int | 队列大小 |
OSQEntries | int | 当前队列大小 |
消息队列是一个环形队列缓冲区,通过对控制块也可以看出,队列中中存放的是地址。
事情10个大小的队列,队列的真正大小是11,有一个空的没有用到没以队列起始与终止的区分。
2.队列的创建与删除
创建队列
OS_EVENT *OSQCreate (void **start, INT16U size)
参数
start :消息内存区的基地址,消息内存区是一个指针数组。
Size :消息内存区的大小。
OS_EVENT *OSQCreate (void **start, INT16U size)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
//事件控制块
OS_EVENT *pevent;
//队列控制块
OS_Q *pq;
//不能在中断调用
if (OSIntNesting > 0) { /* See if called from ISR ... */
return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
}
OS_ENTER_CRITICAL();
//获取空闲事件控制链表的表头指针
pevent = OSEventFreeList; /* Get next free event control block */
//不是最后一个空闲事件控制块
if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
//空闲事件控制链表的表头指针后移1个
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0) { /* See if we have an event control block */
OS_ENTER_CRITICAL();
//获取空闲队列控制链表的表头指针
pq = OSQFreeList; /* Get a free queue control block */
if (pq != (OS_Q *)0) { /* Were we able to get a queue control block ? */
//空闲队列控制链表的表头指针后移1个
OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/
OS_EXIT_CRITICAL();
//队列控制块初始化
pq->OSQStart = start; /* Initialize the queue */
//start[size] 如果传入size为10 则为start[10]
//在循环队列中没有使用
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); /* Initalize the wait list */
} else {
//pq获取失败,归还事件控制块
pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
pevent = (OS_EVENT *)0;
}
}
return (pevent);
}
队列的删除与信号量的删除查不多,多了一个将队列控制块归还给队列控制块链表
OS_EVENT *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
//归还队列控制块归到队列控制块链表
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 */
3.消息获取–阻塞与无阻塞
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
参数:
pevent :是指向即将接受消息的队列的指针, 由OSQCreate()创建。
Timeout :最大等待时长,用以系统超时判断
Err 是指向包含错误码的变量的指针。
返回值: void *(msg)
如果队列缓冲区有消息,msg从队列中获取
如果队列缓冲区无消息,阻塞调度后,msg从 TCB 的 OSTCBMsg 获取
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);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
*err = OS_ERR_PEVENT_NULL;
return ((void *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */
*err = OS_ERR_EVENT_TYPE;
return ((void *)0);
}
#endif
OS_ENTER_CRITICAL();
//获取当前事件的队列指针
//pevent->OSEventPtr是Void * 需要强制转换为OS_Q *
pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */
//如果队列缓冲区有消息
if (pq->OSQEntries > 0) { /* See if any messages in the queue */
//队列缓冲区获取消息指针
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;
}
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
//返回消息指针
return (msg); /* Return message received */
}
//如果队列缓冲区没有消息
// 1.任务状态等待事件置位
OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */
OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */
//2.任务从就绪表移除;3.任务加入事件等待表
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();
//获取消息指针 此时消息是在OSTCBCur->OSTCBMsg中
msg = OSTCBCur->OSTCBMsg;
//判断是否成功获取消息
if (msg != (void *)0) { /* Did we get a message? */
OSTCBCur->OSTCBMsg = (void *)0; /* Extract message from TCB (Put there by QPost) */
OSTCBCur->OSTCBStat = OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (msg); /* Return message received */
}
//等待超时判断
OS_EventTO(pevent); /* Timed out */
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; /* Indicate a timeout occured */
return ((void *)0); /* No message received */
}
//无阻塞的获取消息
void *OSQAccept (OS_EVENT *pevent)
返回值
如果队列有消息:返回消息指针
如果队列无消息:返回void * 0
void *OSQAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
//消息指针
void *msg;
//队列控制块
OS_Q *pq;
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
return ((void *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block 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 */
//获取队列中的消息
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;
}
}
//如果队列有消息
else {
msg = (void *)0; /* Queue is empty */
}
OS_EXIT_CRITICAL();
return (msg); /* Return message received (or NULL) */
}
4.消息释放–3种
INT8U OSQPost:将消息指针放在队头,-----后入后出
INT8U OSQPostFront:将消息指针放在队尾,-----后入先出
OSQPostOpt :虽然通知所有事件控制块的等待任务,但系统仅调度一次,运行最高优先级任务
OSQPost和OSQPostFront中对队列特殊情况的判断
OSQPost须在添加完信息后,判断下一个消息队列是否为最后一个。
OSQPostFront须在添加完信息前,判断当前消息队列位置是否为第一个。
4.1将消息指针放在队首-----后入后出
INT8U OSQPost (OS_EVENT *pevent, void *msg)
INT8U OSQPost (OS_EVENT *pevent, void *msg)
{
#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);
}
if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */
return (OS_ERR_POST_NULL_PTR);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
//如果事件控制块的 任务等待表 有等待任务
if (pevent->OSEventGrp != 0x00) { /* See if any task pending on queue */
//最高优先级任务从事件等待列表移除;任务事件标志msk清除;加入任务就绪表
//任务控制块的ptcb->OSTCBMsg,指向消息指针
OS_EventTaskRdy(pevent, msg, OS_STAT_Q); /* Ready highest priority task waiting on event */
OS_EXIT_CRITICAL();
//系统调度
OS_Sched(); /* Find highest priority task ready to run */
return (OS_NO_ERR);
}
//如果事件控制块的 任务等待表 无等待任务
//消息指针入队
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
//判断队列是否满
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
OS_EXIT_CRITICAL();
return (OS_Q_FULL);
}
//(*pq->OSQIn) = msg :当前消息指针入队 一个解引用
//(pq->OSQIn) ++ :指向消息指针的指针后移
*pq->OSQIn++ = msg; /* Insert message into queue */
// 队列中消息数目加一
pq->OSQEntries++; /* Update the nbr of entries in the queue */
//在消息入队后 判是否是最后一个消息
if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */
pq->OSQIn = pq->OSQStart;
}
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
4.2将消息指针放在队尾-----后入先出
INT8U OSQPostFront (OS_EVENT *pevent, void *msg)
// 将消息指针放在队尾,-----后入先出
INT8U OSQPostFront (OS_EVENT *pevent, void *msg)
{
#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);
}
if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */
return (OS_ERR_POST_NULL_PTR);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* See if any task pending on queue */
OS_EventTaskRdy(pevent, msg, OS_STAT_Q); /* Ready highest priority task waiting on event */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find highest priority task ready to run */
return (OS_NO_ERR);
}
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
// 判断队列是否满
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
OS_EXIT_CRITICAL();
return (OS_Q_FULL);
}
//在消息入队前 判是否是第一个消息
if (pq->OSQOut == pq->OSQStart) { /* Wrap OUT ptr if we are at the 1st queue entry */
pq->OSQOut = pq->OSQEnd;
}
//将消息指针放在队尾
pq->OSQOut--;
*pq->OSQOut = msg; /* Insert message into queue */
//队列中消息数目+1
pq->OSQEntries++; /* Update the nbr of entries in the queue */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
4.3通用的信号量释放函数
INT8U OSQPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
参数:
pevent:指向即将接受消息的消息队列的指针
Msg 是即将实际发送给任务的消息,消息是一个指针
opt可选参数:
OS_POST_OPT_NONE: 消息发给 优先级最高的任务,消息后入后出(OSQPost())
OS_POST_OPT_FRONT: 消息发给 优先级最高的任务,消息后入先出(OSQPostFront())
OS_POST_OPT_BROADCAST: 消息发给 所有等待事件的任务 消息后入后出
OS_POST_OPT_FRONT + OS_POST_OPT_BROADCAST:消息发给 所有等待事件的任务 消息后入先出
INT8U OSQPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
{
#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);
}
if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */
return (OS_ERR_POST_NULL_PTR);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
//如果事件控制块的 任务等待表 有等待任务
if (pevent->OSEventGrp != 0x00) { /* See if any task pending on queue */
//判断将 消息发给 优先级最高的任务,还是将消息发送给所有任务
if ((opt & OS_POST_OPT_BROADCAST) != 0x00) { /* Do we need to post msg to ALL waiting tasks ? */
//轮询 将有消息发送给所有等待任务
//所有等待任务加入就绪表
while (pevent->OSEventGrp != 0x00) { /* Yes, Post to ALL tasks waiting on queue */
OS_EventTaskRdy(pevent, msg, OS_STAT_Q);
}
} else {
//将有消息发送给优先级最高的任务
OS_EventTaskRdy(pevent, msg, OS_STAT_Q); /* No, Post to HPT waiting on queue */
}
OS_EXIT_CRITICAL();
//系统调度一次
OS_Sched(); /* Find highest priority task ready to run */
return (OS_NO_ERR);
}
//如果事件控制块的 任务等待表 无等待任务
pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */
//确保队列非空
if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */
OS_EXIT_CRITICAL();
return (OS_Q_FULL);
}
//消息 后入先出
if ((opt & OS_POST_OPT_FRONT) != 0x00) { /* Do we post to the FRONT of the queue? */
//在消息入队前 判是否是第一个消息
if (pq->OSQOut == pq->OSQStart) { /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
pq->OSQOut = pq->OSQEnd; /* ... are at the 1st queue entry */
}
pq->OSQOut--;
*pq->OSQOut = msg; /* Insert message into queue */
}
//消息 后入后出
else { /* No, Post as FIFO */
*pq->OSQIn++ = msg; /* Insert message into queue */
//在消息入队后 判是否是最后一个消息
if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */
pq->OSQIn = pq->OSQStart;
}
}
//队列中消息数目加1
pq->OSQEntries++; /* Update the nbr of entries in the queue */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
队列创建后的结构
在消息进行获取释放中,消息在队列的来源