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; }

좋은 웹페이지 즐겨찾기