一个简单的时间片轮转多道程序内核代码分析

学号最后三位编号:505
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/

一:实验环境

本次实验采用实验楼里面的实验环境

二:实验过程

本次实验是在实验楼的虚拟机上运行的,MyKernel的实验环境已经部署好了所以直接是使用即可,使用实验楼的虚拟机打开shell

分别输入以下命令

cd LinuxKernel/linux-3.9.4
rm -rf mykernel
patch -p1 < ../mykernel_for_linux3.9.4sc.patch
make allnoconfig
make #编译内核请耐心等待
qemu -kernel arch/x86/boot/bzImage


运行命令后,弹出一个QEMU窗口,会循环输出my_start_kernel here和>>>>>my_timer_handler here <<<<< 

查看main.c文件

发现此文件里面while循环会不停执行,打印my_start_kernel here,打开myinterrupt.c,发现此文件存在一个会被时钟中断周期调用的函数my_timer_handler ,输出>>>>>my_timer_handler here <<<<< 

由于老师已经提供了源码于是直接下载即可

git clone https://github.com/mengning/mykernel

将mymain.c,myinterrupt.c,mypcb.h三个文件复制到mykernel文件夹下并覆盖

运行命令
make clean
make allnoconfig
make

 出现错误

将# unsigned long改为(unsigned long)再次运行

在mypcb.c文件中,定义了 Thread 结构体,用于存储当前进程中正在执行的线程的ip和sp,PCB结构体中的各个字段含义如下
pid:进程号

state:进程状态,在模拟系统中,所有进程控制块信息都会被创建出来,其初始化值就是-1,如果被调度运行起来,其值就会变成0

stack:进程使用的堆栈

thread:当前正在执行的线程信息

task_entry:进程入口函数

next:指向下一个PCB,模拟系统中所有的PCB是以链表的形式组织起来的。

在mymain.c文件中 my_start_kernel 是系统启动后,最先调用的函数,在这个函数里完成了0号进程的初始化和启动,并创建了其它的进程PCB,以方便后面的调度。在模拟系统里,每个进程的函数代码都是一样的,即 my_process 函数,my_process 在执行的时候,会打印出当前进程的 id,从而使得我们能够看到当前哪个进程正在执行。
另外,在 my_process 也会检查一个全局标志变量 my_need_sched,一旦发现其值为 1 ,就调用 my_schedule 完成进程的调度。

在myinterrupt.c中 my_timer_handler 函数会被内核周期性的调用,每调用1000次,就去将全局变量my_need_sched的值修改为1,通知正在执行的进程执行调度程序my_schedule。在my_schedule函数中,完成进程的切换。进程的切换分两种情况,一种情况是下一个进程没有被调度过,另外一种情况是下一个进程被调度过,可以通过下一个进程的state知道其状态。进程切换依然是通过内联汇编代码实现,无非是保存旧进程的eip和堆栈,将新进程的eip和堆栈的值存入对应的寄存器中。

本次实验中首先运行的的是__init my_start_kerne()。最初先初始化进程0,运行起来后再通过一个for循环初始化其他三个进程的pcb。并把这些pcb串成一个链表,通过my_time_handler()函数定时地不断向cpu发出中断,从而实现了时间片轮转。设置变量my_need_sched为1表示当前需要执行,也就是执行mymain.c的my_process()部分。my_schedule是整个程序的关键,它实现的是进程的上下文切换,将前一个进程的相关信息保存,并读入下一个进程的相关信息,从而完成进程的切换。

三:实验体会

通过本次实验了解了linux系统中进程切换和调度机制,学会了如何编译和修改内核代码。

猜你喜欢

转载自blog.csdn.net/zw147258369/article/details/88386036