SmlOS十-系统时钟控制

  • 内容
  • 评论
  • 相关

简介

系统时钟控制也是现代操作系统中,必不可少的功能了。

比如说操作系统的Sleep实现,应用层Timer实现,时钟功能,数据包超时重传等功能,全部都是依赖于系统时钟控制。

那么,操作系统是如何知道时间过了1s钟呢?

这一切都要依赖于一个器件: PIT


PIT简介

PIT (Programmable Interval Timer) 可编程间隔定时器

简要来说就是根据设定,每隔固定周期向cpu发一个中断

比如说:我设定PIT的频率 1/100 秒,也就是说PIT一秒会产生100次时钟中断。

如果我需要知道时间是否过了1s,那么我只要每次发生时钟中断就累加一次,当累加到100的时候就是1s了。


PIT初始化

 io_out8(PIT_CTRL, 0x34);
 io_out8(PIT_CNT0, 0x9c);
 io_out8(PIT_CNT0, 0x2e);

数值的设置需要阅读相关硬件手册。

这里时钟设定中断的频率是每秒执行100次。

初始化完PIT后,就可以收到相关中断了。

时钟中断处理函数,我们之前已经注册,最终跳转到 c实现的inthandler20函数中。


超时管理原理

假如说应用层有非常多的时钟需求,比如有等1s,有等10秒的,
有等100s的,那么系统该如何支持呢?

那么怎么做呢?

首先,每个超时的需求我称之为一个定时器。

系统会维护一个变量,暂时称之为累计时间(count)把,就是每次时钟中断都会自增一,按照现在设定也就是一秒增加100次

假如说有这样的一个情况:

  • 1.在count = 0时, 应用层需要一个定时器5s后通知他

  • 2.到了count = 100时, 应用层需要一个定时器2s后通知

  • 3.到了count = 200时, 应用层需要一个定时器4s后通知

那我要怎么做呢?

有人可能会说,我挨个判断呗,在每次中断时候我都判断下,哪个定时器有没有超时。

如果这样的话,在定时器很多的情况下,系统效率会非常慢。

而且判断操作时放在中断函数里面的,中断函数如果放入很多占时间的操作,那么会可能影响其他中断的产生,所以中断函数需要尽量简短。

所以我们用了一种办法:判断最近超时的定时器

以上面的问题为例子

第一次分配(count = 0,分配5s):

定时器序号 超时时间
1 500 (在count = 500的时候通知)

第二次分配(count = 100,分配2s):

定时器序号 超时时间
2 300
1 500 (在count = 500的时候通知)

第二次分配(count = 200,分配4s):

定时器序号 超时时间
2 300
1 500 (在count = 500的时候通知)
3 600

注意观察:我们在每次分配的时候,都计算出该定时器的预期的超时时间。

且对超时时间进行了排序。

那么我在中断函数中,只要判断最近即将超时的定时器,只需要判断一次,大大增加了效率。


实现

这里介绍两个重要的时钟管理结构体:

struct TIMERCTL
{
 unsigned int count, next, using;
 struct TIMER *timers[MAX_TIMER];
 struct TIMER timers0[MAX_TIMER];
};

count: 累计计数器

next: 下一个超时时间

using: 当前活动的定时器数量

timers: 定时器结构指针数组

(TIMER指针有序数组,排序的时候只移动指针,增加效率)

timers0 定时器结构数组

以及单个时钟结构体:

struct TIMER
{
 unsigned int timeout, flags;
 struct FIFO8 *fifo;
 unsigned char data;
};

timeout: 相对于当前时间的预定时刻

flags: 记录定时器状态

fifo: 定时器队列指针

data: 定时器数据

首先时钟管理表中count成员在每次中断执行后都会自加一,而next是记录下一个即将超时的时钟。

同之前的相关管理表,timers是用来排序的指针数组,而timers0用来分配需要管理的超时时钟。

这里最大时钟数量被指定为500个。

而在单个时钟结构结构体中,timeout是在执行超时设置的操作后,加上count的时间,可以理解为超时时刻。

在时钟中断中一旦发现有时钟超时,那么就向时钟指定的FIFO队列里,写入由data指定的数据,也就是通知该线程。

需要注意的时,每次分配定时器(TIMER)的时候,然后在timers的指针数组中按照timeout的大小进行排序。

相关算法是是进行移位算法,因为是指针的移动,所以移动的总量并非很大。