たなしょのメモ

日々勉強していることをつらつらと

OS作成奮闘記day19

引き続き処理のスピードを上げていきます。
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);
    }

実装過程
・ 8e8e1c3e50a79e1d055ae3479e7dc63b3cefafe9