Linux 커 널 분석 (2) 의 간단 한 프로 세 스 스케줄 링
7541 단어 리 눅 스 커 널
오리지널 작품 전재 출처 를 밝 혀 주 십시오.
MOOC 과정http://mooc.study.163.com/course/USTC-1000029000
본 고 는 간단 한 프로그램 스케줄 링 내 핵 을 실현 하 였 다.
실험 환경: 운영 체제 Ubuntu 14.04 LTS, gcc 버 전 4.8.4
환경 구축 방법:https://github.com/mengning/mykernel
먼저 my kernel / 다음 에 프로그램 제어 블록 과 관련 된 헤더 파일 my pcb. h 를 만 듭 니 다. 코드 는 다음 과 같 습 니 다.
/*
* linux/mykernel/mypcb.h
*
* Kernel internal PCB types
*
* Copyright (C) 2016 Chen Lili
*
*/
#defineMAX_TASK_NUM 10
#defineKERNEL_STACK_SIZE 1024*8 /* 8k bytes */
#defineUNRUNNABLE -1
#defineRUNNABLE 0
#define FALSE 0
#define TRUE 1
/* CPU-specificstate of a task, only fit for 32-bit system. */
struct Thread {
unsignedlong ip;/* instruction pointer */
unsignedlong sp;/* stack pointer */
};
typedefstruct PCB{
int pid; /* process id */
volatilelong state; /* -1 unrunnable, 0 runnable */
char stack[KERNEL_STACK_SIZE];
/* CPU-specific state of this task */
struct Thread thread;
unsignedlong task_entry;
struct PCB *next;
} tPCB;
void my_schedule(void);
이 헤더 파일 은 프로그램 제어 블록 의 구조 체 를 정의 합 니 다.이 구조 체 에는 다음 이 포함 되 어 있다.
1. 프로 세 스 ID, 형식 int.운영 체제 에서 프로 세 스 의 유일한 표지 입 니 다.
2. 프로 세 스 상태, 형식 volatile long.현재 '실행 가능' 과 '실행 불가능' 을 지원 합 니 다.
3. 프로 세 스 스 스 택 공간, 형식 char [].이번 코드 는 스 택 크기 를 8k 바이트 로 설정 합 니 다.
4. 현재 스 레 드.프로 세 스 에서 실행 중인 스 레 드 를 표시 합 니 다.
5. 프로 세 스 의 입구 주소 입 니 다.
6. 다음 프로 세 스 지침.다음 실행 할 프로 세 스 를 가리 키 는 PCB 입 니 다.
또한 헤더 파일 에는 스 레 드 의 구조 체 도 정의 되 어 있다.이 구조 체 에는 다음 이 포함 되 어 있다.
1. 지령 지침.스 레 드 가 실 행 된 다음 명령 의 주소 입 니 다.
2. 창고 꼭대기 지침.스 레 드 스 택 포인터.
이 밖 에 헤더 파일 에 스케줄 링 함수 my 도 밝 혔 다.schedule()。
다음은 프로 세 스 스케줄 링 의 메 인 프로그램 mymain. c 를 소개 합 니 다.
/*
* linux/mykernel/mymain.c
*
* Kernel internal my_start_kernel
*
* Copyright (C) 2016 Chenlili
*
*/
/*
* Headers are omitted.
*/
#ifdefCONFIG_X86_LOCAL_APIC
#include
#endif
#include"mypcb.h"
#define SLICING(1000000000)
tPCB task[MAX_TASK_NUM];
tPCB *my_current_task =NULL;
volatileint my_need_schedule = FALSE;
void my_process(void);
void __init my_start_kernel(void)
{
int pid =0;
int i;
/* Initialize process 0 */
task[pid].pid = pid;
task[pid].state = RUNNABLE;
task[pid].task_entry = task[pid].thread.ip =(unsignedlong)my_process;
task[pid].thread.sp =(unsignedlong)&task[pid].stack[KERNEL_STACK_SIZE -1];
task[pid].next =&task[pid];
/* fork more process */
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 =(unsignedlong)&task[i].stack[KERNEL_STACK_SIZE -1];
task[i].next = task[i-1].next;
task[i-1].next =&task[i];
}
/* start process by task[0] */
pid =0;
my_current_task =&task[pid];
my_need_schedule = TRUE;
asm volatile(
"movl %1,%%esp
\t" /* settask[pid].thread.sp to esp */
"pushl %1
\t" /* push ebp */
"pushl %0
\t" /* push task[pid].thread.ip*/
"ret
\t" /* poptask[pid].thread.ip to eip */
"popl %%ebp
\t"
:
:"c"(my_current_task->thread.ip),"d"(my_current_task->thread.sp)/* "c" = ecx, "d" =edx*/
);
}
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);
}
}
}
프로 세 스 대기 열 을 초기 화하 고 모든 프로 세 스 를 대기 열 에 추가 합 니 다.대기 열 링크 는 단 방향 순환 링크 입 니 다.
마지막 으로 간단 한 스케줄 링 의 핵심 코드 인 myinterupt. c 를 소개 합 니 다.
/*
* linux/mykernel/myinterrupt.c
*
* Kernel internal my_timer_handler
*
* Copyright (C) 2013 Mengning
*
*/
/*
* Headers are omitted.
*/
#defineCREATE_TRACE_POINTS
#include
#include"mypcb.h"
#define SLICING1000
extern tPCB task[MAX_TASK_NUM];
extern tPCB *my_current_task;
externvolatileint my_need_schedule;
volatileint time_count =0;
/*
* Called by timer interrupt.
* It runs in the name of the current process.
*/
void my_timer_handler(void)
{
if(time_count % SLICING ==0&& my_need_schedule != TRUE){
printk(KERN_NOTICE ">>>>>>>>>>>>>>>>>my_timer_handlerhere<<<<<<<<<<<<<<<<<next ==NULL){
printk(KERN_ERR "Error occurs in my_schedule!");
return;
}
printk(KERN_NOTICE ">>>>>>>>>>>>>>>>>my_schedule<<<<<<<<<<<<<<<<<next;
prev = my_current_task;
if(next->state == RUNNABLE){
/* switch to next process */
asm volatile(
"pushl %%ebp
\t" /* save prevprocess’s ebp */
"movl %%esp,%0
\t" /* save prev process’s esp */
"movl %2,%%esp
\t" /* restore nextprocess's ebp */
"movl $start,%1
\t" /* save eip, $start start: */
"pushl %3
\t"
"ret
\t" /* restore nextprocess's eip */
"start:
\t" /* next process start here */
"popl %%ebp
\t" /* restore next process's 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 <<<<<pid, next->pid);
}else{
next->state = RUNNABLE;
my_current_task= next;
printk(KERN_NOTICE ">>>>>> switch from process %d toprocess %d <<<<<pid, next->pid);
/* switch to next process */
asm volatile(
"pushl %%ebp
\t" /* save prevprocess’s ebp */
"movl %%esp,%0
\t" /* save prevprocess’s esp */
"movl %2,%%esp
\t" /* restore nextprocess's sp to esp */
"movl %2,%%ebp
\t"
/* restore next process's sp to ebp
* because the process has neverrun
* bp equals to sp
*/
"movl $start,%1
\t" /* save eip */
"pushl %3
\t" /* restore next process's eip, hereeip->my_process */
"ret
\t"
:"=m"(prev->thread.sp),"=m"(prev->thread.ip)
:"m"(next->thread.sp),"m"(next->thread.ip)
);
}
my_need_schedule = TRUE;
}