代码改变世界

操作系统是如何工作的

2016-03-03 14:56  20135128  阅读(359)  评论(0编辑  收藏  举报

关于操作系统是如何工作的----一个简单的时间片轮转多道程序内核代码

符钰婧

原创作品转载请注明出处 

Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

 

本次实验是通过分析一个简单的时间片轮转多道程序内核源代码来理解操作系统的工作原理。

先使用实验楼的虚拟机打开shell

 

 然后cd mykernel 找到mymain.cmyinterrupt.c两个源代码。

 

 

 

进入https://github.com/mengning/mykernel/blob/master可以找到本次实验需要的几个重要的源代码。然后将上面两个代码修改成网站中找到的代码,除此之外还要加上mypcb.c

 

 

 

返回之后再次运行,可看到0123几个进程相互切换。

 

 

下面将对这三个源代码进行详细的分析。

首先是mypcb.c代码:

 

这个代码的目的是定义一个进程控制块。先定义了一个Thread来存储ipsp,也就是用于eipesp的保存。PCB中定义了进程管理相关的数据结构。最后的函数my_schedule表示的是调度器。

 

接下来是mymain.c代码:

 

先是include mypcb。声明了一个数组task,然后声明了当前task的一个指针,第20行处定义了一个标志,用来判断是否需要调度。然后定义了一个函数my_process

 

my_start_kernel函数中先初始化一个进程0,第32行为定义进程0的入口为my_process,因为一开始系统里只有进程0,所以第34行代码表示的是pidnext还是指向自己。接下来就创建更多其他的进程,在初始化这些进程的时候可以直接把0号进程的代码拷贝过来,第41行表示每个进程都有自己的堆栈,然后把创建好的新进程放到进程列表的尾部,这样就完成了创建。

创建好了之后就可以开始执行0号进程,第48行处到之后的几行代码表示的是一段嵌入式汇编代码。其中的%0表示的是参数thread.ip%1表示的是参数thread.sp。第49行表示的就是把参数thread.sp放到esp中;接下来push %1,又因为当前栈为空,esp=ebp,所以等价于push ebp;然后push thread.ipret等价于pop thread.ip;最后pop ebp

ret之后0号进程就正式启动了。

 

 

函数my_process定义所有进程的工作。这个函数里面定义了一个循环,if语句表示循环1000万次才有机会判断是否需要调度。这是一个主动调度的机制。

最后是myinterrupt.c的代码:

 

 

也是先include mypcb,然后定义了一些全局参数。

 

接着是一个函数my_timer_handler,用于设置时间片的大小,时间片用完时设置一下调度标志。当时钟中断发生1000次,并且my_need_sched!=1时,把my_need_sched赋为1。因为当进程发现my_need_sched=1时,就会执行my_schedule

 

If语句表示task为空,即发生错误时返回。第52行开始介绍my_scheduel的工作,先把当前进程的下一个进程赋给next,当前进程为prev

54行表示如果下一个进程的状态是正在执行的话,就运用if语句中的代码表示的方法来切换进程,这些代码为嵌入式汇编代码,与mymain.c代码中的相似。

%0表示prev->thread.sp%1表示prev->thread.ip%2表示next->thread.sp%3表示next->thread.ippush ebp为保存当前进程的ebp;然后保存当前进程的esp;把下一个进程的sp放到esp中;接下来保存eip$1表示后面的标号1:的位置;然后把下一个进程的eip push到栈里面。

ret之后下一个进程就开始执行了。这是进程切换的关键代码。

 

 

与上一段代码不同的是如果下一个进程为新进程时,就运用else中的这一段代码。首先将这个进程置为运行时状态,将这个进程作为当前正在执行的进程。 

总结:操作系统的“两把剑”:中断上下文和进程上下文的切换。其中中断上下文也就是保存现场和恢复现场。所以操作系统就是通过不同进程的不断切换来完成工作的。