割り込み処理をさらに短くしていきます。
線形リストを作成します。
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);