博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Linux内核分析》 第二节 操作系统是如何工作的
阅读量:5033 次
发布时间:2019-06-12

本文共 6401 字,大约阅读时间需要 21 分钟。

 

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


张嘉琪 原创作品转载请注明出处 《Linux内核分析》MOOC课程

一、函数调用堆栈

  • 计算机工作的三个法宝
  1. 存储程序计算机
  2. 中断机制
  3. 堆栈

 

二、借助Linux内核部分源代码模拟存储程序计算机工作模型及时钟中断

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

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

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

cd LinuxKernel/linux-3.9.4qemu -kernel arch/x86/boot/bzImage

然后cd mykernel ,可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

 

  • 实验源代码

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

mypcb.h

1 /* 2  *  linux/mykernel/mypcb.h 3  * 4  *  Kernel internal PCB types 5  * 6  *  Copyright (C) 2013  Mengning 7  * 8  */ 9 10 #define MAX_TASK_NUM        411 #define KERNEL_STACK_SIZE   1024*812 13 /* CPU-specific state of this task */14 struct Thread {15     unsigned long        ip;16     unsigned long        sp;17 };18 19 typedef struct PCB{20     int pid;    //定义进程的ID21     volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */     //定义进程的状态22     char stack[KERNEL_STACK_SIZE];        //建立搭建进程的堆栈23     /* CPU-specific state of this task */24     struct Thread thread;25     unsigned long    task_entry;      //task_entry指定入口26     struct PCB *next;   //将进程用链表链接起来27 }tPCB;28 29 void my_schedule(void);//调度器
 

 

mymain.c

1 /* 2  *  linux/mykernel/mymain.c 3  * 4  *  Kernel internal my_start_kernel 5  * 6  *  Copyright (C) 2013  Mengning 7  * 8  */ 9 #include 
10 #include
11 #include
12 #include
13 #include
14 15 16 #include "mypcb.h" 17 18 tPCB task[MAX_TASK_NUM]; //声明一个PCB的数组19 tPCB * my_current_task = NULL;20 volatile int my_need_sched = 0; 是否需要调度21 22 void my_process(void);23 24 25 void __init my_start_kernel(void)26 {27 int pid = 0;28 int i;29 /* Initialize process 0*/ //初始化0号进程的数据结构30 task[pid].pid = pid; // 进程id31 task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */ //进程状态32 task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process; //进程入口33 task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];//堆栈的栈顶34 task[pid].next = &task[pid]; //next指向自己35 /*fork more process */ //将新fork的进程放到进程列表的尾部 36 for(i=1;i
thread.sp50 "pushl %1\n\t" /* push ebp */51 "pushl %0\n\t" /* push task[pid].thread.ip */52 "ret\n\t" /* pop task[pid].thread.ip to eip */53 "popl %%ebp\n\t"54 : 55 : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/56 );57 } 58 void my_process(void)59 {60 int i = 0;61 while(1)62 {63 i++;64 if(i%10000000 == 0)65 {66 printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);67 if(my_need_sched == 1)68 {69 my_need_sched = 0;70 my_schedule();71 }72 printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);73 } 74 }75 } /*0号进程的堆栈和0号进程的入口构建完成,my_start_kernel工作完成。循环1000万次才有一次机会判断一下是否需要调度*/

myinterrupt.c

1 /* 2  *  linux/mykernel/myinterrupt.c 3  * 4  *  Kernel internal my_timer_handler 5  * 6  *  Copyright (C) 2013  Mengning 7  * 8  */ 9 #include 
10 #include
11 #include
12 #include
13 #include
14 15 #include "mypcb.h"16 17 extern tPCB task[MAX_TASK_NUM];18 extern tPCB * my_current_task;19 extern volatile int my_need_sched;20 volatile int time_count = 0;21 22 /*23 * Called by timer interrupt.24 * it runs in the name of current running process,25 * so it use kernel stack of current running process26 */27 void my_timer_handler(void)28 {29 #if 130 if(time_count%1000 == 0 && my_need_sched != 1) //设置时间片大小,时间片用完是设置下一个调度标志31 {32 printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");33 my_need_sched = 1;34 } 35 time_count ++ ; 36 #endif37 return; 38 }39 40 void my_schedule(void)41 {42 tPCB * next;43 tPCB * prev;44 45 if(my_current_task == NULL 46 || my_current_task->next == NULL)47 {48 return;49 }50 printk(KERN_NOTICE ">>>my_schedule<<<\n"); //将当前进程的下一个进城赋给next51 /* schedule */52 next = my_current_task->next;53 prev = my_current_task;54 if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */ //下一个进程的状态是0(正在执行)时用switch to next process进行上下文切换55 {56 /* switch to next process */ /*进程切换的关键代码*/ /*将当前ebp保存,esp赋到0,把下一个进程的sp放入esp*/
57         asm volatile(    58             "pushl %%ebp\n\t"         /* save ebp */59             "movl %%esp,%0\n\t"     /* save esp */60             "movl %2,%%esp\n\t"     /* restore  esp */61             "movl $1f,%1\n\t"       /* save eip */       //1f是指接下的标号1:的位置62             "pushl %3\n\t" 63             "ret\n\t"                 /* restore  eip */64             "1:\t"                  /* next process start here */65             "popl %%ebp\n\t"66             : "=m" (prev->thread.sp),"=m" (prev->thread.ip)67             : "m" (next->thread.sp),"m" (next->thread.ip)68         ); 69         my_current_task = next; 70         printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);       71     }72     else73     {74         next->state = 0;75         my_current_task = next;76         printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);77         /* switch to new process */ 78         asm volatile(    79             "pushl %%ebp\n\t"         /* save ebp */ 保存当前进程ebp80             "movl %%esp,%0\n\t"     /* save esp */ 保存eso81             "movl %2,%%esp\n\t"     /* restore  esp */ 下一进程的esp放入esp中82             "movl %2,%%ebp\n\t"     /* restore  ebp */83             "movl $1f,%1\n\t"       /* save eip */    保存eip84             "pushl %3\n\t"                             将下一个进程的eip保存在堆栈中85             "ret\n\t"                 /* restore  eip */86             : "=m" (prev->thread.sp),"=m" (prev->thread.ip)87             : "m" (next->thread.sp),"m" (next->thread.ip)88         );          89     }   90     return;    91 }

 

三、学习总结

  • 进程的启动和进程的切换机制

     进程是接到调度指令才能启动的,进程切换就是从正在运行的进程中收回处理器,然后再使待运行进程来占用处理器。这里所说的从某个进程收回处理器,实质上就是把进程存放在处理器的寄存器中的中间数据找个地方存起来,从而把处理器的寄存器腾出来让其他进程使用。在切换时,一个进程存储在处理器各寄存器中的中间数据叫做进程的上下文,所以进程的切换实质上就是被中止运行进程与待运行进程上下文的切换。在进程未占用处理器时,进程 的上下文是存储在进程的私有堆栈中的。

  • 操作系统是如何工作的

      操作系统也有“两把剑”,分别是中断上下文进程上下文的切换。操作系统身负诸如管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统通过对进程的控制完成每项事物,进程通过控制数据的压入、弹出堆栈,设置时间片等方式进行进程上下文的切换和中断,从而让操作系统可以正常工作

转载于:https://www.cnblogs.com/Juliet5307/p/5245797.html

你可能感兴趣的文章
课堂作业01--架构师的职责
查看>>
iOS计算富文本(NSMutableAttributedString)高度
查看>>
2017/09/15 ( 框架2)
查看>>
Centos下源码安装git
查看>>
gulp-rev-append md5版本号
查看>>
IO流之File类
查看>>
sql 基础语句
查看>>
CF717A Festival Organization(第一类斯特林数,斐波那契数列)
查看>>
oracle直接读写ms sqlserver数据库(二)配置透明网关
查看>>
控件发布:div2dropdownlist(div模拟dropdownlist控件)
查看>>
Oracle composite index column ordering
查看>>
ActiveReports 报表控件官方中文入门教程 (3)-如何选择页面报表和区域报表
查看>>
kaggle竞赛
查看>>
区块链入门教程
查看>>
域 搭建OU 组织单元
查看>>
npm常用命令
查看>>
南海区行政审批管理系统接口规范v0.3(规划)4.2.【queryExpireList】当天到期业务查询...
查看>>
[置顶] 细说Cookies
查看>>
[wp7软件]wp7~~新闻资讯,阅读软件下载大全! 集合贴~~~
查看>>
生成指定位数随机数的方法
查看>>