• 20135202闫佳歆--week2 一个简单的时间片轮转多道程序内核代码及分析


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

    所用代码为课程配套git库中下载得到的。

    一、进程的启动

    /*出自mymain.c*/
    /* start process 0 by task[0] */
        pid = 0;
        my_current_task = &task[pid];
    	asm volatile(
        	"movl %1,%%esp
    	" 	/* 将进程的sp赋给esp寄存器 */
        	"pushl %1
    	" 	        /* ebp入栈:因为在这里栈为空,esp=ebp,所以push的%1就是esp就是ebp。*/
        	"pushl %0
    	" 	        /* 进程入口ip入栈 */
        	"ret
    	" 	            /* 把进程入口ip赋给eip,即从这之后0号进程启动。*/
        	"popl %%ebp
    	"
        	: 
        	: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)	/* input c or d mean %ecx/%edx*/
    	);
    

    二、进程的切换

    进程的切换有两种:

    1.下一个进程next->state == 0 即正在执行时

    /*出自myinterrupt.c*/
    //两个正在运行的进程之间做进程上下文切换
    
    if(next->state == 0)
    /* state值的含义:-1表示没有执行,0表示正在执行,>0表示停止,这里为0,即进程正在执行 */
    {
    	/* 以下是进程切换关键代码 */
    	asm volatile(	
        	"pushl %%ebp
    	" 	    /* 把当前进程的ebp保存*/
        	"movl %%esp,%0
    	" 	/* 把当前进程的esp赋值到sp中保存下来*/
        	"movl %2,%%esp
    	"     /* 把下一个进程的sp放到esp中*/
        	"movl $1f,%1
    	"       /* 把eip保存起来,$1f指接下来的标号1:的位置*/	
        	"pushl %3
    	" 			/*把下一个进程的eip保存起来*/
        	"ret
    	" 	            /* 还原eip */
        	"1:	"                  /* 标号1,下一进程从此开始 */
        	"popl %%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 %d to %d<<<
    ",prev->pid,next->pid);   	
    }
    

    2.进程是一个新进程,还从未执行过

    /*出自myinterrupt.c*/
    /*这段代码是当进程从未执行过时,所执行的动作,即启动一个进程
    
    next->state = 0;	/* 首先要把进程置为运行时状态,作为当前正在执行的进程 */
    my_current_task = next;
    printk(KERN_NOTICE ">>>switch %d to %d<<<
    ",prev->pid,next->pid);
    /* 进程切换时的提示,从当前进程切换至下一进程*/
    asm volatile(   //混合编程	
    	"pushl %%ebp
    	" 	    /* 保存ebp */
    	"movl %%esp,%0
    	" 	/* 保存esp */
    	"movl %2,%%esp
    	"     /* 将下一进程的sp存入esp */
    	"movl %2,%%ebp
    	"     /* 将下一进程的bp存入ebp,因为栈空,所以esp和ebp指向同一位置 */
    	"movl $1f,%1
    	"       /* 保存eip */	
    	"pushl %3
    	" 			/*保存当前进程入口 */
    	"ret
    	" 	            /* 还原eip */
    	: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
    	: "m" (next->thread.sp),"m" (next->thread.ip)
    );  
    

    三、实验截图

    这个实验我是根据github中的步骤,在自己虚拟机中一点点做的,最后成功做出来了,截图如下:
    文件夹内容

    运行截图1

    运行截图2

    运行截图3

    四、操作系统是如何工作的

    就像计算机有三件法宝一样,操作系统也有“两把剑”,分别是中断上下文进程上下文的切换

    有了中断后,就有了多道程序设计,每个程序有自己的执行流,中断发生时,cpu把当前的eip等压入内核堆栈中,然后把eip指向中断处理程序的入口。

    在模拟操作系统的代码里可以看出,mypcb.h中定义了结构体,用于存放sp和ip,以及pcb块,每个pcb块就是一个进程。
    然后在mymain.c中,先创建了几个进程,具体创建过程见上。
    然后设立一个循环,比如循环一百万次再来判定是否需要调度,这是建立了一个主动的调度机制,对应的是这个函数:

    void my_process(void)
    {
        int i = 0;
        while(1)
        {
            i++;
            if(i%10000000 == 0)
            {
                printk(KERN_NOTICE "this is process %d -
    ",my_current_task->pid);
                if(my_need_sched == 1)//执行一千万次才判断是否需要调度。有一个主动调度的机制。
                {
                    my_need_sched = 0;
            	    my_schedule();
            	}
            	printk(KERN_NOTICE "this is process %d +
    ",my_current_task->pid);
            }     
        }
    }
    

    有调度就要有进程的的切换,切换也在上面说过了。
    因为是时间片轮转,所以需要设立一个时间片,当时间片用尽时设立调度标志,如下:

    void my_timer_handler(void)
    {
    #if 1
    	//设置时间片的大小,时间片用完时设置一下调度标志。
        if(time_count%1000 == 0 && my_need_sched != 1)
        {
            printk(KERN_NOTICE ">>>my_timer_handler here<<<
    ");
            my_need_sched = 1;
        } 
        time_count ++ ;  
    #endif
        return;  	
    }
    

    总体思路就是时间片用尽时设置调度标志,然后判断是否需要调度用一个无限循环控制,需要调度了就切换进程。

    最后附上这周的=学习笔记

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

  • 相关阅读:
    洛谷 P2053 :[SCOI2007]修车(拆点+最小费用流)
    LightOJ
    spark简单入门
    crontab 应用
    HttpClient的使用
    build.sbt的定义格式
    Scalatra
    SBT 构建scala eclipse开发
    mysql 存在更新,不存在插入
    Flash Vector例子
  • 原文地址:https://www.cnblogs.com/20135202yjx/p/5246402.html
Copyright © 2020-2023  润新知