多任务操作系统在并行执行多任务时,实际上是不断地在任务间进行切换的,也就是切换上文。首先要保存前一个进程的上下文,然后调度一个就绪的进程,并载入该进程的上下文,cpu开始执行该进程的代码。在切换上下文时,最重要的就是切换eip寄存器的值和esp寄存器的值,eip寄存器指向的指令即时cpu即将执行的指令,esp寄存器指向栈顶。下面我们通过一段比较简单的代码来演示一下cpu是如何切换进程的。
代码已经由孟宁老师编写好了,下载地址孟宁-mykernel
按照readme文件中的的操作打好补丁。使用mykernel-1.1文件中的mymain.c、mypcb.h、myinterrupt.c替换linux-3.9.4/mykernel中的相应的文件,然后make。
这是修改后的linux内核源码,代码太长,我们从中取重要的部分,首先来看mypcb.h,这是我们自定义的进程pcb。
/*
* linux/mykernel/mypcb.h
*
* Kernel internal PCB types
*
* Copyright (C) 2013 Mengning
*
*/
//最大进程数量
#define MAX_TASK_NUM 4
//进程栈的大小
#define KERNEL_STACK_SIZE 1024*8
/* CPU-specific state of this task */
//该进程的cpu状态
struct Thread {
//eip寄存器的值
unsigned long ip;
//栈顶
unsigned long sp;
};
// 进程控制块
typedef struct PCB{
//进程id
int pid;
//进程状态
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
//进程栈,栈底是数组的最后一个元素位置
char stack[KERNEL_STACK_SIZE];
/* CPU-specific state of this task */
//cpu状态
struct Thread thread;
//进程入口
unsigned long task_entry;
//指向下一个进程的指针
struct PCB *next;
}tPCB;
void my_schedule(void);
下面看一下mymain.c,这里包括我们手工创造的第0号进程,以及其他进程的fork();
/*
* linux/mykernel/mymain.c
*
* Kernel internal my_sta