1.多任务和任务切换,还有X86任务切换的原理都在我前面的文章中,已经写明,读者可以自行查看或百度
2.多任务的结构体
采用时间片轮转,优先调度
①一个任务的组成Task 是由段选择子(或可以称之为任务选择子,二者没有区别,因为一个任务 就是注册在GDT/LDT中)标志位,任务优先级, 该任务的现场和他可以占用cpu的权重构成
②我们所创建的多任务 是一个多级LEVEL,每个LEVEL中还分权重来决定占用CPU的时间,当高级LEVEL中有任务正在运行的时候,低级LEVEL是不能运行的,而且高级LEVEL可以抢占CPU
③TaskLevel 是记录当前这个LEVEL他里面有几个正在跑的任务,当前正在跑的那个任务的ID
④TaskCTL 记录当前占用CPU的是哪个级别,在下次任务切换时是否需要更新级别。
#define MAX_TASKS 1000 //最大任务数量
#define TASK_GAT_BEGIN 3 //定义从GDT的几号 开始分配给TSS的
#define ONE_LEVEL_MAX_TASK 100 //每个级别最大任务个数
#define MAX_LEVELS 10 //最多可以分成10个级别
#define TASK_RUNNING 2
#define TASK_ALLOCED 1
#define TASK_NOT_USE 0
struct TSS32
{
int FrontWork;//上一个任务 16位
int ESP0;//堆栈0
int SS0;
int ESP1;
int SS1;
int ESP2;
int SS2;
int CR3;//CR3含有存放页目录表页面的物理地址
int EIP, EFLAGS, EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI;//寄存器
int ES, CS, SS, DS, FS, GS;
int LDTR, IOMAP;
};
struct TASK
{
int nSelector;//存放在GDT的几号
int nFlags;
int nLevel;//设定任务的优先级
struct TSS32 Tss;
int nPriority;//设定任务可占用CPU的时间
};
struct TASKLEVEL
{
int RunCounts;//有几个任务正在运行
int CurRunId;//正在运行的任务ID
struct TASK *pTask[ONE_LEVEL_MAX_TASK];//每个级别100 个任务
};
struct TASKCTL
{
int CurLevel; //当前的Level
char LevelChange; //下次任务切换时 是否需要改变level
struct TASKLEVEL TaskLevelArr[MAX_LEVELS];// 最多10个级别
struct TASK TaskArr[MAX_TASKS];// 1000个任务
};
2.定时器中断所做的事情 任务切换
void IntHandler20(int *pEsp)//定时器中断IRQ0
{
//任务超时定时器标志位
char TaskTimerFlag = 0;
struct TIMER *pTimerTemp;
io_out8(PIC0_OCW2, 0x60);
//每次中断+1 来计数
TimerCtl.u32Count++;
//下一个需要比较的时间 未到 那么什么也不做
if(TimerCtl.u32Next > TimerCtl.u32Count)
{
return;
}
//把定时器链表的 头结点 赋值给 Temp
pTimerTemp = TimerCtl.pTimerHead;
//Temp 在循环结束时候 是第一个未超时的那个 或者都超时了
while(1)
{
//一直运行到 不超时那个TIMER 为止 因为pTimer数组是经过排序的
if(pTimerTemp->u32TimeOut > TimerCtl.u32Count)
{
break;
}
//处理超时的定时器
pTimerTemp->u32Flag = TIMER_FLAGS_ALLOC;
//如果不是任务切换定时器
if(pTimerTemp != g_pTaskTimer)
{
FifoSaveData(pTimerTemp->pFifo, pTimerTemp->nData);
}
else
{
TaskTimerFlag = 1;
}
pTimerTemp = pTimerTemp->pNext;
}
//改变头结点
TimerCtl.pTimerHead = pTimerTemp;
TimerCtl.u32Next = TimerCtl.pTimerHead->u32TimeOut;
if(0 != TaskTimerFlag)
{
TaskSwitch();
}
return;
}
3.具体实现
虽然前面原理什么的都讲了,但是我这里还是简单介绍一下吧,我们在Init中把所有的任务都注册到GDT表中,当任务要发生切换的时候,TR寄存器保存的是当前正在运行的任务,然后保存现场,然后把新的TSS的数据复制到寄存器里面
//命令行任务
void ConsoleTask(struct SHEET *pSheet);
struct TASK *InitTask(struct MEMORY_MAN * MenMan);
//新增一个任务
struct TASK *TaskAlloc(void);
//运行一个任务
void TaskRun(struct TASK *pTask, int Level, int Priority);
//任务切换
void TaskSwitch(void);
//任务休眠
void TaskSleep(struct TASK *pTask);
//获取当前正在运行的任务
struct TASK * GetCurTask(void);
//向TASKLEVEL中添加一个任务
void AddTaskToLevel(struct TASK *pTask);
//从TASKLEVEL中删除一个任务
void RemoveTaskFromLevel(struct TASK *pTask);
//决定要跳转到哪个级别
void TaskSwitchLevel(void);
//最低级的任务 当所有的任务 都休眠时 使系统进入省电模式
void TaskIdle(void);
#include "Tss.h"
#include "Timer.h"
#include "MyAsmFun.h"
#include "dsctbl.h"
#include "Sheet.h"
#include "graphic.h"
#include <stdio.h>
#include "fifo.h"
//管理任务的定时器
struct TIMER *g_pTaskTimer;
//任务管理的结构体
struct TASKCTL *g_pTaskCtl;
void (*pFunConsoleTask)(struct SHEET *pSheet) = ConsoleTask;
//命令行任务
void ConsoleTask(struct SHEET *pSheet)
{
struct FIFO Fifo32;
struct TIMER *pTimer;
struct TASK *pTask = GetCurTask();//用于使自己休眠
int i;
int FifoBuf[128];
int CursorX = 8;
int CursorColor = COL8_BLACK;
InitFifo(&Fifo32, 128, FifoBuf, pTask);
pTimer = GetTimer();
TimerInit(pTimer, & Fifo32, 1);
SetTimer(pTimer, 50);
while (1)
{
io_cli();
if(0 == FifoStatus(&Fifo32))
{
TaskSleep(pTask);
io_sti();
}
else
{
i = FifoReadData(&Fifo32);
io_sti();
if(i <= 1)//光标定时器
{
if(0 != i)
{
TimerInit(pTimer, &Fifo32, 0);
CursorColor = COL8_BLACK;
}
else
{
TimerInit(pTimer, &Fifo32, 1);
CursorColor = COL8_WHITE;
}
SetTimer(pTimer, 50);
DrawBoxFillColor8(pSheet->pu8Buf, pSheet->nBxSize, CursorColor, CursorX, 28, CursorX+7, 43);
SheetRefresh(pSheet, CursorX, 28, CursorX+8, 44);
}
}
}
}
struct TASK *InitTask(struct MEMORY_MAN *MenMan)
{
int i;
struct TASK *pTask;//这是任务A的
struct TASK *pTaskIdle;//任务哨兵
//将0x00270000开始的地址 存放GDT表 0x270000-0x27ffff
struct SEGMENT_DESCRIPTOR *pGDT_Add = (struct SEGMENT_DESCRIPTOR *)ADR_GDT;
//为任务管理分配内存
g_pTaskCtl = (struct TASKCTL *)MemoryManagerMalloc4K(MenMan, sizeof(struct TASKCTL));
//任务初始化
for (i = 0; i < MAX_TASKS; i++)
{
g_pTaskCtl->TaskArr[i].nFlags = TASK_NOT_USE; //没有使用
g_pTaskCtl->TaskArr[i].nSelector = (TASK_GAT_BEGIN + i) * 8; //设置选择子
SetSegmDesc(pGDT_Add + i + TASK_GAT_BEGIN, 103, (int)&(g_pTaskCtl->TaskArr[i].Tss), AR_TSS32);
}
for (i = 0; i < MAX_LEVELS; i++)
{
g_pTaskCtl->TaskLevelArr[i].RunCounts = 0;
g_pTaskCtl->TaskLevelArr[i].CurRunId = 0;
}
pTaskIdle = TaskAlloc();
pTaskIdle->Tss.ESP = MemoryManagerMalloc4K(MenMan, 64*1024) + 64*1024;
pTaskIdle->Tss.EIP = (int)&TaskIdle;
pTaskIdle->Tss.ES = 1*8;
pTaskIdle->Tss.CS = 2*8;
pTaskIdle->Tss.SS = 1*8;
pTaskIdle->Tss.DS = 1*8;
pTaskIdle->Tss.FS = 1*8;
pTaskIdle->Tss.GS = 1*8;
TaskRun(pTaskIdle, MAX_LEVELS-1, 1);
//新增一个任务
pTask = TaskAlloc();
pTask->nFlags = TASK_RUNNING; //活动中标志
pTask->nPriority = 2;//0.02S
pTask->nLevel = 0;//设为最高级别
AddTaskToLevel(pTask);
TaskSwitchLevel();
load_tr(pTask->nSelector);
g_pTaskTimer = GetTimer();
SetTimer(g_pTaskTimer, pTask->nPriority);
return pTask;
}
struct TASK *TaskAlloc(void)
{
int i;
struct TASK *pTask;
for (i = 0; i < MAX_TASKS; i++)
{
//如果没有使用的话
if (TASK_NOT_USE == g_pTaskCtl->TaskArr[i].nFlags)
{
pTask = &(g_pTaskCtl->TaskArr[i]);
pTask->nFlags = TASK_ALLOCED;
pTask->Tss.EFLAGS = 0x00000202;
pTask->Tss.EAX = 0;
pTask->Tss.ECX = 0;
pTask->Tss.EDX = 0;
pTask->Tss.EBP = 0;
pTask->Tss.EBX = 0;
pTask->Tss.EDI = 0;
pTask->Tss.ESI = 0;
pTask->Tss.ES = 0;
pTask->Tss.DS = 0;
pTask->Tss.FS = 0;
pTask->Tss.GS = 0;
pTask->Tss.LDTR = 0;
pTask->Tss.IOMAP = 0x40000000;
return pTask;
}
}
return 0;
}
//运行一个任务
void TaskRun(struct TASK *pTask, int Level, int Priority)
{
//不改变优先级
if (Level < 0)
{
Level = pTask->nLevel;
}
//如果是0的话 那么就不改变优先级
if (Priority > 0)
{
pTask->nPriority = Priority;
}
if((TASK_RUNNING == pTask->nFlags) && (pTask->nLevel != Level)) //改变活动中的Level
{
RemoveTaskFromLevel(pTask);
}
if(TASK_RUNNING != pTask->nFlags)
{
pTask->nLevel = Level;
AddTaskToLevel(pTask);
}
g_pTaskCtl->LevelChange = 1; //下次任务切换时, 检查Level
return;
}
//任务切换
void TaskSwitch(void)
{
struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[g_pTaskCtl->CurLevel]);
struct TASK *pNewTask;
struct TASK *pCurTask = pTaskLevel->pTask[pTaskLevel->CurRunId];
pTaskLevel->CurRunId++;
if (pTaskLevel->CurRunId == pTaskLevel->RunCounts)
{
pTaskLevel->CurRunId = 0;
}
if(0 != g_pTaskCtl->LevelChange)
{
TaskSwitchLevel();
pTaskLevel = &(g_pTaskCtl->TaskLevelArr[g_pTaskCtl->CurLevel]);
}
pNewTask = pTaskLevel->pTask[pTaskLevel->CurRunId];
SetTimer(g_pTaskTimer, pNewTask->nPriority);
if(pNewTask != pCurTask)
{
farjmp(0, pNewTask->nSelector);
}
return;
}
//任务休眠
void TaskSleep(struct TASK *pTask)
{
struct TASK *pCurTask;
//如果指定的任务处于运行状态
if (TASK_RUNNING == pTask->nFlags)
{
pCurTask = GetCurTask();
RemoveTaskFromLevel(pTask);
//如果是要自我休眠
if (pTask == pCurTask)
{
TaskSwitchLevel();
pCurTask = GetCurTask();
farjmp(0, pCurTask->nSelector);
}
}
return;
}
//获取当前正在运行的任务
struct TASK * GetCurTask(void)
{
struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[g_pTaskCtl->CurLevel]);
return (pTaskLevel->pTask[pTaskLevel->CurRunId]);
}
//向TASKLEVEL中添加一个任务
void AddTaskToLevel(struct TASK *pTask)
{
//获取到该任务 所属级别的 结构体地址
struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[pTask->nLevel]);
/*if (pTaskLevel->RunCounts >= ONE_LEVEL_MAX_TASK)
{
return;
}*/
//将该任务 加到数组中 正在运行的+1
pTaskLevel->pTask[pTaskLevel->RunCounts] = pTask;
pTaskLevel->RunCounts++;
pTask->nFlags = TASK_RUNNING;
return;
}
//从TASKLEVEL中删除一个任务
void RemoveTaskFromLevel(struct TASK *pTask)
{
int i;
//获取到该任务 所属级别的 结构体地址
struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[pTask->nLevel]);
/*if(pTaskLevel->RunCounts < 0)
{
return;
}*/
//寻找Task出现在数组中的位置
for (i = 0; i < pTaskLevel->RunCounts; i++)
{
if (pTaskLevel->pTask[i] == pTask)
{
break;
}
}
pTaskLevel->RunCounts--;
//如果当前要删除的任务 位置处在正在运行的任务的前面
if(i < pTaskLevel->CurRunId)
{
pTaskLevel->CurRunId--;
}
if (pTaskLevel->CurRunId >= pTaskLevel->RunCounts)
{
pTaskLevel->CurRunId = 0;
}
pTask->nFlags = TASK_ALLOCED;//休眠
//移动处理
for (; i < pTaskLevel->RunCounts; i++)
{
pTaskLevel->pTask[i] = pTaskLevel->pTask[i + 1];
}
return;
}
//决定要跳转到哪个级别
void TaskSwitchLevel(void)
{
int i;
for ( i = 0; i < MAX_LEVELS; i++)
{
if (g_pTaskCtl->TaskLevelArr[i].RunCounts > 0)
{
break;
}
}
g_pTaskCtl->CurLevel = i;
g_pTaskCtl->LevelChange = 0;
return;
}
//最低级的任务 当所有的任务 都休眠时 使系统进入省电模式
void TaskIdle(void)
{
while(1)
{
io_hlt();
}
}