Day15&Day16多任务和任务切换

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();
    }
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值