三十天自制操作系统(14)

第26天

前一章中我们做的操作系统已经越来越像超作系统了,我们同时打开了2个console窗口,并且把task_a的窗口给了消了。现在我们在启动时显打开一个console窗口,然后用户自己操作打开另一个窗口。我们就这么规定,如果按下shift+f2那么就打开一个命令行窗口。

为了方便我们将把开命令行窗口单独作成一个函数。

    struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal)
    {
        struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
        struct SHEET *sht = sheet_alloc(shtctl);
        unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
        struct TASK *task = task_alloc();
        int *cons_fifo = (int *) memman_alloc_4k(memman, 128 * 4);
        sheet_setbuf(sht, buf, 256, 165, -1); 
        make_window8(buf, 256, 165, "console", 0);
        make_textbox8(sht, 8, 28, 240, 128, COL8_000000);
        task->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 12;
        task->tss.eip = (int) &console_task;
        task->tss.es = 1 * 8;
        task->tss.cs = 2 * 8;
        task->tss.ss = 1 * 8;
        task->tss.ds = 1 * 8;
        task->tss.fs = 1 * 8;
        task->tss.gs = 1 * 8;
        *((int *) (task->tss.esp + 4)) = (int) sht;
        *((int *) (task->tss.esp + 8)) = memtotal;
        task_run(task, 2, 2); /* level=2, priority=2 */
        sht->task = task;
        sht->flags |= 0x20; /* 有光标 */
        fifo32_init(&task->fifo, 128, cons_fifo, task);
        return sht;
    }

这个函数返回一个SHEET结构体指针。只要我们在主函数中实现输入shift + f2就调用定个函数就可以了。

    if (i == 256 + 0x3c && key_shift != 0 && sht_cons[1] == 0) {    /* Shift+F2 */
        sht_cons[1] = open_console(shtctl, memtotal);
        sheet_slide(sht_cons[1], 32, 4);
        sheet_updown(sht_cons[1], shtctl->top);
        /* �自动将焦点切换到新打开的命令行窗口 */
        keywin_off(key_win);
        key_win = sht_cons[1];
        keywin_on(key_win);
    }

看上面的代码知道,目前我们操作系统还只支持最多打开2个命令行窗口。我们接下来想办法能打开更多的命令行窗口。实际上如果我们不用sht_cons[]这个数组保存命令行窗口,那么只要不关闭命令行窗口也不会出现问题。如果要关闭窗口我们就要考虑保存将命令行窗口所对应用栈内存和消息队列内存给释放,还要把窗口对应用图层内存释放。

首先我们将打开命令行窗口时申请的栈空间保存到TASK结构体中。

    struct TASK {
        int sel, flags; 
        int level, priority;
        struct FIFO32 fifo;
        struct TSS32 tss;
        struct CONSOLE *cons;
        int ds_base, cons_stack;
    };

然后在打开窗口的函数中将栈地址保存起来

task->cons_stack = memman_alloc_4k(memman, 64 * 1024);
task->tss.esp = task->cons_stack + 64 * 1024 - 12;

再来写关闭命令行窗口的函数

void close_constask(struct TASK *task)
{
  struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  task_sleep(task);
  memman_free_4k(memman, task->cons_stack, 64 * 1024);
  memman_free_4k(memman, (int) task->fifo.buf, 128 * 4);
  task->flags = 0; 
  return;
}

void close_console(struct SHEET *sht)
{
  struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  struct TASK *task = sht->task;
  memman_free_4k(memman, (int) sht->buf, 256 * 165);
  sheet_free(sht);
  close_constask(task);
  return;
}

接下来我们在命令行窗口中增加exit命令,如果运行这个命令那么命令行窗口就会关闭。

else if (strcmp(cmdline, "exit") == 0) {
  cmd_exit(cons, fat);
}

当用户在命令行窗口中输入exit字符串的时候,操作系统执行cmd_exit函数。

void cmd_exit(struct CONSOLE *cons, int *fat)
{
  struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  struct TASK *task = task_now();
  struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);
  struct FIFO32 *fifo = (struct FIFO32 *) *((int *) 0x0fec);
  timer_cancel(cons->timer);
  memman_free_4k(memman, (int) fat, 4 * 2880);
  io_cli();
  fifo32_put(fifo, cons->sht - shtctl->sheets0 + 768);  /* 768�~1023 */
  io_sti();
  for (;;) {
    task_sleep(task);
  }
}

我们首先取消了光标定时器,然后将FAT用的内存空间释放,然后我们向task_a任务发送消息,消息数据为图层号 + 768。

else if (768 <= i && i <= 1023) {   /*命令行窗口关闭处理� */
  close_console(shtctl->sheets0 + (i - 768));
}

task_a任务中的 i - 768 表示图层号。图层号的值加上shtctl->sheets0就是命令行窗口所对应的图层。

既然已经实现了用exit命令关闭命令行窗口那么我们也可以实现用鼠标点击关闭按钮关闭命令行窗口了。就像之前的关闭应用程序一样。回想起来,之前我们实现关闭应用程序窗口时候做了个判断。

else {  /* 命令行窗口 */
  task = sht->task;
  io_cli();
  fifo32_put(&task->fifo, 4);
  io_sti();
}

如果点击关闭按钮那么我们向命令行窗口发送4这个数据,命令行窗口接收到4就调用cmd_exit函数,那么接下来就和之关闭的流程一样了。

这一章中再实现2个命令start 和ncst。start命令表示打开一个新的命令行窗口然后再在新的命令行窗口中运行start 后面跟着的应用程序。ncst命令不显示命令行窗口,但是运行一个新的应用程序。

start命令相对比较简单

else if(strncmp(cmdline, "start ", 6) == 0){
  cmd_start(cons, cmdline, memtotal);
}

void cmd_start(struct CONSOLE * cons, char  *cmdline, int memtotal){
  struct SHTCTL *shtctl = (struct SHTCTL*) *((int *)0xofe4);
  struct SHEET *sht = open_console(shtctl, memtotal);
  struct FIFO32 *fifo = &sht->task->fif0;
  int i;
  sheet_slide(sht, 32, 4);
  sheet_updown(sht, shtctl->top);
  for(i = 6; cmdline[i] != 0; i++){
    fifo32_put(fifo, cmdline[i] + 256);
  }
  fifo32_put(fifo, 10 + 256);
  cons_newline(cons);
  return;
}

ncst命令比较难。基本思路是:我们新建一个命令行的任务,但是不在屏幕上显示窗口。运行命令行的任务之后马上运行ncst命令之后跟着的应用程序。

首先添加这个命令:

else if(strncmp(cmdline, "ncst ", 5) == 0){
  cmd_ncst(cons, cmdline, memtotal);
}

接下来实现cmd_ncst函数:

void cmd_ncst(struct CONSOLE *cons, char *cmdline, int memtotal){
  struct TASK *task = open_constask(0, memtotal);
  struct FIFO32 *fifo = &task->fifo;
  int i;
  for(i = 5; cmdline[i] != 0; i++){
    fifo32_put(fifo, cmdline[i] + 256);
  }
  fifo32_put(fifo, 10+256);
  cons_newline(cons);
  return;
}

由于现在出现了不同的情况,所有的cons对应用函数都应该判断这个命令行是否有窗口,如果没有窗口,那么cons->sht应该为0。还要修改console_task函数,也就是命令行的主程序。如果没有窗口也就不需要设置光标闪烁的定时器了。cmd_exit函数也要修改,如果没有窗口关闭命令行的时候应该向task_a任务发送1024 + 任务号的消息。接下来实现open_constask函数。实际上之前的open_console已经实现了打开命令行的所有需要做的操作,我们现在把这个函数中创建任务的部分抽离出来。

struct TASK* open_constask(struct *sht, unsigned int memtotal){
  struct MEMMAN *memman = (struct MEMMAN*) MEMMAN_ADDR;
  struct TASK *task = task_alloc();
  int *cons_fifo = (int *)memman_alloc_4k(memman, 128 * 4);
  task->cons_stack = memman_alloc_4l(memman, 64 * 1024);
  task->tss.esp = task->cons_stack + 64 * 1024 - 12;
  task->tss.eip = (int) &console_task;
  task->tss.es = 1 * 8;
  task->tss.cs = 2 * 8;
  task->tss.ss = 1 * 8;
  task->tss.ds = 1 * 8;
  task->tss.fs = 1 * 8;
  task->tss.gs = 1 * 8;
  *((int *)(task->tss.esp + 4)) = (int)sht; 
  *((int *)(task->tss.esp + 4)) = memtotal;
  task_run(task, 2, 2);
  fifo32_init(&task->fifo, 128, cons_fifo, task);
}


struct SHEET *open_console(struct SHTCTL *shtctl, unsigned int memtotal)
{
  struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
  struct SHEET *sht = sheet_alloc(shtctl);
  unsigned char *buf = (unsigned char *) memman_alloc_4k(memman, 256 * 165);
  sheet_setbuf(sht, buf, 256, 165, -1); 
  make_window8(buf, 256, 165, "console", 0);
  make_textbox8(sht, 8, 28, 240, 128, COL8_000000);
  sht->task = open_constask(sht, memtotal);
  sht->flags |= 0x20;   
  return sht;
}

最后修改task_a任务中关于消息处理的部分。

else if (768 <= i && i <= 1023) {   /* 命令行窗口关闭处理 */
  close_console(shtctl->sheets0 + (i - 768));
} else if (1024 <= i && i <= 2023) {
  close_constask(taskctl->tasks0 + (i - 1024));
}

但是运行之后就发现了BUG,因为ncst命令运行之后打开了一个新的命令行任务,但是应用窗口运行完之后这个任务就关闭了。所以点击应用程序窗口的关闭按钮没有任何反应。因为命行任务已经关闭了。估计下一节就是处理这个问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • 第24天 我们已经可以让应用程序显示窗口了,如果一个应用程序显示了N个窗口,我们也应该让各个窗口可以现切换。实现鼠...
    whatcanhumando阅读 733评论 0 5
  • 第23天 操作系统的可执行文件中0x0000存放数据段的大小,0x0020位置存放malloc空间的起始地址这两个...
    whatcanhumando阅读 961评论 7 11
  • 第27天 前一天讲到为什么用ncst命令之后应用程序就无法关闭了。现在看一下程序ncst到底干了什么事情。如果在命...
    whatcanhumando阅读 1,450评论 1 5
  • 第25天 这本书的这一章一开始就讲如果控制主板上的蜂鸣发专声器发声,看到这个我很兴奋。因为到目前为止我还没有用wi...
    whatcanhumando阅读 654评论 0 0
  • 早上醒来漱口的时候我总喜欢照照镜子,看着镜子中的自己陌生又熟悉。这张脸伴随我大半生,但依旧觉得忽近忽远,不能看得很...
    楚浛阅读 1,103评论 5 5