在實際任務(wù)間的通信中,一個或多個任務(wù)發(fā)送一個信號量或者消息給另一個任務(wù)是比常見的,而一個任務(wù)給多個任務(wù)發(fā)送信號量和消息相對比較少。前面所講的信號量和消息隊列均是單獨的內(nèi)核對象,是獨立于任務(wù)存在的。這兩章要講述的任務(wù)信號量和任務(wù)消息隊列是
任務(wù)特有的屬性,緊緊依賴于一個特定任務(wù)。
任務(wù)信號量和任務(wù)消息隊列分別與多值信號量和消息隊列非常相似,不同之處是,前者僅發(fā)布給一個特定任務(wù),而后者可以發(fā)布給多個任務(wù)。因此,前者的操作相對比較簡單,而且省時。如果任務(wù)信號量和任務(wù)消息隊列可以滿足設(shè)計需求,那么盡量不要使用普通多值信號量和消息隊列
任務(wù)信號量伴隨任務(wù)存在,只要創(chuàng)建了任務(wù),其任務(wù)信號量就是該任務(wù)的一個數(shù)據(jù)成員,任務(wù)信號量的數(shù)據(jù)成員被包含在任務(wù)控制塊里。
OSTaskSemPost ()
OSTaskSemPost () 函數(shù)用于給一個任務(wù)發(fā)布任務(wù)信號量。OSTaskSemPost () 函數(shù)的信息如下表所示。
OSTaskSemPost () 函數(shù)的定義也位于“os_task.c”:
S_SEM_CTR OSTaskSemPost (OS_TCB *p_tcb,
//目標(biāo)任務(wù)OS_OPT opt,
//選項OS_ERR *p_err)
//返回錯誤類型
{OS_SEM_CTR ctr;CPU_TS ts;#ifdef OS_SAFETY_CRITICAL //如果使能(默認(rèn)禁用)了安全檢測if (p_err == (OS_ERR *)
0) {
//如果 p_err 為空OS_SAFETY_CRITICAL_EXCEPTION();
//執(zhí)行安全檢測異常函數(shù)return ((OS_SEM_CTR)
0);
//返回0(有錯誤),停止執(zhí)行
}
#endif#if OS_CFG_ARG_CHK_EN > 0u
//如果使能(默認(rèn)使能)了參數(shù)檢測功能switch (opt) {
//根據(jù)選項分類處理case OS_OPT_POST_NONE:
//如果選項在預(yù)期之內(nèi)case OS_OPT_POST_NO_SCHED:break;
//跳出default:
//如果選項超出預(yù)期*p_err = OS_ERR_OPT_INVALID;
//錯誤類型為“選項非法”return ((OS_SEM_CTR)
0u);
//返回0(有錯誤),停止執(zhí)行
}
#endifts = OS_TS_GET();
//獲取時間戳#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
//如果使能了中斷延遲發(fā)布if (OSIntNestingCtr > (OS_NESTING_CTR)
0) {
//如果該函數(shù)是在中斷中被調(diào)用OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_SIGNAL,
//將該信號量發(fā)布到中斷消息隊列(
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);
//返回0(尚未發(fā)布)
}
#endifctr = OS_TaskSemPost(p_tcb,
//將信號量按照普通方式處理
opt,ts,p_err);return (ctr);
//返回信號的當(dāng)前計數(shù)值
}
OSTaskSemPost() 其實,不管是否使能了中斷延遲發(fā)布,最終都是調(diào)用 OS_TaskSemPost() 函數(shù)進(jìn)行發(fā)布信號量。只是使能了中斷延遲發(fā)布的發(fā)布過程會比較曲折,中間會有許多插曲,這是中斷管理范疇的內(nèi)容。
OS_TaskSemPost() 函數(shù)的定義位于“os_task.c”:
OS_SEM_CTR OS_TaskSemPost (OS_TCB *p_tcb,
//目標(biāo)任務(wù)OS_OPT opt,
//選項CPU_TS ts,
//時間戳OS_ERR *p_err)
//返回錯誤類型
{OS_SEM_CTR ctr;CPU_SR_ALLOC(); //使用到臨界段(在關(guān)/開中斷時)時必需該宏,該宏聲明和//定義一個局部變量,用于保存關(guān)中斷前的 CPU 狀態(tài)寄存器// SR(臨界段關(guān)中斷只需保存SR),開中斷時將該值還原。
OS_CRITICAL_ENTER(); //進(jìn)入臨界段if (p_tcb == (OS_TCB *)
0) {
//如果 p_tcb 為空p_tcb = OSTCBCurPtr;
//將任務(wù)信號量發(fā)給自己(任務(wù))
}p_tcb->TS = ts;
//記錄信號量被發(fā)布的時間戳*p_err = OS_ERR_NONE;
//錯誤類型為“無錯誤”switch (p_tcb->TaskState) {
//跟吳目標(biāo)任務(wù)的任務(wù)狀態(tài)分類處理case OS_TASK_STATE_RDY:
//如果目標(biāo)任務(wù)沒有等待狀態(tài)case OS_TASK_STATE_DLY:case OS_TASK_STATE_SUSPENDED:case OS_TASK_STATE_DLY_SUSPENDED:switch (
sizeof(OS_SEM_CTR)) {
//判斷是否將導(dǎo)致該信case 1u:
//號量計數(shù)值溢出,如if (p_tcb->SemCtr == DEF_INT_08U_MAX_VAL) {
//果溢出,則開中斷,OS_CRITICAL_EXIT();
//返回錯誤類型為“計*p_err = OS_ERR_SEM_OVF;
//數(shù)值溢出”,返回0return ((OS_SEM_CTR)
0);
//(有錯誤),不繼續(xù)}
//執(zhí)行。break; case 2u:if (p_tcb->SemCtr ==
DEF_INT_16U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err =
OS_ERR_SEM_OVF;return ((OS_SEM_CTR)
0);}break;case 4u:if (p_tcb->SemCtr ==
DEF_INT_32U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err =
OS_ERR_SEM_OVF;return ((OS_SEM_CTR)
0);}break;default:break;}p_tcb->SemCtr++;
//信號量計數(shù)值不溢出則加1ctr = p_tcb->SemCtr;
//獲取信號量的當(dāng)前計數(shù)值OS_CRITICAL_EXIT();
//退出臨界段break;
//跳出case OS_TASK_STATE_PEND:
//如果任務(wù)有等待狀態(tài)case OS_TASK_STATE_PEND_TIMEOUT:case OS_TASK_STATE_PEND_SUSPENDED:case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:if (p_tcb->PendOn == OS_TASK_PEND_ON_TASK_SEM) {
//如果正等待任務(wù)信號量OS_Post((OS_PEND_OBJ *)
0,
//發(fā)布信號量給目標(biāo)任務(wù)(OS_TCB *
)p_tcb,(void *)
0,(OS_MSG_SIZE )0u,(CPU_TS )ts);ctr = p_tcb->SemCtr;
//獲取信號量的當(dāng)前計數(shù)值OS_CRITICAL_EXIT_NO_SCHED();
//退出臨界段(無調(diào)度)if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)
0) {
//如果選擇了調(diào)度任務(wù)OSSched();
//調(diào)度任務(wù)
}} else {
//如果沒等待任務(wù)信號量switch (
sizeof(OS_SEM_CTR)) {
//判斷是否將導(dǎo)致case 1u:
//該信號量計數(shù)值if (p_tcb->SemCtr == DEF_INT_08U_MAX_VAL) {
//溢出,如果溢出,OS_CRITICAL_EXIT();
//則開中斷,返回*p_err = OS_ERR_SEM_OVF;
//錯誤類型為“計return ((OS_SEM_CTR)
0);
//數(shù)值溢出”,返}
//回0(有錯誤),break;
//不繼續(xù)執(zhí)行。case 2u:if (p_tcb->SemCtr ==
DEF_INT_16U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err =
OS_ERR_SEM_OVF;return ((OS_SEM_CTR)
0);}break;case 4u:if (p_tcb->SemCtr ==
DEF_INT_32U_MAX_VAL) {OS_CRITICAL_EXIT();*p_err =
OS_ERR_SEM_OVF;return ((OS_SEM_CTR)
0);}break;default:break;}p_tcb->SemCtr++;
//信號量計數(shù)值不溢出則加1ctr = p_tcb->SemCtr;
//獲取信號量的當(dāng)前計數(shù)值OS_CRITICAL_EXIT();
//退出臨界段
}break;
//跳出default:
//如果任務(wù)狀態(tài)超出預(yù)期OS_CRITICAL_EXIT();
//退出臨界段*p_err = OS_ERR_STATE_INVALID;
//錯誤類型為“狀態(tài)非法”ctr = (OS_SEM_CTR)
0;
//清零 ctrbreak;
//跳出
}return (ctr);
//返回信號量的當(dāng)前計數(shù)值
}
OS_TaskSemPost() 在 OS_SemPost() 函數(shù)中,又會調(diào)用 OS_Post() 函數(shù)發(fā)布內(nèi)核對象。OS_Post() 函數(shù)是一個底層的發(fā)布函數(shù),它不僅僅用來發(fā)布任務(wù)信號量,還可以發(fā)布多值信號量、互斥信號量、消息隊列、事件標(biāo)志組或任務(wù)消息隊列。注意,在這里,OS_Post() 函數(shù)將任務(wù)信號量直接發(fā)布給目標(biāo)任務(wù)。
OS_Post() 函數(shù)的定義位于“os_core.c”。:
void OS_Post (OS_PEND_OBJ *p_obj,
//內(nèi)核對象類型指針OS_TCB *p_tcb,
//任務(wù)控制塊void *p_void,
//消息OS_MSG_SIZE msg_size,
//消息大小CPU_TS ts)
//時間戳
{switch (p_tcb->TaskState) {
//根據(jù)任務(wù)狀態(tài)分類處理case OS_TASK_STATE_RDY:
//如果任務(wù)處于就緒狀態(tài)case OS_TASK_STATE_DLY:
//如果任務(wù)處于延時狀態(tài)case OS_TASK_STATE_SUSPENDED:
//如果任務(wù)處于掛起狀態(tài)case OS_TASK_STATE_DLY_SUSPENDED:
//如果任務(wù)處于延時中被掛起狀態(tài)break;
//不用處理,直接跳出case OS_TASK_STATE_PEND:
//如果任務(wù)處于無期限等待狀態(tài)case OS_TASK_STATE_PEND_TIMEOUT:
//如果任務(wù)處于有期限等待狀態(tài)if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
//如果任務(wù)在等待多個信號量或消息隊列OS_Post1(p_obj,
//標(biāo)記哪個內(nèi)核對象被發(fā)布
p_tcb,p_void,msg_size,ts);} else {
//如果任務(wù)不是在等待多個信號量或消息隊列
#if (OS_MSG_EN > 0u)
//如果使能了任務(wù)隊列或消息隊列p_tcb->MsgPtr = p_void;
//保存消息到等待任務(wù)p_tcb->MsgSize =
msg_size;
#endifp_tcb->TS = ts;
//保存時間戳到等待任務(wù)
}if (p_obj != (OS_PEND_OBJ *)
0) {
//如果內(nèi)核對象為空OS_PendListRemove(p_tcb);
//從等待列表移除該等待任務(wù)
#if OS_CFG_DBG_EN > 0u
//如果使能了調(diào)試代碼和變量 OS_PendDbgNameRemove(p_obj, //移除內(nèi)核對象的調(diào)試名
p_tcb);
#endif}OS_TaskRdy(p_tcb); //讓該等待任務(wù)準(zhǔn)備運行p_tcb->TaskState = OS_TASK_STATE_RDY;
//任務(wù)狀態(tài)改為就緒狀態(tài)p_tcb->PendStatus = OS_STATUS_PEND_OK;
//清除等待狀態(tài)p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;
//標(biāo)記不再等待break;case OS_TASK_STATE_PEND_SUSPENDED:
//如果任務(wù)在無期限等待中被掛起case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
//如果任務(wù)在有期限等待中被掛起if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
//如果任務(wù)在等待多個信號量或消息隊列OS_Post1(p_obj,
//標(biāo)記哪個內(nèi)核對象被發(fā)布
p_tcb,p_void,msg_size,ts);} else {
//如果任務(wù)不在等待多個信號量或消息隊列
#if (OS_MSG_EN > 0u)
//如果使能了調(diào)試代碼和變量p_tcb->MsgPtr = p_void;
//保存消息到等待任務(wù)p_tcb->MsgSize =
msg_size;
#endifp_tcb->TS = ts;
//保存時間戳到等待任務(wù)
}OS_TickListRemove(p_tcb); //從節(jié)拍列表移除該等待任務(wù)if (p_obj != (OS_PEND_OBJ *)
0) {
//如果內(nèi)核對象為空OS_PendListRemove(p_tcb);
//從等待列表移除該等待任務(wù)
#if OS_CFG_DBG_EN > 0u
//如果使能了調(diào)試代碼和變量 OS_PendDbgNameRemove(p_obj, //移除內(nèi)核對象的調(diào)試名
p_tcb);
#endif}p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
//任務(wù)狀態(tài)改為被掛起狀態(tài)p_tcb->PendStatus = OS_STATUS_PEND_OK;
//清除等待狀態(tài)p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;
//標(biāo)記不再等待break;default:
//如果任務(wù)狀態(tài)超出預(yù)期break;
//直接跳出
}
} OS_Post() OSTaskSemPend ()?
與 OSSemPost () 多值信號量發(fā)布函數(shù)相對應(yīng),OSTaskSemPend () 函數(shù)用于等待任務(wù)信號量。
OSTaskSemPend () 函數(shù)的定義也位于“os_task.c:
OS_SEM_CTR OSTaskSemPend (OS_TICK timeout,
//等待超時時間OS_OPT opt,
//選項CPU_TS *p_ts,
//返回時間戳OS_ERR *p_err)
//返回錯誤類型
{OS_SEM_CTR ctr;CPU_SR_ALLOC(); //使用到臨界段(在關(guān)/開中斷時)時必需該宏,該宏聲明和//定義一個局部變量,用于保存關(guān)中斷前的 CPU 狀態(tài)寄存器// SR(臨界段關(guān)中斷只需保存SR),開中斷時將該值還原。
#ifdef OS_SAFETY_CRITICAL //如果使能了安全檢測if (p_err == (OS_ERR *)
0) {
//如果錯誤類型實參為空OS_SAFETY_CRITICAL_EXCEPTION();
//執(zhí)行安全檢測異常函數(shù)return ((OS_SEM_CTR)
0);
//返回0(有錯誤),停止執(zhí)行
}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
//如果使能了中斷中非法調(diào)用檢測if (OSIntNestingCtr > (OS_NESTING_CTR)
0) {
//如果該函數(shù)在中斷中被調(diào)用*p_err = OS_ERR_PEND_ISR;
//返回錯誤類型為“在中斷中等待”return ((OS_SEM_CTR)
0);
//返回0(有錯誤),停止執(zhí)行
}
#endif#if OS_CFG_ARG_CHK_EN > 0u
//如果使能了參數(shù)檢測switch (opt) {
//根據(jù)選項分類處理case OS_OPT_PEND_BLOCKING:
//如果選項在預(yù)期內(nèi)case OS_OPT_PEND_NON_BLOCKING:break;
//直接跳出default:
//如果選項超出預(yù)期*p_err = OS_ERR_OPT_INVALID;
//錯誤類型為“選項非法”return ((OS_SEM_CTR)
0);
//返回0(有錯誤),停止執(zhí)行
}
#endifif (p_ts != (CPU_TS *)
0) {
//如果 p_ts 非空*p_ts = (CPU_TS )
0;
//清零(初始化)p_ts
}CPU_CRITICAL_ENTER(); //關(guān)中斷 if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)
0) {
//如果任務(wù)信號量當(dāng)前可用OSTCBCurPtr->SemCtr--;
//信號量計數(shù)器減1ctr = OSTCBCurPtr->SemCtr;
//獲取信號量的當(dāng)前計數(shù)值if (p_ts != (CPU_TS *)
0) {
//如果 p_ts 非空*p_ts = OSTCBCurPtr->TS;
//返回信號量被發(fā)布的時間戳
}
#if OS_CFG_TASK_PROFILE_EN > 0u
//如果使能了任務(wù)控制塊的簡況變量OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->TS;
//更新任務(wù)等待if (OSTCBCurPtr->SemPendTimeMax < OSTCBCurPtr->SemPendTime) {
//任務(wù)信號量的OSTCBCurPtr->SemPendTimeMax = OSTCBCurPtr->SemPendTime;
//最長時間記錄。
}
#endifCPU_CRITICAL_EXIT(); //開中斷 *p_err = OS_ERR_NONE;
//錯誤類型為“無錯誤”return (ctr);
//返回信號量的當(dāng)前計數(shù)值
}/* 如果任務(wù)信號量當(dāng)前不可用 */if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)
0) {
//如果選擇了不阻塞任務(wù)CPU_CRITICAL_EXIT();
//開中斷*p_err = OS_ERR_PEND_WOULD_BLOCK;
//錯誤類型為“缺乏阻塞”return ((OS_SEM_CTR)
0);
//返回0(有錯誤),停止執(zhí)行}
else {
//如果選擇了阻塞任務(wù)if (OSSchedLockNestingCtr > (OS_NESTING_CTR)
0) {
//如果調(diào)度器被鎖CPU_CRITICAL_EXIT();
//開中斷*p_err = OS_ERR_SCHED_LOCKED;
//錯誤類型為“調(diào)度器被鎖”return ((OS_SEM_CTR)
0);
//返回0(有錯誤),停止執(zhí)行
}}/* 如果調(diào)度器未被鎖 */OS_CRITICAL_ENTER_CPU_EXIT(); //鎖調(diào)度器,重開中斷 OS_Pend((OS_PEND_DATA *)
0,
//阻塞任務(wù),等待信號量。(OS_PEND_OBJ *)
0,
//不需插入等待列表。
(OS_STATE )OS_TASK_PEND_ON_TASK_SEM,(OS_TICK )timeout);OS_CRITICAL_EXIT_NO_SCHED(); //開調(diào)度器(無調(diào)度)
OSSched(); //調(diào)度任務(wù)/* 任務(wù)獲得信號量后得以繼續(xù)運行 */CPU_CRITICAL_ENTER(); //關(guān)中斷switch (OSTCBCurPtr->PendStatus) {
//根據(jù)任務(wù)的等待狀態(tài)分類處理case OS_STATUS_PEND_OK:
//如果任務(wù)成功獲得信號量if (p_ts != (CPU_TS *)
0) {
//返回信號量被發(fā)布的時間戳*p_ts = OSTCBCurPtr->
TS;
#if OS_CFG_TASK_PROFILE_EN > 0u
//更新最長等待時間記錄OSTCBCurPtr->SemPendTime = OS_TS_GET() - OSTCBCurPtr->
TS;if (OSTCBCurPtr->SemPendTimeMax < OSTCBCurPtr->
SemPendTime) {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) {
//返回時間戳為0*p_ts = (CPU_TS )
0;}*p_err = OS_ERR_TIMEOUT;
//錯誤類型為“等待超時”break;
//跳出default:
//如果等待狀態(tài)超出預(yù)期*p_err = OS_ERR_STATUS_INVALID;
//錯誤類型為“狀態(tài)非法”break;
//跳出
} ctr = OSTCBCurPtr->SemCtr;
//獲取信號量的當(dāng)前計數(shù)值CPU_CRITICAL_EXIT();
//開中斷return (ctr);
//返回信號量的當(dāng)前計數(shù)值
}
OSTaskSemPend() 當(dāng)需要阻塞任務(wù),等待任務(wù)信號量時,OSTaskSemPend () 函數(shù)會調(diào)用一個更加底層的等待函數(shù)來執(zhí)行當(dāng)前任務(wù)對多值信號量的等待,該函數(shù)就是 OS_Pend()。與 OS_Post() 函數(shù)一樣,OS_Pend() 函數(shù)不僅僅用來等待任務(wù)信號量,還可以等待多值信號量、互斥信號量、消息隊列、事件標(biāo)志組或任務(wù)消息隊列。注意,在這里,OS_Pend()函數(shù)并沒有把當(dāng)前任務(wù)插入到等待列表。
OS_Pend() 函數(shù)的定義位于“os_core.c”:
void OS_Pend (OS_PEND_DATA *p_pend_data,
//待插入等待列表的元素OS_PEND_OBJ *p_obj,
//等待的內(nèi)核對象OS_STATE pending_on,
//等待哪種對象內(nèi)核OS_TICK timeout)
//等待期限
{OS_PEND_LIST *
p_pend_list;OSTCBCurPtr->PendOn = pending_on;
//資源不可用,開始等待OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK;
//正常等待中
OS_TaskBlock(OSTCBCurPtr, //阻塞當(dāng)前運行任務(wù),timeout);
//如果 timeout 非0,把任務(wù)插入的節(jié)拍列表if (p_obj != (OS_PEND_OBJ *)
0) {
//如果等待對象非空p_pend_list = &p_obj->PendList;
//獲取對象的等待列表到 p_pend_listp_pend_data->PendObjPtr = p_obj;
//保存要等待的對象OS_PendDataInit((OS_TCB *)OSTCBCurPtr,
//初始化 p_pend_data(待插入等待列表)(OS_PEND_DATA *
)p_pend_data,(OS_OBJ_QTY )1);OS_PendListInsertPrio(p_pend_list, //按優(yōu)先級將 p_pend_data 插入到等待列表
p_pend_data);} else {
//如果等待對象為空OSTCBCurPtr->PendDataTblEntries = (OS_OBJ_QTY )
0;
//清零當(dāng)前任務(wù)的等待域數(shù)據(jù)OSTCBCurPtr->PendDataTblPtr = (OS_PEND_DATA *)
0; }
#if OS_CFG_DBG_EN > 0u
//如果使能了調(diào)試代碼和變量 OS_PendDbgNameAdd(p_obj, //更新信號量的 DbgNamePtr 元素為其等待OSTCBCurPtr);
//列表中優(yōu)先級最高的任務(wù)的名稱。
#endif
} OS_Pend() OSTaskSemPendAbort ()?
OSTaskSemPendAbort() 函數(shù)用于中止一個任務(wù)對其任務(wù)信號量的等待。要使用OSTaskSemPendAbort() 函數(shù),還得事先使能 OS_CFG_TASK_SEM_PEND_ABORT_EN(位于“os_cfg.h”)
#define OS_CFG_TASK_SEM_PEND_ABORT_EN 1u
//使能/禁用函數(shù) OSTaskSemPendAbort() OSTaskSemPendAbort() 函數(shù)的信息如下表所示。
OSTaskSemPendAbort() 函數(shù)的定義位于“os_task.c”:
#if OS_CFG_TASK_SEM_PEND_ABORT_EN > 0u
//如果使能了 OSTaskSemPendAbort()
CPU_BOOLEAN OSTaskSemPendAbort (OS_TCB *p_tcb,
//目標(biāo)任務(wù)OS_OPT opt,
//選項OS_ERR *p_err)
//返回錯誤類型
{CPU_TS ts;CPU_SR_ALLOC(); //使用到臨界段(在關(guān)/開中斷時)時必需該宏,該宏聲明和//定義一個局部變量,用于保存關(guān)中斷前的 CPU 狀態(tài)寄存器// SR(臨界段關(guān)中斷只需保存SR),開中斷時將該值還原。
#ifdef OS_SAFETY_CRITICAL //如果使能了安全檢測if (p_err == (OS_ERR *)
0) {
//如果錯誤類型實參為空OS_SAFETY_CRITICAL_EXCEPTION();
//執(zhí)行安全檢測異常函數(shù)return (DEF_FALSE);
//返回(失敗),停止執(zhí)行
}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
//如果使能了中斷中非法調(diào)用檢測if (OSIntNestingCtr > (OS_NESTING_CTR)
0) {
//如果該函數(shù)是在中斷中被調(diào)用*p_err = OS_ERR_PEND_ABORT_ISR;
//錯誤類型為“在中斷中創(chuàng)建對象”return (DEF_FALSE);
//返回(失敗),停止執(zhí)行
}
#endif#if OS_CFG_ARG_CHK_EN > 0u
//如果使能了參數(shù)檢測switch (opt) {
//根據(jù)選項匪類處理case OS_OPT_POST_NONE:
//如果選項在預(yù)期內(nèi)case OS_OPT_POST_NO_SCHED:break;
//直接跳出default:
//如果選項超出預(yù)期*p_err = OS_ERR_OPT_INVALID;
//錯誤類型為“選項非法”return (DEF_FALSE);
//返回(失敗),停止執(zhí)行
}
#endifCPU_CRITICAL_ENTER(); //關(guān)中斷if ((p_tcb == (OS_TCB *)
0) ||
//如果 p_tcb 為空,或者(p_tcb == OSTCBCurPtr)) {
//p_tcb 指向當(dāng)前運行任務(wù)。CPU_CRITICAL_EXIT();
//開中斷*p_err = OS_ERR_PEND_ABORT_SELF;
//錯誤類型為“中止自身”return (DEF_FALSE);
//返回(失敗),停止執(zhí)行
}/* 如果 p_tcb (目標(biāo)任務(wù)) 不是當(dāng)前運行任務(wù)(自身) */if (p_tcb->PendOn != OS_TASK_PEND_ON_TASK_SEM) {
//如果目標(biāo)任務(wù)沒在等待任務(wù)信號量CPU_CRITICAL_EXIT();
//開中斷*p_err = OS_ERR_PEND_ABORT_NONE;
//錯誤類型為“沒在等待任務(wù)信號量”return (DEF_FALSE);
//返回(失敗),停止執(zhí)行
}CPU_CRITICAL_EXIT(); //開中斷
OS_CRITICAL_ENTER(); //進(jìn)入臨界段ts = OS_TS_GET();
//獲取時間戳OS_PendAbort((OS_PEND_OBJ *)
0,
//中止目標(biāo)任務(wù)對信號量的等待
p_tcb, ts);OS_CRITICAL_EXIT_NO_SCHED(); //退出臨界段(無調(diào)度)if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)
0) {
//如果選擇了任務(wù)調(diào)度OSSched();
//調(diào)度任務(wù)
}*p_err = OS_ERR_NONE;
//錯誤類型為“無錯誤”return (DEF_TRUE);
//返回(中止成功)
}
#endif OSTaskSemPendAbort() OSTaskSemPendAbort() 函數(shù)會調(diào)用一個更加底層的中止等待函數(shù)來執(zhí)行當(dāng)前任務(wù)對多值信號量的等待,該函數(shù)就是 OS_PendAbort()。OS_PendAbort() 函數(shù)不僅僅用來中止對任務(wù)信號量的等待,還可以中止對多值信號量、互斥信號量、消息隊列、事件標(biāo)志組或任務(wù)消息隊列的等待。
OS_PendAbort() 函數(shù)的定義位于“os_core.c”:
void OS_PendAbort (OS_PEND_OBJ *p_obj,
//被等待對象的類型OS_TCB *p_tcb,
//任務(wù)控制塊指針CPU_TS ts)
//等待被中止時的時間戳
{switch (p_tcb->TaskState) {
//根據(jù)任務(wù)狀態(tài)分類處理 case OS_TASK_STATE_RDY:
//如果任務(wù)是就緒狀態(tài)case OS_TASK_STATE_DLY:
//如果任務(wù)是延時狀態(tài)case OS_TASK_STATE_SUSPENDED:
//如果任務(wù)是掛起狀態(tài)case OS_TASK_STATE_DLY_SUSPENDED:
//如果任務(wù)是在延時中被掛起break;
//這些情況均與等待無關(guān),直接跳出case OS_TASK_STATE_PEND:
//如果任務(wù)是無期限等待狀態(tài)case OS_TASK_STATE_PEND_TIMEOUT:
//如果任務(wù)是有期限等待狀態(tài)if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
//如果任務(wù)在等待多個信號量或消息隊列OS_PendAbort1(p_obj,
//強制解除任務(wù)對某一對象的等待
p_tcb,ts);}
#if (OS_MSG_EN > 0u)
//如果使能了任務(wù)隊列或消息隊列p_tcb->MsgPtr = (
void *)
0;
//清除(復(fù)位)任務(wù)的消息域p_tcb->MsgSize = (OS_MSG_SIZE)
0u;
#endifp_tcb->TS = ts;
//保存等待被中止時的時間戳到任務(wù)控制塊if (p_obj != (OS_PEND_OBJ *)
0) {
//如果等待對象非空OS_PendListRemove(p_tcb);
//將任務(wù)從所有等待列表中移除
}OS_TaskRdy(p_tcb); //讓任務(wù)進(jìn)準(zhǔn)備運行p_tcb->TaskState = OS_TASK_STATE_RDY;
//修改任務(wù)狀態(tài)為就緒狀態(tài)p_tcb->PendStatus = OS_STATUS_PEND_ABORT;
//標(biāo)記任務(wù)的等待被中止p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;
//標(biāo)記任務(wù)目前沒有等待任何對象break;
//跳出case OS_TASK_STATE_PEND_SUSPENDED:
//如果任務(wù)在無期限等待中被掛起case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
//如果任務(wù)在有期限等待中被掛起if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
//如果任務(wù)在等待多個信號量或消息隊列OS_PendAbort1(p_obj,
//強制解除任務(wù)對某一對象的等待
p_tcb,ts);}
#if (OS_MSG_EN > 0u)
//如果使能了任務(wù)隊列或消息隊列p_tcb->MsgPtr = (
void *)
0;
//清除(復(fù)位)任務(wù)的消息域p_tcb->MsgSize = (OS_MSG_SIZE)
0u;
#endifp_tcb->TS = ts;
//保存等待被中止時的時間戳到任務(wù)控制塊if (p_obj != (OS_PEND_OBJ *)
0) {
//如果等待對象非空OS_PendListRemove(p_tcb);
//將任務(wù)從所有等待列表中移除
}OS_TickListRemove(p_tcb); //讓任務(wù)脫離節(jié)拍列表p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
//修改任務(wù)狀態(tài)為掛起狀態(tài)p_tcb->PendStatus = OS_STATUS_PEND_ABORT;
//標(biāo)記任務(wù)的等待被中止p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;
//標(biāo)記任務(wù)目前沒有等待任何對象break;
//跳出default:
//如果任務(wù)狀態(tài)超出預(yù)期break;
//不需處理,直接跳出
}
} OS_PendAbort() ?
?
轉(zhuǎn)載于:https://www.cnblogs.com/tianxxl/p/10385933.html
總結(jié)
以上是生活随笔為你收集整理的任务信号量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。