[自制简单操作系统] 7、多任务(二)——任务管理自动化&任务休眠

 

前言

>_<" 这里仿照窗口管理的方式将任务管理也修改成相应的管理模式,这样可以灵活的添加多个任务,而不必每次都要修改任务切换函数;此外还在任务休眠做了尝试,通过将任务挂起和唤醒从而加快运行速度~

 

一、任务管理自动化

>_<" 为了仿照窗口管理模式对任务进行管理,于是在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 }
  • 第17行,因为任务管理结构体很大,所以要提前分配内存
  • 第18~22行,是初始化所有任务的flags,sel,以及定义每个任务的GDT
  • 第23~34行,是生成一个基础的任务,并进行任务切换时钟设置
  • 第39~65行,是遍历所有的任务,发现当前有没有使用的任务对其进行初始化并返回,实现任务分配的功能
  • 第69~75行,是任务唤醒函数
  • 第80~91行,是任务切换函数,当running=1时不进行切换,当running>2时,把now+1,然后把now所代表的当前任务进行切换,其中第85~87行的判断是当now跑到末尾时,让其跑到开头

 

二、任务休眠

>_<" 如果仅仅是采用上述方式,只能实现每个任务分配大约相同的时间,这样会导致过于平均而不是很优的策略~与其让一个任务空闲着不如直接让其挂起,将自己多出的时间都分配给另一些需要大量时间的任务来执行。这里就要用到休眠:即,将一个任务从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 }
本次bootpack.c

 

三、效果展示

>_<" 可见比上一节讲的多任务要快很多,这主要是采用休眠的的结果~

四、相关链接

 

 

 

 

 

 

 

 

 

 

  

 

posted @ 2014-09-26 11:04  beautifulzzzz  阅读(1803)  评论(0编辑  收藏  举报