一个操作系统的实现(2)

接上文:http://www.cnblogs.com/SuperXJ/archive/2010/12/02/1894639.html

                                                                                                                                     xiongjian

                                                                                                                           2010.12.22  msn:cug@live.cn

 

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,分别为内存管理进程和文件系统进程,下面看看一个微内核是如何实现进程创建的。

²       1 用户调用fork函数

²       2 fork调用sys_call(MM, FORK);  //表示消息要发给MM进程,消息内容为FORK,内部通过send_recv实现,即先发送在接收消息

²       3 send_recv内部使用int触发IDT中的一个中断,假设中断处理函数为s_call(ring0)

²       4 s_call内部会将消息从寄存器中取出,并向MM进程发送消息(msg_send() ).

²       5  msg_send(sender, dest, msg) //发送者/接收者/要发送的消息体   ××发送消息××

       {

                 检查发送者和接收者不能相等

                     检查是否会发生死锁,例如A->B->A  即A和B在同时相互发送消息,AB进程都会堵死在发送程序处。

                     If(接收者是处理RECEIVE状态)

                     {

                            在线性地址(物理地址)层面将要发送的消息复制到接收者的缓存中(虚拟地址-)线性地址)。因为发送者的消息是存放在物理地址里面的,所以必须要找到消息的物理位置才能将消息复制到接收者进程。

                     }     

                     Else 发送者处于SEND状态,并等待一直到接收者处于RECEIVE为止,通过调用进程调度进程实现。

         }

²       6 通过msg_send的调用,在物理地址层面,消息就被复制到了接收进程中(消息可以保持在接收进程的进程表项中)。下面看看接受进程:接收进程调用msg_recv来阻塞的接收消息

msg_recv(接收者,发送者,接收消息的指针m)

{

       If(接收者有来自硬件的消息)

       If(接收者队列里有消息) 将接收到的消息复制到m里。

       Else (没有消息) 阻塞

}

²       7 到目前为止,进程可以实现发送和接收消息了。实现的根本原理还是通过物理地址的消息复制。 现在的进程有了以下状态:发送(消息)状态,接收(消息)状态,运行状态,休眠状态。 其中 发送/接收/休眠状态都不会获得CPU运行机会。

 

,同时MM进程会不停的查询,如果有消息,则调用do_fork真正创建进程。

 

从这一系列流程可以看出,微内核仅仅给上层发送和接收消息2个接口,而不关心具体实现。具体的实现是他们通过参数传给具体的ring1进程(例如FS,MM……)来实现。

 

以上就是微内核的思想,同时也是一个简单同步IPC思想

 

 

未完待续(文件系统+内存管理)

上一篇:软件测试用例设计生命周期


下一篇:项目管理修炼之道札记:创造出色团队