目錄
等待互斥信號量
信號量未被占用
信號量被自己占用
信號量被高優先級任務占用
信號量被低優先級任務占用
釋放互斥信號量
未發生優先級繼承
發生優先級繼承
等待互斥信號量
信號量未被占用
- 標記為已經被占用
- 鎖定計數+1
信號量被自己占用
- 鎖定計數+1
信號量被高優先級任務占用
- 低優先級任務插入事件控制塊的等待隊列中
信號量被低優先級任務占用
- 高優先級任務插入到等待隊列中
- 低優先級任務設置成高優先級任務一樣的優先級
釋放互斥信號量
未發生優先級繼承
- 釋放信號量
- 從等待隊列中喚醒一個任務占用信號量
發生優先級繼承
- 低優先級任務從信號量中釋放,不再占用信號量,同時低優先級任務優先級改為原有的優先級
- 從等待隊列中喚醒一個任務占用信號量
tMutex.c
#include "tinyOS.h"/* 互斥信號量初始化函數 */
void tMutexInit(tMutex *mutex)
{tEventInit(&mutex->event, tEventTypeMutex);mutex->lockedCount = 0;mutex->owner = (tTask *)0;mutex->ownerOriginalPrio = TINYOS_PRO_COUNT;//初始設為無效值
}/* 等待互斥信號量函數 */
//參數:互斥信號量,超時時間
uint32_t tMutexWait(tMutex *mutex, uint32_t waitTicks)
{uint32_t status = tTaskEnterCritical();//互斥信號量是否被鎖定if(mutex->lockedCount <= 0){//未鎖定:當前任務可以占用互斥信號量mutex->owner = currentTask;mutex->ownerOriginalPrio = currentTask->prio;mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}else{//已鎖定://判斷是否是當前任務鎖定的if(mutex->owner == currentTask){mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}else{//不是當前任務鎖定://判斷當前任務優先級和互斥信號量占有者優先級哪個高if(currentTask->prio < mutex->owner->prio){//當前任務優先級高://任務優先級繼承機制tTask *owner = mutex->owner;//判斷當前任務是否為就緒狀態if(owner->state == TINYOS_TASK_STATE_RDY){//當前任務為就緒狀態:tTaskSchedUnRdy(owner);//從原有就緒隊列中移出owner->prio = currentTask->prio;//更改所有者優先級tTaskSchedRdy(owner);//插入新的隊列}else{owner->prio = currentTask->prio;}}tEventWait(&mutex->event, currentTask, (void *)0, tEventTypeMutex, waitTicks);//當前任務插入事件控制塊中tTaskExitCritical(status);tTaskSched();return currentTask->waitEventResult;}}
}/* 無等待獲取互斥信號量函數 */
//僅需檢查互斥信號量能否被當前任務獲取到
uint32_t tMutexNoWaitGet(tMutex *mutex)
{uint32_t status = tTaskEnterCritical();//判斷互斥信號量是否被鎖定if(mutex->lockedCount <= 0){//沒有被鎖定:由當前任務鎖定mutex->owner = currentTask;mutex->ownerOriginalPrio = currentTask->prio;mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}else{//被鎖定://判斷互斥信號量所有者是否是當前任務if(mutex->owner == currentTask){mutex->lockedCount++;tTaskExitCritical(status);return tErrorNoError;}tTaskExitCritical(status);return tErrorResourceUnavailable;}
}/* 釋放互斥信號量函數 */
uint32_t tMutexNotify(tMutex *mutex)
{uint32_t status = tTaskEnterCritical();//判斷信號量是否被鎖定if(mutex->lockedCount <= 0){tTaskExitCritical(status);return tErrorNoError;}//判斷信號量所有者if(mutex->owner != currentTask){tTaskExitCritical(status);return tErrorOwner;}//對鎖定計數--仍大于0:沒有到最終釋放任務的過程if(--mutex->lockedCount > 0){tTaskExitCritical(status);return tErrorNoError;}//判斷是否發生優先級繼承if(mutex->ownerOriginalPrio != mutex->owner->prio){//發生優先級繼承://判斷任務是否在就緒狀態if(mutex->owner->state == TINYOS_TASK_STATE_RDY){//更改任務所在就緒列表位置及優先級tTaskSchedUnRdy(mutex->owner);currentTask->prio = mutex->ownerOriginalPrio;tTaskSchedUnRdy(mutex->owner);}else{currentTask->prio = mutex->ownerOriginalPrio;}}//判斷當前等待隊列中是否有任務if(tEventWaitCount(&mutex->event) > 0){tTask *task = tEventWakeUp(&mutex->event, (void *)0, tErrorNoError);//取出一個任務//信號量的所有者設置為新任務mutex->owner = task;mutex->ownerOriginalPrio = task->prio;mutex->lockedCount++;//判斷任務的優先級是否比當前任務的優先級高if(task->prio < currentTask->prio){tTaskSched();}}tTaskExitCritical(status);return tErrorNoError;
}
tMutex.h
#ifndef __TMUTEX_H
#define __TMUTEX_H#include "tEvent.h"/* 互斥信號量結構 */
typedef struct _tMutex
{tEvent event; //事件控制塊uint32_t lockedCount; //鎖定計數器tTask *owner; //當前互斥信號量所有者uint32_t ownerOriginalPrio; //所有者原始優先級
}tMutex;void tMutexInit(tMutex *mutex);
uint32_t tMutexWait(tMutex *mutex, uint32_t waitTicks);
uint32_t tMutexNoWaitGet(tMutex *mutex);
uint32_t tMutexNotify(tMutex *mutex);#endif
tintOS.h
#ifndef __TINYOS_H
#define __TINYOS_H#include <stdint.h>
#include "tLib.h"
#include "tConfig.h"
#include "tTask.h"
#include "tEvent.h"
#include "tSem.h"
#include "tMbox.h"
#include "tMemBlock.h"
#include "tFlagGroup.h"
#include "tMutex.h"/* 錯誤碼 */
typedef enum _tError{tErrorNoError = 0, //沒有錯誤發生tErrorTimeout, //超時tErrorResourceUnavailable,//資源不可用tErrorDel, //被刪除tErrorResourceFull, //資源已滿tErrorOwner, //擁有者錯誤
}tError;extern tTask *currentTask;
extern tTask *nextTask; uint32_t tTaskEnterCritical(void);
void tTaskExitCritical(uint32_t status);void tTaskSwitch(void); //和CPU相關,寫在switch.c
void tTaskRunFirst(void);void tTaskSchedInit(void);
void tTaskSchedDisable(void);
void tTaskSchedEnable(void);
void tTaskSchedRdy(tTask *task);
void tTaskSchedUnRdy(tTask *task);
void tTaskSchedRemove(tTask *task);
void tTaskSched(void);
void tTimeTaskWait(tTask *task, uint32_t ticks);
void tTimeTaskWakeUp(tTask *task);
void tTimeTaskRemove(tTask *task);
void tTaskSystemTickHandler(void);
void tTaskDelay(uint32_t delay);void tSetSysTickPeriod(uint32_t ms);
void tInitApp(void);#endif
tEvent.c
#include "tinyOS.h"/* 事件控制塊初始化函數 */
void tEventInit(tEvent *event, tEventType type)
{event->type = tEventTypeUnknow;tListInit(&event->waitList);
}/* 事件控制塊等待函數 */
//參數:事件控制塊,任務,消息(傳入消息來源,在事件發生以后存放具體的消息),等待的狀態,超時時間
void tEventWait(tEvent *event, tTask *task, void *msg, uint32_t state, uint32_t timeout)
{uint32_t status = tTaskEnterCritical();task->state |= state << 16;task->waitEvent = event;task->eventMsg = msg;task->waitEventResult = tErrorNoError;tTaskSchedUnRdy(task);//移出就緒隊列tListAddLast(&event->waitList, &task->linkNode);//插入事件控制塊等待隊列的尾部if(timeout){tTimeTaskWait(task, timeout);//設置了超時事件,插入延時隊列}tTaskExitCritical(status);
}/* 事件控制塊通知函數(將任務從事件控制塊中喚醒,喚醒隊列首部任務) */
//參數:事件控制塊,消息,喚醒結果
tTask *tEventWakeUp(tEvent *event, void *msg, uint32_t result)
{tNode *node;tTask *task = (tTask *)0;uint32_t status = tTaskEnterCritical();if((node = tListRemoveFirst(&event->waitList)) != (tNode *)0){task = (tTask *)tNodeParent(node, tTask, linkNode);//插入到事件控制塊是用linknodetask->waitEvent = (tEvent *)0;//不等待任何事件task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;if(task->delayTicks != 0)//有延時{tTimeTaskWakeUp(task);//強制將任務從延時隊列中移除}tTaskSchedRdy(task);//插入就緒隊列}tTaskExitCritical(status);return task;
}/* 事件控制塊通知函數(將任務從事件控制塊中喚醒,喚醒隊列中的指定任務) */
//參數:事件控制塊,指定喚醒的任務,消息,喚醒結果
tTask *tEventWakeUpTask(tEvent *event, tTask *task, void *msg, uint32_t result)
{uint32_t status = tTaskEnterCritical();tListRemove(&event->waitList, &task->linkNode);//直接將任務移出隊列task->waitEvent = (tEvent *)0;//不等待任何事件task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;if(task->delayTicks != 0)//有延時{tTimeTaskWakeUp(task);//強制將任務從延時隊列中移除}tTaskSchedRdy(task);//插入就緒隊列tTaskExitCritical(status);return task;
}/* 事件控制塊移除函數 */
void tEventRemoveTask(tTask *task, void *msg, uint32_t result)
{uint32_t status = tTaskEnterCritical();tListRemove(&task->waitEvent->waitList, &task->linkNode);task->waitEvent = (tEvent *)0;task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;tTaskExitCritical(status);
}/* 事件控制塊清空函數 */
//返回值:事件任務塊被清空時,它的等待隊列中有多少任務
uint32_t tEventRemoveAll(tEvent *event, void *msg, uint32_t result)
{tNode *node;uint32_t count = 0;uint32_t status = tTaskEnterCritical();count = tListCount(&event->waitList);//等待隊列中有多少任務while((node = tListRemoveFirst(&event->waitList)) != (tNode *)0)//移除等待隊列頭部任務{tTask *task = (tTask *)tNodeParent(node, tTask, linkNode);//獲取task結構task->waitEvent = (tEvent *)0;//不再等待事件task->eventMsg = msg;task->waitEventResult = result;task->state &= ~TINYOS_TASK_WAIT_MASK;if(task->delayTicks != 0)//任務有延時{tTimeTaskWakeUp(task);//移出延時隊列}tTaskSchedRdy(task);}tTaskExitCritical(status);return count;
}/* 獲取事件控制塊中等待任務函數 */
uint32_t tEventWaitCount(tEvent *event)
{uint32_t count = 0;uint32_t status = tTaskEnterCritical();count = tListCount(&event->waitList);tTaskExitCritical(status);return count;
}
app.c
#include "tinyOS.h"
#include "string.h"//定義任務,分別為它們配備獨立的堆棧空間
tTask tTask1;
tTask tTask2;
tTask tTask3;
tTask tTask4;
tTaskStack task1Env[1024];
tTaskStack task2Env[1024];
tTaskStack task3Env[1024];
tTaskStack task4Env[1024];tMutex mutex;//定義任務要執行的功能
int task1Flag;
void task1Entry(void *param)
{tSetSysTickPeriod(10);//初始化tMutexInit(&mutex);for(;;)//任務里是for的死循環{//嵌套的申請互斥信號量再釋放tMutexWait(&mutex, 0);tMutexWait(&mutex, 0);task1Flag = 0; tTaskDelay(1);task1Flag = 1;tTaskDelay(1);tMutexNotify(&mutex);tMutexNotify(&mutex);}
}int task2Flag;
void task2Entry(void *param)
{for(;;){tMutexWait(&mutex, 0);tMutexWait(&mutex, 0);task2Flag = 0;tTaskDelay(1);task2Flag = 1;tTaskDelay(1);tMutexNotify(&mutex);tMutexNotify(&mutex);}
}
int task3Flag;
void task3Entry(void *param)
{for(;;){task3Flag = 0;tTaskDelay(1);task3Flag = 1;tTaskDelay(1);}
}
int task4Flag;
void task4Entry(void *param)
{for(;;){task4Flag = 0;tTaskDelay(1);task4Flag = 1;tTaskDelay(1);}
}/* 應用任務初始化函數 */
void tInitApp(void)
{//最后一個參數:傳堆棧末端地址,因為堆棧是向下生長的,初始堆棧地址是堆棧空間最后一個單元地址的末端tTaskInit(&tTask1, task1Entry, (void *)0x11111111, 0, &task1Env[1024]);tTaskInit(&tTask2, task2Entry, (void *)0x22222222, 1, &task2Env[1024]);tTaskInit(&tTask3, task3Entry, (void *)0x22222222, 1, &task3Env[1024]);tTaskInit(&tTask4, task4Entry, (void *)0x22222222, 1, &task4Env[1024]);
}