Appearance
day15多任务
任务切换
任务状态段TSS, 有16位和32位两个版本, 也是内存的一部分, 在定义了GDT之后使用
c
struct TSS32 {
//这一行的保存任务设置相关的信息
int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
//32位的寄存器, epi记录执行到的位置
int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
//16位的寄存器
int es, cs, ss, ds, fs, gs;
//任务设置相关的, 设置为0和0x40000000
int ldtr, iomap;
};
实际上切换任务就是使用JMP改变EIP, 有两种, 只改变EIP的叫做near模式, 同时改变CS的叫做far模式
JMP跳转的位置是TSS的话就会进行任务切换
c
struct TSS32 tss_a, tss_b;
tss_a.ldtr = 0;
tss_a.iomap = 0x40000000;
tss_b.ldtr = 0;
tss_b.iomap = 0x40000000;
c
#define AR_TSS32 0x0089
struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
//设置两个段
set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);
set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32);
load_tr(3 * 8);
assembly
_load_tr: ; void load_tr(int tr);
LTR [ESP+4] ; tr
RET
这个是向task register任务寄存器TR写入GDT的值, 需要乘8, 这时候切换任务会自动记录当前的值
c
_taskswitch4: ; void taskswitch4(void);
JMP 4*8:0
RET
RET这个是在任务结束之后可能会返回, 之后返回C的主函数
c
//申请一个栈
task_b_esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024; //这里直接设置为栈的尾部
//这个是返回的位置
tss_b.eip = (int) &task_b_main;
tss_b.eflags = 0x00000202; /* IF = 1; */
tss_b.eax = 0;
tss_b.ecx = 0;
tss_b.edx = 0;
tss_b.ebx = 0;
tss_b.esp = task_b_esp;
tss_b.ebp = 0;
tss_b.esi = 0;
tss_b.edi = 0;
tss_b.es = 1 * 8;
tss_b.cs = 2 * 8;
tss_b.ss = 1 * 8;
tss_b.ds = 1 * 8;
tss_b.fs = 1 * 8;
tss_b.gs = 1 * 8;
在这里设置的段和bootpack.c相同
之后设置切换回去
c
void task_b_main(void)
{
struct FIFO32 fifo;
struct TIMER *timer;
int i, fifobuf[128];
fifo32_init(&fifo, 128, fifobuf);
timer = timer_alloc();
timer_init(timer, &fifo, 1);
timer_settime(timer, 500);
for (;;) {
io_cli();
if (fifo32_status(&fifo) == 0) {
io_sti();
io_hlt();
} else {
i = fifo32_get(&fifo);
io_sti();
if (i == 1) { /* 5秒タイムアウト */
taskswitch3(); /* タスクAにもどる */
}
}
}
}
c
_taskswitch3: ; void taskswitch3(void);
JMP 3*8:0
RET
抽象切换任务
c
_farjmp: ; void farjmp(int eip, int cs);
JMP FAR [ESP+4] ; eip, cs
RET
c
if (i == 2) {
farjmp(0, 4 * 8);
timer_settime(timer_ts, 2);
}
时间到就进行切换, 切换回来之后设置另一个定时器
c
void task_b_main(void)
{
struct FIFO32 fifo;
struct TIMER *timer_ts;
int i, fifobuf[128];
fifo32_init(&fifo, 128, fifobuf);
timer_ts = timer_alloc();
timer_init(timer_ts, &fifo, 1);
timer_settime(timer_ts, 2);
for (;;) {
io_cli();
if (fifo32_status(&fifo) == 0) {
io_sti();
io_hlt();
} else {
i = fifo32_get(&fifo);
io_sti();
if (i == 1) { /* 时间到了 */
farjmp(0, 3 * 8);
timer_settime(timer_ts, 2);
}
}
}
}
实现在任务中打印
需要传递图层的结构体
c
//把图层的信息存储在这个位置
*((int *) 0x0fec) = (int) sht_back;
void task_b_main(void)
{
struct FIFO32 fifo;
struct TIMER *timer_ts;
int i, fifobuf[128], count = 0;
char s[11];
struct SHEET *sht_back;
fifo32_init(&fifo, 128, fifobuf);
timer_ts = timer_alloc();
timer_init(timer_ts, &fifo, 1);
timer_settime(timer_ts, 2);
//获取图层
sht_back = (struct SHEET *) *((int *) 0x0fec);
for (;;) {
count++;
sprintf(s, "%10d", count);
putfonts8_asc_sht(sht_back, 0, 144, COL8_FFFFFF, COL8_008484, s, 10);
io_cli();
if (fifo32_status(&fifo) == 0) {
io_sti();
} else {
i = fifo32_get(&fifo);
io_sti();
if (i == 1) { /* 任务的时间到了 */
farjmp(0, 3 * 8);
timer_settime(timer_ts, 2);
}
}
}
}
减少不必要的打印
c
void task_b_main(struct SHEET *sht_back)
{
struct FIFO32 fifo;
struct TIMER *timer_ts, *timer_put;
int i, fifobuf[128], count = 0;
char s[12];
fifo32_init(&fifo, 128, fifobuf);
timer_ts = timer_alloc();
timer_init(timer_ts, &fifo, 2);
timer_settime(timer_ts, 2);
timer_put = timer_alloc();
timer_init(timer_put, &fifo, 1);
timer_settime(timer_put, 1);
for (;;) {
count++;
io_cli();
if (fifo32_status(&fifo) == 0) {
io_sti();
} else {
i = fifo32_get(&fifo);
io_sti();
if (i == 1) {
sprintf(s, "%11d", count);
putfonts8_asc_sht(sht_back, 0, 144, COL8_FFFFFF, COL8_008484, s, 11);
timer_settime(timer_put, 1);
} else if (i == 2) {
farjmp(0, 3 * 8);
timer_settime(timer_ts, 2);
}
}
}
改变传递的方式
在Intel架构里面传递的信息是在ESP+4的位置, 所以可以使用这个方式进行传递, ESP记录的是返回的地址
c
task_b_esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;
tss_b.eip = (int) &task_b_main;
tss_b.eflags = 0x00000202; /* IF = 1; */
tss_b.eax = 0;
tss_b.ecx = 0;
tss_b.edx = 0;
tss_b.ebx = 0;
tss_b.esp = task_b_esp;
tss_b.ebp = 0;
tss_b.esi = 0;
tss_b.edi = 0;
tss_b.es = 1 * 8;
tss_b.cs = 2 * 8;
tss_b.ss = 1 * 8;
tss_b.ds = 1 * 8;
tss_b.fs = 1 * 8;
tss_b.gs = 1 * 8;
//在这里设置传入的数据
*((int *) (task_b_esp + 4)) = (int) sht_back;
如果在最初的时候减的是4会在最后导致溢出, 因为这里的内存计算是从0开始的
c
int mt_tr;
void mt_init(void)
{
//初始化一个计数器
mt_timer = timer_alloc();
/* timer_init设置一个时间 */
timer_settime(mt_timer, 2);
// 初始化主任务
mt_tr = 3 * 8;
return;
}
//切换的函数
void mt_taskswitch(void)
{
if (mt_tr == 3 * 8) {
mt_tr = 4 * 8;
} else {
mt_tr = 3 * 8;
}
timer_settime(mt_timer, 2);
farjmp(0, mt_tr);
return;
}
进阶任务切换
c
void inthandler20(int *esp)
{
struct TIMER *timer;
char ts = 0;
io_out8(PIC0_OCW2, 0x60); /* IRQ-00受付完了をPICに通知 */
timerctl.count++;
if (timerctl.next > timerctl.count) {
return;
}
timer = timerctl.t0; /* とりあえず先頭の番地をtimerに代入 */
for (;;) {
/* timers循环找到 */
if (timer->timeout > timerctl.count) {
break;
}
/* タイムアウト */
timer->flags = TIMER_FLAGS_ALLOC;
if (timer != mt_timer) {
fifo32_put(timer->fifo, timer->data);
} else {
ts = 1; /* 这个是任务切换的时间到了 */
}
timer = timer->next; /* 更新下一个是时钟 */
}
timerctl.t0 = timer;
timerctl.next = timer->timeout;
if (ts != 0) {
mt_taskswitch();
}
return;
}