云课堂回顾学习

1. 进程调度的时机

  • 中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();
  • 内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
  • 用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

总结:

  • 用户态进程只能被动调度
  • 内核线程是只有内核态没有用户态的特殊进程
  • 内核线程既可以主动调度也可以被动调度

2. 进程的切换

  • 为了控制进程的执行,内核必须有能力挂起正在CPU上执行的进程,并恢复以前挂起的某个进程的执行,这叫做进程切换、任务切换、上下文切换;
  • 挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行;
  • 进程上下文包含了进程执行需要的所有信息

    用户地址空间:包括程序代码,数据,用户堆栈等

    控制信息:进程描述符,内核堆栈等

    硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)
  • schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换

    next = pick_next_task(rq, prev);//进程调度算法都封装这个函数内部

    context_switch(rq, prev, next);//进程上下文切换

    switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

实验

cd LinuxKernel
ls
cd menu
vi test.c

这里我们使用time系统调用,在test.c中加入time函数以及main中加入相关语句,如同之前的实验。

然后make rootfs进行编译。

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage initrd rootfs.img -s -S
gdb
file linux-3.18.6/vmlinux //加载内核
target remote:1234 //链接到menu os里
b sys_time
c

context_switch 实现进程上下文切换

这里面包装了使用某种进程调度策略,选择了下一个进程,从运行队列中挑出了一个进程作为next进行切换

查看context_switch详细内容



switch_to

指令流的切换

31#define switch_to(prev, next, last)
32do {
33 /*
34 * Context-switching clobbers all registers, so we clobber
35 * them explicitly, via unused output variables.
36 * (EAX and EBP is not listed because EBP is saved/restored
37 * explicitly for wchan access and EAX is the return value of
38 * __switch_to())
39 */
40 unsigned long ebx, ecx, edx, esi, edi;
41
42 asm volatile("pushfl\n\t" /* 保存当前进程flags */
43 "pushl %%ebp\n\t" /* 当前进程堆栈基址压栈*/ 44 "movl %%esp,%[prev_sp]\n\t" /*保存ESP,将当前堆栈栈顶保存起来*/
45 "movl %[next_sp],%%esp\n\t" /*更新ESP,将下一栈顶保存到ESP中*/ //完成内核堆栈的切换
46 "movl $1f,%[prev_ip]\n\t" /*保存当前进程EIP*/
47 "pushl %[next_ip]\n\t" /*将next进程起点压入堆栈,即next进程的栈顶为起点*/
48
//完成EIP的切换
__switch_canary
//next_ip一般是$1f,对于新创建的子进程时ret_from_fork
49 "jmp __switch_to\n" /*prev进程中,设置next进程堆栈*/
//jmp不同于call是通过寄存器(a、d)传递参数
50 "1:\t" //next进程开始执行
51 "popl %%ebp\n\t"
52 "popfl\n"
53
54 /*输出变量定义*/
55 : [prev_sp] "=m" (prev->thread.sp), //[prev_sp]定义内核堆栈栈顶
56 [prev_ip] "=m" (prev->thread.ip), //[prev_ip]当前进程EIP
57 "=a" (last),
58
59 /* 要破坏的寄存器: */
60 "=b" (ebx), "=c" (ecx), "=d" (edx),
61 "=S" (esi), "=D" (edi)
62
63 __switch_canary_oparam
64
65 /* 输入变量: */
66 : [next_sp] "m" (next->thread.sp), //[next_sp]下一个内核堆栈栈顶
67 [next_ip] "m" (next->thread.ip),
68 //[next_ip]下一个进程执行起点,一般是$1f,对于新创建的子进程是ret_from_fork 69 /* regparm parameters for __switch_to(): */
70 [prev] "a" (prev),
71 [next] "d" (next) //用a、d两个寄存器传递参数
72
73 __switch_canary_iparam
74
75 : /* 重新加载段寄存器 */
76 "memory");
77} while (0)

书上内容

  1. 一个进程的地址空间与另一个进程的地址空间即使有相同的内存地址,实际上也彼此互不相干。如果父进程希望和其子进程共享地址空间,可以在调用clone()时,设置CLONE_VM标志。我们称这样的进程为线程。

  2. 内存区域可以包含各种内存对象,比如:可执行文件代码的内存映射,称为代码段(text section)。可执行文件的已初始化全局变量的内存映射,称为数据段(datasection)。包含未初始化全局变量,也就是bss段的零页(页面中的信息仝部为0值,所以可用于映射bss段等目的)的内存映射。用于进程用户空间栈(不要和进程内核栈混淆,进程的内核栈独立存在并由内核维护)的零页的内存映射。每一个诸如c库或动态连接程序等共享库的代码段、数据段和bss也会被载人进程的地址空间。任何内存映射文件。任何共享内存段。任何匿名的内存映射,比如由malloc()分配的内存。

  3. 内核使用内存描述符结构体表示进程的地址空间,该结构包含了和进程地址空间有关的全部信息。

  4. VMA具体操作方法

void open (struct vm area struct *area) 当指定的内存区域被加人到一个地址空间时,该函数被调用。

void close(struct vm_area struct *area)当指定的内存区域从地址空间删除时,该函数被调用。

int fault(struct vm area sruct *area, struct 0 fault *vmf) 当没有出现在物理内存中的页面被访问时,该函数被页面故障处理调用。

int page mkwrite(struct vm_area sruct *area, struct vrn fault *vmf) 当某个页面为只读页面时,该函数被页面故障处理调用。

int access(struct vm_area struct *Vtna, unsigned long address, void *buf,int len, int write) 当get user-pages()函数调用失败时,该函数被access—process—vm()函数调用。

  1. find_vma()函数在指定的地址空间中搜索第一个vm_end大于addrd的内存区域。find_vma_prev()函数和find_vma()工作方式相同,但是它返回第一个小于adddr的VMA。find_vma_intersection()函数返回第一个和指定地址区间相交的VMA。
  2. Linux中使用三级页表完成地址转换:顶级页表是页全局目录(PGD),二级页表是中间页目录(PMI),最后一级的页表简称页表,其中包含了pte_t类型的页表项,该页表项指向物理页面。
  3. 缓存一般被实现成下面三种策略之一:第一种策略称为不缓存(nowrite),也就是说高速缓存不去缓存任何写操作。第二种策略,写操作将自动更新内存缓存,同时也更新磁盘文件。第三种策略,也是Linux所采用的,称为“回写"。
  4. 在以下三种情况发生时,脏页被写回磁盘:当空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘以便释放内存,因为只有干净(不脏的)内存才可以被回收。当内存干净后,内核就可以从缓存清理数据,然后收缩缓存,最终释放出更多的内存。当脏页在内存中驻留时间超过一个特定的阈值时,内核必须将超时的脏页写回磁盘,以确保脏页不会无限期地驻留在内存中。当用户进程调用sync()和fsync()系统调用时,内核会按要求执行回写动作。
  5. pdflush内核线程:负责定时将脏数据刷入磁盘。pdflush线程可以有多个处理不同的设备列队。

20169212《Linux内核原理与分析》 第十周作业的更多相关文章

  1. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  2. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

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

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  4. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  5. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  6. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

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

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

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

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. iTunes

    我们的电脑都要下载比较好的显卡那项 https://support.apple.com/zh_CN/downloads/itunes

  2. POJ 3070 Fibonacci

    Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. F ...

  3. 传感器介绍之DHT11

    一.DHT11介绍 DHT11 数字温湿度传感器,如图所示,是一款含有已校准数字信号输出的温湿度复合传感器.它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性.传 ...

  4. No module named 'urllib2'

    import urllib2 response = urllib2.urlopen('http://www.baidu.com/') html = response.read() print html ...

  5. jquery.validate 使用--验证表单隐藏域

    jQuery validate很不错的一个jQuery表单验证插件.升级到了1.9版的后,发现隐藏表单域验证全部失效,特别是在jquery.ui.tabs.min.js构造的Tabs里的验证. 是因为 ...

  6. eclipse gradle插件(buildship)的安装和使用

    一.下载gradle https://gradle.org/gradle-download/ 二.手动安装gradle插件 我选择的是buildship,经过实际使用,体验很好. 插件的下载地址是: ...

  7. 微信小程序-视图列表渲染

    wx:for 在组件上使用wx:for控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件. 默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item <view ...

  8. 数据源增量处理(Delta Proess)三大属性:Recod Mode、Delta Type、Serialization

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  9. latex给表格添加注释

    给表格加注释的确是很多TeX用户不好用的地方,这里提供一个样式和代码,或许对于你的学习使用有所帮助,样式如下: 代码如下: \documentclass[11pt,a4paper,english]{a ...

  10. org.dbunit.database.ambiguoustablenameexception

    对于一个数据库下面多个shema的情况,如果使用DBUNIT配置会出现,上面的错误,不清楚的表名,解决如下 增加红色的shema指定 参考:http://stackoverflow.com/quest ...