前言
本文的内容来自于
《Linux内核分析》MOOC课程。
文中实现对进程控制块结构(PCB)提到定义以及一个简单的Linux内核调度函数。
实验环境
操作系统Ubuntu 14.04 LTS,gcc版本4.8.4。
实验环境搭建方法
代码分析
进程和线程的定义
首先在mykernel/下建立一个与程序控制块相关的头文件mypcb.h,该文件中主要实现了对进程控制块结构体(tPCB)和线程结构体(Thread)的声明和定义,以及
my_schedule
函数和其他一些宏的声明。代码及详细分析如下:
#define MAX_TASK_NUM 4 /* 支持的最大进程数(4个) */
#define KERNEL_STACK_SIZE 1024*8 /* 进程栈空间的大小(8k word,即64kB) */
#define UNRUNNABLE -1 /* 进程可执行 */
#define RUNNABLE 0 /* 进程不可执行 */
#define FALSE 0
#define TRUE 1
struct Thread {
unsigned long ip;
unsigned long sp;
};
typedef struct PCB{
int pid;
volatile long state;
char stack[KERNEL_STACK_SIZE];
struct Thread thread;
unsigned long task_entry;
struct PCB *next;
} tPCB;
void my_schedule(void);
进程的初始化
#ifdef CONFIG_X86_LOCAL_APIC
#include
#endif
#include "mypcb.h"
#define SLICING (10000000)
tPCB task[MAX_TASK_NUM];
tPCB *my_current_task = NULL;
volatile int my_need_schedule = FALSE;
void my_process(void);
void __init my_start_kernel(void)
{
int pid =0;
int i;
task[pid].pid = pid;
task[pid].state = RUNNABLE;
task[pid].task_entry = task[pid].thread.ip =(unsigned long)my_process;
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE -1];
task[pid].next = &task[pid];
for(i =1; i < MAX_TASK_NUM; i ++){
memcpy(&task[i],&task[0],sizeof(tPCB));
task[i].pid = i;
task[i].state = UNRUNNABLE;
task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE -1];
task[i].next = task[i-1].next;
task[i-1].next =&task[i];
}
pid =0;
my_current_task = &task[pid];
my_need_schedule = TRUE;
asm volatile(
"movl %1,%%esp
"
"pushl %1
"
"pushl %0
"
"ret
"
"popl %%ebp
"
:
:"c"(my_current_task->thread.ip),"d"(my_current_task->thread.sp)
);
}
void my_process(void){
int i = 0;
while(1) {
i ++;
if(i % SLICING == 0){
printk(KERN_NOTICE "This is process %d -
", my_current_task->pid);
if(my_need_schedule == TRUE){
my_need_schedule = FALSE;
my_schedule();
}
printk(KERN_NOTICE "This is process %d +
", my_current_task->pid);
}
}
}
进程调度
#define CREATE_TRACE_POINTS
#include
#include"mypcb.h"
#define SLICING 1000
extern tPCB task[MAX_TASK_NUM];
extern tPCB *my_current_task;
extern volatile int my_need_schedule;
volatile int time_count =0;
void my_timer_handler(void)
{
if(time_count % SLICING == 0 && my_need_schedule != TRUE){
printk(KERN_NOTICE ">>>>>>>>>>>>>>>>>my_timer_handlerhere<<<<<<<<<<<<<<<<<<
");
my_need_schedule = TRUE;
}
time_count ++;
return;
}
void my_schedule(void){
tPCB *next;
tPCB *prev;
if(my_current_task == NULL
|| my_current_task->next == NULL){
printk(KERN_ERR "Error occurs in my_schedule!");
return;
}
printk(KERN_NOTICE ">>>>>>>>>>>>>>>>>my_schedule<<<<<<<<<<<<<<<<<<
");
next = my_current_task->next;
prev = my_current_task;
if(next->state == RUNNABLE){
asm volatile(
"pushl %%ebp
"
"movl %%esp,%0
"
"movl %2,%%esp
"
"movl $start,%1
"
"pushl %3
"
"ret
"
"start:
"
"popl %%ebp
"
:"=m"(prev->thread.sp),"=m"(prev->thread.ip)
:"m"(next->thread.sp),"m"(next->thread.ip)
);
my_current_task = next;
printk(KERN_NOTICE ">>>>>> switch from process %d toprocess %d <<<<<<
",
prev->pid, next->pid);
}else{
next->state = RUNNABLE;
my_current_task= next;
printk(KERN_NOTICE ">>>>>> switch from process %d toprocess %d <<<<<<
",
prev->pid, next->pid);
asm volatile(
"pushl %%ebp
"
"movl %%esp,%0
"
"movl %2,%%esp
"
"movl %2,%%ebp
"
"movl $start,%1
"
"pushl %3
"
"ret
"
:"=m"(prev->thread.sp),"=m"(prev->thread.ip)
:"m"(next->thread.sp),"m"(next->thread.ip)
);
}
}