第七章
操作系统是由中断驱动的。
中断分为外部中断和内部中断。
外部中断分为可屏蔽中断和不可屏蔽中断,内部中断分为软中断和异常。
外部中断
来自CPU外部的中断。
可屏蔽中断:通过INTR引脚进入CPU,外部设备如硬盘、网卡、打印机等发出的中断
CPU可以不理会,因为不会宕机。
Linux把中断分为上半部和下半部分开处理,把中断立即需要执行的部分划分到上半部,不紧急的部分划分到下半部。上半部是在关中断的情况下执行的。
不可屏蔽中断:通过NMI引脚进入CPU,它表示系统发生了致命的错误。
三种常见原因:1.内存读写错误 2电源掉电 3总线奇偶校验错误
内部中断
软中断:软件主动发起的中断
异常:指令执行期间CPU内部产生的错误引起的。
中断描述符表(IDT)
IDT中有中断描述符,还有任务门描述符和陷阱门描述符。
这些描述符都是门,门是通往另一段程序的入口。门描述符中添加了各种属性,就是进门的条件。
中断处理过程:
CPU外:
CPU内:
1.处理器根据中断向量号定位中断描述符
2.处理器进行特权级检查
3执行中断处理程序
如下图:
这里我突然想起个问题,访问内核地址空间不需要经过页表吗?因为内核地址空间一般是连续的。
答案是也需要,不过是内核页表。一旦CPU进入了保护模式,开启分页机制,不管在内核空间,还是用户空间,都是使用虚拟地址进行寻址了。
在32位的系统,内核页表记录内核对高端内存访问而进行的映射关系。因为现代 CPU 的寻址不能绕过 MMU。不过内核空间和用户空间不同,它一般不做 swap,也就没有 page fault,而且它一般不会把连续的虚拟地址空间映射成不连续的物理空间,一般只是做一个 offset。
8259A编程
一个中断控制器
8253编程
一个定时器,打节拍,最重要功能:定时向处理器发时间中断
第八章
makefile编写
略
实现ASSERT
因为要打印屏幕,所以最好关中断
开中断:原理是执行sti指令把eflags中的IF位置1
关中断:原理是执行cli指令把eflags中的IF位置0
实现字符串操作函数
包括memset、memcpy、strcpy、strlen、strcmp、strcat、strchr(从左到右查找字符串str中首次出现字符ch的地址)、strchrs(查找在字符串str中ch出现的次数)
位图实现
略
内存管理
每个任务(内核和用户)都要维护自己的虚拟地址池。
声明了一个叫virtual_addr的结构体用来表示虚拟内存池,存储一个位图结构和虚拟地址起始地址。
实现了malloc_page函数,2个参数,一个是pf,用来指明内存池(内核还是用户),一个是pg_cnt,用来指明页数,此函数的功能是在pf指向的内存池中分配pg_cnt个页,成功则返回虚拟地址,失败则返回NULL。
此函数干了三件事:
1.通过vaddr_get在虚拟内存池中申请虚拟地址
2.通过palloc在物理内存池中申请物理页
3.通过page_table_add将上两步得到的虚拟地址和物理地址在页表中完成映射
tips
在ubuntu下用gcc编译链接,出现错误
undefined reference to `__stack_chk_fail’
解决方法:
add -fno-stack-protector to your CFLAGS.
第九章
PCB
每个进程都有自己的PCB,所有PCB放到一张表格中维护,这就是进程表。调度器可以根据这张表选择处理器运行的进程。
这里写图片描述
寄存器映像用来保存进程的现场,用于进程切换。
PCB最顶端为线程在0特权级下所用的栈。
实现线程
两种实现方式
1.用户空间实现,线程表就在用户进程中,用户进程要专门写个线程用作线程调度器。
优点:
调度算法自己实现
线程切换不用陷入内核态装载寄存器映像
缺点:
某个线程出现阻塞,整个进程都会阻塞(操作系统不知道进程中存在线程)
2.内核空间实现,线程表就在内核中,该线程由操作系统一调度,无论线程属于内核还是用户空间。
优点:
内核提供的线程相当于让进程多占用了处理器资源(因为一个进程有多个线程可以放上调度器),提速明显。
进程中某一线程阻塞后,只会阻塞这一个线程,变相提速。
缺点:
会陷入内核态,增加了一些保护现场的操作,但比起提速可以忽略。
本文用第二种实现方法,Linux中严格来说,用户空间是没有Thread这个概念的,Thread的相关实现是gcc等提供的模拟thread, gcc是使用了clone这个系统调用,利用linux的轻量级进程实现了类似thread的库。下面的链接有详细介绍
http://www.360doc.com/content/13/1008/11/13047933_319789998.shtml
线程PCB由双向链表串联
任务调度
在 schedule 中要判断当前线程是出于什么原因才“沦落到”要被换下处理器
的地步 。 是线程的时间片到期了?还是线程时间片未到,但它被阻塞了,以至于不得不换下处理器?其实这就是查看线程的状态,如果线程的状态为TASK RUNNING ,这说明时间片到期了,将其 ticks 重新赋值为它的优先级 prio ,将其状态由 TASK_RUNNING 置为 TASK_READY ,并将其加入到就绪队列的末尾。如果状态为其他,这不需要任何操作,因为调度器是从就绪队列中取出下一个线程,而当前运行的钱程并不在就绪队列中。
完整的调度需要三部分的配合:
1.时钟中断函数
2.调度器schedule
3.任务切换函数switch_to
第十章
出现GP错误原因:多个线程访问光标寄存器,一个线程更新完高8位后被换下,另一个线程通知显卡马上要写来的是寄存器高8位,这时被换下,第一个线程继续写低8位,但显卡认为这是高8位。需要实现锁来同步
信号量
一个全局共享变量,变量的加减必须是原子操作,需要关中断来保证
锁
本文的锁是用二元信号量实现的
---------------------
作者:月黑风高云游诗人
来源:CSDN
原文:https://blog.csdn.net/lqygame/article/details/73824702
版权声明:本文为博主原创文章,转载请附上博文链接!