8 取消定时器(harib21h)
上一节我们所实现的定时器功能,其实有个问题,接下来我们来解决它。
这个问题是在应用程序结束之后发生的,请大家想象一下noodle.hrb结束之后的情形。应用程序设置了一个1秒的定时器,当定时器到达指定时间时会产生超时,并向任务发送事先设置的数据。问题是,如果这时应用程序已经结束了,定时器的数据就会被发送到命令行窗口,而命令行窗口肯定是一头雾水。
为了确认这个问题,我们在harib21g中运行noodle.hrb,按回车键或者其他任意键结束程序看看。大约1秒钟之后,命令行窗口中会自动出现一个神秘的字符。用鼠标按“×”关闭窗口之后,也会出现同样的现象。
noodle.hrb结束后出现的神秘字符(不是C哦)
要解决这个问题,我们需要取消待机中的定时器,这样一来,就可以在应用程序结束的同时取消定时器,问题也就迎刃而解了。
■■■■■
首先我们来编写用于取消指定定时器的函数。
本次的timer.c节选
int timer_cancel(struct TIMER *timer)
{
int e;
struct TIMER *t;
e = io_load_eflags();
io_cli(); /*在设置过程中禁止改变定时器状态*/
if (timer->flags == TIMER_FLAGS_USING) { /*是否需要取消?*/
if (timer == timerctl.t0) {
/*第一个定时器的取消处理*/
t = timer->next;
timerctl.t0 = t;
timerctl.next = t->timeout;
} else {
/*非第一个定时器的取消处理*/
/*找到timer前一个定时器*/
t = timerctl.t0;
for (;;) {
if (t->next == timer) {
break;
}
t = t->next;
}
t->next = timer->next; /*将之前“timer的下一个”指向“timer的下一个”*/
}
timer->flags = TIMER_FLAGS_ALLOC;
io_store_eflags(e);
return 1; /*取消处理成功*/
}
io_store_eflags(e);
return 0; /*不需要取消处理*/
}
详细的解说已经写在程序的注释中了,请大家自行阅读。
接下来,我们来编写在应用程序结束时取消全部定时器的函数。在此之前,我们需要在定时器上增加一个标记,用来区分该定时器是否需要在应用程序结束时自动取消。如果没有这个标记的话,命令行窗口中用来控制光标闪烁的定时器也会被取消掉了。
本次的bootpack.h节选
struct TIMER {
struct TIMER *next;
unsigned int timeout;
char flags, flags2; /*这里!*/
struct FIFO32 *fifo;
int data;
};
通常情况下,这里的flags2为0,为了避免忘记置0,我们来修改一下timer.alloc。
本次的timer.c节选
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;
timerctl.timers0[i].flags2 = 0; /*这里!*/
return &timerctl.timers0[i];
}
}
return 0; /*没有找到*/
}
接下来,我们将应用程序所申请的定时器的flags2设为1。
本次的console.c节选
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
(中略)
} else if (edx == 16) {
reg[7] = (int) timer_alloc();
((struct TIMER *) reg[7])->flags2 = 1; /*允许自动取消*/ /*这里!*/
} else if (edx == 17) {
(中略)
}
准备完成了,下面我们就编写一个函数,来取消应用程序结束时所不需要的定时器。
本次的console.c节选
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{
(中略)
if (finfo != 0) {
(中略)
if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {
(中略)
start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0));
shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
for (i = 0; i < MAX_SHEETS; i++) {
sht = &(shtctl->sheets0[i]);
if ((sht->flags & 0x11) == 0x11 && sht->task == task) {
/*找到应用程序残留的窗口*/
sheet_free(sht); /*关闭*/
}
}
timer_cancelall(&task->fifo); /*这里!*/
memman_free_4k(memman, (int) q, segsiz);
} else {
(中略)
}
(中略)
}
(中略)
}
本次的timer.c节选
void timer_cancelall(struct FIFO32 *fifo)
{
int e, i;
struct TIMER *t;
e = io_load_eflags();
io_cli(); /*在设置过程中禁止改变定时器状态*/
for (i = 0; i < MAX_TIMER; i++) {
t = &timerctl.timers0[i];
if (t->flags != 0 && t->flags2 != 0 && t->fifo == fifo) {
timer_cancel(t);
timer_free(t);
}
}
io_store_eflags(e);
return;
}
大功告成了!
我们来“make run”,运行noodle.hrb,然后让程序结束。哦哦成功了,神秘字符再也不出现了,太好了。
神秘字符消失了
好了,今天的内容就到这里吧,明天见哦!