?? 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 + -