操作系统进程切换的一些理解

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

————————————————————————————————————————————————————————————————

实验目的:

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

实验步骤:

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

  2.cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c;

  3.完成一个简单的时间片轮转多道程序内核代码,代码见视频中,或从mykernel找。

      修改相关文档mymain.c 和 myinterrupt.c,完成相关内核代码;

    增添进程调度头文件mypcb.h,完善和调整实验。

  4. 调试和测试:

    cd  .. 返回上级目录(方法来自讨论区,谢谢);

     make  编译和测试。

5.验证和测试

      qemu -kernel arch/x86/boot/bzImage

    

实验分析:

  本次小实验主要是由以下几个文档控制的:

    mymain.c,myinterrupt.c,mypcb.h

  1.   mypcb.h

    重要头文件,主要定义了进程控制结构PCB、内核堆栈大小和调度算法的声明。

/* 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;

  2.myinterrupt.c

    主要定义时间中断函数和调度函数。

  时间中断处理函数:

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;
}/*这里为了明显看到中断的处理效果。可通过调节取模运算来增强实验效果。*/

调度函数:

...............................................

/* 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);

.............................................

  3.mymain.c

    是本次实验的入口文件,主要定义初始化及执行函数和示例进程函数。

    初始化进程:

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];

    示例进程函数:

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);
    }
  }
}

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

     主要从my_start_kernel函数进入进程,通过上述初始化进程进行0号进程的初始化和调用;

     同时利用类似的方法构建了n个pcb进程:

        其中重要代码:

..................
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];
....................

    使用了内联汇编来完成对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*/
  );

    让esp 指向 0进程 栈顶(同时是栈底),将栈底ebp入栈,调用my_process 入口地址, 跳转到 my_process.

   利用if....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)
);

  将当前进程的state改为0(runnable[可运行状态]),并修改当前运行进程指针指向的PCB结构体,执行完后开始执行内联汇编语句,进行进程切换操作.进而调用进程调度函数。逆向完成返回操作。ret指令从栈里弹出数值到eip,并且令栈缩小。

总结:

  我们实际生活中所使用的计算机由于各种需要和要求进而采用不同调度算法,但是进程的基本切换上述过程类似,不过更加复杂和效率更高。中断机制的使用也使得计算机能够从事更加复杂的运算和分析。进程的定义是:在自身的虚拟地址空间运行的一个独立的程序,从操作系统的角度来看,所有在系统上运行的东西,都可以称为进程。按照进程的功能和运行的程序分类,进程可划分为两大类:系统进程:可以执行内存资源分配和进程切换等管理工作,而且,该进程的运行不受用户的干预,即使是root用户也不能干预系统进程的运行;用户进程:通过执行用户程序、应用程序或内核之外的系统程序而产生的进程,此类进程可以在用户的控制下运行或关闭。

  用户级应用程序,通过系统调用,进入内核空间。内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行。而“进程上下文”,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈上的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

参考文档:

http://blog.chinaunix.net/uid-27717694-id-3803944.html

http://www.2cto.com/os/201412/359261.html

时间: 2024-07-29 11:17:39

操作系统进程切换的一些理解的相关文章

(转)几个常用的操作系统进程调度算法

几个常用的操作系统进程调度算法 转自:http://blog.csdn.net/wanghao109/article/details/13004507 一.先来先服务和短作业(进程)优先调度算法 1.先来先服务调度算法 先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度.当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为它们分配资源.创建进程,然后放入就绪队列.在进程调度中采用FCFS算法时,

Installshield停止操作系统进程的代码--IS5版本适用

原文:Installshield停止操作系统进程的代码--IS5版本适用 出处:http://www.installsite.org/pages/en/isp_ext.htm这个地址上有不少好东西,有空要好好研究下里面的“List and Shut Down Running Applications”就是演示了Installshield如何停止操作系统进程 Code/*****************************************************************

Installshield停止操作系统进程的代码 --IS6及以上版本适用

原文:Installshield停止操作系统进程的代码 --IS6及以上版本适用 setup.rul的代码 Code //////////////////////////////////////////////////////////////////////////////////                                                                            //  IIIIIII SSSSSS               

linux终端vi同时显示多个文件的分屏操作及切换操作

以前看到那边分屏操作的觉得很高端,现在初步整理了一下. 这里不是那个用代码实现的分屏,完全属于linux的操作命令 一.打开并显示文件 1.打开 这个不用说了,就是vi xx.c,或者vi xx1.c xx2.c 如果vi已经打开,则在底行模式输入 :open xx.c 2.显示 终端底行模式输入 :split     垂直分屏 :vsplit   水平分屏 (没输入一次分屏命令多一个分屏窗口) 二.窗口间的切换 这里有一下几种切换方法: 1.底行模式 :bn  下一个文件 :bp  上一个文件

C#操作系统进程的源码演示

下边内容内容是关于C#操作系统进程的演示的内容. private bool CloseProcess(string CloseProcessName) { try { Process[] MyProcessS = Process.GetProcessesByName(CloseProcessName); foreach (Process MyProcess in MyProcessS) { MyProcess.Kill(); MyProcess.WaitForExit(); MyProcess.

操作系统进程实验课程设计

题目:操作系统--进程实验 姓名:郑兆涵                          学校:烟台大学                       专业:计算机科学与技术(嵌入式方向) 班级:计146-2                        学号:201458506230              目录: 一.设计目的.意义 二.设计分析 三.方案分析 四.功能模块实现 1 进程创建 2 进程的控制 3 软中断通信 4 进程的管道通信 5 消息的创建,发送和接收 6 共享存储区的创

对现代操作系统进程地址空间的想法

什么是堆,什么是栈,什么是数据段,什么是代码段...这些都是历史遗留问题.如今编程真的没有必要在意这些了!不要被/proc/xx/{maps,smaps}里面的内容所迷惑和萦绕.自己管理好自己的内存分配就好.假设程序不是自己写的,那么就找写它的人.本文将从一个链接动态库的可运行文件怎样载入进程地址空间開始,谈一下我对进程地址空间布局的看法.我没有採用精确的方式描写叙述ELF或PE文件怎样载入的,而仅仅表述一种思想过程,目的是为了不让看到本文的人重新的陷入无穷尽的代码分析的深渊,因此我仅仅讲过程而

python - web自动化测试 - 元素操作 - 窗口切换

# -*- coding:utf-8 -*- ''' @project: web学习 @author: Jimmy @file: 元素操作-切换.py @ide: PyCharm Community Edition @time: 2019-01-19 10:43 @blog: https://www.cnblogs.com/gotesting/ ''' ''' windows窗口切换:切换到要操作的窗口 有多个窗口 1. 触发新窗口的出现 2. 得知道新窗口是谁 -- 依据窗口的window_h

robot framework + selenium2——切换窗口操作以及切换浏览器

list windows关键字:获取当前打开的所有页面窗口 不需要接收任何参数,返回一个列表 open browser http://www.baidu.com chrome ${result} list windows log ${result} sleep 2 close browser =======================================================================================================