您的位置:首页 > 其它

《30天自制操作系统》读书笔记Day16

2013-10-03 20:42 330 查看
1.任务管理自动化

注:感觉这里先参考以下两篇文章会对理解程序有所帮助

/article/7717389.html

http://blog.chinaunix.net/uid-26918989-id-3715043.html

虽然前面的两个任务可以自动的切换,但是系统默认只有两个任务,如果需要添加任务只能重新编写系统的源代码,非常不靠谱。考虑像当初定时器或者窗口背景那样,需要时新增一个即可。

所以模仿struct SHTCTL编写struct TASKCTL:

#define MAX_TASKS		1000	//最大任务数量
#define TASK_GDT0		3		//定义从GDT的第几号开始分配给TSS

struct TSS32
{
int backlink, esp0, ss0, esp1, ss1, esp2, ss2, 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 sel, flags; //sel用于存放GDT的编号
struct TSS32 tss;
};

struct TASKCTL
{
int running;	//正在运行的任务数量
int now;		//记录当前正在运行的是哪个任务
struct TASK *tasks[MAX_TASKS];
struct TASK tasks0[MAX_TASKS];
};

接下来对这些结构进行初始化:

struct TASKCTL *taskctl;
struct TIMER *task_timer;

struct TASK *task_init(struct MEMMAN *memman)
/* 任务相关结构体初始化 */
{
int i;
struct TASK *task;
struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof(struct TASKCTL));
for (i = 0; i < MAX_TASKS; i++)
{
/* 初始化所有的任务的task结构 */
taskctl->tasks0[i].flags = 0;
taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;	//选择子初始化
set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32); //描述符初始化
}
task = task_alloc();
task->flags = 2; //活动中的标志
/*
* 关于task结构中flags成员变量的取值
* 0是未活动 	1是休眠 	2是运行
*/
taskctl->running = 1;
taskctl->now = 0;
taskctl->tasks[0] = task;
load_tr(task->sel);	//修改TR寄存器
task_timer = timer_alloc();	//任务切换定时器
timer_settime(task_timer, 2);
return task;
}

struct TASK *task_alloc(void)
/* 任务分配 */
{
int i;
struct TASK *task;
/* 遍历所有的task结构 */
for (i = 0; i < MAX_TASKS; i++)
{
if (taskctl->tasks0[i].flags == 0) //未活动
{
task = &taskctl->tasks0[i];
task->flags = 1; //正在使用
task->tss.eflags = 0x00000202; //IF = 1
/* 初始化各个寄存器 */
task->tss.eax = 0;
task->tss.ecx = 0;
task->tss.edx = 0;
task->tss.ebx = 0;
task->tss.ebp = 0;
task->tss.esi = 0;
task->tss.edi = 0;
task->tss.es = 0;
task->tss.ds = 0;
task->tss.fs = 0;
task->tss.gs = 0;
task->tss.ldtr = 0;
task->tss.iomap = 0x40000000;
return task;
}
}
return 0; //全部正在使用
}

接着是让任务运行

void task_run(struct TASK *task)
/* 运行任务 */
{
task->flags = 2; //活动中
taskctl->tasks[taskctl->running] = task;
taskctl->running++;
return;
}

然后添加任务切换函数替代以前用的函数:

void task_switch(void)
/* 任务切换 */
{
timer_settime(task_timer, 2);
if (taskctl->running >= 2) {
taskctl->now++;
if (taskctl->now == taskctl->running) {
taskctl->now = 0;
}
farjmp(0, taskctl->tasks[taskctl->now]->sel);
}
return;
}

最后将所有用到以上变化的部分都进行修改。

2.让任务休眠

操作系统运行过程中,有的任务可能没有执行什么东西,比如在不进行输入的过程中,A任务就是这样。因此考虑对任务进行休眠,把更多的时间让给其他任务。当任务没有事做时,进行休眠,当有事做则进行唤醒。

创建task_sleep:

void task_sleep(struct TASK *task)
/* 任务休眠 */
{
int i;
char ts = 0;
if (task->flags == 2)//任务处于唤醒状态
{
if (task == taskctl->tasks[taskctl->now])
{
ts = 1;//让自己休眠,稍后需要进行任务切换
}
//寻找task所在的位置
for (i = 0; i < taskctl->running; i++)
{
if (taskctl->tasks[i] == task)
{
break;
}
}
taskctl->running--;
if (i < taskctl->now)
{
taskctl->now--;//需要移动成员,要相应的处理
}
for (; i < taskctl->running; i++)//移动成员
{
taskctl->tasks[i] = taskctl->tasks[i + 1];
}
task->flags = 1;//休眠
if (ts != 0)//任务切换
{
if (taskctl->now >= taskctl->running)
{
taskctl->now = 0;//针对now值出现的异常进行修正
}
farjmp(0, taskctl->tasks[taskctl->now]->sel);
}
}
}

然后在FIFO中有写入数据时把任务唤醒,修改结构体:

struct FIFO32
{
int *buf;
int p, q, size, free, flags;//p,q为队列前后指针,size为队列空间总大小,free为空闲空间大小,flags用于标志溢出
struct TASK *task;
};

改写fifo32_init,让其可以在参数中指定一个唤醒任务:

void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task)
/* fifo缓冲区的初始化 */
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /* 初始化时空闲大小等于总大小 */
fifo->flags = 0;
fifo->p = 0; /* 下一个数据写入位置 */
fifo->q = 0; /* 下一个数据读取位置 */
fifo->task = task;//有数据写入时需要唤醒的任务
return;
}

接着让写入数据时,唤醒任务(修改fifo32_put):

int fifo32_put(struct FIFO32 *fifo, int data)
/* 向FIFO传送数据并保存 */
{
if (fifo->free == 0) {
/* 没有空余空间,发生溢出 */
fifo->flags |= FLAGS_OVERRUN;
return -1;
}
fifo->buf[fifo->p] = data;
fifo->p++;
if (fifo->p == fifo->size) {
fifo->p = 0;
}
fifo->free--;
if (fifo->task != 0)
{
if (fifo->task->flags != 2)//任务处于休眠状态
{
task_run(fifo->task);
}
}
return 0;
}

最后修改使用到上述修改的地方(HariMain.c)。

3.增加窗口的数量

接下来为了增加更多的任务,形成A、B0、B1、B2这几个任务,并为每个任务增加窗口。并且A的3秒、10秒计时器均不再使用

/*
*bootpack.c
*其他处理
*/
#include "bootpack.h"
#include <stdio.h>

void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act);
void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l);
void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c);
void task_b_main(struct SHEET *sht_back);

void HariMain(void)
{

struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
struct FIFO32 fifo;
char s[40];
int fifobuf[128];
int mx, my, i;
int task_b_esp;	//为任务B定义的栈
unsigned int memtotal;
int count;	//计数
struct MOUSE_DEC mdec;
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
struct SHTCTL *shtctl;
struct SHEET *sht_back, *sht_mouse;
unsigned char *buf_back, buf_mouse[256];
struct SHEET *sht_win, *sht_win_b[3];	//添加窗口图层
unsigned char *buf_win, *buf_win_b;		//窗口图层的缓冲区
static char keytable[0x54] = {
'`',   0,   '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0,   0,
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', 0,   0,   'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':', 0,   0,   '\\', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', ',', '.', '/', 0,   '*', 0,   ' ', 0,   0,   0,   0,   0,   0,
0,   0,   0,   0,   0,   0,   0,   '7', '8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.'
};
int cursor_x;	//光标位置,每次输入一个字符向后移动8
int cursor_c;	//光标状态,通知光标闪烁
struct TIMER *timer;
struct TASK *task_a,*task_b[3];

init_gdtidt();
init_pic();
io_sti(); //结束IDT/PIC初始化,解除CPU中断禁用
fifo32_init(&fifo, 128 , fifobuf,0);
init_pit();
init_keyboard(&fifo, 256);
enable_mouse(&fifo, 512, &mdec);
io_out8(PIC0_IMR, 0xf8); /* PIT和PIC1以外全部禁止(11111000) */
io_out8(PIC1_IMR, 0xef); //鼠标设置为许可

memtotal = memtest(0x00400000, 0xbfffffff);
memman_init(memman);
memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */
memman_free(memman, 0x00400000, memtotal - 0x00400000);

init_palette();
shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);
task_a = task_init(memman);
fifo.task = task_a;

//sht_back
sht_back  = sheet_alloc(shtctl);
buf_back  = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);
sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 没有透明色 */
init_screen8(buf_back, binfo->scrnx, binfo->scrny);

//sht_win_b
for (i = 0; i < 3; i++)
{
sht_win_b[i] = sheet_alloc(shtctl);
buf_win_b = (unsigned char *) memman_alloc_4k(memman, 144 * 52);
sheet_setbuf(sht_win_b[i], buf_win_b, 144, 52, -1); //无透明色
sprintf(s, "task_b%d", i);
make_window8(buf_win_b, 144, 52, s, 0);
task_b[i] = task_alloc();
task_b[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;
task_b[i]->tss.eip = (int) &task_b_main;
task_b[i]->tss.es = 1 * 8;
task_b[i]->tss.cs = 2 * 8;
task_b[i]->tss.ss = 1 * 8;
task_b[i]->tss.ds = 1 * 8;
task_b[i]->tss.fs = 1 * 8;
task_b[i]->tss.gs = 1 * 8;
*((int *) (task_b[i]->tss.esp + 4)) = (int) sht_win_b[i];
task_run(task_b[i]);
}

//sht_win
sht_win = sheet_alloc(shtctl);		//将窗口图层添加到窗口管理中
buf_win = (unsigned char *) memman_alloc_4k(memman, 160*52);		//分配窗口内存
sheet_setbuf(sht_win, buf_win, 144, 52, -1);	//没有透明色
make_window8(buf_win, 144, 52, "task_a",1);	//显示窗口函数调用
make_textbox8(sht_win, 8, 28, 128, 16, COL8_FFFFFF);
cursor_x = 8;
cursor_c = COL8_FFFFFF;

timer = timer_alloc();
timer_init(timer, &fifo, 1);
timer_settime(timer, 50);

//sht_mouse
sht_mouse = sheet_alloc(shtctl);
sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99);	//透明色号99
init_mouse_cursor8(buf_mouse, 99);	//背景色号99
mx = (binfo->scrnx - 16) / 2; /* 按显示在画面中央来计算最终坐标 */
my = (binfo->scrny - 28 - 16) / 2;

sheet_slide(sht_back, 0, 0);
sheet_slide(sht_win, 8, 56);
sheet_slide(sht_win_b[0], 168, 56);
sheet_slide(sht_win_b[1], 8, 116);
sheet_slide(sht_win_b[2], 168, 116);
sheet_slide(sht_mouse, mx, my);

sheet_updown(sht_back,  0);
sheet_updown(sht_win_b[0], 1);
sheet_updown(sht_win_b[1], 2);
sheet_updown(sht_win_b[2], 3);
sheet_updown(sht_win,   4);
sheet_updown(sht_mouse, 5);
sprintf(s, "(%3d, %3d)", mx, my);
putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
sprintf(s, "memory %dMB   free : %dKB",
memtotal / (1024 * 1024), memman_total(memman) / 1024);
putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40);

for (;;) {
io_cli();
if (fifo32_status(&fifo) == 0) {
task_sleep(task_a);
io_sti();
} else {
i = fifo32_get(&fifo);
io_sti();

if (i <= 511 && i >=256) //键盘数据
{
sprintf(s, "%02X", i - 256);
putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
if (i < 256 + 0x54)
{
if (keytable[i - 256] != 0 && cursor_x < 128)	//一般字符
{
s[0] = keytable[i - 256 ];
s[1] = 0;
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1);
cursor_x += 8;
}
if (i == 256 + 0x0e && cursor_x > 8)	//退格
{
putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1);
cursor_x -= 8;
}
//光标再显示
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44);
}
}
else if (i <= 767 && i >=512) //鼠标数据
{
if (mouse_decode(&mdec, i - 512) != 0)
{

sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
if ((mdec.btn & 0x01) != 0)
{
s[1] = 'L';
}
if ((mdec.btn & 0x02) != 0)
{
s[3] = 'R';
}
if ((mdec.btn & 0x04) != 0)
{
s[2] = 'C';
}
putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);
/* 移动光标 */
mx += mdec.x;
my += mdec.y;
if (mx < 0)
{
mx = 0;
}
if (my < 0)
{
my = 0;
}
if(mx > binfo->scrnx - 1)
mx = binfo->scrnx - 1;
if(my > binfo->scrny - 1)
my = binfo->scrny - 1;
sprintf(s, "(%3d, %3d)", mx, my);
putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
sheet_slide(sht_mouse, mx, my); /* 包含sheet_refresh */
if ((mdec.btn & 0x01) != 0)
//按下左键,移动窗口
{
sheet_slide(sht_win, mx-80, my - 8);
}
}
}
else if (i <= 1)
{
if (i != 0)
{
timer_init(timer, &fifo, 0);	//然后设置0
cursor_c = COL8_000000;
}
else
{
timer_init(timer, &fifo, 1);	//然后设置1
cursor_c = COL8_FFFFFF;
}
timer_settime(timer, 50);
boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43);
sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44);
}
}
}
}
void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act)
/* 显示窗口 */
{
static char closebtn[14][16] = {
/* 关闭图标 */
"OOOOOOOOOOOOOOO@",
"OQQQQQQQQQQQQQ$@",
"OQQQQQQQQQQQQQ$@",
"OQQQ@@QQQQ@@QQ$@",
"OQQQQ@@QQ@@QQQ$@",
"OQQQQQ@@@@QQQQ$@",
"OQQQQQQ@@QQQQQ$@",
"OQQQQQ@@@@QQQQ$@",
"OQQQQ@@QQ@@QQQ$@",
"OQQQ@@QQQQ@@QQ$@",
"OQQQQQQQQQQQQQ$@",
"OQQQQQQQQQQQQQ$@",
"O$$$$$$$$$$$$$$@",
"@@@@@@@@@@@@@@@@"
};
int x, y;
char c, tc, tbc;
if (act != 0) {
tc = COL8_FFFFFF;
tbc = COL8_000084;
} else {
tc = COL8_C6C6C6;
tbc = COL8_848484;
}
/* 绘制多个矩形,显示窗口 */
boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
boxfill8(buf, xsize, tbc,         3,         3,         xsize - 4, 20       );
boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
putfonts8_asc(buf, xsize, 24, 4, tc, title);	//显示标题
for (y = 0; y < 14; y++) {
/* 绘制关闭图标 */
for (x = 0; x < 16; x++) {
c = closebtn[y][x];
if (c == '@') {
c = COL8_000000;
} else if (c == '$') {
c = COL8_848484;
} else if (c == 'Q') {
c = COL8_C6C6C6;
} else {
c = COL8_FFFFFF;
}
buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
}
}
return;
}
void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l)
/* 显示字符串。x,y,c,b,s,l分别代表:显示横纵坐标、字符颜色、背景颜色、字符串、字符串长度 */
{
boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15);
putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s);
sheet_refresh(sht, x, y, x + l * 8, y + 16);
return;
}

void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c)
//绘制文字输入框
{
int x1 = x0 + sx, y1 = y0 + sy;
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3);
boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2);
boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1);
boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1);
boxfill8(sht->buf, sht->bxsize, c,           x0 - 1, y0 - 1, x1 + 0, y1 + 0);
return;
}
void task_b_main(struct SHEET *sht_win_b)
{
struct FIFO32 fifo;
int i, fifobuf[128];
struct TIMER *timer_1s;
int count = 0, count0 = 0;
char s[12];

fifo32_init(&fifo, 128, fifobuf,0);
timer_1s = timer_alloc();
timer_init(timer_1s, &fifo, 100);
timer_settime(timer_1s, 100);

for (;;) {
count++;
io_cli();
if (fifo32_status(&fifo) == 0)
{
io_sti();
}
else
{
i = fifo32_get(&fifo);
io_sti();
if (i == 100)
{
sprintf(s, "%11d", count - count0);
putfonts8_asc_sht(sht_win_b, 24, 28, COL8_000000, COL8_C6C6C6, s, 11);
count0 = count;
timer_settime(timer_1s, 100);
}
}
}
}

4.设定任务优先级

支持任务优先级对一个操作系统来说是必要的。想要让系统支持优先级其实很简单,前面让每个任务固定0.02秒进行切换,接下来根据优先级大小切换即可。是任务在0.01到0.1秒之间进行切换。

修改TASK结构体,添加优先级:

struct TASK {
int sel, flags; //sel用于存放GDT的编号
struct TSS32 tss;
int priority;	//优先级
};

然后改写mtask.c,以应用更改:

任务初始化中添加:

task->priority = 2;	//0.02秒

并与计时器关联:

timer_settime(task_timer, task->priority);

这样则把初始化的所有任务的切换时间设定为0.02。

然后task_run通过参数接收优先级:

void task_run(struct TASK *task, int priority)
/* 运行任务 */
{
if (priority > 0)
{
task->priority = priority;
}
if (task->flags != 2)
{
task->flags = 2; //活动中
taskctl->tasks[taskctl->running] = task;
taskctl->running++;
}
return;
}
void task_switch(void)
/* 任务切换 */
{
struct TASK *task;
taskctl->now++;
if (taskctl->now == taskctl->running)
{
taskctl->now = 0;
}
task = taskctl->tasks[taskctl->now];
timer_settime(task_timer, task->priority);
if (taskctl->running >= 2)
{
farjmp(0, taskctl->tasks[taskctl->now]->sel);
}
return;
}

然后在fifo32_put中唤醒任务时传入优先级0,即不改变优先级。

最后改变HariMain,检测优先级是否能使用:

把b任务初始化中的task_run修改为:

task_run(task_b[i],i+1);

这样运行即可发现b0,b1,b2显示的数字基本满足 1:2:3关系。

运行发现鼠标出现卡顿现象,把A任务的优先级提高到10即可。但是如果两个以上的任务都是最高优先级还是会出现问题。

考虑创建多层的任务管理,高层的任务比底层的任务高级,只有执行完高层的才能执行低层任务。

#define MAX_TASKS_LV	100
#define MAX_TASKLEVELS	10

struct TASK {
int sel, flags; //sel用于存放GDT的编号
struct TSS32 tss;
int priority;	//优先级
int level;
};

struct TASKLEVEL {
int running;	//正在运行的任务数量
int now;
struct TASK *tasks[MAX_TASKS_LV];
};

struct TASKCTL
{
int now_lv;		//当前任务的LEVEL
char lv_change;	//下次任务切换是否改变LEVEL
struct TASKLEVEL level[MAX_TASKLEVELS];
struct TASK tasks0[MAX_TASKS];
};

接着编写一些操作struct TASKLEVEL的函数:

struct TASK *task_now(void)
//返回现在活动中的struct TASK的内存地址
{
struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];
return tl->tasks[tl->now];
}

void task_add(struct TASK *task)
//向struct TASKLEVEL中添加一个任务
{
struct TASKLEVEL *tl = &taskctl->level[task->level];
tl->tasks[tl->running] = task;
tl->running++;
task->flags = 2;
return;
}

void task_remove(struct TASK *task)
//删除任务
{
int i;
struct TASKLEVEL *tl = &taskctl->level[task->level];
//寻找task所在的位置
for (i = 0; i < tl->running; i++)
{
if (tl->tasks[i] == task)
{
break;
}
}
tl->running--;
if (i < tl->now)
{
tl->now--;
}
if (tl->now >= tl->running)
{
tl->now = 0;
}
task->flags = 1;

//移动
for (; i < tl->running; i++)
{
tl->tasks[i] = tl->tasks[i+1];
}
return;
}

void task_switchsub(void)
//决定任务切换时切换到哪个LEVEL
{
int i;
//寻找最上层的level
for (i = 0; i < MAX_TASKLEVELS; i++)
{
if (taskctl->level[i].running > 0)
{
break;
}
}
taskctl->now_lv = i;
taskctl->lv_change = 0;
return;
}

然后开始修改task_init:

struct TASK *task_init(struct MEMMAN *memman)
/* 任务相关结构体初始化 */
{
int i;
struct TASK *task;
struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));
for (i = 0; i < MAX_TASKS; i++) {
taskctl->tasks0[i].flags = 0;
taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;
set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);
}
for (i = 0; i < MAX_TASKLEVELS; i++) {
taskctl->level[i].running = 0;
taskctl->level[i].now = 0;
}
task = task_alloc();
task->flags = 2; //活动中的标志
/*
* 关于task结构中flags成员变量的取值
* 0是未活动 	1是休眠 	2是运行
*/
task->priority = 2;	//0.02秒void task_run(struct TASK *task, int level, int priority)
/* 运行任务 */
{
if (level < 0)
{
level = tesk->level;
}
if (priority > 0)	//为0表示不更改当前的优先级
{
task->priority = priority;
}
if (task->flags == 2 && task->level != level)	//改变任务level
{
task_remove(task);
}
if (task->flags != 2)
{
task->level = level;
task_add(task);
}
taskctl->lv_change = 1;	//下次任务切换时检查level
return;
}

接着是task_run:

void task_run(struct TASK *task, int level, int priority)
/* 运行任务 */
{
if (level < 0)
{
level = task->level;
}
if (priority > 0)	//为0表示不更改当前的优先级
{
task->priority = priority;
}
if (task->flags == 2 && task->level != level)	//改变任务level
{
task_remove(task);
}
if (task->flags != 2)
{
task->level = level;
task_add(task);
}
taskctl->lv_change = 1;	//下次任务切换时检查level
return;
}

然后是task_sleep:

void task_sleep(struct TASK *task)
/* 任务休眠 */
{
struct TASK *now_task;
if (task->flags == 2)//任务处于唤醒状态
{
now_task = task_now();
task_remove(task);
if (task == now_task)
{
task_switchsub();
now_task = task_now();
farjmp(0, now_task->sel);
}
}
return;
}

最后是task_switch:

void task_switch(void)
/* 任务切换 */
{
struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];
struct TASK *new_task, *now_task = tl->tasks[tl->now];
tl->now++;
if (tl->now == tl->running) {
tl->now = 0;
}
if (taskctl->lv_change != 0) {
task_switchsub();
tl = &taskctl->level[taskctl->now_lv];
}
new_task = tl->tasks[tl->now];
timer_settime(task_timer, new_task->priority);
if (new_task != now_task) {
farjmp(0, new_task->sel);
}
return;
}

这样就改好了mtask.c文件。

接着修改fifo32_put:

task_run(fifo->task, -1, 0);

最后修改HariMain,将任务A设为LEVEL1,B0~B2设为LEVEL2即可。

但是当B0~B2任务没有运行时,如果A休眠依然会出现问题。可以采用前面定时器那里使用“卫兵”的思路。

写一个闲置的任务,并放在最下层即可。

闲置任务:

void task_idle(void)
//闲置任务,防止没有任务执行
{
for (;;)
{
io_hlt();
}
}

然后在init中将其放在最下层:

idle = task_alloc();
idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
idle->tss.eip = (int) &task_idle;
idle->tss.es = 1 * 8;
idle->tss.cs = 2 * 8;
idle->tss.ss = 1 * 8;
idle->tss.ds = 1 * 8;
idle->tss.fs = 1 * 8;
idle->tss.gs = 1 * 8;
task_run(idle, MAX_TASKLEVELS-1, 1);

运行即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: