linux系统介绍

linux系统介绍

从九十年代初诞生至今,各种各样的linux发行版本让我们充分领略了它的魅力,也极大地享受到了它给学习工作带来的方便。一个优秀的操作系统离不开一个优秀的内核。在世界各地的成千上万的自由软件爱好者的共同努力下,linux的内核不断地完善,功能越来越丰富,因而粉丝团也正以指数级的速度增长,那么,现在就让我们来分析一下其“灵魂”——内核。

一.内核体系结构

Linux内核主要由 5 个模块构成,它们分别是:进程调度模块、内存管理模块、文件系统模块、进程

间通信模块和网络接口模块。

进程调度模块用来负责控制进程对 CPU 资源的使用。所采取的调度策略是各进程能够公平合理地访

问 CPU,同时保证内核能及时地执行硬件操作。内存管理模块用于确保所有进程能够安全地共享机器主内

存区,同时,内存管理模块还支持虚拟内存管理方式,使得 Linux 支持进程使用比实际内存空间更多大的

内存容量。并可以利用文件系统把暂时不用的内存数据块会被交换到外部存储设备上去,当需要时再交换

回来。文件系统模块用于支持对外部设备的驱动和存储。虚拟文件系统模块通过向所有的外部存储设备提

供一个通用的文件接口,隐藏了各种硬件设备的不同细节。从而提供并支持与其它操作系统兼容的多种文

件系统格式。进程间通信模块子系统用于支持多种进程间的信息交换方式。网络接口模块提供对多种网络

通信标准的访问并支持许多网络硬件。 结构如下图:

其中内核级中的几个方框,除了硬件控制方框以外,其它粗线方框分别对应内核源代码的目录组织结

构。 除了这些图中已经给出的依赖关系以外,所有这些模块还会依赖于内核中的通用资源。这些资源包括内核所有子系统都会调用的内存分配和收回函数、打印警告或出错信息函数以及一些系统调试函数。

二.内核对进程的控制

程序是一个可执行的文件,而进程(process)是一个执行中的程序实例。在 Linux 操作系统上同时可

以执行多个进程。系统除了第一个进程是“手工”建立以外,其余的都是进程使用系统调用 fork 创建的新进程,被创建的进程称为子进程(child process),创建者,则称为父进程(parent process)。内核程序使用进程标识号(process ID,pid)来标识每个进程。进程由可执行的指令代码、数据和堆栈区组成。进程中的代码和数据部分分别对应一个执行文件中的代码段、数据段。每个进程只能执行自己的代码和访问自己的数据及堆栈区。进程之间相互之间的通信需要通过系统调用了进行。对于只有一个 CPU 的系统,在某一时刻只能有一个进程正在运行。内核通过调度程

序分时调度各个进程运行。

Linux 系统中,一个进程可以在内核态(kernel mode)或用户态(user mode)下执行,因此,linux 内

核栈和用户栈是分开的。用户栈用于进程在用户态下临时保存调用函数的参数、局部变量等数据。内核栈

则含有内核程序执行函数调用时的信息。

内核程序是通过进程表对进程进行管理的,每个进程在进程表中占有一项。在 linux 系统中,进程表

项是一个 task 结构。

当一个进程在执行时,CPU 的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下

文。当内核需要切换(switch)至另一个进程时,它就需要保存当前进程的所有状态,也即保存当前进程

的上下文,以便在再次执行该进程时,能够恢复到切换时的状态执行下去。在发生中断时,内核就在被中

断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中断服务结

束时能恢复被中断进程的执行。

当进程正在被 CPU 执行时,被称为处于执行状态(running)。当进程正在等待系统中的资源而处于等

待状态时,则称其处于睡眠等待状态。在 linux 系统中,还分为可中断的和不可中断的等待状态。当系统

资源已经可用时,进程就被唤醒而进入准备运行状态,该状态称为就绪态。当进程已停止运行,但其父进

程还没有询问其状态时,则称该进程处于僵死状态。当进程被终止时,称其处于停止状态。

只有当进程从“内核运行态”转移到“睡眠状态”时,内核才会进行进程切换操作。在内核态下运行

的进程不能被其它进程抢占,而且一个进程不能改变另一个进程的状态。为了避免进程切换时造成内核数

据错误,内核在执行临界区代码时会禁止一切中断。

三.内核对内存的使用

linux内核程序占据在物理内存的开始部分,接下来是用于供硬盘或软盘等块设备使用的高速缓冲区部分。当一个进程需要读取块设备中的数据时,系统会首先将数据读到高速缓冲区中;当有数据需要写到块设备上去时,系统也是先将数据放到高速缓冲区中,然后由块设备驱动程序写到设备上。最后部分是供所有程序可以随时申请使用的主内存区部分。内核程序在使用主内存区时,也同样要首先向内核的内存管理模块提出申请,在申请成功后方能使用。对于含有RAM虚拟盘的系统,主内存区头部还要划去一部分,共虚拟盘存放数据。 由于计算机系统中所含的实际物理内存容量是有限制的。为了能有效地使用这些物理内存,Linux 采用了Intel CPU的内存分页管理机制,使用虚拟线性地址与实际物理内存地址映射的方法让所有同时执行的程序共同使用有限的内存。内存分页管理的基本原理是将整个主内存区域划分成 4096 字节为一页的内存页面。程序申请使用内存时,就以内存页为单位进行分配。

为了使用实际物理内存,每个进程的线性地址通过二级内存页表动态地映射到主内存区域的不同内存

页上。因此每个进程最大可用的虚拟内存空间是 64MB。每个进程的逻辑地址通过加上任务号*64M,即可

转换为线性地址。不过在注释中,通常将进程中的地址简单地称为线性地址。

四.内核源代码结构

Linux内核完整的源代码目录结构如下:

五.内核与用户程序的关系

在Linux系统中,内核为应用程序提供了两方面的接口。其一是系统调用接口,也即中断调用int 0x80;另一方面是通过内核库函数与内核进行信息交流。内核库函数是基本C函数库libc的组成部分。许多的系统调用是作为基本C语言函数库的一部分实现的。 系统调用主要是提供给系统软件直接使用或用于库函数的实现。而一般用户开发的程序则是通过调用象libc等库中的函数来访问内核资源。通过调用这些库中的程序,应用程序代码能够完成各种常用工作,例如,打开和关闭对文件或设备的访问、进行科学计算、出错处理以及访问组和用户标识号 ID 等系统信息。 系统调用是内核与外界接口的最高层。在内核中,每个系统调用都有一个序列号(在include/linux/unistd.h头文件中定义),并常以宏的形式实现。应用程序不应该直接使用系统调用,因为这样的话,程序的移植性就不好了。因此目前Linux标准库LSB(Linux Standard Base)和许多其它标准都不允许应用程序直接访问系统调用宏。系统调用的有关文档可参见Linux操作系统的在线手册的第2部分。 库函数一般包括C语言又没有提供的执行高级功能的用户级函数,例如输入/输出和字符串处理函数。某些库函数只是系统调用的增强功能版。例如,标准I/O库函数fopen和fclose提供了与系统调用open和close类似的功能,但却是在更高的层次上。在这种情况下,系统调用通常能提供比库函数略微好一些的性能,但是库函数却能提供更多的功能,而且更具检错能力。系统提供的库函数有关文档可参见操作系统的在线手册第3部分。

六.内核的配置和编译

配置与编译内核用到的工具很多,下面是对几个关键工具的介绍:

Make

Make是一种帮助大型软件工程的编译工作实现自动化的编程语言。正确地使用Make可以大大减少因编译程序而花费的时间,因为它可以消除不必要的再编译。Make的基本设计思想是如果目标文件是在最近一次对源文件的修改之后编译的,它就是“新的”,不需要重新编译;如果最近一次对源文件的修改之后没有及时更新目标文件,那么该目标文件就是“旧的”,需要重新编译。为了理解Make如何执行一个任务,需要了解一些术语:

◆目标 需要执行的一个任务。多数情况下它就是用户要生成的文件的名字,但是它也可以仅是个任务的名字。

◆依赖关系 两个目标之间相互依存的关系。如果修改目标B会造成目标A的修改,那么就说目标A依赖于目标B,B是A的先决条件。

◆变量 一种存储临时信息的载体。Make中使用的变量应该加上括号,例如$(TEMP)。

◆命令 执行任务时使用的指令,可以是一条、多条,甚至没有。

◆规则 一条完整的规则具有以下格式:

目标(target) : 先决条件(prerequisites)

规则(command)

......

其中只有目标必须要有,其它成分可以没有。一条完整的规则描述了编译一个目标的方法和依赖关系,是Makefile中最重要的部分。

◆Makefile文件 描述如何生成一个或多个目标的文件。它列出目标依赖的各个文件,并提供正确编译这些目标所需要的规则。

接下来以2.4.23的kbuild为例,简要介绍一下内核的构建过程。首先,完整的内核构建过程由以下五种Makefile封装。

1.根目录Makefile

它是最重要的Makefile,定义所有与体系结构无关的变量和目标。它读取.config文件,并根据其信息最终生成vmlinux和modules。Make通过向下递归调用子目录中的Makefile来编译这两个目标。

2.配置文件.config

执行“make ”会在根目录下生成该配置文件,其内容记录了具体的配置选择,也可以将旧内核的配置文件放在这里。

3.arch/*/Makefile

这是与特定体系结构相关的Makefile。它包含在根目录下的Makefile中,为kbuild提供体系结构的特定信息。

4.子目录Makefiles

它们存在于每个子目录下,大约有几百个。它们接受来自上层Make传递下来的信息,并根据这些信息来构造一个需要编译的文件列表,并交由Rules.make处理。

5.Rules.make

几乎每个子目录Makefile都包含该Makefile。根据子目录Makefiles构建的文件列表,Make使用Rules.make定义的通用规则来编译所有来自列表的源文件。

kbuild的执行过程是:Make从根目录Makefile开始执行,从中获得与体系结构无关的变量和依赖关系,并同时从arch/*/Makefile中获得体系特定的变量等信息,这些信息扩展了根目录Makefile提供的变量。此时kbuild已经拥有构建内核需要的所有变量和目标。然后,Make进入子目录,把部分变量传递给子目录Makefile。子目录Makefile根据配置信息决定编译哪些源文件,从而构建出一个需要编译的文件列表。最后,Rules.make根据其定义的编译规则决定这些文件的编译方式。

需要注意的是,由于Make的向下递归特性和无序性,其执行过程并不完全遵守顺序逐行执行的规则,但无论Make的执行有多复杂,也只分为两个阶段。第一个阶段Make会读取所有变量和分析所有目标的依赖关系,并最终建立一棵依赖关系树。同时,所有的立即型变量(通过“:=”赋值)在这个过程中被扩展,就像C变量一样。而在这个阶段的最后,所有的延迟型变量才被扩展(通过“=”赋值)。这点需要格外注意。第二个阶段Make会根据依赖关系树执行命令。

因此,一个目标和其先决条件的规则定义的顺序是无所谓的,很可能一个目标的先决条件的规则定义在百行以后才出现。Make会耐心读完所有的Makefile后分析得出依赖关系树。

GCC

GCC是GNU的免费编译程序,也是内核惟一指定使用的编译器。GCC在执行一个完整的编译任务时会经过以下步骤:

◆预处理 GCC会调用cpp程序来分析各种宏指令,如#define、#if、#include等。

◆编译 这一阶段根据输入文件产生汇编语言指令。由于通常情况下是立即调用汇编程序as,所以输出一般不保存在文件中,可以使用-S选项强制输出源程序的汇编版本。

◆汇编 这一阶段将汇编语言源程序作为输入,生成.o目标文件。

◆链接 这是最后一个阶段。该阶段中,各个.o模块被链接在一起构成可执行文件。

as

用户可以明确地要求使用as来直接处理汇编文件。as产生的目标文件可以分为文本段(.text)、数据段(.data)和未初始化数据段(.bss)。

ld

与as相似,用户可以明确地要求使用ld链接程序将几个模块组合成一个单独的可执行文件。其链接过程通常由一个叫ld链接脚本的文件来描述。该脚本使用Linker Command Language编写。使用“ld --verose”命令可以看到这个默认使用的ld链接脚本。

ar

ar是GNU的二进制文件处理程序,用于创建、修改及从归档文件中抽取文件。由它生成的.a归档文件实际上是一个包含许多可执行二进制代码子程序集合的库文件。

RPMBuild

使用“make rpm”可以把内核源代码制作成RPM包。在此之前,kbuild会执行“make spec”生成rpmbuild程序用到的spec文件,详见“man rpmbuild”。

中间件

根目录scripts下的各种脚本和C源文件都可以称作中间件。它们并不是内核组件的一部分,只是在kbuild执行过程中的辅助程序。以split-include为例,讲述配置文件的运作机理。

.config由关键字/值对组成,其内容类似于:

CONFIG_MPENTIUMIII=y

# CONFIG_MPENTIUM4 is not set

CONFIG_REISERFS_FS=m

这些信息在执行“make ”时自动生成。同时include/linux/autoconf.h依照.config的内容生成。它的格式类似于:

#define CONFIG_MPENTIUMIII 1

#undef CONFIG_MPENTIUM4

#undef CONFIG_REISERFS_FS

#define CONFIG_REISERFS_FS_MODULE 1

对比一下不难发现,include/linux/autoconf.h明确地洞悉了.config的意图:哪些组件不编译,哪些需要编译进内核,而哪些又要作为模块来编译?split-include根据include/linux/autoconf.h在include/config/下建立相关的目录和.h文件。每个.h文件只包括include/linux/autoconf.h中的某一行,比如在配置内核选项时支持NTFS文件系统,并把它编译进内核,在.config中就会生成“CONFIG_NTFS_FS=y”,相应地在include/linux/autoconf.h中会生成“#define CONFIG_NTFS_FS 1”一项。这样,所有与NTFS文件系统相关的C源文件都会包含include/config/ntfs/fs.h头文件。

如果以前编译过内核,并且没有使用过“make mrproper”,.config、include/linux/autoconf.h和include/linux/config/就不会被删除。这里涉及到新旧内核的配置问题。一个全新的内核代码是未经配置的。如果只在原内核的功能基础上增加对NTFS的支持,那么从头开始配置无疑是浪费时间。可以继续使用原内核的.config文件,而所有的配置信息不会有任何更改,并且可以直接在原配置的基础上增加新功能。

旧值保存在include/config/下的.h文件中,新值保存在新生成的include/linux/autoconf.h文件中。split-include的代码不仅描述了如何处理这五种情况,还描述了include/config/下文件和子目录的生成过程。

总结:随着硬件更新速度的日益加快,linux内核的升级也会加快,尤其是驱动程序,让我们加入到开发者的行列,一起享受创造的乐趣,自由的空气。

相关推荐

世界盃棒球賽
365bet真人体育

世界盃棒球賽

🗓️ 06-29 👁️ 8560
《诗经》国风·豳风·鸱鸮
最佳娱乐365bet娱乐场下载

《诗经》国风·豳风·鸱鸮

🗓️ 09-25 👁️ 1486
[求助]请问下,大家对魔技纳米这家公司了吗
最佳娱乐365bet娱乐场下载

[求助]请问下,大家对魔技纳米这家公司了吗

🗓️ 07-11 👁️ 412
gta5花园银行在哪 gta5花园银行楼顶怎么上去
最佳娱乐365bet娱乐场下载

gta5花园银行在哪 gta5花园银行楼顶怎么上去

🗓️ 09-13 👁️ 5817
魔兽世界暗月马戏团炽燃之翼怎么获取 暗月马戏团炽燃之翼获取攻略
最佳娱乐365bet娱乐场下载

魔兽世界暗月马戏团炽燃之翼怎么获取 暗月马戏团炽燃之翼获取攻略

🗓️ 08-01 👁️ 534
哪些SUV符合国六排放标准
最佳娱乐365bet娱乐场下载

哪些SUV符合国六排放标准

🗓️ 07-05 👁️ 7478
古墓丽影 崛起 图文全攻略 全关卡流程全收集攻略
365根据什么来封号

古墓丽影 崛起 图文全攻略 全关卡流程全收集攻略

🗓️ 09-11 👁️ 3499
五星巴西世界杯十大进球,哪粒使你印象深刻
最佳娱乐365bet娱乐场下载

五星巴西世界杯十大进球,哪粒使你印象深刻

🗓️ 07-18 👁️ 8886
马航mh370是从哪飞向哪的,马航mh370是什么机型
365根据什么来封号

马航mh370是从哪飞向哪的,马航mh370是什么机型

🗓️ 07-19 👁️ 7874
王石被踢出万科原因 王石万科争夺战始末
最佳娱乐365bet娱乐场下载

王石被踢出万科原因 王石万科争夺战始末

🗓️ 08-05 👁️ 1535
负反馈 —— 拉扎维 第二版第八章笔记
365根据什么来封号

负反馈 —— 拉扎维 第二版第八章笔记

🗓️ 08-23 👁️ 3195
海尔工资
最佳娱乐365bet娱乐场下载

海尔工资

🗓️ 08-28 👁️ 857