Linux内核分析— —操作系统是如何工作的(20135213林涵锦)

mykernel实验指导(操作系统是如何工作的)

实验要求

运行并分析一个精简的操作系统内核,理解操作系统是如何工作的

使用实验楼的虚拟机打开shell

  1. cd LinuxKernel/linux-3.9.4
  2. qemu -kernel arch/x86/boot/bzImage
然后cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

实验截图

首先是

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)_第1张图片

然后是

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)_第2张图片

之后是

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)_第3张图片

要建立一个简单的时间片轮转多道程序,按照实验楼给的链接,找到了几个源代码,如图

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)_第4张图片

然后按这些修改文件,并加入文件mypcb.h

再运行,0,1,2,3,之间的进程切换

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)_第5张图片

Linux内核分析— —操作系统是如何工作的(20135213林涵锦)_第6张图片

分析进程的启动和进程的切换机制

mypcb.h

/*
  * linux/mykernel/mypcb.h
  *
  * Kernel internal PCB types
  *
  * Copyright (C) 2013 Mengning
  *
  */
   
  #define MAX_TASK_NUM 4
  #define KERNEL_STACK_SIZE 1024*8
   
  /* 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 */
  char 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);

void my_schedule(void);函数的功能为调度器,用于进程之间的调度运行。

mymain.c

/*
  * linux/mykernel/mymain.c
  *
  * Kernel internal my_start_kernel
  *
  * Copyright (C) 2013 Mengning
  *
  */
  #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;
  /* Initialize process 0*/
  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];
  /*fork more process */
  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];
  }
  /* 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 */
  "popl %%ebp\n\t"
  :
  : "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 -\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);
  }
  }
  }
  • 在myprocess的函数之中输出时采用了主动调度,循环1000万次才有一次机会判断一下是否需要调度。
  • 调度完切换回来时,则从myschedule();函数继续执行。

myinterrupt.c

#include <linux/vmalloc.h>
     
    #include "mypcb.h"
    +
    extern tPCB task[MAX_TASK_NUM];
    extern tPCB * my_current_task;
    -extern int task_count;
    -
    +extern volatile int my_need_sched;
    +volatile int time_count = 0;
     
    /*
    * Called by timer interrupt.
  @@ -25,21 +26,33 @@ extern int task_count;
    */
    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;
    - printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");
     
    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 */
    {
    - printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);
    /* switch to next process */
    asm volatile(
    "pushl %%ebp\n\t" /* save ebp */
  @@ -53,9 +66,27 @@ void my_timer_handler(void)
    : "=m" (prev->thread.sp),"=m" (prev->thread.ip)
    : "m" (next->thread.sp),"m" (next->thread.ip)
    );
    - my_current_task = next;
    + 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;
    }
     

void my_timer_handler(void)函数的作用是设置时间片的大小,时间片用完时设置一下调度标志,当进程调度发现状态为1时,则会执行一次my_process,而后执行一次my_schedule。

  • 当前进程的下一个进程赋给next,当前进程赋给prev。如果下一个进程状态为0的话,即正在执行,则需要在两个正在运行的进程之间做进程上下文切换:
    • 保存当前进程的ebp
    • 将当前进程的esp赋给prev->thread.sp,从而将其保存起来
    • 将下一个进程的sp放置esp中
    • 保存当前进程的eip至当前进程所属的pcb中
    • 将下一个进程的eip保存至当前栈中
    • 通过ret,即可调用下一个进程
  • 若下一个进程的状态还未执行过,则进行以下步骤:
    • 将下一个进程设置为运行时状态,并将其设置为当前进程
    • 保存当前进程的ebp,将其压入栈中
    • 保存当前进程的esp至当前进程的pcb中
    • 由于该程序并未执行过,所以它的堆栈为空栈,空栈的创建则是通过将ebp和esp都赋予同一个值。
    • 保存当前进程的eip
    • 将当前进程的eip压入栈中
    • 通过ret,即可调用下一个进程

总结部分

对“操作系统是如何工作的”理解:

首先要了解计算机工作的三个法宝:

1.存储程序计算机

所有计算机的基础性的逻辑框架。

2.函数调用堆栈

在低级语言中并不很重要,但是堆栈技术是高级语言可以运行的基础。

3.中断机制

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

 

然后我们知道:操作系统是一管理电脑硬件与软件资源的程序,同时也是计算机系统的内核与基石。操作系统身负诸如管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统是管理计算机系统的全部硬件资源包括软件资源及数据资源;控制程序运行;改善人机界面;为其它应用软件提供支持等,使计算机系统所有资源最大限度地发挥作用,为用户提供方便的、有效的、友善的服务界面。(源自百度)

操作系统是一个庞大的管理控制程序,大致包括5个方面的管理功能:进程与处理机管理、作业管理、存储管理、设备管理、文件管理。

 

最终可知:操作系统保存了一些队列,每个队列都是一组等待某些资源的进程。资源在操作系统中得以合理的分配以及调度,用于解决处理这些进程。

 

注:

姓名:林涵锦 

 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 

你可能感兴趣的:(Linux内核分析— —操作系统是如何工作的(20135213林涵锦))