网易公开课《Linux内核分析》学习心得-mykernel实验的实践和分析

来源:互联网 发布:php数据库管理系统 编辑:程序博客网 时间:2024/06/10 08:23

网易公开课《Linux内核分析》学习心得-mykernel实验的实践和分析

杨怡泽 原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

实验

根据实验要求在实验楼中进行实验,输入命令

cd LinuxKernel/linux-3.9.4qemu -kernel arch/x86/boot/bzImage

得到如下结果:
这里写图片描述
现在程序中只有一个进程不断运行,但是依然可以分析出进程的启动机制。让我们观察一下mymain.c和myinterrupt.c两个文件中的核心代码。

在mymain.c中:

void __init my_start_kernel(void){    int i = 0;    while(1)    {        i++;        if(i%100000 == 0)            printk(KERN_NOTICE "my_start_kernel here  %d \n",i);    }}

这段代码是操作系统的入口,从这里开始操作系统开始执行。

myinterrupt.c中,这段代码是用来处理时钟中断的,时钟中断是由linux内核完成,这段代码的主要功能就是将时钟中断进行处理:

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

现在我们需要在这个的基础上构建一个简单的操作系统。在mykernel文件夹中写入mypcb.h,其主要代码如下:

typedef struct PCB{    int pid; // 表示进程的状态    volatile long state;    char stack[KERNEL_STACK_SIZE];// 表示内核的堆栈    /* CPU-specific state of this task */    struct Thread thread;    unsigned long   task_entry;// 操作系统的程序入口    struct PCB *next;//进程链表    unsigned long priority;}tPCB;

这里写图片描述
修改mymain.c:

tPCB task[MAX_TASK_NUM]; //task数组tPCB * my_current_task = NULL; //声明当前task指针volatile int my_need_sched = 0; //是否需要标志void my_process(void);unsigned long get_rand(int);void sand_priority(void){    int i;    for(i=0;i<MAX_TASK_NUM;i++)        task[i].priority=get_rand(PRIORITY_MAX);}void __init my_start_kernel(void){    int pid = 0;  //当前进程为0号进程    task[pid].pid = pid;    task[pid].state = 0; //状态为正在运行    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 其他进程 */    for(pid=1;pid<MAX_TASK_NUM;pid++)    {        memcpy(&task[pid],&task[0],sizeof(tPCB));        task[pid].pid = pid;        task[pid].state = -1;        task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];    task[pid].priority=get_rand(PRIORITY_MAX);    }    task[MAX_TASK_NUM-1].next=&task[0];    printk(KERN_NOTICE "\n\n\n\n\n\n                system begin :>>>process 0 running!!!<<<\n\n");    pid = 0; //从零号开始执行    my_current_task = &task[pid]; //开始执行/*嵌入式汇编*/asm volatile(     "movl %1,%%esp\n\t"      "pushl %1\n\t"      "pushl %0\n\t"      "ret\n\t"      "popl %%ebp\n\t"     :     : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)); //汇编代码启动0号进程,内核初始化完成}

这段代码主要是为了启动进程,在asm volatile中初始化完成内核启动0号进程。

修改myinterrupt.c用来启动其他进程和切换进程。如果下一个进程已经执行,则切换进程通过如下代码:

asm volatile(            "pushl %%ebp\n\t" /* 保存 ebp */         "movl %%esp,%0\n\t" /* 移动esp到prev->thread.sp处 */         "movl %2,%%esp\n\t" /* 恢复esp */         "movl $1f,%1\n\t" /* 保存 eip */             "pushl %3\n\t" /*调用下一个进程 */         "ret\n\t" /* 恢复 eip */         "1:\t" /* 下一进程开始执行 */         "popl %%ebp\n\t"         : "=m" (prev->thread.sp),"=m" (prev->thread.ip)         : "m" (next->thread.sp),"m" (next->thread.ip)     );

如果下一进程尚未执行,则需要先启动类似进程:

asm volatile(            "pushl %%ebp\n\t"          "movl %%esp,%0\n\t"          "movl %2,%%esp\n\t"          "movl %2,%%ebp\n\t"          "movl $1f,%1\n\t"              "pushl %3\n\t" //保存当前进程的入口         "ret\n\t"          : "=m" (prev->thread.sp),"=m" (prev->thread.ip)         : "m" (next->thread.sp),"m" (next->thread.ip)     );

总结

操作系统的内核通过管理不同进程之间的运行,停止,切换和断点等来实现计算机的运转。当操作系统在运行进程的时候通过实现不同进程之间的切换,来保证每个进程都能顺利进行。当设备满足了读请求时,有一个中断就会通知内核,从而恢复以前的进程继续执行。

0 0
原创粉丝点击