Linux 内核深入理解 - 绪论

目录

多用户系统

进程

内核体系架构

文件系统概述

Base

硬链接和软链接

Unix文件类型

文件描述符与索引节点

文件操作的系统调用

Unix内核简述

进程的实现

可重入内核

进程地址空间

同步和临界区

信号与进程之间的通信

进程管理

内存管理

虚拟内存

随机访问存储器的使用

内核分配器

进程的虚拟地址空间处理

高速缓存


任何计算机系统都包含一个名为操作系统的基本程序集合!在这个集合里最重要的程序被称为内核。当操作系统启动的时候内核会被装进RAM当中。

操作系统说来说去就是两个主要目标:他充当底层的物理部件好用的抽象,给予上层服务一个好的平台

  • 与硬件部分进行交互,为包含在硬件平台上的所有底层可编程部件提供服务!

  • 为运行在计算机系统上层的应用程序即所谓的用户程序提供一个执行环境!

为了保障安全。我们的操作系统引入了一组概念,也就是用户模式和特权模式。我们会在之后的博客中有所涉及:简单的讲:一些涉及到底层硬件访问的操作需要在特权模式下进行,反之则会在用户模式下进行!程序的运行有时会在两者之间进行频繁的切换,从而更好地完成程序所提供的服务。

多用户系统

多用户系统就是一台能够并发的执行和独立的执行分别属于两个或者多个用户的若干应用程序的计算机。

并发意味着几个应用程序同时处于活动状态执行自己应用进程所需要执行的任务,而并不需要考虑其它应用程序在做什么!

多用户操作系统必须包含以下几个特点

  1. 核实用户身份的认证机制

  2. 防止有错误的用户程序妨碍其它应用程序在系统中运行的保护机制

  3. 防止有恶意的用户程序干涉或者窥视其他用户的活动的保护机制

  4. 限制分配给每个用户的资源数的记账机制

于是我们会把用户进行分为用户组在多用户系统中每个用户在机器上都会有自己的私用空间!典型的它需要一些磁盘空间来存储文件!以及接受私人邮件信息等!这一些都需要分层的特权来实现一定的保护机制!

所有的用户都用一个唯一的数字来进行标识,也就是用户标识符!通常一个计算机系统只能够由有限个人来使用。当其中的某个用户开始一个工作session的时候,操作系统会要求输入一个登录口令。如果用户输入无效则会拒绝登录,从而保障用户的隐私。

进程

所有的操作系统都有一个基本的抽象:也就是进程!

进程可以定义为一个程序执行时的一个实例或者一个运行程序所使用的上下文。在传统的操作系统中:一个进程在地址空间中执行一个独立的指令序列,地址空间是允许引用的内存地址集合。

在多用户系统中必须实施一种执行环境:在这样的环境里,几个进程可以并发的活动,并能竞争系统资源。允许进程并发活动的系统叫多道程序系统或多处理系统。

作为一个单处理器系统上,只有一个进程能够占用CPU。这也就意味着实际上只有一条执行流,那么他们是如何实现一种感官上的并发呢?

这需要操作系统的进程是抢占式的!也就是说操作系统需要记录每个进程所占有的CPU时间,并且周期性地激活调度程序。以保证感官上的并发!Unix操作系统是一个具有抢占式进程的多处理操作系统。换而言之,Unix操作系统是一个抢占式的多道处理操作系统!

内核体系架构

大部分Unix内核是单块结构的!也就是说它们属于宏内核操作系统!每一个内核层都被集成到整个内核程序中,并且代表当前进程是在内核态下运行!相反微内核操作系统只需要内核有一个很小的函数:即通常包括几个同步原语,一个简单的调度程序,和IPC通信机制。运行在微内核上的几个系统进程实现宏内核操作系统实现的功能:如内存分配,设备驱动,系统调用处理等。

事实证明微内核操作系统的效率比较低,因为它需要花费大量的时间进行进程之间的通信。不过微内核操作系统比单核快内核有一定的理论优势,因为它强迫系统程序员采用模块化的方法来构建程序。所以Linux充分吸收了微内核操作系统的优点:提供了一个模块的机制!模块是这样的一个目标文件:它上面的代码可以在运行时链接到内核,或者从内核中解除链接。这种目标代码通常是由一组函数组成,从而来实现文件系统,驱动程序,或其他内核上层功能。

使用模块的主要优点有:

  • 首先它保证了一种模块化的方法

  • 其次它实现了一种平台无关性

  • 接着它可以节省内存使用,当我们不再需要他的时候可以动态的进行解除,同样的在我们需要它的时候可以动态的进行加载

  • 最后他无性能损失!

文件系统概述

Base

我们这样定义文件:

Unix文件是一个以字节序列组成的信息载体!

内核并不负责解释自己文件的内容!

文件或目录名由除/和空字符之外的任意ASCII字符序列组成!大多数文件系统对文件名的长度都会有所限制。(比如说我们的常见的Ext2是255,你不可以把文件名搞得太长!)

这个可以查看自己的ulimit值

与树的根相对应的目录被称为根目录,按照惯例它的名字是/

在同一目录中的文件名并不能相同,而在不同目录中的文件名则可以相同(因为可以通过连接不同的目录文件名从而唯一的标识这个文件)

Unix的每个进程都有一个工作目录(pwd,想你的shell怎么区分你当前在文件系统海洋的何处!)

当标识文件名时引用符号...:它们分别标识当前工作目录,和父目录。如果当前工作目录是根目录,那么这两个目录就是完全一致的!

硬链接和软链接

包含在文件目录的文件名就是一个文件的硬链接,或者简称链接。

在同一目录或不同的目录中同一个文件可以有好几个链接!因此对应几个文件名。

他有两方面的限制:首先他不允许用户给目录创建硬链接,因为这可能会把目录树变为环形图,从而就不可能通过名字来定位一个文件!

其次只有在同一文件系统中的文件才能创建链接!这带来比较大的限制!因为现在操作系统可能包含了多种文件系统!这些文件系统位于不同的磁盘和根目录或分区,用户也许无法知道它们的物理划分!

为了克服这些限制则引入了软链接,或者是符号链接。符号链接是短文件这些文件包含了另一个文件的任意路径名。路径名可以指向位于任意一个操作系统文件系统的任意文件或目录,甚至可以指向一个根本不存在的文件!

Unix文件类型

Unix文件类型可以是以下列的一种:

  • 普通文件

  • 目录

  • 符号链接

  • 面向块的设备文件

  • 面向字符的设备文件

  • 管道

  • 命名管道

  • 套接字

前三种文件类型是所有Unix文件系统的基本类型

文件描述符与索引节点

Unix对文件的内容和描述文件的信息给出了清楚的区分!除了设备文件和特殊文件系统外,每个文件都由字符序列组成!文件内容不包含任何克控制信息!如文件长度或者文件结束符。

我们使用索引节点在内核中表示文件,从而代表一大块文件数据进行管理!

文件也有访问权限和文件模式:文件的潜在用户有三种

  1. 作为文件所有者的

  2. 用户同组用户但是不包括所有者

  3. 所有剩下的用户

文件有三种访问类型:读,写与执行!

文件操作的系统调用

有open, read, write, close等,这里我们暂时不加讨论!(可以参考Linux系统编程手册学习!)

Unix内核简述

我们下面重点来讨论Unix内核,首先我们要说的是进程/内核模式:

如前所述CPU既可以运行在用户态,也可以运行在内核态。当一个程序在用户态下执行的时候,它并不能直接访问内核的数据结构和程序,然而当应用程序在内核态下运行时则不再会有这些限制。当应用程序有所请求内核服务时,内核才会把这个进程流陷入内核态。当完成任务时把进程送回用户态。进程是动态的实体,在系统内通常只有有限的生存期。创建,撤销,同步现有进程的任务都要委托给内核中的一组例程来完成!

内核本身不是一个进程,而是进程的管理者。除用户进程之外:Unix系统还包括几个所谓的内核进程的特权进程。它们具有以下特点:

  • 它们以内核态运行在内核地址空间

  • 他们不与用户直接交互,因此不需要终端设备!

  • 他们通常在系统启动时创建然后一直处于活跃状态直到系统关闭

进程的实现

为了让内核管理进程所有的进程都需要用一个进程描述符进行抽象。当内核暂停一个进程的时候,就会把几个相关处理器寄存器的内容保存在进程描述符里,包括:

  • 程序计数器和栈指针寄存器

  • 通用寄存器

  • 浮点寄存器

  • 包括CPU状态信息的处理器控制器

  • 用来跟踪进程对RAM访问的内存管理寄存器

当内核决定恢复一个进程的时候,他用进程描述符中合适的字段来装载CPU寄存器。因为程序计数器中所存的值指向下一条将要执行的指令,所以进程恐怕停止的地方恢复执行!

可重入内核

所有的Unix内核都是可重入的!

这意味着若干个进程可以同时在内核态下执行,当然在单处理器系统上只有一个进程在真正的执行!但是有许多进程可能在等待CPU或者某一个IO操作完成时在内核台下被阻塞!

提供可重入的一种方式就是编写函数,以便这些函数只能更改局部变量,而不更改全局数据结构。这样的函数叫做可重入函数!

如果一个硬件中断发生,可重入内核可以挂起正在执行的进程,即使这个进程处于内核态

在最简单的情况下CPU从第一条指令到最后一条指令顺序的执行内核控制路径。也就是表示内核处理系统调用异常或中断所执行的指令序列

然而当下述事情发生之一,CPU交错执行内核控制路径:

  • 运行在用户态下的进程调用了一个系统调用,而相应的内核控制路径。正是这个请求没有办法立即得到满足,然后内核控制路径调用调度程序选择一个新的进程。进行调度完成后,进程切换。发生第一个内核控制路径还没有完成,而CPU又重新执行其他的内核控制路径。在这种情况下,两条控制路径代表两个不同的进程。

  • 在执行当执行一个内核控制路径时,CPU检测到了一个异常:比如说访问了一个不在RAM中的页,那么第一个控制路径将会被挂起,而CPU开始执行合适的过程。比如说在这个例子中我们则是给那进程分配一个新页,并从磁盘中读取它的内容。当这个过程结束后第一个控制路径可以恢复执行,在这种情况下两个控制路径代表同一个进程在执行

  • 当CPU在运行一个启用了中断的内核控制路径时,一个硬件中断发生。一个控制路径还没执行完,CPU马上开始执行另一个内核控制路径来处理这个中断。当这个中断处理程序终止时,第一个内核控制路径恢复。在这个情况下两条内核控制路径运行是同一进程的可执行上下文。所花费的系统CPU时间都算给了这个进程。然而中断处理程序无需代表这个进程运行

  • 在支持抢占式调度的内核中,CPU正在运行。但是被一个更加高级的进程加入就绪队列。中断发生,调度开始。第一个内核控制路径并没有执行完。CPU代表高优先级进程又开始了另一个内核控制路径,只有把内核编译成支持抢占式调度后才有可能会出现这种情况!(你放心,咱们就是这个hhh)

进程地址空间

每个进程运行在它的私有地址空间!在用户态下运行的进程涉及到私有栈,数据区和代码区。

当在内核态运行时,进程访问内核的数据区,代码区。但是使用的是另外的私有栈。尽管看起来每个进程都在访问他们自己的私有栈,但是为了更好的进程间通信,有时进程之间也会共享部分地址空间!

Linux支持映射内存(mmap)系统调用,该系统调用将允许存放在块设备上的文件或信息映射到进程的部分地址空间。这为正常的读写传送数据方式提供了另一种选择

同步和临界区

实现可重入的内核需要利用同步机制,如果内核控制路径对某个内核数据结构进行操作被挂起时,那么其他内核控制路径就不应该对这个数据结构进行操作,否则会破坏一致性状态!

如何同步内核控制路径呢最彻底的办法就是使用非抢占式的内核(Weird huh?),其次就是禁止中断,再就是使用信号量自旋锁等内核机制来防止竞争条件!

在我们使用防止竞争条件的内核上锁机制时,需要避免死锁情况!在这里不予详细讨论!

信号与进程之间的通信

Unix信号提供了一种把系统事件报告给进程的一种机制。

有两种系统事件:

  • 异步通告

  • 同步错误或异常

如果进程并没有指定如何处理信号时,内核会按照信号的编号进行默认操作。有可能有以下五种默认操作:

终止进程

将执行上下文和进程地址空间的内容写入一个文件,并且终止进程

忽略信号

挂起进程

如果进程曾被暂停,则恢复它

进程管理

Unix在进程和它正在执行的程序之间做出了清晰的划分!fork和_exit这两个系统调用分别用来创建一个进程和终止,与exec类系统调用则是装入一个全新的程序!以及还有僵死进程。如果父进程丢失了跟踪子进程的情况,那么这个子进程就认为僵尸进程。内核会检查子进程是否终止。引入僵死进程的特殊状态是为了表示终止的进程。很多内核也实现了waitpid系统调用,让父进程可以显示的等待一个特殊的子进程。对于那些已经成为僵尸进程的进程,他们将会被一个以init的特殊系统进程收养进行清除!

内存管理

虚拟内存

所有新进的Unix系统都提供了一种有用的抽象:叫做虚拟内存!

它作为一种逻辑层处于应用程序的内在请求与硬件内存单元管理单元之间。虚拟内存有很多用途与优点,它可以让

  • 若干进程并发执行

  • 应用程序所需内存大于可用物理内存时也可以运行

  • 程序集有部分代码装入内存时进程可以执行

  • 允许每个进程访问可用物理内存的子集进程

  • 可以共享库数据或程序或函数等一个单独内存映像

  • 程序是可定位的!也就是说我们可以把程序放在物理内存中的任何地方

  • 程序员可以编写与机器无关的代码!因为他们根本不需要关心物理内存的组织结构,也就是说他把物理内存进行了一层抽象

虚拟内存子系统的主要成分是虚拟地址空间进程所用的一组内存地址。不同于物理内存地址!

随机访问存储器的使用

随机访问存储器的使用分为两个部分:

一部分被专门用来存放内核映像,另一部分则由虚拟内存系统来进行处理:

  • 用来满足内核对缓冲区描述服务及其它动态内核数据结构的请求

  • 满足进程对一般性内存区的请求即对文件内存映射的请求

  • 借助于高速缓存从磁盘或者其他缓冲设备获得较好的性能内存

内核分配器

它是一个子系统,试图满足系统中所有部分对内存的请求!其中一些请求可能来自内核其他子系统。他们需要一些内核使用的内存,还有一些请求则是来自用户程序的系统调用,以用来增加用户程序进程的地址空间!

一个好的内核内存分配器需要具有以下特点:

它必须快,实际上这是最重要的属性!因为它为所有的内核子系统所调用

必须把内存的浪费减到最少

必须努力减轻内存的碎片问题

必须能与其他内存管理子系统进行合作,以便借用和释放页框

现在已经提出了好几种内核内存分配器进程!这个可以查询其他资料!

进程的虚拟地址空间处理

进程的虚拟地址空间包括了进程可以引用的所有虚拟内存地址,内核通常用一组内存区描述符描述进程!虚拟地址空间内核分配给进程的虚拟地址空间主要有以下这几个部分:

  • 组成程序的可执行代码

  • 程序的初始化和未初始化的数据

  • 初始程序栈

  • 所需共享库的可执行代码和数据

高速缓存

物理内存的一大优势就是用来磁盘和其它块设备的高速缓存!因为磁盘访问非常的慢,这与访问内存相比实在太长!因此磁盘通常是影响系统性能的一大瓶颈所在,最早的Unix系统中早就已经实现了一个策略就是对推迟写磁盘的时间,我们将在后续的实现中看看Linux是如何做到的!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/579044.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AD修改元器件的引脚长度

这个地方的两个引脚长度不一样 双击其中的一个引脚。 修改这个位置就好了。

Docker学习(二十五)构建 Arthas 基础镜像

目录 一、简介二、构建基础镜像2.1 下载 Arthas2.2 编写 Dockerfile2.3 构建镜像2.4 创建容器2.5 测试 一、简介 Arthas 是一款由 阿里巴巴 开发的 线上监控诊断工具。通过全局视角实时查看应用负载、内存、GC、线程等信息,能在不修改代码的情况下,对业…

SUPIR图像放大模型介绍与实际测试

✨背景 正如,最顶级的料理只需要最简单的烹饪方法一样,图像放大,是设计领域里边最常面对的一个问题,在AI绘画里边也是很常见的一个课题。虽然现在放大算法、放大模型有很多,但是真的能实现的比较好的,并不…

语义分割——json文件转shp

前言 在用labelme标注遥感图像后会生成json文件,如果我们想要shp文件,下面给出了具体实现流程。 一、依赖配置 import json import geopandas as gpd from shapely.geometry import Polygon from osgeo import gdal import argparse import glob import…

【论文解析】笔触渲染生成 前沿工作梳理

最近的一些工作梳理 2023年 Stroke-based Neural Painting and Stylization with Dynamically Predicted Painting Region 2022年Im2Oil: Stroke-Based Oil Painting Rendering with Linearly Controllable Fineness Via Adaptive Sampling 文章目录 1 Stroke-based Neural P…

【海博】雅思该怎么考?

文章目录 考试类型 考试内容 考试形式 备考资源 考试报名 考试成绩 考试类型 学术类(A类)适用于:出国留学申请本科,研究生及以上学位,或获得专业资质。学术类考试评估考生的英语水平是否满足进行大学或研究生学习…

【C语言】文件操作(1)

为什么使⽤⽂件? 如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的…

Sylar C++高性能服务器学习记录07 【协程模块-知识储备篇】

早在19年5月就在某站上看到sylar的视频了,一直认为这是一个非常不错的视频,由于本人一直是自学编程,基础不扎实,也没有任何人的督促,没能坚持下去,每每想起倍感惋惜。恰逢互联网寒冬,在家无事&a…

vim 插件01:插件管理神器pathogen

1、pathogen简介 Vim 插件 pathogen 是一款历史比较悠久的 Vim 插件管理器。Pathogen 的主要功能是提供一种模块化的方式来管理和加载 Vim 插件。说人话:vim是一款管理各类插件的插卡,使用它会让插件的安装和使用非常方便。 以下是 Pathogen 的主要特点…

【大模型应用篇5】应对裁员潮,突发奇想,打造“收割offer”智能体.......

前段时间飞书大裁员, 不禁让人感到危机四伏,加上《【大模型应用篇4】普通人构建智能体的工具》之前文章介绍了普通人打造智能体的工具, 这节课就带大家利用字节产品coze构建“程序员智能体”, 方便应对裁员,随时做好找工作的准备.打造一款面试智能体,方便各位程序员面试, 这个智…

错误代码126:加载d3dcompiler_43.dll失败,分享多种解决方法

在正常使用电脑的过程中,当我尝试启动并运行一款心仪的游戏时,系统却突然弹出一个令人困扰的错误提示“错误代码126:加载d3dcompiler_43.dll失败”,它会导致游戏无法正常运行。为了解决这个问题,我经过多次尝试和总结,…

22年全国职业技能大赛——Web Proxy配置(web 代理)

前言:原文在我的博客网站中,持续更新数通、系统方面的知识,欢迎来访! 系统服务(22年国赛)—— web Proxy服务(web代理)https://myweb.myskillstree.cn/114.html 目录 RouterSrv …

OGG extract进程占据大量虚拟内存导致服务器内存异常增长分析

现象 oracle服务器一节点内存,一个月来持续升高,近一月上涨10%左右。 问题分析 OS内存使用情况 使用内存最大的10个进程如下,PID为279417占用最大的内存。 查询279417,发现是ogg相关进程。 发现ogg的extract进程占用了大量的虚拟内…

软件测试(Web自动化测试)(二)

一.Selenium WebDriver的基本应用 (一)安装浏览器驱动 1.关闭浏览器的自动更新功能 以Windows7(64位)操作系统为例,讲解如何关闭Chrome浏览器的自动更新。首先按下快捷键“WinR”,打开运行对话框&#x…

【备战软考(嵌入式系统设计师)】02-计算机指令

指令集 我们计算机要执行程序,本质上是执行一条条的指令,而指令是从指令集中取出的,目前常见的指令集有CISC(Complex Instruction Set Computer,复杂指令集)和RISC(Reduced Instruction Set Co…

2024最新智慧医疗智慧医院大数据展示,医院数据采集概况、医院指标分析、医院就诊趋势分析等。源代码免费下载。

系列文章目录 【复制就能用1】2分钟玩转轮播图,unslider的详细用法 【复制就能用2】css实现转动的大风车,效果很不错。 【复制就能用3】2分钟自己写小游戏:剪刀石头布小游戏、扫雷游戏、五子棋小游戏 【复制就能用4】2024最新智慧医疗智慧医院大数据…

c++并查集

文章目录 前言一、并查集1、并查集原理2、并查集实现3、并查集应用1.省份数量2.等式方程的可满足性 前言 一、并查集 1、并查集原理 在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后…

应急行业的智能安全帽(高端)

前面介绍了低端、中端安全帽,接着再讲讲高端安全帽。做高端安全帽的企业非常少,估计一只手都数的出来。确实也和智能安全帽这个领域体量有关系,并且他有一个新的“劲敌”——智能眼镜从其他领域瓜分原属于他的市场,这些都是题外话…

SpringBoot引入Layui样式总是出现404

一般出现Layui样式文件如css,js404的错误 解决方案 (1)首先将其中的静态资源下载resources/static中 (2)在启动类中重写方法 package com.gq.booksystem;import org.mybatis.spring.annotation.MapperScan; import …

【ETAS CP AUTOSAR工具链】RTE层基本概念与开发流程

本篇文章续接上篇文章【ETAS CP AUTOSAR工具链】基本概念与开发流程,继续按上篇文章描述的ETAS CP工具链进行开发的基本框架,讲述了“RTE集成与配置”这部分的基本概念与开发流程。 RTE(Runtime Environment)处于应用层与基础软件…
最新文章