MacOS环境-手写操作系统-25-实现定时器

简介: MacOS环境-手写操作系统-25-实现定时器

实现定时器

1.简介

当指定的时间过去后 系统会触发你给定的回调函数


Timer功能实在是太重要了 如果没有定时器 操作系统很多任务都做不了


至少你编程画个时钟 搞个闹钟程序什么的 你就没法实现


从这节开始 我们看看timer功能是怎么实现的


2.代码

主控制器的IRQ0对应的就是时钟中断


只要我们做好相关配置 那么在指定间隔内 IRQ0导线就会像CPU发送中断信号


首先我们代码要做的是初始化8259A时 打开这一中断功能


在内核实现的汇编部分做如下修改(kernel.asm)


init8259A:
....
mov  al, 11111000b ;允许键盘和时钟中断
     out  021h, al
     call io_delay
....

注意看 三个0表示打开主8259A的IRQ0 IRQ1 IRQ2三根信号线


IRQ0对应的就是时钟中断 打开IRQ0后 当中断信号发送到CPU时


我们需要CPU调用我们提供的中断程序 因此还需做以下修改


LABEL_IDT:
%rep  32
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep

;响应时钟中断的中断描述符
.020h:
    Gate SelectorCode32, timerHandler,0, DA_386IGate

.021h:
    Gate SelectorCode32, KeyBoardHandler,0, DA_386IGate

%rep  10
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep

.2CH:
    Gate SelectorCode32, mouseHandler,0, DA_386IGate

我们在中断向量表中 增加了一个用于调用时钟中断的描述符 该描述符对应的中断调用 名字叫timerHandler

我们继续看timerHandler的实现

_timerHandler:
timerHandler equ _timerHandler - $$
     push es
     push ds
     pushad
     mov  eax, esp
     push eax
     
     call intHandlerForTimer
     
     pop  eax
     mov  esp, eax
     popad
     pop  ds
     pop  es
     iretd

这段代码的实现跟以前的中断处理方法一样 先把寄存器压到堆栈上保存起来


然后调用C语言实现的中断处理函数intHandlerForTimer


在查看C语言对intHandlerForTimer的实现之前 我们需要搞清楚的是


如何配置时钟中断 使其在一秒内发生几次中断合适?


我们这里暂定1秒内产生100次中断 这种中断频率足以满足我们系统开发需求


于是我们需要做相应配置 配置的方法是 像8259A芯片的对应端口发送指定数据


首先需要向端口0x43发送一个数值0x34 紧接着向端口0x40发送两个数据0x9c,0x2d


这样时钟中断就能在1秒内发生100次了


配置代码如下(Timer.h)

#define PIT_CTRL   0x0043
#define PIT_CNT0   0x0040


void init_pit(void);

struct TIMERCTL {
    unsigned int count;
    unsigned int timeout;
    struct FIFO8 *fifo;
    unsigned char data;
};

struct TIMERCTL* getTimerController();

void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data);

init_pit(void) 就是用来实现时钟中断配置的


它的作用是向指定端口发送指定数据 TIMERCTL 数据结构叫时钟管理器


其中的count用来记录时钟中断发送了多少次


timeout用来计时 一旦timeout为0


管理器将触发指定动作 其他的数据在后面我们会详细解释


时钟中断的初始化实现


void  init_pit(void) {
    io_out8(PIT_CTRL, 0x34);
    io_out8(PIT_CNT0, 0x9c);
    io_out8(PIT_CNT0, 0x2e);
    timerctl.count = 0;
    timerctl.timeout = 0;
}


初始化就如同前面我们所说的 向指定端口发送一些指定数据而已


设置好中断机制后 我们可以实现超时功能 也就是通过时钟管理器设置一个时间片


一旦时间片结束后 让时钟管理器触发我们提供的一个函数


这个时间片的大小对应的就是TIMECTRL结构体里面的timeout


C语言模块是怎么响应中断信号的


void intHandlerForTimer(char *esp) {
    io_out8(PIC0_OCW2, 0x60);
    timerctl.count++;
    if (timerctl.timeout > 0) {
        timerctl.timeout--;
        if (timerctl.timeout == 0) {
            fifo8_put(timerctl.fifo, timerctl.data);
        }
    }
    return;
}


每次响应中断信号时 先向8259A发送一个命令 命令的数值是0x60


要求8259A下次继续发送中断信号 如果不这么做 下次芯片就不给我们发送信号了


然后把时钟管理器的count计数加一 对应中断响应的次数


每次中断发送 我们都把时间片对应的数值减一


如果时间片减少到0 表明超时 此时向时钟管理器附带的FIFO队列写入一个数据


FIFO队列我们在实现鼠标响应的章节介绍过


这个队列的作用主要用来通知内核 超时发生了在内核的主循环里面会不停的监控时钟管理器这个队列是否为空


如果是空 那么内核就认为没有超时事件发生


如果队列里面有数据 那表明超时事件发生了


怎么设定超时对应的时间片呢?


我们在时钟管理器的实现中 增加一个settimer函数


void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data) {
    int eflags;
    eflags = io_load_eflags();
    io_cli();//暂时停止接收中断信号
    timerctl.timeout = timeout;//设定时间片
    timerctl.fifo = fifo;//设定数据队列,内核在主循环中将监控这个队列
    timerctl.data = data;
    io_store_eflags(eflags);//恢复接收中断信号
    return;
}
struct TIMERCTL* getTimerController() {
    return &timerctl;
}


io_load_eflags() 和 io_store_eflags() 这两个函数我们以前提到过


CPU会根据一系列状态信息来调整自己的运行状况


例如当前中断功能是否打开 是否有计算溢出等等


这些状态信息都存储在指定寄存器的指定比特位中(CPU上的相关硬件)


io_load_eflags() 就是获取这些信息 把他们存储到变量eflags中


io_store_eflags(eflags) 是把前面存储的状态信息重新设置回去


io_cli()的作用是让CPU停止接收一切中断信号 也就是设置对应的比特位让CPU运行时忽略到来的中断请求


io_store_eflags作用就是重新恢复原来状态 让CPU重新接收中断信号


内核主循环的处理


....
static struct FIFO8 timerinfo;
static char timerbuf[8];
....
void CMain(void) {
    ....
    init_pit();
    fifo8_init(&timerinfo, 8, timerbuf);
    settimer(500, &timerinfo, 1);
    ....
}


内核启动时 初始化时钟控制器 并初始化一个FIFO队列和用于该队列的缓冲区


通过settimer函数 设置一个5秒的超时时间片 数值1对应TIMERCTL结构体里面的data

void CMain(void) {
    ....
    int data = 0;
    int count = 0;
    struct TIMERCTL *timerctl = getTimerController();

    for(;;) {
       char* pStr = intToHexStr(timerctl->timeout);
       boxfill8(shtMsgBox->buf, 160, COL8_C6C6C6, 40, 28, 119, 43);
       showString(shtctl, shtMsgBox, 40, 28, COL8_000000,pStr);

       io_cli();
       if (fifo8_status(&keyinfo) + fifo8_status(&mouseinfo) +
 fifo8_status(&timerinfo)  == 0) {

           io_sti();
       } ....

      else {
      //超时发生后进入这里
           io_sti();
           showString(shtctl, sht_back, 0, 0, COL8_FFFFFF, "5[sec]");
      }
}

在进入内核主循环前 先获取时钟控制器


然后把控制器对应的时间片信息转换成字符串后 显示到Message Box 窗体里


每次循环时 看看控制器对应的数据队列里面是否有数据


如果有数据表明超时发送 于是进入最后的else 部分 在else 里面


我们在桌面的左上角打印出一个字符串”5[sec]”。


3.运行

目录
打赏
0
0
0
0
103
分享
相关文章
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
60 10
【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
132 3
|
5月前
|
MacOS环境-手写操作系统-46,47-C语言开发应用程序
MacOS环境-手写操作系统-46,47-C语言开发应用程序
70 1
MacOS环境-手写操作系统-48-让内核从错误中恢复
MacOS环境-手写操作系统-48-让内核从错误中恢复
77 0
MacOS环境-手写操作系统-45-C语言开发应用程序
MacOS环境-手写操作系统-45-C语言开发应用程序
87 0
MacOS环境-手写操作系统-44-运行简单的程序
MacOS环境-手写操作系统-44-运行简单的程序
55 0
OS Copilot-操作系统智能助手-Linux新手小白的福音
OS Copilot 是阿里云推出的一款操作系统智能助手,专为Linux新手设计,支持自然语言问答、辅助命令执行和系统运维调优等功能。通过简单的命令行操作,用户可以快速获取所需信息并执行任务,极大提升了Linux系统的使用效率。安装步骤简单,只需在阿里云服务器上运行几条命令即可完成部署。使用过程中,OS Copilot不仅能帮助查找命令,还能处理文件和复杂场景,显著节省了查找资料的时间。体验中发现,部分输出格式和偶尔出现的英文提示有待优化,但整体非常实用,特别适合Linux初学者。
168 10
OS Copilot-操作系统智能助手-Linux新手小白的福音
OS Copilot是由阿里云推出的操作系统智能助手,专为Linux新手设计,支持自然语言问答、辅助命令执行等功能,极大提升了Linux系统的使用效率。用户只需通过简单的命令或自然语言描述问题,OS Copilot即可快速提供解决方案并执行相应操作。例如,查询磁盘使用量等常见任务变得轻松快捷。此外,它还支持从文件读取复杂任务定义,进一步简化了操作流程。虽然在某些模式下可能存在小问题,但总体上大大节省了学习和操作时间,提高了工作效率。
156 2
OS Copilot-操作系统智能助手-Linux新手小白的福音
os-copilot在Alibaba Cloud Linux镜像下的安装与功能测试
我顺利使用了OS Copilot的 -t -f 功能,我的疑惑是在换行的时候就直接进行提问了,每次只能写一个问题,没法连续换行更有逻辑的输入问题。 我认为 -t 管道 功能有用 ,能解决环境问题的连续性操作。 我认为 -f 管道 功能有用 ,可以单独创建可连续性提问的task问题。 我认为 | 对文件直接理解在新的服务器理解有很大的帮助。 此外,我还有建议 可以在非 co 的环境下也能进行连续性的提问。
93 7

热门文章

最新文章