《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:
接下来对这些结构进行初始化:
接着是让任务运行
然后添加任务切换函数替代以前用的函数:
最后将所有用到以上变化的部分都进行修改。
2.让任务休眠
操作系统运行过程中,有的任务可能没有执行什么东西,比如在不进行输入的过程中,A任务就是这样。因此考虑对任务进行休眠,把更多的时间让给其他任务。当任务没有事做时,进行休眠,当有事做则进行唤醒。
创建task_sleep:
然后在FIFO中有写入数据时把任务唤醒,修改结构体:
改写fifo32_init,让其可以在参数中指定一个唤醒任务:
接着让写入数据时,唤醒任务(修改fifo32_put):
最后修改使用到上述修改的地方(HariMain.c)。
3.增加窗口的数量
接下来为了增加更多的任务,形成A、B0、B1、B2这几个任务,并为每个任务增加窗口。并且A的3秒、10秒计时器均不再使用
4.设定任务优先级
支持任务优先级对一个操作系统来说是必要的。想要让系统支持优先级其实很简单,前面让每个任务固定0.02秒进行切换,接下来根据优先级大小切换即可。是任务在0.01到0.1秒之间进行切换。
修改TASK结构体,添加优先级:
然后改写mtask.c,以应用更改:
任务初始化中添加:
并与计时器关联:
这样则把初始化的所有任务的切换时间设定为0.02。
然后task_run通过参数接收优先级:
然后在fifo32_put中唤醒任务时传入优先级0,即不改变优先级。
最后改变HariMain,检测优先级是否能使用:
把b任务初始化中的task_run修改为:
这样运行即可发现b0,b1,b2显示的数字基本满足 1:2:3关系。
运行发现鼠标出现卡顿现象,把A任务的优先级提高到10即可。但是如果两个以上的任务都是最高优先级还是会出现问题。
考虑创建多层的任务管理,高层的任务比底层的任务高级,只有执行完高层的才能执行低层任务。
接着编写一些操作struct TASKLEVEL的函数:
然后开始修改task_init:
接着是task_run:
然后是task_sleep:
最后是task_switch:
这样就改好了mtask.c文件。
接着修改fifo32_put:
最后修改HariMain,将任务A设为LEVEL1,B0~B2设为LEVEL2即可。
但是当B0~B2任务没有运行时,如果A休眠依然会出现问题。可以采用前面定时器那里使用“卫兵”的思路。
写一个闲置的任务,并放在最下层即可。
闲置任务:
然后在init中将其放在最下层:
运行即可。
注:感觉这里先参考以下两篇文章会对理解程序有所帮助
/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);
运行即可。
相关文章推荐
- 《30天自制操作系统》读书笔记(2)hello, world
- 读书笔记《30天自制操作系统》day12~day13
- 读书笔记《30天自制操作系统》day12~day13
- 《30天自制操作系统》读书笔记(6) 鼠标键盘
- 《30天自制操作系统》读书笔记Day14
- 《30天自制操作系统》读书笔记Day15
- 读书笔记《30天自制操作系统》day02
- 多定时器处理1(30天自制操作系统--读书笔记)
- 《30天自制操作系统》读书笔记(4) 绘图
- 读书笔记《30天自制操作系统》day01
- 《30天自制操作系统》读书笔记Day3
- 单字节的FIFO缓存(30天自制操作系统--读书笔记)
- 读书笔记《30天自制操作系统》day02
- 读书笔记《30天自制操作系统》day11
- 内存管理(30天自制操作系统--读书笔记)
- 读书笔记《30天自制操作系统》day03
- 【1】--《30天自制操作系统》读书笔记--0~3天
- 读书笔记《30天自制操作系统》day03
- 读书笔记《30天自制操作系统》day04
- 《30天自制操作系统》读书笔记Day5