/*
** ver : 2.52
** file : os_sem.c
** brief : 信號量相關函數C文件
*/
#ifndef OS_MASTER_FILE
#include "includes.h" /* 包含頭文件 */
#endif
#if OS_SEM_EN > 0
/*
***************************************************************************
* 無等待的請求信號量
*
* brief : 該函數用於無等待的請求信號量,信號量無效時也不會使任務掛起
*
* pevent : 指向事件控制塊的指針
*
* Returns : > 0 信號量有效
* == 0 信號量無效
***************************************************************************
*/
#if OS_SEM_ACCEPT_EN > 0
INT16U OSSemAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT16U cnt;
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
return (0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
return (0); /* 無效的事件類型 */
}
#endif
OS_ENTER_CRITICAL();
cnt = pevent->OSEventCnt; /* 記錄當前信號量值 */
if (cnt > 0) { /* 信號量有效 */
pevent->OSEventCnt--; /* 信號量值減 1 */
}
OS_EXIT_CRITICAL();
return (cnt); /* 返回信號量值 */
}
#endif
/*$PAGE*/
/*
*******************************************************************************
* 創建信號量
*
* brief : 該函數用於創建信號量
*
* cnt : 信號量初始值.如果信號量是用來表示一個或多個事件發生的
* 那麼該信號量的初始值通常賦爲0,如果信號量用於對共享資
* 源的訪問,那麼該信號量的初始化賦爲1(例如把它當做二值
* 信號量使用),如果信號量用來表示允許任務訪問n個相同的
* 資源,那麼該信號量的初始值應被賦爲n
*
* returns : != (void *)0 事件控制塊指針,創建信號量成功
* == (void *)0 創建失敗
********************************************************************************
*/
OS_EVENT *OSSemCreate (INT16U cnt)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
if (OSIntNesting > 0) { /* 中斷中不允許創建信號量 */
return ((OS_EVENT *)0);
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList; /* 獲取一個空事件控制塊 */
if (OSEventFreeList != (OS_EVENT *)0) { /* 調整事件控制塊鏈表 */
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0) { /* 獲得一個事件控制塊 */
pevent->OSEventType = OS_EVENT_TYPE_SEM;
pevent->OSEventCnt = cnt; /* 設置信號量初始值 */
pevent->OSEventPtr = (void *)0; /* 不在屬於空事件控制塊鏈表 */
OS_EventWaitListInit(pevent); /* 初始化等待任務表 */
}
return (pevent);
}
/*$PAGE*/
/*
********************************************************************************
* 刪除信號量
*
* brief : 該函數用於刪除信號量
*
* pevent : 指向事件控制塊的指針
*
* opt : 刪除信號量的選項:
* opt == OS_DEL_NO_PEND 無任務等待時刪除
* opt == OS_DEL_ALWAYS 有無任務等待都刪除,如有等待則進入就緒態
*
* err : 指向錯誤代碼的指針,可能取值:
* OS_NO_ERR 成功刪除
* OS_ERR_DEL_ISR 不能再中斷中刪除信號量
* OS_ERR_INVALID_OPT 無效的刪除選項
* OS_ERR_TASK_WAITING 有任務正在等待信號量
* OS_ERR_EVENT_TYPE 錯誤的事件類型
* OS_ERR_PEVENT_NULL 事件控制塊指針爲空
*
* returns : pevent 出錯
* (OS_EVENT *)0 成功刪除
*
* Note(s) : 1) 該函數必須謹慎的使用.任務可能會請求已經刪除了的信號量
* 應該檢查OSSemPend()的返回值.
* 2) 調用OSSemAccept()的函數不知道信號量已經被刪除了
* 3) 該函數將中斷關閉. 中斷關閉的時間取決於正在等待信號量
* 的任務數
* 4) 因爲所有等待的任務都將進入就緒態,所以必須小心的使用
* 該函數
*******************************************************************************
*/
#if OS_SEM_DEL_EN > 0
OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
if (OSIntNesting > 0) { /* 不允許在中斷中刪除信號量 */
*err = OS_ERR_DEL_ISR;
return (pevent);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的時間控制塊指針 */
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
*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) {
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 事件類型 */
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_SEM);
}
pevent->OSEventType = OS_EVENT_TYPE_UNUSED; /* 事件類型 */
pevent->OSEventPtr = OSEventFreeList; /* 返還事件控制塊 */
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);
}
}
#endif
/*$PAGE*/
/*
******************************************************************************
* 請求一個信號量
*
* brief : 該函數用於請求信號量
*
* pevent : 指向信號量的指針
*
* timeout : 等待超時時限.
* 爲0 : 無限的等待或者等待的事件發生
* 不爲0 : 超時進入就緒或者等待的事件發生
*
* err : 指向出錯代碼的指針,可能取值:
*
* OS_NO_ERR 成功
* OS_TIMEOUT 等待超時
* OS_ERR_EVENT_TYPE 錯誤的事件類型
* OS_ERR_PEND_ISR 不能在中斷中請求信號量
* OS_ERR_PEVENT_NULL 錯誤的事件控制塊指針
*
*******************************************************************************
*/
void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
if (OSIntNesting > 0) { /* 中斷中不能請求信號量 */
*err = OS_ERR_PEND_ISR;
return;
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
*err = OS_ERR_PEVENT_NULL;
return;
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
*err = OS_ERR_EVENT_TYPE; /* 無效的事件類型 */
return;
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventCnt > 0) { /* 信號量有效 */
pevent->OSEventCnt--; /* 信號量值減 1 */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return;
}
/* 無有效的信號量 */
OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* 任務狀態爲等待信號量 */
OSTCBCur->OSTCBDly = timeout; /* 超時時限 */
OS_EventTaskWait(pevent); /* 任務進入等待狀態 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任務調度 */
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBStat & OS_STAT_SEM) {/* 超時而進入就緒態 */
OS_EventTO(pevent);
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; /* 等待超時 */
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
/*$PAGE*/
/*
******************************************************************************
* 釋放信號量
*
* brief : 該函數用於釋放信號量
*
* pevent : 指向事件控制塊的指針
*
* Returns : OS_NO_ERR 成功
* OS_SEM_OVF 信號量值超過最大值
* OS_ERR_EVENT_TYPE 無效的事件類型
* OS_ERR_PEVENT_NULL 無效的事件控制塊指針
******************************************************************************
*/
INT8U OSSemPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {
return (OS_ERR_EVENT_TYPE); /* 無效的事件類型 */
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* 是否有任務在等待信號量 */
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);/* 優先級最高的等待任務就緒 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任務調度 */
return (OS_NO_ERR);
}
if (pevent->OSEventCnt < 65535) { /* 確保信號量值正確 */
pevent->OSEventCnt++; /* 增加信號量值 */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
OS_EXIT_CRITICAL(); /* 信號量值錯誤 */
return (OS_SEM_OVF);
}
/*$PAGE*/
/*
******************************************************************************
* 查詢信號量
*
* brief : 該函數用於獲取信號量的信息
*
* pevent : 指向事件控制塊的指針
*
* pdata : 指向返回信號量信息數據結構的指針
*
* Returns : OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 無效的事件類型
* OS_ERR_PEVENT_NULL 無效的事件控制塊指針
******************************************************************************
*/
#if OS_SEM_QUERY_EN > 0
INT8U OSSemQuery (OS_EVENT *pevent, OS_SEM_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U *psrc;
INT8U *pdest;
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* 無效的事件類型 */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pdata->OSEventGrp = pevent->OSEventGrp; /* 複製等待任務表 */
psrc = &pevent->OSEventTbl[0];
pdest = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 1
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 2
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 3
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 4
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 5
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 6
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 7
*pdest = *psrc;
#endif
pdata->OSCnt = pevent->OSEventCnt; /* 複製信號量值 */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
#endif
uC/OS-II源碼解析(os_sem.c)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.