/*
** ver : 2.52
** file : os_mutex.c
** brief : 互斥型信號量相關函數 C 文件
**
** mutex : 互斥型信號量
** PIP : 優先級繼承優先級
*/
#ifndef OS_MASTER_FILE
#include "includes.h" /* 包含頭文件 */
#endif
/*
******************************************************************************
* 邏輯常量
******************************************************************************
*/
#define OS_MUTEX_KEEP_LOWER_8 0x00FF /* 低八位 : 標註mutex是否有效 */
#define OS_MUTEX_KEEP_UPPER_8 0xFF00 /* 高八位 : 記錄優先級繼承優先級 */
#define OS_MUTEX_AVAILABLE 0x00FF /* mutex有效 */
#if OS_MUTEX_EN > 0
/*
*******************************************************************************
* 無等待的獲取mutex
*
* brief : 該函數用於無等待的請求mutex.
*
* pevent : 指向事件控制塊的指針
*
* err : 指向錯誤代碼的指針,可能取值:
* OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 錯誤的事件類型
* OS_ERR_PEVENT_NULL 無效的事件控制塊指針
* OS_ERR_PEND_ISR 不能在中斷內請求
*
* Returns : == 1 mutex有效
* == 0 a) mutex無效
* b) 錯誤的事件控制塊指針
* c) 中斷內調用
*
**************************************************************************************
*/
#if OS_MUTEX_ACCEPT_EN > 0
INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
if (OSIntNesting > 0) { /* 不允許在中斷內調用 */
*err = OS_ERR_PEND_ISR;
return (0);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
*err = OS_ERR_PEVENT_NULL;
return (0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 錯誤的事件類型 */
*err = OS_ERR_EVENT_TYPE;
return (0);
}
#endif
OS_ENTER_CRITICAL();
if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* 記錄優先級 */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
pevent->OSEventPtr = (void *)OSTCBCur; /* 鏈接TCB */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (1);
}
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (0);
}
#endif
/*$PAGE*/
/*
**************************************************************************************
* 創建 Mutex
*
* breif : 該函數用於創建mutex.
*
* prio : PIP
*
* err : 指向錯誤代碼的指針,可能取值:
* OS_NO_ERR 成功.
* OS_ERR_CREATE_ISR 不允許在中斷中創建mutex
* OS_PRIO_EXIST PIP的任務已經存在
* OS_ERR_PEVENT_NULL 無空餘事件控制塊
* OS_PRIO_INVALID 無效優先級
*
* Note(s) : 1) '.OSEventCnt' 低八位爲0xFF表示mutex有效,否則爲佔用資源的任務優先級
* 2) '.OSEventCnt' 高八位記錄PIP
***************************************************************************************
*/
OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
if (OSIntNesting > 0) { /* 不允許中斷創建mutex */
*err = OS_ERR_CREATE_ISR;
return ((OS_EVENT *)0);
}
#if OS_ARG_CHK_EN > 0
if (prio >= OS_LOWEST_PRIO) { /* 無效的優先級 */
*err = OS_PRIO_INVALID;
return ((OS_EVENT *)0);
}
#endif
OS_ENTER_CRITICAL();
if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* PIP任務已經存在 */
OS_EXIT_CRITICAL();
*err = OS_PRIO_EXIST;
return ((OS_EVENT *)0);
}
OSTCBPrioTbl[prio] = (OS_TCB *)1; /* 佔用 OSTCBPrioTbl[prio] */
pevent = OSEventFreeList; /* 獲取事件控制塊 */
if (pevent == (OS_EVENT *)0) { /* 無剩餘事件控制塊可用 */
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* 釋放 OSTCBPrioTbl[prio] */
OS_EXIT_CRITICAL();
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;/* 調整ECB鏈表 */
OS_EXIT_CRITICAL();
pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
pevent->OSEventCnt = (prio << 8) | OS_MUTEX_AVAILABLE;/* PIP|資源有效 */
pevent->OSEventPtr = (void *)0; /* 無任務等待 */
OS_EventWaitListInit(pevent);
*err = OS_NO_ERR;
return (pevent);
}
/*$PAGE*/
/*
**********************************************************************************
* 刪除 Mutex
*
* brief : 該函數用刪除 mutex
*
* 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 無效的事件控制塊指針
*
**********************************************************************************
*/
#if OS_MUTEX_DEL_EN
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
INT8U pip;
if (OSIntNesting > 0) { /* 中斷中不能刪除mutex */
*err = OS_ERR_DEL_ISR;
return (pevent);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
*err = OS_ERR_PEVENT_NULL;
return ((OS_EVENT *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 無效的事件類型 */
*err = OS_ERR_EVENT_TYPE;
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* 是否有任務在等待mutex*/
tasks_waiting = TRUE;
} else {
tasks_waiting = FALSE;
}
switch (opt) {
case OS_DEL_NO_PEND: /* 無任務等待刪除mutex*/
if (tasks_waiting == FALSE) {
pip = (INT8U)(pevent->OSEventCnt >> 8);
OSTCBPrioTbl[pip] = (OS_TCB *)0;/* 釋放PIP,創建信號量時佔用 */
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_MUTEX);
}
pip = (INT8U)(pevent->OSEventCnt >> 8);
OSTCBPrioTbl[pip] = (OS_TCB *)0; /* 釋放PIP */
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*/
/*
*******************************************************************************
* 請求mutex
*
* brief : 該函數用來請求mutex
*
* pevent : 指向事件控制塊的指針
*
* timeout : 等待超時
*
* err : 指向錯誤代碼的指針,可能取值:
* OS_NO_ERR 成功
* OS_TIMEOUT 超時
* OS_ERR_EVENT_TYPE 錯誤的事件類型
* OS_ERR_PEVENT_NULL 無效的事件控制塊指針
* OS_ERR_PEND_ISR 不允許在中斷中請求
*
* Note(s) : 1) 擁有mutex的任務,不能在請求任何其他mutex
* 2) 不一定非要改變任務的優先級
********************************************************************************
*/
void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U pip; /* 優先級繼承優先級(PIP) */
INT8U mprio; /* 當前佔用mutex的任務優先級 */
BOOLEAN rdy; /* 任務就緒標誌 */
OS_TCB *ptcb;
if (OSIntNesting > 0) { /* 中斷內不能請求mutex */
*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_MUTEX) {/* 無效的事件類型 */
*err = OS_ERR_EVENT_TYPE;
return;
}
#endif
OS_ENTER_CRITICAL();
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* mutex有效 */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* 記錄優先級 */
pevent->OSEventPtr = (void *)OSTCBCur; /* 指向任務控制塊 */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return;
}
/* 獲取優先級繼承優先級 */
pip = (INT8U)(pevent->OSEventCnt >> 8);
/* 獲取佔用mutex任務的優先級 */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
/* 獲取佔用mutex任務的控制塊 */
ptcb = (OS_TCB *)(pevent->OSEventPtr);
/* 是否需要提升佔用任務優先級*/
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) {
if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { /* 查看是否就緒 */
/* 取消就緒 */
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
rdy = TRUE;
} else {
rdy = FALSE;
}
ptcb->OSTCBPrio = pip; /* 修改優先級 */
ptcb->OSTCBY = ptcb->OSTCBPrio >> 3; /* 預計算 */
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
if (rdy == TRUE) { /* 新優先級就緒 */
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
OSTCBPrioTbl[pip] = (OS_TCB *)ptcb;
}
OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* 等待mutex狀態 */
OSTCBCur->OSTCBDly = timeout; /* 記錄等到超時 */
OS_EventTaskWait(pevent); /* 任務進入等待 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任務調度 */
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) { /* 查看是否超時繼續運行 */
OS_EventTO(pevent);
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; /* 超時進入就緒 */
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
/*$PAGE*/
/*
******************************************************************************
* 釋放mutex
*
* brief : 該函數用於釋放 mutex
*
* pevent : 指向事件控制塊的指針
*
* Returns : OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 錯誤的事件類型
* OS_ERR_PEVENT_NULL 無效的事件控制塊指針
* OS_ERR_POST_ISR 不能自中斷中釋放mutex
* OS_ERR_NOT_MUTEX_OWNER 釋放mutex的任務並沒有佔用mutex
********************************************************************************
*/
INT8U OSMutexPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U pip; /* 優先級繼承優先級 */
INT8U prio;
if (OSIntNesting > 0) { /* 中斷內不允許釋放mutex */
return (OS_ERR_POST_ISR);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 無效的事件類型 */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pip = (INT8U)(pevent->OSEventCnt >> 8); /* 獲取PIP */
/* 獲取佔用mutex的任務優先級 */
prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
if (OSTCBCur->OSTCBPrio != pip &&
OSTCBCur->OSTCBPrio != prio) {/* 當前任務未佔有mutex */
OS_EXIT_CRITICAL();
return (OS_ERR_NOT_MUTEX_OWNER);
}
if (OSTCBCur->OSTCBPrio == pip) { /* 優先級被提升 */
/* 移除PIP的就緒 */
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBPrio = prio; /* 修改爲原來優先級 */
OSTCBCur->OSTCBY = prio >> 3; /* 預運算 */
OSTCBCur->OSTCBBitY = OSMapTbl[OSTCBCur->OSTCBY];
OSTCBCur->OSTCBX = prio & 0x07;
OSTCBCur->OSTCBBitX = OSMapTbl[OSTCBCur->OSTCBX];
OSRdyGrp |= OSTCBCur->OSTCBBitY;/* 置就緒 */
OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
OSTCBPrioTbl[prio] = (OS_TCB *)OSTCBCur;
}
OSTCBPrioTbl[pip] = (OS_TCB *)1; /* 佔用OSTCBPrioTbl[pip] 請求mutex時用 */
if (pevent->OSEventGrp != 0x00) { /* 是否有任務在等待mutex */
/* 等待任務進入就緒 */
prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* 記錄優先級 */
pevent->OSEventCnt |= prio;
pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* 鏈接任務控制塊 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任務調度 */
return (OS_NO_ERR);
}
pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* 使mutex有效 */
pevent->OSEventPtr = (void *)0;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
/*$PAGE*/
/*
*******************************************************************************
* 查詢mutex
*
* brief : 該函數用於查詢mutex
*
* pevent : 指向事件控制塊的指針
*
* pdata : 保存mutex信息的數據結構指針
*
* Returns : OS_NO_ERR 成功
* OS_ERR_QUERY_ISR 不能再中斷中請求
* OS_ERR_PEVENT_NULL 無效的事件控制塊指針
* OS_ERR_EVENT_TYPE 錯誤的事件類型
********************************************************************************
*/
#if OS_MUTEX_QUERY_EN > 0
INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U *psrc;
INT8U *pdest;
if (OSIntNesting > 0) { /* 不允許在中斷內調用 */
return (OS_ERR_QUERY_ISR);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 無效的事件控制塊指針 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {/* 錯誤的事件類型 */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pdata->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8);/* 優先級繼承優先級 */
/* 佔有mutex的任務優先級,若爲0xFF則爲被佔用mutex有效 */
pdata->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
if (pdata->OSOwnerPrio == 0xFF) {
pdata->OSValue = 1; /* mutex有效 */
} else {
pdata->OSValue = 0; /* mutex無效 */
}
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
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
#endif
uC/OS-II源碼解析(os_mutex.c)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.