目标
通过一个时间片轮转多道程序来解释操作系统的工作原理
准备工作
下载linux-3.9.4源代码,解压后打上补丁(在linux-3.9.4目录下将会增加mykernel文件夹,文件夹中将会有mymain.c和myinterrupt.c);
进入linux-3.9.4目录设置make allnoconfig之后,进行make编译;
然后在终端中输入:
cd LinuxKernel/linux-3.9.4
qemu -kernel arch/x86/boot/bzImage
运行得到的可执行程序,如下图:
简单的时间中断处理函数
mymain.c 源文件中的部分代码
void __init my_start_kernel(void)
{
int i = 0;
while (1)
{
++ i;
if (0 == i%100000)
{
printk(KERN_NOTICE "my_start_kernel here %d \n",i);
}
}
}
这是内核代码的开始运行的位置;
函数体中有个死循环,循环中有累加器,且累加器,不出意外的话,会无限变大;
如果累加器可整除10万,那么就打印该累加器中的数值(可以从图中看出,打印出的数字都是10万的整数倍);
可以预见,这个程序会一直这样无聊的运行下去:i不断变大,心情好点儿的话,打印一下 "my_start_kernel here i \n"
myinterrupt.c 源文件中的部分源代码
void my_timer_handler(void)
{
printk(KERN_NOTICE "\n>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<\n\n");
}
这个my_timer_handler是一个中断处理函数;
计算机每隔一段时间就会发出时钟中断,操作系统接收到时钟中断后,就会调用在内存某个地方的中断处理函数;
而中断处理函数是事先在预设地点埋伏好的,中断处理函数操作系统早已预先知道(预先注册了,告诉OS有我在哦),由系统回调;
故每次发生中断,操作系统都会调用这个处理函数,
然后打印 “\n>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<\n\n”
本来内核程序是很寂寞,很无聊地在那里打印 "my_start_kernel here i \n" ,但现在有了时钟中断,那么内核启动程序会偶尔休息一下,时钟中断处理程序会出来耍会儿;
由此,就出现一个别开生面的情形,两个程序交替出现,各自负责自己的工作(这里是打印一些字符),如果说内核启动程序是日常化的工作,是定数,是常量,那么时钟中断处理程序就是变数,是变量。
更复杂的程序
目标
接下来我们要在内核启动程序和时钟中断处理程序的基础上添加代码,把它变成一个时间片轮转的多道程序;
代码结构
mypcb.h
需要修改mykernel 文件夹中的部分内容,增加mypcb.h,其源码如下所示:
#define MAX_TASK_NUM 4
#define KERNEL_STACK_SIZE 1024*8
/* CPU specific state of this task */
struct Thread {
unsigned long ip ;
unsigned long sp ;
} ;
typedef struct PCB {
int pid ;
volatile long state ; /* -1 unrunnable, 0 */
char stack[KERNEL_STACK_SIZE] ;
/* CPU specific state of this task */
struct Thread thread ;
unsigned long task_entry ;
struct PCB *next ;
}tPCB ;
void my_schedule(void) ;
mymain.c
mymain.c 中代码结构如下:
#include "mypcb.h"
tPCB task[MAX_TASK_NUM] ;
tPCB *my_current_task = NULL ;
volatile int my_need_sched = 0 ;
void my_process(void) ;
void __init my_start_kernel(void) ;
myinterrupt.c
myinterrupt.c 中代码结构如下:
#include "mypcb.h"
extern tPCB task[MAX_TASK_NUM] ;
extern tPCB *my_current_task ;
extern volatile int my_need_sched ;
volatile int time_count = 0 ;
void my_timer_handler(void) ;
void my_schedule(void) ;
至此,应该对整个mykernel下的源代码结构有个宏观上的认识,接下来就来看每个文件中具体的代码!
源码分析
mymain.c
mymain.c中的源代码修改为以下内容:
#include "mypc