2013年(32)
分类: LINUX
2013-11-20 09:43:48
原文地址:一个操作系统的实现(2) 作者:sun5411
10 下面开始进程,首先引入几个基本原则:
1)进程表A用来保存进程A的信息和进程A切换时,保存当前A运行时寄存器信息。定义为: PROCESSproc_table[1024]; 表示系统最多可以有1024个进程,PROCESS里面就保存了本进程运行时的各个寄存器信息(这样可以在进程切换回来的时候返回寄存器信息),该进程对应的LDT描述符(一般指向代码段和数据段),最后还有一个指向GDT中该进程位置的描述符。
实现一个最简单的进程切换系统,需要下面3个子模块:
时钟中断处理程序/进程调度模块/至少1个主进程和2个子进程
一个进程(ring1)的最小需要的元素为进程执行体,堆栈大小和位置。另外需要GDT中有一个选择符指向一个该进程的LDT。在时钟中断发生时,时钟中断处理函数(ring0)将esp指向将要运行的进程在进程表中的位置。
当做到这里,系统应该可以定时触发时间中断处理函数,时间中断处理函数会轮流的调用进程A和B了。(这也是个ring0到ring1直接相互切换的过程)
到此为止,操作系统的启动可以高于段落。
其他需要注意的是:系统调用
系统调用的简单实现就是进程(ring1)将参数例如:num,保存在寄存器中,然后自己产生一个中断,例如int 100h.表示软件发生100H号中断(假设中断处理函数为sys_call)。
I/O system(注意以下都是微内核形态)
IO首先第一个想到的就是键盘,其实键盘驱动非常简单,只要注意以下几个方面即可:
1 建立键盘中断处理函数
2 打开8259a的键盘中断
3 解析中断发生时的数据以确定用户按下的具体按键
4 键盘有一个缓冲区,用于保存用户按键信息,驱动需要及时的吧这个缓冲区的数据读取出来,如果不是一个完整数据,需要做临时缓存。
系统有一个固定的显存内存位置,显示的最基本原理就是N个字节里面保存字符和颜色信息,最常见的是的565色。Linux的多终端机制的一般规则为多个终端对应一个屏幕,用户在使用一个屏幕的时候,可以随时切换到其他屏幕而好像是切换了用户一样。实现这样机制的一个进程叫做TTY进程,他作为第一个微内核以为的系统进程而存在,已区别于一般的用户进程。下面就来看看他的大概实现思路:
Tty_task()
{
Init_keyboard();
For(循环3次) init_tty(i);
While(1)
{
//依次遍历每一个tty
For(I= 0; i<3 ; i++)
{
Tty_read(i);//如果当前活跃的tty是我,则从键盘驱动中读取键盘缓存
In_process(i,key); //将读出的缓存存放到当前tty的缓存中,另外处理alt+Fn的切换控制台命令(即Fn)
Tty_write(i);
}
}
}
微内核有MM和FS,分别为内存管理进程和文件系统进程,下面看看一个微内核是如何实现进程创建的。
2 1 用户调用fork函数
2 2 fork调用sys_call(MM, FORK); //表示消息要发给MM进程,消息内容为FORK,内部通过send_recv实现,即先发送在接收消息
2 3 send_recv内部使用int触发IDT中的一个中断,假设中断处理函数为s_call(ring0)
2 4 s_call内部会将消息从寄存器中取出,并向MM进程发送消息(msg_send() ).
2 5 msg_send(sender, dest, msg) //发送者/接收者/要发送的消息体 ××发送消息××
{
检查发送者和接收者不能相等
检查是否会发生死锁,例如A->B->A 即A和B在同时相互发送消息,AB进程都会堵死在发送程序处。
If(接收者是处理RECEIVE状态)
{
在线性地址(物理地址)层面将要发送的消息复制到接收者的缓存中(虚拟地址-)线性地址)。因为发送者的消息是存放在物理地址里面的,所以必须要找到消息的物理位置才能将消息复制到接收者进程。
}
Else 发送者处于SEND状态,并等待一直到接收者处于RECEIVE为止,通过调用进程调度进程实现。
}
2 6 通过msg_send的调用,在物理地址层面,消息就被复制到了接收进程中(消息可以保持在接收进程的进程表项中)。下面看看接受进程:接收进程调用msg_recv来阻塞的接收消息
msg_recv(接收者,发送者,接收消息的指针m)
{
If(接收者有来自硬件的消息)
If(接收者队列里有消息) 将接收到的消息复制到m里。
Else (没有消息) 阻塞
}
2 7 到目前为止,进程可以实现发送和接收消息了。实现的根本原理还是通过物理地址的消息复制。 现在的进程有了以下状态:发送(消息)状态,接收(消息)状态,运行状态,休眠状态。 其中 发送/接收/休眠状态都不会获得CPU运行机会。
,同时MM进程会不停的查询,如果有消息,则调用do_fork真正创建进程。
从这一系列流程可以看出,微内核仅仅给上层发送和接收消息2个接口,而不关心具体实现。具体的实现是他们通过参数传给具体的ring1进程(例如FS,MM……)来实现。
以上就是微内核的思想,同时也是一个简单同步IPC思想。