引き続き処理のスピードを上げていきます。
fifo.c
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, 0); /* 起こしてあげる */ } } return 0; }
bootpack.c
/* 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], i + 1); }
これで速くなりました。
さらにさらに速くしてみます。
bootpack.h
/* mtask.c */ #define MAX_TASKS 1000 /* 最大タスク数 */ #define TASK_GDT0 3 /* TSSをGDTの何番から割り当てるのか */ #define MAX_TASKS_LV 100 #define MAX_TASKLEVELS 10 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の番号のこと */ int level, priority; struct TSS32 tss; }; struct TASKLEVEL { int running; /* 動作しているタスクの数 */ int now; /* 現在動作しているタスクがどれだか分かるようにするための変数 */ struct TASK *tasks[MAX_TASKS_LV]; }; struct TASKCTL { int now_lv; /* 現在動作中のレベル */ char lv_change; /* 次回タスクスイッチのときに、レベルも変えたほうがいいかどうか */ struct TASKLEVEL level[MAX_TASKLEVELS]; struct TASK tasks0[MAX_TASKS]; }; extern struct TIMER *task_timer; struct TASK *task_init(struct MEMMAN *memman); struct TASK *task_alloc(void); void task_run(struct TASK *task, int level, int priority); void task_switch(void); void task_sleep(struct TASK *task);
mtask.c
/* マルチタスク関係 */ #include "bootpack.h" struct TASKCTL *taskctl; struct TIMER *task_timer; struct TASK *task_now(void) { struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv]; return tl->tasks[tl->now]; } void task_add(struct TASK *task) { 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) { /* nowがおかしな値になっていたら、修正する */ tl->now = 0; } task->flags = 1; /* スリープ中 */ /* ずらし */ for (; i < tl->running; i++) { tl->tasks[i] = tl->tasks[i + 1]; } return; } void task_switchsub(void) { int i; /* 一番上のレベルを探す */ for (i = 0; i < MAX_TASKLEVELS; i++) { if (taskctl->level[i].running > 0) { break; /* 見つかった */ } } taskctl->now_lv = i; taskctl->lv_change = 0; return; } 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->priority = 2; /* 0.02秒 */ task->level = 0; /* 最高レベル */ task_add(task); task_switchsub(); /* レベル設定 */ load_tr(task->sel); task_timer = timer_alloc(); timer_settime(task_timer, task->priority); return task; } struct TASK *task_alloc(void) { int i; struct 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; /* とりあえず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, int level, int priority) { if (level < 0) { level = task->level; /* レベルを変更しない */ } if (priority > 0) { task->priority = priority; } if (task->flags == 2 && task->level != level) { /* 動作中のレベルの変更 */ task_remove(task); /* これを実行するとflagsは1になるので下のifも実行される */ } if (task->flags != 2) { /* スリープから起こされる場合 */ task->level = level; task_add(task); } taskctl->lv_change = 1; /* 次回タスクスイッチのときにレベルを見直す */ return; } void task_sleep(struct TASK *task) { struct TASK *now_task; if (task->flags == 2) { /* 動作中だったら */ now_task = task_now(); task_remove(task); /* これを実行するとflagsは1になる */ if (task == now_task) { /* 自分自身のスリープだったので、タスクスイッチが必要 */ task_switchsub(); now_task = task_now(); /* 設定後での、「現在のタスク」を教えてもらう */ farjmp(0, now_task->sel); } } return; } 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; }
fifo.c
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, -1, 0); /* 起こしてあげる */ } } return 0; }
bootpack.c
init_palette(); shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny); task_a = task_init(memman); fifo.task = task_a; task_run(task_a, 1, 0); /* 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], 2, i + 1); }