uC/OS-III之任務訊號量
阿新 • • 發佈:2019-02-08
1.給任務釋出訊號量是一種非常常用的同步方法,因此,在uC/OS-III中,每個任務都有它自己的內嵌訊號量。
2.當建立任務時,任務訊號量會被自動建立,且初始計數為零。
3.等待任務訊號量使用函式OSTaskSemPend(),它的定義位於os_task.c中。
OS_SEM_CTR OSTaskSemPend (OS_TICK timeout, // 1190行 - 1293行,超時時間
OS_OPT opt, // 等待的方式
CPU_TS * p_ts, // 時間戳
OS_ERR *p_err) // 錯誤碼
{
OS_SEM_CTR ctr;
CPU_SR_ALLOC(); // 宣告變數cpu_sr,用來臨時儲存CPU的狀態暫存器
#ifdef OS_SAFETY_CRITICAL // 允許進行系統安全性檢查
if (p_err == (OS_ERR * )0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_SEM_CTR)0);
}
#endif
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允許進行ISR呼叫檢查
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 不允許在ISR中呼叫
*p_err = OS_ERR_PEND_ISR;
return ((OS_SEM_CTR)0 );
}
#endif
if (p_ts != (CPU_TS *)0) {
*p_ts = (CPU_TS )0; // 初始化返回的時間戳
}
CPU_CRITICAL_ENTER(); // 進入臨界區
if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)0) { // 計數值 > 0,表示訊號量可用
OSTCBCurPtr->SemCtr--; // 計數值減1
ctr = OSTCBCurPtr->SemCtr;
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
#if OS_CFG_TASK_PROFILE_EN > 0u // ???
OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
if (OSTCBCurPtr->SemPendTime > OSTCBCurPtr->SemPendTimeMax) {
OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
}
#endif
CPU_CRITICAL_EXIT(); // 退出臨界區
*p_err = OS_ERR_NONE;
return (ctr);
}
// 計數值 == 0,訊號量不可用
if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { // 非阻塞型
CPU_CRITICAL_EXIT(); // 退出臨界區
*p_err = OS_ERR_PEND_WOULD_BLOCK;
return ((OS_SEM_CTR)0);
} else { // 阻塞型
if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 任務排程器鎖定,無法掛起任務
CPU_CRITICAL_EXIT(); // 退出臨界區
*p_err = OS_ERR_SCHED_LOCKED;
return ((OS_SEM_CTR)0);
}
}
OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 鎖定排程器,使能中斷
OS_Pend((OS_PEND_DATA *)0, // 把任務新增到掛起表中
(OS_PEND_OBJ *)0,
(OS_STATE )OS_TASK_PEND_ON_TASK_SEM,
(OS_TICK )timeout);
OS_CRITICAL_EXIT_NO_SCHED(); // 退出臨界區,不排程
OSSched(); // 執行任務排程程式
CPU_CRITICAL_ENTER(); // 進入臨界區
switch (OSTCBCurPtr->PendStatus) { // 檢視等待訊號量的結果
case OS_STATUS_PEND_OK: // 訊號量釋出了
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
#if OS_CFG_TASK_PROFILE_EN > 0u
OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
if (OSTCBCurPtr->SemPendTime > OSTCBCurPtr->SemPendTimeMax) {
OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
}
#endif
}
*p_err = OS_ERR_NONE;
break;
case OS_STATUS_PEND_ABORT: // 等待操作被其他任務取消了
if (p_ts != (CPU_TS *)0) {
*p_ts = OSTCBCurPtr->TS;
}
*p_err = OS_ERR_PEND_ABORT;
break;
case OS_STATUS_PEND_TIMEOUT: // 在特定的超時時間內,訊號量沒有被髮布
if (p_ts != (CPU_TS *)0) {
*p_ts = (CPU_TS )0;
}
*p_err = OS_ERR_TIMEOUT;
break;
default: // 其他情況
*p_err = OS_ERR_STATUS_INVALID;
break;
}
ctr = OSTCBCurPtr->SemCtr;
CPU_CRITICAL_EXIT(); // 退出臨界區
return (ctr);
}
4.釋出任務訊號量使用OSTaskSemPost(),它的定義位於os_task.c中。
OS_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb, // 1401行 - 1439行
OS_OPT opt, // 釋出任務訊號量的方式
OS_ERR *p_err)
{
OS_SEM_CTR ctr;
CPU_TS ts;
#ifdef OS_SAFETY_CRITICAL // 允許進行系統安全性檢查
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_SEM_CTR)0);
}
#endif
ts = OS_TS_GET(); // 獲取時間戳
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u // 延遲釋出模式
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 檢視是否是在ISR中呼叫該函式
OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_SIGNAL, // 寫入到中斷佇列中
(void *)p_tcb,
(void *)0,
(OS_MSG_SIZE)0,
(OS_FLAGS )0,
(OS_OPT )0,
(CPU_TS )ts,
(OS_ERR *)p_err);
return ((OS_SEM_CTR)0);
}
#endif
ctr = OS_TaskSemPost(p_tcb, // 釋出訊號量
opt,
ts,
p_err);
return (ctr);
}
釋出任務訊號量的方式有以下兩種:
OS_OPT_POST_NONE表明釋出任務訊號量之後呼叫排程程式;
OS_OPT_POST_NO_SCHED表明在OSTaskSemPost()的末尾不會呼叫排程程式。
5.任務訊號量做雙向同步時,不能用於任務和ISR之間的同步,因為ISR不能等待訊號量。