操作系统是如何工作的————一个精简的操作系统内核
作者:20135304 刘世鹏
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
实验过程
使用实验楼虚拟机打开shell,加载实验所需linux内核,执行搭建好的系统
cd LinuxKernel/linux-3.9.4 qemu -kernel arch/x86/boot/bzImage
一直在执行mystartkernel,交替执行mytimerhandler
查看mymain.c代码
voidinit mystartkernel(void)从这开始是操作系统的入口 每循环10万次打印一个mystartkernel
查看myinterrupt.c代码
每次时钟中断调用printk打印一个mytimerhandler,是在中断实际发生时做的一些中断处理。
至此模拟硬件平台的工作,包括初始化动作就已完成
在https://github.com/mengning/mykernel中可以找到实验所需多进程时间片轮转代码
运行后可观察到在0、1、2、3进程中切换
代码分析
打开mypcb.h
thread用来保存eip和esp,在pcb里,int pid 定义了进程ID;volatile long state定义了进程状态;char stack[KERNEL_STACK_SIZE]定义了内核堆栈。my_schedule表示调度器,task_entry为入口
打开mymain.c
mymain.c告诉我们如何初始化,并对初始化0号进程进行了描述
这段代码目的在于创建多个进程
创建后启动0号进程,此处为一段嵌入式汇编代码,其中的%0表示的是参数thread.ip,%1表示的是参数thread.sp。第49行表示的就是把参数thread.sp放到esp中;接下来push %1,又因为当前栈为空,esp=ebp,所以等价于push ebp;然后push thread.ip;ret等价于pop thread.ip;最后pop ebp。
ret之后0号进程就正式启动了
函数my_process定义所有进程的工作。这个函数里面定义了一个循环,if语句表示循环1000万次才有机会判断是否需要调度。这是一个主动调度的机制。
打开myinterrupt.c
next = my_current_task->next;//当前进程的下一个进程赋给next
prev = my_current_task;//当前进程
if(next->state == 0)如果下一个进程状态是0(正在执行)
/* switch to next process *///(进程上下文切换),此处是一个嵌入式汇编代码,
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.ip。push ebp为保存当前进程的ebp;然后保存当前进程的esp;把下一个进程的sp放到esp中;接下来保存eip,$1表示后面的标号1:的位置;然后把下一个进程的eip push到栈里面。
ret之后下一个进程就开始执行了。这是进程切换的关键代码。
与上一段代码不同的是如果下一个进程为新进程时,就运用else中的这一段代码。首先将这个进程置为运行时状态,将这个进程作为当前正在执行的进程。之后的代码为嵌入式汇编代码,与上文稍微有点不同,但语句都差不多类似,这里就不赘述了。
总结
第一周的学习让我学习到了计算机的工作基本模型,就是存储程序计算机+函数调用对战,在本周深入学习操作系统的工作原理,首先引入一个重要模型就是中断机制,我认为这是现代计算机操作系统的工作的核心,早期的计算机在cpu完全处理完一个程序之后才会进行下一个任务的处理,这样大大降低了计算机的工作效率,而现代计算机引入中断机制,而时间片轮转模型又是现代计算机的基础模型,这就使得计算机通过中断机制在多个进程中以时钟信号我依据进行切换,从宏观的角度来看便是多个程序共同执行,大大提高了计算机的工作效率。