操作系统01-启动-进程-IO

操作系统 专栏收录该内容
1 篇文章 0 订阅

操作系统概述

1. 现代PC机的组成


一个微型计算机的组成如上图所示:
名词解释:
MCH:内存控制器中心,即北桥芯片,用于连接CPU、MM、AGP视频接口,这些设备具有很高的传输速率。MCH还起着MM控制作用。(原书中讲述存储器控制作用,这里的存储器本人认为是MM。)
ICH:IO控制器中心,即南桥芯片。用于连接SATA、网络接口、USB、PCI-E等低中速接口(设备中、低速)。

操作系统内核模块

操作系统的内核模块主要有以下基本组成,其依赖关系如下图所示:
在这里插入图片描述

  1. 进程调度
  2. 进程间通信
  3. 内存管理
  4. 文件系统
  5. 网络接口
    从上图应该可以意识到,进程管理和内存管理应当是相当复杂的逻辑过程。

计算机的启动过程

  1. BIOS启动设置
    当计算机系统上电开启或者按了机箱上复位按钮之后,CPU会自动把代码寄存器CS设置为0xF000,其段基址为0xFFFF0000,段长为64KB,而IP被设置为0xFFF0,此时CPU代码指针指向0xFFFFFFF0处,即4G空间最后一个64KB中的最后16字节处,即ROM BIOS的地址,并且BIOS在此处有一个JMP跳转指令,跳转到BIOS代码中64KB范围内的某一条指令中,并用一种称为32位大模式(Big Mode)技术,将将数据段寄存器的访问范围设置成4G,这样便可以在整个内存空间(0-4G)内执行和操作数据。

  2. BIOS硬件检测与初始化
    此后BIOS开始执行硬件检测和初始化操作,如果出现问题,就会阻塞到那个地方(陷入死循环,并触发警报),如果一切正常,BIOS就会将本身的代码和数据复制到,内存低端1M末端的最后64K处,然后跳转到这个地方继续执行。

  3. 加载引导程序bootsect并载入setup
    下一步,计算机从选择好的存储设备中(选择系统启动盘)读取起始的512Byte,也就是主引导记录(MBR,master boot record),一般引导程序都会分成两个部分,一部分写在MBR中,一部分写在MBR后面的磁道中(因MBR太小,才512Byte),程序执行MBR中的引导程序,将后序的引导程序加载进入内存(0x7c00),引导加载程序存储有操作系统(OS)的相关信息,比如操作系统名称、内核所在位置等,具体启动那个操作系统,由用户来选择。然后调用BIOS从硬盘或者其他块设备把操作系统引导程序加载到内存中,首先加载setup.s中的程序,然后调用BIOS例程,装载内核影响的其他部分分,然后跳转到setup部分开始执行。

  4. setup.s
    Setup函数执行初始化计算机中的硬件设备并为内核程序的执行建立环境,并调用BIOS例程,建立描述系统物理内存布局的表,并执行以下操作:
    (1) 启动A20pn;
    (2) 建立临时中断描述符表idt和全局描述符表gdt
    (3) 对于可编程控制中断进行重新编辑;
    (4)设置CR0状态寄存器将CPU从实地址模式切换到保护模式,并禁止分页功能。

  5. Head.s
    该程序主要功能是加载内核代码head,并设置好临时GDT,将处理器设置成运行在保护模式下,然后跳转到head处去执行内核代码。首先boot程序利用BIOS中断int 0x13将内核代码读入内存0x10000(64KB)处,然后复制到0开始处,最后设置CR0控制寄存器开启保护运行模式标志,并跳转到内存0处开始执行head代码。

  6. 系统初始化
    head.s程序运行在32位保护模式下,其主要任务有
    初始化段寄存器和临时堆栈,重新设置GDT表,设置系统定时器芯片,重新设置IDT表,并设置时钟和系统调用中断门,如果设置CR0开启分页,还需要为系统建立页目录,并设置CR3寄存器指向页目录基址,然后建立起Linux的第一个进程(进程0),
    用非空中断处理函数填充idt表,识别处理器模式,并将GDT和IDT地址加载到gdtr和idtr中,最后跳转到start_kernel()。
    首先初始化调度器,初始化内存区域,并对idt做最后的初始化,对时间日期做初始化,最后调用kernel_thread()启动进程1(init进程)的内核线程,然后该线程再去创建其他的内核线程执行程序。

进程管理

操作系统对于内存的管理进程管理主要依托进程控制块(PCB,Process Control Block),需要注意的是,在Linux系统中,任务(task)和进程(process)是两个相同的术语,task_struct就是PCB,是系统对进程控制的唯一手段,也是最有效的手段。在Linux2.4中,Linux为每个新创建的进程动态的分配一个task_struct结构,系统所允许的最大进程数是由机器所拥有的物理内存的大小决定的,GDT中的TSS正是task_struct中的一个内部属性。
由于计算机系统的有限的资源和复杂的体系,进程间的关系既有竞争,又有协作;对资源的使用既有独占(exclusion),又有共享(share)。为了解决进程对资源使用的一致性问题,引入了锁的概念,锁内的操作属于原子操作。然后这又增加了进程之间关系的复杂性。由于进程之间复杂的关系,导致进程容易出现两种异常状态:死锁和饥饿。为了解决进程出现的异常状态,又提出了以下解决办法,使用进程调度算法来尽量规避饥饿现象,提高系统的的运行效率和吞吐量,同时引入了一系列的规避死锁的策略,以及死锁发生后,解决死锁的策略。

  1. 进程调度算法

    FCFS(先来先服务)
    SJF(最短作业优先)
    Priority(优先级调度)
    时间片轮转
    多级反馈优先级队列

  2. 死锁发生的原因和条件
    竞争:两个或多个线程争相执行同一段代码或访问同一资源的现象。
    临界区:可能造成竞争的共享代码段或资源。
    互斥:在任何时刻都只能能有一个线程在临界区中的现象。

原因:

系统资源不足。
进程调度顺序不合适。
资源分配不当。

条件

资源有限
持有等待
不可抢占
循环等待

  1. 死锁的应对方法
    (1)顺其自然不予理睬
    (2)死锁的检测与恢复

     1. 干掉某个线程,将其资源瓜分
     2. 时光倒流
    

    (3)死锁的动态避免
    在每次进行资源分配时,必须经过仔细计算,确保该资源请求批准后系统不会进入死锁或潜在的死锁状态。
    (4)死锁的静态防止
    该策略的中心思想是:清除死锁发生的土壤(即死锁的4个必要条件),只要清除4个必要条件中的一个,那么死锁将无法发生。

  1. 清除资源独占条件:一是增加资源到所有线程满足的资源需要,但这并不实际,因为资源是有限的;二是将资源变为共享,但并不适合与所有的资源(例如键盘输入就无法共享)。
  2. 清除保持和请求条件:一个线程必须一次请求其所需的所有资源,而不是一般情况下的请求一点资源做一点事情。由于一个线程一次就获得了其所需的所有资源,该线程就可以顺利执行,不会发生死锁。
  3. 清除非抢占条件:允许抢占资源,也就是说可以从一个线程手上将资源抢夺过来。
  4. 清除循环等待条件:出现循环等待是因为线程请求资源的顺序是随机的,所以只要约定线程对资源的使用顺序,那么死锁就不能发生。

规避死锁  
(1)哲学家就餐问题
(2)银行家算法
(3)生产者消费者模型

  1. 进程间通信

1.管道
特点:半双工的,只存在于内存中,对于它的读写也可以使用普通的read、write 等函数,但不属于文件系统,且只存在于内存中。
缺点:速度慢,容量有限,只有父子/兄弟进程能通讯,先进先出。
2.FIFO
特点:可以在任何进程之间交换数据,且有路径名与之相关联,并以一种特殊设备文件形式存在于文件系统中。先进先出。
缺点:速度慢
3.消息队列:
特点:
消息的链接表,存放在内核中,一个消息队列由队列ID标识。面向记录,具有特定的格式及特定的优先级,独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除,消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
缺点:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
4.信号量:
特点:是一个计数器,用于实现进程间的互斥与同步,不能传递复杂消息,若要在进程间传递数据需要结合共享内存。信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。支持信号量组。

5.共享内存区:
特点:能够很容易控制容量,速度快,直接对内存进行存取,需要进行同步,信号量+共享内存常常一起使用。
却带你:需要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存

I/O端口和寻址和访问控制方式

IO端口设计之初,就被设计成要通过寄存器的方式同cpu进行通信,其内部有专门用于数据交换的寄存器,只不过这些寄存器在IO接口之中,为了区别cpu内部的寄存器,IO端口中的寄存器被称作端口。

  1. I/O端口寻址方式
    (1)端口统一寻址
    把I/O控制器中的端口地址归入存储器寻址地址空间范围内。
    (2)独立编址
    把I/O控制器和控制卡的寻址空间单独作为一个独立的地址空间对待,成为I/O地址空间。

  2. 接口访问控制
    CPU与IO设备间的数据传输方式主要有四种:
    (1)轮询方式
    由CPU不断的向控制器发送测试指令,直到读出数据。
    (2)中断控制
    引入:由于轮询占用CPU时间过长,造成CPU资源的浪费,引入了中断控制来控制CPU与外不设备的交互。
    工作方式:系统根据IO请求,向IO设备发出一条I/O命令,然后CPU继续执行其他工作,当I/O设备完成操作后,由控制器通过控制总线向CPU(8259A)发送一条中断信号,当该中断信号被选中处理后,CPU会根据中断向量表(IDT,中断描述符表)来寻址相应的中断处理服务过程的入口地址,然后进入中断处理程序来处理相关的中断请求。
    相关:采用中断控制方式时,系统应开启中断服务,并在head.s加载时,设置好IDT。
    (3)DMA(Direct Memory Access)
    引入:由于中断控制是按字(节)读取设备数据,每次都要先读入CPU,然后才能放入内存,且每次中断的开始和结束都需要CPU的参与,因此仍旧会占用CPU计算周期,不使用大批量数据的传输,因此引入了DMA。
    工作方式:
    CPU向DMA控制器发送读命令,并同时给其发送数据传输源地址和目标地址的起始位置以及数据长度,启动DMA控制器进行数据传输,此时CPU继续执行其他工作,DMA控制器按字节将数据从源地址传输到目标地址,直至传输完成向CPU发送一个中断请求,告知CPU已完成。

    (4)通道控制方式
    引入目的:进一步减少CPU对I/O操作的干预;
    以多个块为单位进行数据传送;
    一次传送多组数据到多个不同的内存区域。

参考资料:
《Linux内核0.11完全注释》
《操作系统概念与设计第六版》
操作系统18———IO系统之中断机构和设备驱动程序
GRUB——系统的引导程序简单介绍
很好的linux启动说明( bootsect.S、setup.S、head.S)
setup.s 分析—— Linux-0.11 学习笔记(二)
进程控制块PCB结构 task_struct 描述
操作系统核心原理-4.线程原理(下):死锁基础原理
进程间通信(IPC)介绍
进程间的五种通信方式介绍

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值