Day24 窗口操作
文章目录
- 1. 定时器API(harib21g)
- 2. 取消定时器(harib21h)
1. 定时器API(harib21g)
// console.c 文件
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{struct TASK *task = task_now();/* 省略 */if (edx == 16) {reg[7] = (int) timer_alloc();} else if (edx == 17) {timer_init((struct TIMER *) ebx, &task->fifo, eax + 256);} else if (edx == 18) {timer_settime((struct TIMER *) ebx, eax);} else if (edx == 19) {timer_free((struct TIMER *) ebx);}return 0;
}
应用程序:
# a_nask.nas 文件
_api_alloctimer: # int api_alloctimer(void);MOV EDX,16INT 0x40RET_api_inittimer: ; void api_inittimer(int timer, int data);PUSH EBXMOV EDX,17MOV EBX,[ESP+ 8] # timerMOV EAX,[ESP+12] # dataINT 0x40POP EBXRET_api_settimer: ; void api_settimer(int timer, int time);PUSH EBXMOV EDX,18MOV EBX,[ESP+ 8] # timerMOV EAX,[ESP+12] # timeINT 0x40POP EBXRET_api_freetimer: # void api_freetimer(int timer);PUSH EBXMOV EDX,19MOV EBX,[ESP+ 8] # timerINT 0x40POP EBXRET
// noodle.c 文件
#include <stdio.h>int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_putstrwin(int win, int x, int y, int col, int len, char *str);
void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
void api_initmalloc(void);
char *api_malloc(int size);
int api_getkey(int mode);
int api_alloctimer(void);
void api_inittimer(int timer, int data);
void api_settimer(int timer, int time);
void api_end(void);void HariMain(void)
{char *buf, s[12];int win, timer, sec = 0, min = 0, hou = 0;api_initmalloc();buf = api_malloc(150 * 50);win = api_openwin(buf, 150, 50, -1, "noodle");timer = api_alloctimer();api_inittimer(timer, 128);for (;;) {sprintf(s, "%5d:%02d:%02d", hou, min, sec);api_boxfilwin(win, 28, 27, 115, 41, 7 /* 白色 */);api_putstrwin(win, 28, 27, 0 /* 黑色 */, 11, s);api_settimer(timer, 100); /* 1秒 */if (api_getkey(1) != 128) {break;}sec++;if (sec == 60) {sec = 0;min++;if (min == 60) {min = 0;hou++;}}}api_end();
}
api_getkey(1)
是阻塞等待,就是当fifo为空时,本任务会先休眠等待直到fifo中有内容。当定时器超时时,会产生128这个值(键盘编码不会产生128)。
2. 取消定时器(harib21h)
当前存在的一个问题是,如果应用程序被取消了,那么定时器还在按照频率触发。
// 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->flags = TIMER_FLAGS_ALLOC;io_store_eflags(e);return 1; /* 取消处理成功 */}io_store_eflags(e);return 0; /* 不需要取消处理 */
}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;
}
还需要在定时器结构体中增加一个标记,标识该定时器是否需要在应用程序结束时结束自动取消。
// bootpack.h 文件
struct TIMER {struct TIMER *next;unsigned int timeout;char flags;char flags2; // 通常情况下为0,为1标识应用程序结束时取消定时器struct FIFO32 *fifo;int data;
};
// timer.c 文件
struct TIMER *timer_alloc(void)
{int i;for (i = 0; i < MAX_TIMER; i++) {/* 省略 */timerctl.timers0[i].flags2 = 0; // 初始值为0return &timerctl.timers0[i];}}return 0;
}
// console.c 文件
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{/* 省略 */if (edx == 16) {reg[7] = (int) timer_alloc();((struct TIMER *) reg[7])->flags2 = 1; /* 标记为应用程序结束时自动取消 */}/* 省略 */
}
// console.c 文件
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{/* 省略 */if (finfo != 0) {/* 省略 */start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0)); // 跳到用户态,执行应用程序,应用程序调用api_end()函数之后才会从本行往下执行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);}/* 省略 */
}