• 2018-2019-1 20189221《Linux内核原理与分析》第三周作业


    2018-2019-1 20189221《Linux内核原理与分析》第三周作业


    实验二 完成一个简单的时间片轮转多道程序内核代码

    实验过程

    在实验楼中编译内核

    编写mymain.c函数和myinterrupt.c函数实现时间片轮转调用

    mymain.c:

    myinterrupt.c:


    make:

    内核实现:

    代码分析

    代码使用的是《 庖丁解牛Linux内核分析》书中代码:

    mypcb.h:定义了PCB结构体

    #define MAX_TASK_NUM        4
    #define KERNEL_STACK_SIZE   1024*8
    
    struct Thread {
        unsigned long       ip
        unsigned long       sp
    };
    
    typedef struct PCB
        int pid;
        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
        char stack[KERNEL_STACK_SIZE];
        struct Thread thread;
        unsigned long   task_entry;
        struct PCB *next;
    }tPCB;
    
    void my_schedule(void)
    
    • ip用于eip的保存
    • sp用于esp的保存
    • pid--> 进程号
    • state--> 进程状态
    • stack[KERNEL_STACK_SIZE]--> 进程的栈
    • Thread Thread--> Thread结构体
    • task_entry--> 起始入口地址
    • PCB *next-->next指针。

    mymain.c:初始化进程,启功0号进程

    #include <linux/types.h>
    #include <linux/string.h>
    #include <linux/ctype.h>
    #include <linux/tty.h>
    #include <linux/vmalloc.h>
    
    #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
        int i;
        task[pid].pid = pid;
        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];
    
        for(i=1;i<MAX_TASK_NUM;i++)
        {
            memcpy(&task[i],&task[0],sizeof(tPCB));
            task[i].pid = i;
            task[i].state = -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];
        }
        pid = 0;
        my_current_task = &task[pid];
        asm volatile(
            "movl %1,%%esp
    	"   
            "pushl %1
    	"          
            "pushl %0
    	"        
            "ret
    	"      
            "popl %%ebp
    	"
            : 
            : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)   
            /* input c or d mean %ecx/%edx*/
        );
    }
    
    
    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);
            }     
        }
    }
    
    • my_start_kernel作为标志,用来表示是否调度
    • 创建的新进程放在进程列表尾部,所有的进程是一个循环链表

    myinterrupt.c:产生中断,my_need_sched标志设1,

    #include <linux/types.h>
    #include <linux/string.h>
    #include <linux/ctype.h>
    #include <linux/tty.h>
    #include <linux/vmalloc.h>
    
    #include "mypcb.h"
    
    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%10000 == 0 && my_need_sched != 1)
        {
            printk(KERN_NOTICE ">>>my_timer_handler here<<<
    ");
            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<<<
    ");
        /* schedule */
        next = my_current_task->next;
        prev = my_current_task;
        if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */
        {
            asm volatile(   
                "pushl %%ebp
    	"       
                "movl %%esp,%0
    	"  
                "movl %2,%%esp
    	"   
                "movl $1f,%1
    	"         
                "pushl %3
    	" 
                "ret
    	"         
                "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);      
        }
        else
        {
            next->state = 0;
            my_current_task = next;
            printk(KERN_NOTICE ">>>switch %d to %d<<<
    ",prev->pid,next->pid);
            /* switch to new process */
            asm volatile(   
                "pushl %%ebp
    	"      
                "movl %%esp,%0
    	"    
                "movl %2,%%esp
    	"    
                "movl %2,%%ebp
    	"     
                "movl $1f,%1
    	"         
                "pushl %3
    	" 
                "ret
    	"          
                : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
                : "m" (next->thread.sp),"m" (next->thread.ip)
            );          
        }   
        return; 
    }
    
    
    • if判断下一个进程是否可运行,执行进程切换

    以myinterrupt.c中的asm内嵌汇编程序为例:

    "pushl %%ebp"       /* 保存当前ebp */
    "movl %%esp,%0"     /* 保存当前esp */
    "movl %2,%%esp"     /* 重新记录要跳转进程的esp,%2为 next->thread.sp*/
    "movl $1f,%1"       /* 保存当前eip ,%1为prev->thread.ip*/   
    "pushl %3" 
    "ret"               /* 记录要跳转进程的eip,%3为 next->thread.ip*/
    "1:	"                  /* 下一个进程开始执行 */
    "popl %%ebp"
    : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
    : "m" (next->thread.sp),"m" (next->thread.ip) 
    

    堆栈调用过程:

    "pushl %%ebp"       /* 保存当前ebp */
    "movl %%esp,%0"     /* 保存当前esp */
    "movl %2,%%esp"     /* 重新记录要跳转进程的esp ,%2为 next->thread.sp*/
    "movl %2,%%ebp"     /* 重新记录要跳转进程的ebp,%2为 next->thread.sp */
    "movl $1f,%1"       /* 保存当前eip ,%1为prev->thread.ip,%1f就是指标号1:的代码在内存中存储的地址*/   
    "pushl %3" 
    "ret"               /* 重新记录要跳转进程的eip,%3为 next->thread.ip */
    : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
    : "m" (next->thread.sp),"m" (next->thread.ip)
    

    遇到的问题

    这周遇到的问题很低级

    • Markdown的书写问题,列表中无序列表的嵌套总是会格式不对。
    • 想要自己设计代码实现mykernel时间片轮转多道程序,心有不逮,行有不逮
    • 这周的学习时间分配不均匀,因为一些客观存在的外部因素和一些主观上的内在因素干扰,学习计划没有很好实施。之后要严格执行自己的计划表。
    • 时间片轮转调度是操作系统调度算法的基础组成部分,在此基础上复习其他调度算法,尝试实现一下,参考博客:[浅析Linux内核调度]![]
  • 相关阅读:
    bat windows批处理 移动所有子目录文件
    Oracle常见的QA
    [转载]行动起来
    [转载]微笑
    Excel数据更新至Mysql数据库
    sql server QA
    关于SharpZipLib的压缩与解压问题
    整合Spring.net到asp.net网站开发中初探
    设计模式概要
    Oracle 常用语句档案(二)
  • 原文地址:https://www.cnblogs.com/gdman/p/9847715.html
Copyright © 2020-2023  润新知