たなしょのメモ

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

OS作成奮闘記day14

割り込み処理をさらに短くしていきます。
線形リストを作成します。
bootpack.h

struct TIMER {
    struct TIMER *next;
    unsigned int timeout, flags;
    struct FIFO32 *fifo;
    int data;
};
struct TIMERCTL {
    unsigned int count, next, using;
    struct TIMER *t0;
    struct TIMER timers0[MAX_TIMER];
};

timer.c

void timer_settime(struct TIMER *timer, unsigned int timeout)
{
    int e;
    struct TIMER *t, *s;
    timer->timeout = timeout + timerctl.count;
    timer->flags = TIMER_FLAGS_USING;
    e = io_load_eflags();
    io_cli();
    timerctl.using++;
    if (timerctl.using == 1) {
        /* 動作中のタイマはこれ一つになる場合 */
        timerctl.t0 = timer;
        timer->next = 0; /* 次はない */
        timerctl.next = timer->timeout;
        io_store_eflags(e);
        return;
    }
    t = timerctl.t0;
    if (timer->timeout <= t->timeout) {
        /* 先頭に入れる場合 */
        timerctl.t0 = timer;
        timer->next = t; /* 次はt */
        timerctl.next = timer->timeout;
        io_store_eflags(e);
        return;
    }
    /* どこに入れればいいかを探す */
    for (;;) {
        s = t;
        t = t->next;
        if (t == 0) {
            break; /* 一番うしろになった */
        }
        if (timer->timeout <= t->timeout) {
            /* sとtの間に入れる場合 */
            s->next = timer; /* sの次はtimer */
            timer->next = t; /* timerの次はt */
            io_store_eflags(e);
            return;
        }
    }
    /* 一番うしろに入れる場合 */
    s->next = timer;
    timer->next = 0;
    io_store_eflags(e);
    return;
}

void inthandler20(int *esp)
{
    int i;
    struct TIMER *timer;
    io_out8(PIC0_OCW2, 0x60);  /* IRQ-00受付完了をPICに通知 */
    timerctl.count++;
    if (timerctl.next > timerctl.count) {
        return;
    }
    timer = timerctl.t0; /* とりあえず先頭の番地をtimerに代入 */
    for (i = 0; i < timerctl.using; i++) {
        /* timersのタイマは全て動作中のものなので、flagsを確認しない */
        if (timer->timeout > timerctl.count) {
            break;
        }
        /* タイムアウト */
        timer->flags = TIMER_FLAGS_ALLOC;
        fifo32_put(timer->fifo, timer->data);
        timer = timer->next; /* 次のタイマの番地をtimerに代入 */
    }
    timerctl.using -= i;

    /* 新しいずらし */
    timerctl.t0 = timer;

    /* timerctl.nextの設定 */
    if (timerctl.using > 0) {
        timerctl.next = timerctl.t0->timeout;
    } else {
        timerctl.next = 0xffffffff;
    }
    return;
}

次は番兵法を利用してtimer.cのソースコードを短くします。
timer.c

void init_pit(void)
{
    int i;
    struct TIMER *t;
    io_out8(PIT_CTRL, 0x34);
    io_out8(PIT_CNT0, 0x9c);
    io_out8(PIT_CNT0, 0x2e);
    timerctl.count = 0;
    for (i = 0; i < MAX_TIMER; i++) {
        timerctl.timers0[i].flags = 0; /* 未使用 */
    }
    t = timer_alloc(); /* 一つもらってくる */
    t->timeout = 0xffffffff;
    t->flags = TIMER_FLAGS_USING;
    t->next = 0; /* 一番うしろ */
    timerctl.t0 = t; /* 今は番兵しかいないので先頭でもある */
    timerctl.next = 0xffffffff; /* 番兵しかいないので番兵の時刻 */
    return;
}

struct TIMER *timer_alloc(void)
{
    int i;
    for (i = 0; i < MAX_TIMER; i++) {
        if (timerctl.timers0[i].flags == 0) {
            timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC;
            return &timerctl.timers0[i];
        }
    }
    return 0; /* 見つからなかった */
}

void timer_free(struct TIMER *timer)
{
    timer->flags = 0; /* 未使用 */
    return;
}

void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data)
{
    timer->fifo = fifo;
    timer->data = data;
    return;
}

void timer_settime(struct TIMER *timer, unsigned int timeout)
{
    int e;
    struct TIMER *t, *s;
    timer->timeout = timeout + timerctl.count;
    timer->flags = TIMER_FLAGS_USING;
    e = io_load_eflags();
    io_cli();
    t = timerctl.t0;
    if (timer->timeout <= t->timeout) {
        /* 先頭に入れる場合 */
        timerctl.t0 = timer;
        timer->next = t; /* 次はt */
        timerctl.next = timer->timeout;
        io_store_eflags(e);
        return;
    }
    /* どこに入れればいいかを探す */
    for (;;) {
        s = t;
        t = t->next;
        if (timer->timeout <= t->timeout) {
            /* sとtの間に入れる場合 */
            s->next = timer; /* sの次はtimer */
            timer->next = t; /* timerの次はt */
            io_store_eflags(e);
            return;
        }
    }
}

void inthandler20(int *esp)
{
    struct TIMER *timer;
    io_out8(PIC0_OCW2, 0x60);  /* IRQ-00受付完了をPICに通知 */
    timerctl.count++;
    if (timerctl.next > timerctl.count) {
        return;
    }
    timer = timerctl.t0; /* とりあえず先頭の番地をtimerに代入 */
    for (;;) {
        /* timersのタイマは全て動作中のものなので、flagsを確認しない */
        if (timer->timeout > timerctl.count) {
            break;
        }
        /* タイムアウト */
        timer->flags = TIMER_FLAGS_ALLOC;
        fifo32_put(timer->fifo, timer->data);
        timer = timer->next; /* 次のタイマの番地をtimerに代入 */
    }
    timerctl.t0 = timer;
    timerctl.next = timer->timeout;
    return;
}

テスト用のタイマを追加して過去のソースを使って速度を測りたいと思います。
bootpack.c

void set490(struct FIFO32 *fifo, int mode)
{
    int i;
    struct TIMER *timer;
    if (mode != 0) {
        for (i = 0; i < 490; i++) {
            timer = timer_alloc();
            timer_init(timer, fifo, 1024 + i);
            timer_settime(timer, 100 * 60 * 60 * 24 * 50 + i * 100);
        }
    }
    return;
}

timer.c

/* タイマ関係 */

#include "bootpack.h"

#define PIT_CTRL   0x0043
#define PIT_CNT0   0x0040

struct TIMERCTL timerctl;

#define TIMER_FLAGS_ALLOC      1  /* 確保した状態 */
#define TIMER_FLAGS_USING      2  /* タイマ作動中 */

void init_pit(void)
{
    int i;
    io_out8(PIT_CTRL, 0x34);
    io_out8(PIT_CNT0, 0x9c);
    io_out8(PIT_CNT0, 0x2e);
    timerctl.count = 0;
    timerctl.next = 0xffffffff; /* 最初は作動中のタイマがないので */
    timerctl.using = 0;
    for (i = 0; i < MAX_TIMER; i++) {
        timerctl.timers0[i].flags = 0; /* 未使用 */
    }
    return;
}

struct TIMER *timer_alloc(void)
{
    int i;
    for (i = 0; i < MAX_TIMER; i++) {
        if (timerctl.timers0[i].flags == 0) {
            timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC;
            return &timerctl.timers0[i];
        }
    }
    return 0; /* 見つからなかった */
}

void timer_free(struct TIMER *timer)
{
    timer->flags = 0; /* 未使用 */
    return;
}

void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data)
{
    timer->fifo = fifo;
    timer->data = data;
    return;
}

void timer_settime(struct TIMER *timer, unsigned int timeout)
{
    int e, i, j;
    timer->timeout = timeout + timerctl.count;
    timer->flags = TIMER_FLAGS_USING;
    e = io_load_eflags();
    io_cli();
    /* どこに入れればいいかを探す */
    for (i = 0; i < timerctl.using; i++) {
        if (timerctl.timers[i]->timeout >= timer->timeout) {
            break;
        }
    }
    /* うしろをずらす */
    for (j = timerctl.using; j > i; j--) {
        timerctl.timers[j] = timerctl.timers[j - 1];
    }
    timerctl.using++;
    /* あいたすきまに入れる */
    timerctl.timers[i] = timer;
    timerctl.next = timerctl.timers[0]->timeout;
    io_store_eflags(e);
    return;
}

void inthandler20(int *esp)
{
    int i, j;
    io_out8(PIC0_OCW2, 0x60);  /* IRQ-00受付完了をPICに通知 */
    timerctl.count++;
    if (timerctl.next > timerctl.count) {
        return;
    }
    for (i = 0; i < timerctl.using; i++) {
        /* timersのタイマは全て動作中のものなので、flagsを確認しない */
        if (timerctl.timers[i]->timeout > timerctl.count) {
            break;
        }
        /* タイムアウト */
        timerctl.timers[i]->flags = TIMER_FLAGS_ALLOC;
        fifo32_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data);
    }
    /* ちょうどi個のタイマがタイムアウトした。残りをずらす。 */
    timerctl.using -= i;
    for (j = 0; j < timerctl.using; j++) {
        timerctl.timers[j] = timerctl.timers[i + j];
    }
    if (timerctl.using > 0) {
        timerctl.next = timerctl.timers[0]->timeout;
    } else {
        timerctl.next = 0xffffffff;
    }
    return;
}

bootpack.h

/* timer.c */
#define MAX_TIMER       500
struct TIMER {
    unsigned int timeout, flags;
    struct FIFO32 *fifo;
    int data;
};
struct TIMERCTL {
    unsigned int count, next, using;
    struct TIMER *timers[MAX_TIMER];
    struct TIMER timers0[MAX_TIMER];
};
extern struct TIMERCTL timerctl;
void init_pit(void);
struct TIMER *timer_alloc(void);
void timer_free(struct TIMER *timer);
void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data);
void timer_settime(struct TIMER *timer, unsigned int timeout);
void inthandler20(int *esp);

実装過程
・ 27de4e76b4e3613336208f6817962bd76ad75657