6 加快中断处理(2)(harib09f)
虽然像上面那样做了改进,但笔者还是觉得中断处理程序太慢了,因此我们再来改善一下吧。
改善前的timer.c节选
void inthandler20(int *esp)
{
int i;
io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC */
timerctl.count++;
for (i = 0; i < MAX_TIMER; i++) {
if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
if (timerctl.timer[i].timeout <= timerctl.count) {
timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
}
}
}
return;
}
如果看一下 harib09e的inthandler20,大家会发现每次中断都要执行500次(=MAX_TIMER的次数)if语句,很浪费时间。由于1秒钟就要发生100次中断,这个if语句1秒钟就要执行5万次。尽管如此,这两个if语句都为真,而其中的flags值得以更改,或者是fifo8_put函数能够执行的频率,最多也就是每0.5秒1次,即每秒2次左右。其余的49998次if语句都是在做无用功,基本没什么意义。
■■■■■
我们来变通一下思考方式,如果是人在进行着这样的定时器管理,会怎么做呢?定时器加在一起最多有500个。其中有3秒钟以后超时的,有50秒钟以后超时的,也有0.3秒钟以后超时的,还有一天以后超时的。这种情况下,我们首先会关注哪一个?应该是0.3秒钟以后的那个吧。0.3秒钟的结束后,下次是3秒钟以后的。也就是没必要把500个都看完,只要看到“下一个”的时刻就可以了。因此,我们追加一个变量timerctl.next,让它记住下一个时刻。
本次的bootpack.h节选
struct TIMERCTL {
unsigned int count, next; /* 这里! */
struct TIMER timer[MAX_TIMER];
};
本次的timer.c节选
void inthandler20(int *esp)
{
int i;
io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC */
timerctl.count++;
if (timerctl.next > timerctl.count) {
return; /* 还不到下一个时刻,所以结束*/
}
timerctl.next = 0xffffffff;
for (i = 0; i < MAX_TIMER; i++) {
if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
if (timerctl.timer[i].timeout <= timerctl.count) {
/* 超时 */
timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
} else {
/* 还没有超时 */
if (timerctl.next > timerctl.timer[i].timeout) {
timerctl.next = timerctl.timer[i].timeout;
}
}
}
}
return;
}
虽然程序变长了,但要做的处理却减少了。在大多数情况下,第一个if语句的return都会执行,中断处理就到此结束了。当到达下一个时刻时,使用之前那种方法检查是否超时。超时的话,就写入到FIFO中;还没超时的话就调查是否将其设定为下一个时刻(未超时时刻中,最小的时刻是下一个时刻)。
如果用这样的方法,就能大大减少没有意义的if语句的执行次数,速度也应该快多了。
■■■■■
由于使用了next,所以其他地方也要修改一下。
本次的timer.c节选
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; /* 因为最初没有正在运行的定时器 */
for (i = 0; i < MAX_TIMER; i++) {
timerctl.timer[i].flags = 0; /* 没有使用 */
}
return;
}
void timer_settime(struct TIMER *timer, unsigned int timeout)
{
timer->timeout = timeout + timerctl.count;
timer->flags = TIMER_FLAGS_USING;
if (timerctl.next > timer->timeout) {
/* 更新下一次的时刻 */
timerctl.next = timer->timeout;
}
return;
}
这样就好了。现在我们来确认是否能正常运行。“make run”。……和以前一样,虽然仍不能切身地感受到速度变快了,但还是自我满足一下吧(笑)。