第一章:计算机是如何工作的
计算机大部分都是用冯诺依曼体系结构,即存储程序计算机。
两个层面: 1.硬件: cpu(IP寄存器:指针,指向内存的某块区域)——总线——内存(代码与数据) 2.程序员: 内存存储指令与数据, CPU解释执行指令 计算机在执行程序时须先将要执行的相关程序和数据放入内存储器中, 在执行程序时CPU根据当前程序指针寄存器的内容取出指令并执行指令, 然后再取出下一条指令并执行,如此循环下去直到程序结束指令时才停 止执行。其工作过程就是不断地取指令和执行指令的过程,最后将计算 的结果放入指令指定的存储器地址中。
第二章:操作系统是如何工作的
学习内容:
函数调用堆栈
借助Linux内核部分源代码模拟存储程序计算机工作模型及时钟中断
构造一个简单的操作系统内核
通过内核源代码了解,从环境搭建起来,mystartkernerl开始初始化至完成,启动0号进程, 利用时间片,每个进程每隔1000万次,判断是否需要调度,调度使用myshedule()进行调度. 设置时间片的大小,时间片用完时,设置一下调度标识。 if(timecount%1000==0&&myneedsched!=1) 当进程执行到的时候,发现 needsched==1,就执行myschedule,调度分两种情况,一种是下一个进程正在进行的, 另一种是从未调度过的,进程从未执行过,执行起来特殊点,将状态转成运行时状态,作为当 前执行的进程,esp,ebp指向同一位置两种汇编代码略有不同,是关键。
第三章:构造一个简单的Linux系统MenuOS
Linux的启动过程:内核启动相关的代码基本在init目录下,init/main.c内核启动起点 start_kernel函数相当于普通C程序中的main函数,搭建环境,启动内核。 start_kernel的最后一句rest_init创建0号进程里的kernel_init创建1号进程, run_init_process创建1号进程,是第1个用户态进程。pid_kernel_thread(kthreadd,..)用内核线程管理系统资源(创建其他内核服务线程)。 rest_init启动完后,call .. cpu_idl , call_startup_entry,cpu_idle_loop里面while(1)0号进程,当系统无进程须执行时就调度到idle进程
课本第二章:Linux内核源代码的获取、解压、配置、编译与安装
第四章:系统调用
1
|
系统调用通过软中断向内核发出明确的请求。(eg:sysenter) |
1
2
3
4
5
6
7
8
9
10
|
操作系统提供API和系统调用的关系 Libc库定义的一些API引用封装例程(wrapper routine). 一般每个系统调用对应一个封装例程。 库再用这些封装例程定义给用户的API. 不是每个API对应一个特定系统调用 返回值:1.大部分封装例程返回一个整数,值含义依赖于相应的系统调用; 2.-1,多数情况——内核不满足进程请求。 3.Libc定义errno变量包含特定出错码 |
使用库函数触发一个系统调用 C代码中嵌入汇编代码的写法 使用嵌入式汇编代码触发同一个系统调用 系统调用在内核代码中的处理过程
应用程序应该以某种方式(库函数或汇编代码)通知系统 告诉内核自己需要执行一个系统调用,希望系统切换到内核态。 内核就可以代表应用程序在内核空间执行系统调用。 通知内核的机制是靠软中断实现的: 通过引发异常将系统切换内核态执行异常处理程序(系统调用处理程序)。
自学课本第五章 系统调用 系统调用与API的异同 系统调用触发过程、参数传递
第五章 进程的描述和进程的创建
进程提供两种虚拟机制:虚拟处理器和虚拟内存
PS:线程之间可以共享虚拟内存,但每个都拥有各自的虚拟处理器 1.fork()创建新进程,父进程用fork创建子进程。fork系统调用从内核返回两次:一次回到父进程,一次回到子进程。 2.exec()可以创建新的地址空间,把新的程序载入其中 3.在Linux内核中,fork()实际有clone()系统调用实现的。 4.程序通过exit()系统调用退出执行。最终中介进程并将其占用的资源释放掉。 5.父进程通过wait4()系统调用查询子进程是否终结,这使得进程拥有了等待特定进程执行 完毕的能力。
第六章:程序和进程
进程描述符PCB----task_struct数据结构
操作系统:1.进程管理 2.内存管理 3 文件系统
新进程如何创建和修改task_struct数据结构
1.复制当前进程(创建新进程通过复制当前进程来实现) 2.给新进程分配新的内核堆栈 3.修改复制过来的进程数据(如pid,状态链表,内核堆栈,ip,sp)
进程:处于执行期的程序以及相关的资源的总称。
1.fork()创建新进程,父进程用fork创建子进程。fork系统调用从内核返回两次:一次回到父进程,一次回到子进程。 2.在Linux内核中,fork()实际有clone()系统调用实现的。 3.程序通过exit()系统调用退出执行。最终中介进程并将其占用的资源释放掉。
进程描述符及任务结构
内核把进程的列表存放在任务队列的双向循环列表中 链表中每一项都是类型为task_struck,称为进程描述符的结构,该结构定义在<linux/sched.h>文件中
进程状态
(1)TASK_RUNNING(运行)——进程是可执行。进程在用户空间中执行的唯一可能的状态,也可以应用到内核空间中正在执行的 (2)TSK_INTERRUPTIBLE (3) TASK_UNINTERRUPTIBLE (4)_TASK_TRACED (5)_TASK_STOOPED
进程上下文
一般程序在用户空间执行。当一个程序调执行了系统调用或者触发了某个异常,它就陷入了内核空间。成内核“代表进程执行”,并处于进程上下文中。
进程家族数
所有的进程都是PID为1的init进程的后代,内核在系统启动的最后阶段启动init进程。
Linux系统创建一个新进程的理解
1.fork实际开销是复制父进程的页表以及给子进程创建唯一的进程描述符** 2.Linux通过clone()系统调用实现fork()** 3.fork(),vfork(),和clone()库函数都是根据各自需要的参数标志去调用clone(),然后由clone()调用do_fork** do_fork函数调用了copy_process()函数,然后让进程执行 Linux通过复制父进程创建新进程,fork、vfork、clone都是通过do_exit实现进程的创建。 -A.复制一个PCB -B.给新进程分配一个新的内核堆栈(复制了thread_info,不是复制了内核堆栈) -C.修改复制的数据,即子进程初始化。 从用户态代码看父进程和子进程各返回一次,而子进程从ret_from_fork函数开始执行,从函数中跳转到syscall_exit,即system_call中的语句。
第七章 进程的切换和执行过程概览
用户态堆栈和内核态堆栈
进程上下文的保存和恢复
进程切换的关键代码switch_to分析
内核是各种中断处理过程和内核线程的集合 (1)中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule(); (2)内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度; (3)用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。 中断和中断返回:有一个CPU上下文的切换 进程调度过程中:有一个进程上下文的切换,从一个进程的内核态堆栈切换到另一个进程的内核态堆栈。
自学课本第四章 进程调度
期中总结
前八周重点与难点 :
感想:期中感想,这几周的重点在于进程切换这段汇编代码,堆栈的变化的分析,老是记得有点混,所以特此百度的堆栈变化图片,以便查阅复习。