6 加快中断处理(2)(harib09f)

虽然像上面那样做了改进,但笔者还是觉得中断处理程序太慢了,因此我们再来改善一下吧。

改善前的timer.c节选

  1. void inthandler20(int *esp)
  2. {
  3. int i;
  4. io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC */
  5. timerctl.count++;
  6. for (i = 0; i < MAX_TIMER; i++) {
  7. if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
  8. if (timerctl.timer[i].timeout <= timerctl.count) {
  9. timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
  10. fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
  11. }
  12. }
  13. }
  14. return;
  15. }

如果看一下 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节选

  1. struct TIMERCTL {
  2. unsigned int count, next; /* 这里! */
  3. struct TIMER timer[MAX_TIMER];
  4. };

本次的timer.c节选

  1. void inthandler20(int *esp)
  2. {
  3. int i;
  4. io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC */
  5. timerctl.count++;
  6. if (timerctl.next > timerctl.count) {
  7. return; /* 还不到下一个时刻,所以结束*/
  8. }
  9. timerctl.next = 0xffffffff;
  10. for (i = 0; i < MAX_TIMER; i++) {
  11. if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
  12. if (timerctl.timer[i].timeout <= timerctl.count) {
  13. /* 超时 */
  14. timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
  15. fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
  16. } else {
  17. /* 还没有超时 */
  18. if (timerctl.next > timerctl.timer[i].timeout) {
  19. timerctl.next = timerctl.timer[i].timeout;
  20. }
  21. }
  22. }
  23. }
  24. return;
  25. }

虽然程序变长了,但要做的处理却减少了。在大多数情况下,第一个if语句的return都会执行,中断处理就到此结束了。当到达下一个时刻时,使用之前那种方法检查是否超时。超时的话,就写入到FIFO中;还没超时的话就调查是否将其设定为下一个时刻(未超时时刻中,最小的时刻是下一个时刻)。

如果用这样的方法,就能大大减少没有意义的if语句的执行次数,速度也应该快多了。

■■■■■

由于使用了next,所以其他地方也要修改一下。

本次的timer.c节选

  1. void init_pit(void)
  2. {
  3. int i;
  4. io_out8(PIT_CTRL, 0x34);
  5. io_out8(PIT_CNT0, 0x9c);
  6. io_out8(PIT_CNT0, 0x2e);
  7. timerctl.count = 0;
  8. timerctl.next = 0xffffffff; /* 因为最初没有正在运行的定时器 */
  9. for (i = 0; i < MAX_TIMER; i++) {
  10. timerctl.timer[i].flags = 0; /* 没有使用 */
  11. }
  12. return;
  13. }
  14. void timer_settime(struct TIMER *timer, unsigned int timeout)
  15. {
  16. timer->timeout = timeout + timerctl.count;
  17. timer->flags = TIMER_FLAGS_USING;
  18. if (timerctl.next > timer->timeout) {
  19. /* 更新下一次的时刻 */
  20. timerctl.next = timer->timeout;
  21. }
  22. return;
  23. }

这样就好了。现在我们来确认是否能正常运行。“make run”。……和以前一样,虽然仍不能切身地感受到速度变快了,但还是自我满足一下吧(笑)。