前言
>_<" 这里仿照窗口管理的方式将任务管理也修改成相应的管理模式,这样可以灵活的添加多个任务,而不必每次都要修改任务切换函数;此外还在任务休眠做了尝试,通过将任务挂起和唤醒从而加快运行速度~
一、任务管理自动化
>_<" 为了仿照窗口管理模式对任务进行管理,于是在bootpack.h里做如下定义:
1 /* mtask.c 任务切换相关*/ 2 #define MAX_TASKS 1000 /* 最大任务数量 */ 3 #define TASK_GDT0 3 /* 定义从GDT的几号开始分配给TSS */ 4 5 struct TSS32 {//task status segment 任务状态段 6 int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入) 7 int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器 8 int es, cs, ss, ds, fs, gs;//16位寄存器 9 int ldtr, iomap;//有关任务设置部分 10 }; 11 struct TASK { 12 int sel, flags; /* sel用来存放GDT的编号 */ 13 struct TSS32 tss; 14 }; 15 struct TASKCTL { 16 int running; /* 正在运行的任务量数 */ 17 int now; /* 这个变量用来记录当前正在运行的任务是哪一个 */ 18 struct TASK *tasks[MAX_TASKS]; 19 struct TASK tasks0[MAX_TASKS]; 20 }; 21 extern struct TIMER *task_timer; 22 struct TASK *task_init(struct MEMMAN *memman);//初始化任务控制 23 struct TASK *task_alloc(void);//分配一个任务 24 void task_run(struct TASK *task);//将task添加到tasks的末尾,然后running加1 25 void task_switch(void);//running为1的时候不用进行任务切换,函数直接结束,当running大于2的时候,先把now加1 26 //再把now代表的任务切换成当前的任务,最后再将末尾的任务移到开头
PS:可以看出和窗口管理很相似,TASK是一个任务,TASKCTL是任务管理结构体
>_<" 下面是对应的任务管理.c文件,其中task_init函数是初始化任务控制,task_alloc是分配一个任务函数,task_run其实就相当于唤醒,task_switch任务切换
1 /* 任务管理相关程序 */ 2 3 #include "bootpack.h" 4 5 struct TASKCTL *taskctl; 6 struct TIMER *task_timer; 7 8 ///////////////////////////////////////////////////////////////////////////////////// 9 //功能:初始化任务控制 10 //参数: 11 //返回:返回一个内存地址,意思是现在正在运行这个程序,已经变成一个任务 12 struct TASK *task_init(struct MEMMAN *memman) 13 { 14 int i; 15 struct TASK *task; 16 struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; 17 taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));//TASKCTL是个很大的结构体,所以要申请一个内存空间 18 for (i = 0; i < MAX_TASKS; i++) { 19 taskctl->tasks0[i].flags = 0; 20 taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; 21 set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);//定义在gdt的号,段长限制为103字节 22 } 23 task = task_alloc(); 24 task->flags = 2; /* 活动中标志 */ 25 taskctl->running = 1; 26 taskctl->now = 0; 27 taskctl->tasks[0] = task; 28 load_tr(task->sel); 29 //向TR寄存器写入这个值,因为刚才把当前运行任务的GDT定义为3号,TR寄存器是让CPU记住当前正在运行哪一个任务 30 //每当进行任务切换时,TR寄存器的值也会自动变换,task register 31 //每次给TR赋值的时候,必须把GDT的编号乘以8 32 task_timer = timer_alloc(); 33 timer_settime(task_timer, 2); 34 return task; 35 } 36 ///////////////////////////////////////////////////////////////////////////////////// 37 //功能:任务分配[遍历所有的任务,发现任务处于空闲状态的进行初始化] 38 //参数: 39 struct TASK *task_alloc(void) 40 { 41 int i; 42 struct TASK *task; 43 for (i = 0; i < MAX_TASKS; i++) { 44 if (taskctl->tasks0[i].flags == 0) { 45 task = &taskctl->tasks0[i]; 46 task->flags = 1; /* 正在使用标志 */ 47 task->tss.eflags = 0x00000202; /* IF = 1; */ 48 task->tss.eax = 0; /* 这里先设置为0 */ 49 task->tss.ecx = 0; 50 task->tss.edx = 0; 51 task->tss.ebx = 0; 52 task->tss.ebp = 0; 53 task->tss.esi = 0; 54 task->tss.edi = 0; 55 task->tss.es = 0; 56 task->tss.ds = 0; 57 task->tss.fs = 0; 58 task->tss.gs = 0; 59 task->tss.ldtr = 0;//先这样设置 60 task->tss.iomap = 0x40000000; 61 return task; 62 } 63 } 64 return 0; /* 全部都正在使用 */ 65 } 66 ///////////////////////////////////////////////////////////////////////////////////// 67 //功能:将task添加到tasks的末尾,然后running加1 68 //参数: 69 void task_run(struct TASK *task) 70 { 71 task->flags = 2; /* 活动中标志 */ 72 taskctl->tasks[taskctl->running] = task; 73 taskctl->running++; 74 return; 75 } 76 ///////////////////////////////////////////////////////////////////////////////////// 77 //功能:running为1的时候不用进行任务切换,函数直接结束,当running大于2的时候,先把now加1 78 //再把now代表的任务切换成当前的任务,最后再将末尾的任务移到开头 79 //参数: 80 void task_switch(void) 81 { 82 timer_settime(task_timer, 2); 83 if (taskctl->running >= 2) { 84 taskctl->now++; 85 if (taskctl->now == taskctl->running) { 86 taskctl->now = 0; 87 } 88 farjmp(0, taskctl->tasks[taskctl->now]->sel); 89 } 90 return; 91 }
二、任务休眠
>_<" 如果仅仅是采用上述方式,只能实现每个任务分配大约相同的时间,这样会导致过于平均而不是很优的策略~与其让一个任务空闲着不如直接让其挂起,将自己多出的时间都分配给另一些需要大量时间的任务来执行。这里就要用到休眠:即,将一个任务从tasks中删除。不过,当一个任务休眠时,当FIFO有数据传过来时还要让其唤醒,使其再具有数据处理能力~下面是mtask.c中的任务休眠函数:
1 ///////////////////////////////////////////////////////////////////////////////////// 2 //功能:任务休眠,从任务数组中删除该任务,如果处于正在运行的任务,就让其休眠 3 //参数: 4 void task_sleep(struct TASK *task) 5 { 6 int i; 7 char ts = 0; 8 if (task->flags == 2) { /* 如果指定任务处于唤醒状态 */ 9 if (task == taskctl->tasks[taskctl->now]) { 10 ts = 1; /* 让自己休眠的话,稍后需要进行任务切换 */ 11 } 12 /* 寻找task所在的位置 */ 13 for (i = 0; i < taskctl->running; i++) { 14 if (taskctl->tasks[i] == task) { 15 break; 16 } 17 } 18 taskctl->running--;//当前正在运行的任务数量减1 19 if (i < taskctl->now) {//欲休眠的任务在当前任务前,因为想删除该任务,所以当前任务标号要减1 20 taskctl->now--; /* 需要移动成员,所以做相应的处理 */ 21 } 22 /* 移动成员 */ 23 for (; i < taskctl->running; i++) { 24 taskctl->tasks[i] = taskctl->tasks[i + 1]; 25 } 26 task->flags = 1; /* 不做工作的状态 */ 27 if (ts != 0) { 28 /* 任务切换 */ 29 if (taskctl->now >= taskctl->running) { 30 /* now值越界进行让其变为开始 */ 31 taskctl->now = 0; 32 } 33 farjmp(0, taskctl->tasks[taskctl->now]->sel); 34 } 35 } 36 return; 37 }
PS: 整个过程就类似于从数组中删除一个数据~就这么简单
>_<" 要实现唤醒功能,就要在FIFO结构体中加入用于记录唤醒任务的成员信息,如下:bootpack.h里的FIFO结构体
1 /* fifo.c */ 2 struct FIFO32 {//FIFO缓冲区数据结构 3 int *buf;//缓冲区 4 int p, q, size, free, flags;//下一个数据的写入地址,下一个数据的读出地址,缓冲区的大小,free是缓冲区没有数据的字节数,flag是是否溢出 5 struct TASK *task;//当FIFO中写数据的时候将任务唤醒,用于记录要唤醒任务的信息 6 }; 7 8 void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task);//缓冲区结构体指针,大小,缓冲区开始位置,有数据写入的时候要唤醒任务的任务 9 int fifo32_put(struct FIFO32 *fifo, int data);//往缓冲区内插入一个数据,当有任务处于休眠的时候要唤醒S 10 int fifo32_get(struct FIFO32 *fifo); 11 int fifo32_status(struct FIFO32 *fifo);
>_<" 然后还要修改fifo32_init函数,其中最后一个参数就是指定的一个任务,如果不想使用任务自动唤醒功能,就将task置为0即可!
>_<" 接着要修改fifo32_put函数,实现向FIFO中写数据时,唤醒某个任务的功能~
1 int fifo32_put(struct FIFO32 *fifo, int data) 2 { 3 if (fifo->free == 0) {//溢出 4 fifo->flags |= FLAGS_OVERRUN; 5 return -1; 6 } 7 fifo->buf[fifo->p] = data; 8 fifo->p++; 9 if (fifo->p == fifo->size) {//当插入位置到达最后时再返回第一个位置 10 fifo->p = 0; 11 } 12 fifo->free--; 13 if(fifo->task!=0){//如果设置了有唤醒任务就唤醒 14 if(fifo->task->flags!=2){//如果处于休眠状态 15 task_run(fifo->task);//将任务唤醒 16 } 17 } 18 return 0; 19 }
1 /* bootpack */ 2 3 #include "bootpack.h" 4 #include <stdio.h> 5 6 void make_window8(unsigned char *buf, int xsize, int ysize, char *title); 7 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l);//字符串显示 8 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c); 9 void task_b_main(struct SHEET *sht_back); 10 11 void HariMain(void) 12 { 13 struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; 14 struct FIFO32 fifo;//定时器FIFO 15 char s[40]; 16 int fifobuf[128]; 17 struct TIMER *timer,*timer2,*timer3;//3个定时器 18 int mx, my, i ,cursor_x, cursor_c;//cursor_x是记录光标位置的变量,cursor_c表示光标现在的颜色 19 unsigned int memtotal; 20 struct MOUSE_DEC mdec; 21 struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR; 22 struct SHTCTL *shtctl;//图层管理 23 struct SHEET *sht_back, *sht_mouse, *sht_win;//3个图层 24 unsigned char *buf_back, buf_mouse[256], *buf_win; 25 static char keytable[0x54] = {//键盘映射表 26 0, 0, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘, ‘7‘, ‘8‘, ‘9‘, ‘0‘, ‘-‘, ‘^‘, 0, 0, 27 ‘Q‘, ‘W‘, ‘E‘, ‘R‘, ‘T‘, ‘Y‘, ‘U‘, ‘I‘, ‘O‘, ‘P‘, ‘@‘, ‘[‘, 0, 0, ‘A‘, ‘S‘, 28 ‘D‘, ‘F‘, ‘G‘, ‘H‘, ‘J‘, ‘K‘, ‘L‘, ‘;‘, ‘:‘, 0, 0, ‘]‘, ‘Z‘, ‘X‘, ‘C‘, ‘V‘, 29 ‘B‘, ‘N‘, ‘M‘, ‘,‘, ‘.‘, ‘/‘, 0, ‘*‘, 0, ‘ ‘, 0, 0, 0, 0, 0, 0, 30 0, 0, 0, 0, 0, 0, 0, ‘7‘, ‘8‘, ‘9‘, ‘-‘, ‘4‘, ‘5‘, ‘6‘, ‘+‘, ‘1‘, 31 ‘2‘, ‘3‘, ‘0‘, ‘.‘ 32 }; 33 34 struct TASK *task_a , *task_b;//建立任务 35 36 init_gdtidt();//在dsctbl.c中,负责分区和中断分区初始化[包括键盘和鼠标中断设定] 37 init_pic();//在int.c中,负责中断初始化(硬件) 38 io_sti();//在naskfunc.nas中,仅仅执行STI指令,是CLI的逆指令,前者是开中断,后者是禁止中断 39 /* 40 同一占用一个fifo,这里: 41 0~1 光标闪烁用定时器 42 3 3秒定时器 43 10 10秒定时器 44 256~511 键盘输入(从键盘控制器读入的值再加上256) 45 512~767 鼠标输入(从键盘控制器读入的值再加上512) 46 */ 47 fifo32_init(&fifo, 128, fifobuf,0);//初始化fifo,先让最后一个task参数为0,我们现在还没有初始化完成a任务 48 init_pit();//负责计时器初始化100hz 49 init_keyboard(&fifo, 256);//初始化键盘控制电路//在fifo.c中,负责缓冲区初始化(缓冲区结构体,大小,缓冲区首址) 50 enable_mouse(&fifo, 512, &mdec);//使能鼠标 51 /*这里IMR是(interrupt mask register),意思是“中断屏蔽寄存器”,是8位寄存器,分别对应8路IRQ信号,如果一路是1则该路被屏蔽,因为键盘中断是IRQ1,鼠标中断是IRQ12,且PIC分主从2个,从PIC连接主PIC的IRQ2,所以想要有鼠标和键盘中断,要PIC0的IRQ1和IRQ2,和PIC1的IRQ4*/ 52 io_out8(PIC0_IMR, 0xf8); /* (11111000) *///PIT,PIC1,键盘许可 53 io_out8(PIC1_IMR, 0xef); /* (11101111) */ 54 55 timer = timer_alloc();//4个定时器 56 timer_init(timer, &fifo, 10); 57 timer_settime(timer, 1000); 58 timer2 = timer_alloc(); 59 timer_init(timer2, &fifo, 3); 60 timer_settime(timer2, 300); 61 timer3 = timer_alloc(); 62 timer_init(timer3, &fifo, 1); 63 timer_settime(timer3, 50); 64 65 //memman需要32KB内存 66 memtotal = memtest(0x00400000, 0xbfffffff);//计算总量memtatal 67 memman_init(memman); 68 memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff 将现在不用的字节以0x1000个字节为单位注册到memman里*/ 69 memman_free(memman, 0x00400000, memtotal - 0x00400000); 70 71 init_palette();//调色板 72 shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);//图层初始化函数 73 sht_back = sheet_alloc(shtctl);//分配一个背景窗口 74 sht_mouse = sheet_alloc(shtctl);//分配一个鼠标窗口 75 sht_win = sheet_alloc(shtctl);//分配一个小窗口 76 buf_back = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);//为背景窗口和普通小窗口分配缓存空间 77 buf_win = (unsigned char *) memman_alloc_4k(memman, 160 * 52); 78 sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 设定涂层缓冲区的大小和透明色的函数 */ 79 sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); 80 sheet_setbuf(sht_win, buf_win, 160, 52, -1); /* 设定涂层缓冲区的大小和透明色的函数 */ 81 init_screen8(buf_back, binfo->scrnx, binfo->scrny);//初始化屏幕,画矩形,形成最初的窗口界面 82 init_mouse_cursor8(buf_mouse, 99);//准备鼠标指针(16*16),99是窗口背景颜色 83 make_window8(buf_win, 160, 52, "WINDOW");//就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了 84 make_textbox8(sht_win, 8, 28, 144, 16, COL8_FFFFFF);//窗口上的文件编辑部分 85 cursor_x = 8; 86 cursor_c = COL8_FFFFFF; 87 sheet_slide(sht_back, 0, 0);//上下左右移动窗口,即移动窗口至0,0 88 mx = (binfo->scrnx - 16) / 2; /* 计算鼠标初始位置 */ 89 my = (binfo->scrny - 28 - 16) / 2; 90 sheet_slide(sht_mouse, mx, my);//移动鼠标窗口 91 sheet_slide(sht_win, 80, 72);//移动消息窗口 92 sheet_updown(sht_back, 0);//设置窗口对的高度,背景在最下面 93 sheet_updown(sht_win, 1); 94 sheet_updown(sht_mouse, 2); 95 sprintf(s, "(%3d, %3d)", mx, my);//显示鼠标位置 96 putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10); 97 sprintf(s, "memory %dMB free : %dKB", 98 memtotal / (1024 * 1024), memman_total(memman) / 1024); 99 putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40); 100 101 task_a = task_init(memman);//初始化任务管理器,task_init会返回自己的构造地址,我们将这个地址存入fifo.task 102 fifo.task = task_a;//记录休眠任务名 103 task_b = task_alloc();//分配一个任务b 104 task_b->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;//给任务B分配栈空间 105 //要为任务B专门分配栈,直接用任务A的栈就会乱成一团糟 106 //这里任务B的函数式是带参数的,这里采用汇编函数参数传递的思想,传进任务B函数的参数其实就在[ESP+4] 107 //这里用申请的内存+64*1024要减8因为*((int *) (task_b_esp + 4)) = (int) sht_back;这句将sht_back写入task_b_esp + 4 108 //从这个地址开始向后写4字节的sht_back的值,正好在分配的内存范围 109 task_b->tss.eip = (int) &task_b_main;//任务B的入口函数 110 task_b->tss.es = 1 * 8; 111 task_b->tss.cs = 2 * 8; 112 task_b->tss.ss = 1 * 8; 113 task_b->tss.ds = 1 * 8; 114 task_b->tss.fs = 1 * 8; 115 task_b->tss.gs = 1 * 8; 116 *((int *) (task_b->tss.esp + 4)) = (int) sht_back;//任务B函数的参数 117 task_run(task_b);//运行任务B 将task添加到tasks的末尾,然后running加1 118 119 for (;;) { 120 io_cli(); 121 if (fifo32_status(&fifo) == 0) { 122 task_sleep(task_a);//应该在中断屏蔽的时候进入休眠状态 123 io_sti(); 124 } else { 125 i = fifo32_get(&fifo); 126 io_sti(); 127 if (256 <= i && i <= 511) {//键盘数据 128 sprintf(s, "%02X", i - 256);//减去256 129 putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);//清,显,刷 130 if (i < 0x54 + 256) { 131 if (keytable[i - 256] != 0 && cursor_x < 144) {//一般字符 132 /* 显示一次就前移一次光标 */ 133 s[0] = keytable[i - 256]; 134 s[1] = 0; 135 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, s, 1); 136 cursor_x += 8;//记录光标位置 137 } 138 } 139 if (i == 256 + 0x0e && cursor_x > 8) { /* 退格键 */ 140 /* 用空格键把光标消去后,后移1次光标 */ 141 putfonts8_asc_sht(sht_win, cursor_x, 28, COL8_000000, COL8_FFFFFF, " ", 1); 142 cursor_x -= 8; 143 } 144 /* 光标再显示 */ 145 boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); 146 sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); 147 }else if (512 <= i && i <= 767) {//鼠标数据 148 //已经收集了3字节的数据,所以显示出来 149 if (mouse_decode(&mdec, i - 512) != 0) { 150 sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y); 151 if ((mdec.btn & 0x01) != 0) { 152 s[1] = ‘L‘; 153 } 154 if ((mdec.btn & 0x02) != 0) { 155 s[3] = ‘R‘; 156 } 157 if ((mdec.btn & 0x04) != 0) { 158 s[2] = ‘C‘; 159 } 160 putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);//清,显,刷 161 /* 移动鼠标 */ 162 mx += mdec.x; 163 my += mdec.y; 164 if (mx < 0) { 165 mx = 0; 166 } 167 if (my < 0) { 168 my = 0; 169 } 170 if (mx > binfo->scrnx - 1) { 171 mx = binfo->scrnx - 1; 172 } 173 if (my > binfo->scrny - 1) { 174 my = binfo->scrny - 1; 175 } 176 sprintf(s, "(%3d, %3d)", mx, my); 177 putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);//清,显,刷 178 sheet_slide(sht_mouse, mx, my); 179 //移动窗口计算 180 if((mdec.btn & 0x01)!=0){ 181 sheet_slide(sht_win,mx-80,my-80); 182 }//按下左键移动sht_win 183 } 184 }else if(i==10){//10s定时 185 putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);//清,显,刷、 186 }else if (i == 3) { //3秒定时器 187 putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6); 188 }else if (i<=1) { //光标用定时器 189 if (i != 0) { 190 timer_init(timer3, &fifo, 0); /* 師偼0傪 */ 191 cursor_c = COL8_000000; 192 } else { 193 timer_init(timer3, &fifo, 1); /* 師偼1傪 */ 194 cursor_c = COL8_FFFFFF; 195 } 196 timer_settime(timer3, 50); 197 boxfill8(sht_win->buf, sht_win->bxsize, cursor_c, cursor_x, 28, cursor_x + 7, 43); 198 sheet_refresh(sht_win, cursor_x, 28, cursor_x + 8, 44); 199 } 200 } 201 } 202 } 203 ///////////////////////////////////////////////////////////////////////////////////// 204 //功能:就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了 205 //参数: 206 void make_window8(unsigned char *buf, int xsize, int ysize, char *title) 207 { 208 static char closebtn[14][16] = { 209 "OOOOOOOOOOOOOOO@", 210 "OQQQQQQQQQQQQQ$@", 211 "OQQQQQQQQQQQQQ$@", 212 "OQQQ@@QQQQ@@QQ$@", 213 "OQQQQ@@QQ@@QQQ$@", 214 "OQQQQQ@@@@QQQQ$@", 215 "OQQQQQQ@@QQQQQ$@", 216 "OQQQQQ@@@@QQQQ$@", 217 "OQQQQ@@QQ@@QQQ$@", 218 "OQQQ@@QQQQ@@QQ$@", 219 "OQQQQQQQQQQQQQ$@", 220 "OQQQQQQQQQQQQQ$@", 221 "O$$$$$$$$$$$$$$@", 222 "@@@@@@@@@@@@@@@@" 223 }; 224 int x, y; 225 char c; 226 boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, xsize - 1, 0 ); 227 boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, xsize - 2, 1 ); 228 boxfill8(buf, xsize, COL8_C6C6C6, 0, 0, 0, ysize - 1); 229 boxfill8(buf, xsize, COL8_FFFFFF, 1, 1, 1, ysize - 2); 230 boxfill8(buf, xsize, COL8_848484, xsize - 2, 1, xsize - 2, ysize - 2); 231 boxfill8(buf, xsize, COL8_000000, xsize - 1, 0, xsize - 1, ysize - 1); 232 boxfill8(buf, xsize, COL8_C6C6C6, 2, 2, xsize - 3, ysize - 3); 233 boxfill8(buf, xsize, COL8_000084, 3, 3, xsize - 4, 20 ); 234 boxfill8(buf, xsize, COL8_848484, 1, ysize - 2, xsize - 2, ysize - 2); 235 boxfill8(buf, xsize, COL8_000000, 0, ysize - 1, xsize - 1, ysize - 1); 236 putfonts8_asc(buf, xsize, 24, 4, COL8_FFFFFF, title); 237 for (y = 0; y < 14; y++) { 238 for (x = 0; x < 16; x++) { 239 c = closebtn[y][x]; 240 if (c == ‘@‘) { 241 c = COL8_000000; 242 } else if (c == ‘$‘) { 243 c = COL8_848484; 244 } else if (c == ‘Q‘) { 245 c = COL8_C6C6C6; 246 } else { 247 c = COL8_FFFFFF; 248 } 249 buf[(5 + y) * xsize + (xsize - 21 + x)] = c; 250 } 251 } 252 return; 253 } 254 ///////////////////////////////////////////////////////////////////////////////////// 255 //功能:先图上背景颜色,再显示字符,最后完成刷新 256 //参数:图层,位置,字体颜色,背景颜色,字符串,字符串长度 257 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l) 258 { 259 boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15); 260 putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s); 261 sheet_refresh(sht, x, y, x + l * 8, y + 16); 262 return; 263 } 264 ///////////////////////////////////////////////////////////////////////////////////// 265 //功能:描绘文字输入背景的 266 //参数: 267 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c) 268 { 269 int x1 = x0 + sx, y1 = y0 + sy; 270 boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3); 271 boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1); 272 boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2); 273 boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2); 274 boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2); 275 boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0); 276 boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1); 277 boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1); 278 boxfill8(sht->buf, sht->bxsize, c, x0 - 1, y0 - 1, x1 + 0, y1 + 0); 279 return; 280 } 281 ///////////////////////////////////////////////////////////////////////////////////// 282 //功能:任务b的函数 283 //参数: 284 //附加:这里所使用的变量名和HariMain里面一样的,不过别担心,计算机会把他们当成不同的变量来处理 285 //这里,在每个任务重,当farjmp返回的时候,我们都将定时器设定到0.02s之后,以便让程序在返回0.02s之后再次执行任务切换 286 //这里的带参数传递采用了汇编函数的思想, 287 void task_b_main(struct SHEET *sht_back) 288 { 289 struct FIFO32 fifo; 290 struct TIMER *timer_put, *timer_1s;//2个定时器 291 int i, fifobuf[128], count = 0, count0 = 0; 292 char s[12]; 293 294 fifo32_init(&fifo, 128, fifobuf,0);//B任务不需要再让FIFO唤醒 295 timer_put = timer_alloc(); 296 timer_init(timer_put, &fifo, 1);//0.01s 297 timer_settime(timer_put, 1); 298 timer_1s = timer_alloc();//1s 299 timer_init(timer_1s, &fifo, 100); 300 timer_settime(timer_1s, 100); 301 302 for(;;){ 303 count++; 304 io_cli(); 305 if(fifo32_status(&fifo)==0){ 306 io_sti(); 307 }else{ 308 i=fifo32_get(&fifo); 309 io_sti(); 310 if(i==1){//0.01s刷新一次计数器显示用来加快速度 311 sprintf(s,"%11d",count); 312 putfonts8_asc_sht(sht_back,0,144,COL8_FFFFFF,COL8_008484,s,11); 313 timer_settime(timer_put,1); 314 }else if(i==100){//1s刷新一次,计算1s内计数量 315 sprintf(s, "%11d", count - count0); 316 putfonts8_asc_sht(sht_back, 0, 128, COL8_FFFFFF, COL8_008484, s, 11); 317 count0 = count; 318 timer_settime(timer_1s, 100); 319 } 320 } 321 } 322 }
三、效果展示
>_<" 可见比上一节讲的多任务要快很多,这主要是采用休眠的的结果~
四、相关链接
[自制简单操作系统] 7、多任务(二)——任务管理自动化&任务休眠
原文:http://www.cnblogs.com/zjutlitao/p/3994405.html