[自制简单操作系统] 6、多任务(一)

 

#前言#

>_<" 这里主要是多任务的初探~比较简单,主要是尝试保存当前任务、任务切换、恢复当前任务,而真正的多任务要比这个复杂的多,因为包含互不干扰,甚至是高度优化的并行技术!

 

一、保存当前任务:

>_<" 当向CPU发出切换命令的时候,CPU会先把寄存器中的值全部写入内存中,这样当切换回来时,可以从中断的地方继续执行。接下来,为了运行下一个程序,CPU会把所有的寄存器中的值从内存中读取出来,这就完成了一次切换。

>_<" 这里的结构TSS32是task status segment,是32位任务状态段,其也是内存段的一种,需要再GDT中进行定以后使用。

1 struct TSS32 {//task status segment 任务状态段
2     int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入)
3     int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器
4     int es, cs, ss, ds, fs, gs;//16位寄存器
5     int ldtr, iomap;//有关任务设置部分
6 };

 

二、任务切换:从任务A到任务B[12a]

>_<" 接下来要在main函数中创建两个TSS:任务A的TSS和任务B的TSS,然后对其初始化,接着再在GDT中定义...见下面的main函数(有删减,这里只展示核心部分):

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

  • 第110~113是对A和B的TSS任务的成员变量的初始化,这里不能乱赋值否则不能正常切换

  • 第114和第115两行是定义两个TSS的GDT,分别是段3和段4

  • 第119行load_tr(3 * 8);是用汇编写的函数,目的是给TR寄存器赋值,因为刚才设置任务a的GDT为3,而TR寄存器是让CPU记住当前执行那一条任务,所以,要给TR重新设置值,这里*8是和硬件有关~

  • 第120行是给任务B分配栈,否则和任务A混在一起就会出现混乱

  • 第121~136是对B的TSS的初始化设置,其中第一行指定任务B的入口地址,当任务切换到任务B时,就会转到第303行任务B的函数执行~

  • 第204行是任务切换,同样这里的函数也是用汇编写的,里面就是一个JMP语句:JMP 4*8:0 用来转到任务B所对应的段地址,我们可以看到这是在10s定时器中写的,所以每隔10s就进行任务切换了

  • @总的来说,这段代码的任务就是做一个10s后的任务切换工作,先运行A任务,然后任务切换进入B,一直处于进行hlt()~

 

三、任务切换:任务A和B的互相切换[12b]

>_<" 上面只是实现了从任务A切换到任务B,然后就一直处于hlt()了~这里我们只要简单的改一下任务B的函数就能实现任务的切回了:

 1 void task_b_main(void)
 2 {
 3     struct FIFO32 fifo;
 4     struct TIMER *timer;
 5     int i,fifobuf[128];
 6     
 7     fifo32_init(&fifo,128,fifobuf);
 8     timer=timer_alloc();
 9     timer_init(timer,&fifo,1);
10     timer_settime(timer,500);
11     
12     for(;;){
13         io_cli();
14         if(fifo32_status(&fifo)==0){
15             io_stihlt();
16         }else{
17             i=fifo32_get(&fifo);
18             io_sti();
19             if(i==1){//超时时间为5s
20                 taskswitch3();//返回任务A
21             }
22         }
23     }
24 }

PS: 这里在任务B的函数里写了和任务A中相同的变量名,其实是互不影响的~

 

四、多任务:每隔0.02s切换任务 & 变量传递[这里是窗口sht_back][12e]

>_<" 这里把汇编写的taskswitch3();和taskswitch4();合并为一个可以带参数的任务切换函数farjmp(),并声明一个定时器0.02s中断一次用于任务切换,注意这里每次切换后要重新设置定时器,以便下次仍然是0.02s切换一次~,对于参数传递采用的思路是:把sht_back在任务A的时候找一个内存存进去(*((int*)0x0fec)=(int) sht_back;),然后在任务B的时候再从这个内存中读出sht_back的值(sht_back=(struct SHEET *)*((int*)0x0fec);)

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

 

五、任务自动切换[12g]

>_<" 真正的多任务是程序本身不知道的情况下进行任务切换!这里直接创建一个mtask.c专门用来处理多任务

 1 /* 任务管理相关程序 */
 2 
 3 #include "bootpack.h"
 4 
 5 struct TIMER *mt_timer;
 6 int mt_tr;
 7 
 8 /////////////////////////////////////////////////////////////////////////////////////
 9 //功能:初始化mt_timer和mt_tr的值,并将计数器设定为0.02s,仅此而已
10 //参数:
11 //附加:变量mt_tr实际上代表了TR寄存器,而不需要timer_init是因为在超时的时候不需要向FIFO缓冲区写入数据
12 //接下来,mt_taskswitch函数的功能是按照当前的mt_tr变量的值计算下一个mt_tr的值,将计时器重新设定为0.02s之后并进行任务切换
13 void mt_init(void)
14 {
15     mt_timer = timer_alloc();
16     /* 这里没有必要使用timer_init */
17     timer_settime(mt_timer, 2);
18     mt_tr = 3 * 8;
19     return;
20 }
21 /////////////////////////////////////////////////////////////////////////////////////
22 //功能:按照当前的mt_tr变量的值计算下一个mt_tr的值,将计时器重新设定为0.02s之后并进行任务切换
23 //参数:
24 void mt_taskswitch(void)
25 {
26     if (mt_tr == 3 * 8) {
27         mt_tr = 4 * 8;
28     } else {
29         mt_tr = 3 * 8;
30     }
31     timer_settime(mt_timer, 2);
32     farjmp(0, mt_tr);
33     return;
34 }
  • mt_init函数是初始化mt_timer和mt_tr的值,并将计数器设置为0.02s之后,mt_tr代表TR寄存器,而不需要使用timer_init()是因为发生超时时不需要向FIFO写数据~

  • mt_taskswitch是按照当前的mt_tr变量的值计算出下一个mt_tr的值,并设置计时器为0.02s,然后任务切换~

>_<" 这里就必须对timer.c里的定时器中断响应函数inthandler20进行响应的修改了:

 1 void inthandler20(int *esp)
 2 {
 3     char ts=0;//标记mt_timer任务切换计时器是否超时,如果直接在else语句直接调用任务切换会出现错误,因为这个中断处理还没完成
 4     struct TIMER *timer;
 5     io_out8(PIC0_OCW2, 0x60);    /* 把IRQ-00信号接受完了的信息通知给PIC */
 6     timerctl.count++;
 7     if (timerctl.next > timerctl.count) {//如果下一个还没计数完毕就直接返回
 8         return;
 9     }
10     timer = timerctl.t0; //把最前面的地址赋址给timer
11     for (;;) {
12         if (timer->timeout > timerctl.count) {
13             break;
14         }//从前往后遍历,一旦发现有计时未完成的计时器就跳出循环
15         /*除了上面的情况,都是定时已达的定时器*/
16         timer->flags = TIMER_FLAGS_ALLOC;
17         if(timer!=mt_timer){
18             fifo32_put(timer->fifo, timer->data);
19         }else{
20             ts=1;/* mt_timer超时 */
21         }
22         timer = timer->next;//下一个定时器的地址赋址给timer
23     }
24     timerctl.t0 = timer;//新移位
25     timerctl.next = timer->timeout;//timectl.next设定
26     if(ts!=0){
27         mt_taskswitch();
28     }
29     return;
30 }
  • 如果发生超时的是mt_timer的话,不向FIFO写数据,而是置ts为1,最后根据这个标志看是否要进行任务切换~(这里一定不能直接在第20行进行任务切换,因为中断还没进行完毕~)

 

六、效果展示:

>_<" 这里每隔1s就显示一下累计的数据:7370035,下面一行是总的数据~

 

七、代码链接:

 

posted @ 2014-09-25 22:58  beautifulzzzz  阅读(1410)  评论(0编辑  收藏  举报