实验:基于Mykernel的多进程简单内核源码分析

实验:基于mykernel完成多进程的简单内核

学号:243

原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/


实验要求:

  • 完成一个简单的时间片轮转多道程序内核代码,参考代码见mykernel版本库。
  • 详细分析该精简内核的源代码并给出实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:
  • 题目自拟,内容围绕操作系统是如何工作的进行;
  • 博客中需要使用实验截图
  • 博客内容中需要仔细分析进程的启动和进程的切换机制
  • 总结部分需要阐明自己对“操作系统是如何工作的”理解。
  • 博客URL提交到https://github.com/mengning/linuxkernel/issues/2 截止日期3月12日24:00

实验环境:

虚拟机VMware+Ubuntu18+gcc4.9

注意:

1,执行wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.9.4.tar.xz

wget https://raw.github.com/mengning/mykernel/master/mykernel_for_linux3.9.4sc.patch时,可能会报错,尝试

wget --no-check-certificate https://...

2,make的时候,可能会出现提示找不到gcc-XX.h头文件找不到,查看include/linux/下的gcc头文件,安装对应版本gcc编译器即可.

比如:我的查看结果是gcc3和gcc4(真的是...)

安装gcc4.9:

执行:

sudo apt install gcc-4.9

sudo apt install g++-4.9

进入/usr/bin下面修改gcc链接:

sudo rm gcc

sudo rm g++

sudo ln -s gcc-4.9 gcc

sudo ln -s g++-4.9 gcc

查看gcc版本:

gcc --version


运行结果

  • qemu -kernel arch/x86/boot/bzImage 从qemu窗口中您可以看到my_start_kernel在执行,同时my_timer_handler时钟中断处理程序周期性执行。
  • cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c
  • 当前有一个CPU执行C代码的上下文环境,同时具有中断处理程序的上下文环境,我们初始化好了系统环境。
  • 您只要在mymain.c基础上继续写进程描述PCB和进程链表管理等代码,在myinterrupt.c的基础上完成进程切换代码,一个可运行的小OS kernel就完成了。
  • start to write your own OS kernel,enjoy it!

1.执行qemu -kernel arch/x86/boot/bzImage

2.查看mykernel/下myinterrupt.c和mymain.c以及Makefile文件

mymain.c和mykernel.c编译进内核,mykernel.c不断地打印"my_start_kernel here xxxxxxx",时间片轮转函数my_timer_handler()周期性发出中断,输出"my_timer_handler here"

3.获取源码https://github.com/mengning/mykernel,替换mymain.c myinterrupt.c和mypcb.h,重新编译

make allnoconfig

make

然后,重新执行:

qemu -kernel arch/x86/boot/bzImage

程序分析:

mypcb.h

#define MAX_TASK_NUM        4
#define KERNEL_STACK_SIZE   1024*2 # unsigned long

/* 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 runnable, >0 stopped */

    unsigned long 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);

PCB:进程线程控制块,进程线程的结构体

Thread:存储当前进程的ip和sp

pid:进程编号

state:进程的状态,初始-1,0表示运行状态

stack:进程的栈

thread:进程的ip sp的值

task_entry:进程的入口函数

next:指向下一个进程的地址,所有进程控制块PCB以链表形式存在.


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)

{

    int pid = 0;//设置运行pid=0

    int i;

    /* Initialize process 0*/
    
    //初始化0线程
    task[pid].pid = pid;
    //初始化状态为0,表示运行
    task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
    //设置函数入口为当前进程
    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];

    /*fork more process */
    //循环创建所有线程的PCB,MAX_TASK_NUM在头文件中定义4
    for(i=1;i<MAX_TASK_NUM;i++)

    {
        //分配内存
        memcpy(&task[i],&task[0],sizeof(tPCB));

        task[i].pid = i;

	//*(&task[i].stack[KERNEL_STACK_SIZE-1] - 1) = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];

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

    }

    /* start process 0 by task[0] */

    pid = 0;

    my_current_task = &task[pid];

	asm volatile(

    	"movl %1,%%esp\n\t" 	/* set task[pid].thread.sp to esp */

    	"pushl %1\n\t" 	        /* push ebp */

    	"pushl %0\n\t" 	        /* push task[pid].thread.ip */

    	"ret\n\t" 	            /* pop task[pid].thread.ip to eip */

    	: 

    	: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)	/* input c or d mean %ecx/%edx*/

	);

} 


int i = 0;



void my_process(void)

{    

    while(1)

    {

        i++;

        if(i%10000000 == 0)

        {

            printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);

            if(my_need_sched == 1)

            {

                my_need_sched = 0;

        	    my_schedule();

        	}

        	printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);

        }     

    }

}

程序显示初始化pid=0的进程,然后设置状态0,运行状态;然后根据头文件中的MAX_TASK_NUM创建各个任务的PCB,并且以链表形式连起来.各个进程执行my_process函数,打印pid信息.

myinterrupt.c

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)

{

#if 1

    if(time_count%1000 == 0 && my_need_sched != 1)

    {

        printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");

        my_need_sched = 1;

    } 

    time_count ++ ;  

#endif

    return;  	

}



void my_schedule(void)

{

    tPCB * next;

    tPCB * prev;



    if(my_current_task == NULL 

        || my_current_task->next == NULL)

    {

    	return;

    }

    printk(KERN_NOTICE ">>>my_schedule<<<\n");

    /* schedule */

    next = my_current_task->next;

    prev = my_current_task;

    if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */

    {        

    	my_current_task = next; 

    	printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);  

    	/* switch to next process */

    	asm volatile(	

        	"pushl %%ebp\n\t" 	    /* save ebp */

        	"movl %%esp,%0\n\t" 	/* save esp */

        	"movl %2,%%esp\n\t"     /* restore  esp */

        	"movl $1f,%1\n\t"       /* save eip */	

        	"pushl %3\n\t" 

        	"ret\n\t" 	            /* restore  eip */

        	"1:\t"                  /* next process start here */

        	"popl %%ebp\n\t"

        	: "=m" (prev->thread.sp),"=m" (prev->thread.ip)

        	: "m" (next->thread.sp),"m" (next->thread.ip)

    	); 

    }  

    return;	

}

my_timer_handler()函数,通过time_count和my_need_sched两个变量实现时间片轮转和进程的切换,各个进程不断执行My_process函数,通过PCB链表不断更新ip,sp,bp.


总结:

Linux操作系统,通过编译链接形成可执行文件,通过创建进程线程,信息保存在PCB中,包括pid,函数调用堆栈,next指针等信息.在发生中断的时候,通过各个寄存器ebp,esp,eip完成中断现场保护,进程切换和恢复的不间断的运行.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值