Bootstrap

互斥信号量的等待与通知

目录

等待互斥信号量

信号量未被占用

信号量被自己占用

信号量被高优先级任务占用

信号量被低优先级任务占用

释放互斥信号量

未发生优先级继承

发生优先级继承


等待互斥信号量

信号量未被占用
  • 标记为已经占用
  • 锁定计数+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);//插入到事件控制块是用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;
}

/* 事件控制块通知函数(将任务从事件控制块中唤醒,唤醒队列中的指定任务) */
//参数:事件控制块,指定唤醒的任务,消息,唤醒结果
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]);
}

;