Linux内核分析——操作系统是如何工作的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux内核分析——操作系统是如何工作的相关的知识,希望对你有一定的参考价值。

姓名:王晨光

学号:20133232

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

一、进程的启动和切换源代码及分析

技术分享

typedef struct PCB用于表示定义了一个进程,定义了进程管理相关的数据结构。同时也设置了用于保存EIP和ESP的数据类型。

下列代码为mymain.c部分代码:

 

void __init my_start_kernel(void)
{
int pid = 0;
    int i;
    task[pid].pid = pid;/*将进程号初始化为0*/
    task[pid].state = 0;
task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
/*把进程的入口和eip都初始化为my_process函数的入口地址*/
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
/*将堆栈的栈顶地址保存为栈的最后一个元素,即最高的地址*/
task[pid].next = &task[pid];
/*next指针指向自己*/
    for(i=1;i<MAX_TASK_NUM;i++)
    {
        memcpy(&task[i],&task[0],sizeof(tPCB));
/*将task[0]的信息全部复制到各个新进程中*/
        task[i].pid = i;/*将新进程的pid设置为变量i*/
        task[i].state = -1;/*新进程的状态为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];
    }
    /* start process 0 by task[0] */
    pid = 0;
    my_current_task = &task[pid];//将当前进程设置为0号进程
    asm volatile(
/*把0号进程的esp放入esp寄存器*/
        "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 */
        "popl %%ebp\n\t"
        : 
        : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)   /* input c or d mean %ecx/%edx*/
    );
}


系统总是从0号进程开始启动。以上代码完成的任务主要是初始化进程,然后开始执行第一个进程,执行完RET操作之后将会跳转到下一个函数中执行。

一下代码为myinterrupt.c部分代码:

 

void my_timer_handler(void)
{
#if 1
/*函数每执行1000次,并且my_need_sched不等于1的时候执行if判断,然后把my_need_sched置为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 */
    {
        /* 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)
        ); 
        my_current_task = next; 
        printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);      
    }
    else
{
        next->state = 0;
        my_current_task = next;
        printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
        /* switch to new process */
        asm volatile(   
            "pushl %%ebp\n\t"       /* save ebp */
            "movl %%esp,%0\n\t"     /* save esp */
            "movl %2,%%esp\n\t"     /* restore  esp */
            "movl %2,%%ebp\n\t"     /* restore  ebp */
            "movl $1f,%1\n\t"       /* save eip */ 
            "pushl %3\n\t" 
            "ret\n\t"               /* restore  eip */
            : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
            : "m" (next->thread.sp),"m" (next->thread.ip)
        );          
    }   
    return; 
}

     这段代码中,my_schedule函数是重点,它实现了时间片轮转的中断处理过程。这个函数分两次执行,第一次是0号进程跳转到1号进程,而第二次进入则是执行pop1 ebp恢复现场,然后return函数,返回到原调用者也就是0号进程的process里面。

二、实验过程

技术分享

在实验楼中运用搭建好的环境打开文件

技术分享

运行的程序

技术分享

mymain.c程序代码

技术分享

myinterrupt.c程序代码

 

实验总结:实验过程中源代码中的很多行代码看不懂,通过百度、观看视频有了一定的了解,也大致了解了操作系统是如何工作的。我们可以认为一个进程相当于一个堆栈,每个进程有自己的堆栈空间。如果将ebp和esp修改为另一个进程的ebp和esp,就可以完成进程的切换。当进程切换时,系统也会保存当前的工作状态,以便于下次恢复进程,使进程继续执行。

 

以上是关于Linux内核分析——操作系统是如何工作的的主要内容,如果未能解决你的问题,请参考以下文章

《Linux内核分析》 第二节 操作系统是如何工作的

linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码

Linux内核分析—完成一个简单的时间片轮转多道程序内核代码

“linux系统内核分析”实验报告1

“linux系统内核分析”实验报告1

Linux内核分析之操作系统是如何工作的