- 论坛徽章:
- 0
|
最近断断续续写了一些OS内核的代码,昨天终于调通了,Semaphore, Mutex 已经可以用了,下一步的计划是在此OS上实现Event机制,继续维护,以此OS为基础做一些硬件实验。内核机制很简单,所有的API都是以系统调用的方式来实现的,这样做的好处是不必支持内核下的中断服务,因为使用SWI中断后,ARM的CPSR状态字为0x93,也就是SVC模式且禁止IRQ中断,因此FIQ目前也是不支持的。当然,当前内核的效率也不是很高,不过就目前来看,这样的内核用来处理通用任务已经足够了,比如实现GUI框架,支持SD卡,实现TCP/IP stack都是可以的,虽说可能慢点。
如果要实现抢占式内核,普遍的做法是内核API也在用户模式下运行,且内核状态下允许IRQ/FIQ中断,只有在必要的时候才临时禁止;而Critical Section的实现也是用ARM的SWP指令完成;为了在用户态下实现快速用户切换,TCB的数据一般保存在当前任务的stack的最顶层,这样的好处一个轮回就能保存所有的寄存器(R0-R16);只是目前还没有太多的精力去实现抢占式内核,不过当前OS内核的大部分代码是可以重用的。
当前实现的OS调度原则比较简单,采用优先级制,优先级的数字越小,其优先级越高;理论上说相同优先级的任务具被平等的调度,这个在VC上的模拟数据已经证明了。调度算法描述如下:
定义:
next_tick := 任务的下一次运行时刻。
curr_tick := 当前系统时刻。
每当任务需要被调度出去时,计算它下一次运行的时刻:
next_tick = curr_tick + ( prio
其中PRIO_SHIFT 为优先级缩放系数,或者以后也可以采用查表法来定义各个优先级下的调度系数。
而任务调度模块需要维护3个任务队列:
第一个为READY队列,也即所有即将被调度的任务按下一次运行时刻排序。
第二个为SLEEP队列,也即SLEEPING任务的队列,也是按照下一次运行时刻排序,每当TICK中断发生后,内核的时钟服务程序就会在SLEEP队列中需要被WAKE UP的任务,按优先级放入READY队列(这里可能产生一个现象,即优先级低的任务在WAKEUP的时候抢占优先级高的任务,目前来说没有改善的计划)。没当一个任务请求SLEEP的时候,就讲它从READY队列切换到SLEEP队列,并计算其下一次运行时刻。
第三个为SUSPEND队列,在此队列中的任务将一直睡眠,除非它被唤醒,比如Semaphore,Mutex,Event事件,或者直接被KILL掉。
每个任务都有一个HOOK函数,可以随时启用。当任务的状态发生改变时,该HOOK函数就被调用,用来通知其监听者。比如,有一个TASK在Waiting一个信号量,Waiting事件为3 TICKs,那么该信号量首先会将该Task切换到SLEEP状态,然后设置HOOK函数,当该Task被WakeUp的时候,该HOOK函数就会将该Task的描述符从其Semaphore的Waiting Queue中删除掉,以保证其Context的正确性。
另外,当前内核的内存使用完全是静态的,也就是说,任务数量,Semaphore数量等等这些内核对象全都是预先分配好的,可以通过kcfg.h文件进行配置。另外,由于Semaphore,Mutex等其他模块有时也需要保存Task Context的指针,为了简化这些模块对Task的引用,再考虑到Task总数不变,所以为每个Task定义了2条Chain。第一条为调度Chain,包括前面提到的READY,SLEEP,SUSPEND队列,因为这3个队列是互斥的;另一条为引用Chain,除了调度模块以外,所有其他模块在保存Task指针的时候,都使用Reference Chain,因为Semaphore,Mutex,Event这些模块只有在阻塞Task的时候才需要保存其引用指针,而一个Task同时只能被一个Semaphore,Mutex,Event或者是其它类型的对象所阻塞。因此,只需要为每个Task定义2条Chain,并且严格遵守使用规则,就可以由实现静态分配的Task指针来实现Semaphore,Mutex,Event的等待队列了。
内核代码如下:
![]()
文件:
my_os.rar
大小:
59KB
下载:
下载
VC测试程序如下:
![]()
文件:
os_test.rar
大小:
164KB
下载:
下载
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/94507/showart_1985548.html |
|