《Linux内核设计与实现》第一、二章学习笔记
《Linux内核设计与实现》第一、二章学习笔记
姓名:王玮怡 学号:20135116
第一章 Linux内核简介
一、关于Unix
——一个支持抢占式多任务、多线程、虚拟内存、换页、动态链接和TCP/IP网络的现代化操作系统
1、主要发展过程
1969年,贝尔实验室的程序员们设计了一个文件系统原型,最终发展演化成了Unix
1971年,Unix被移植到PDP-11型机中
1973年,整个Unix系统使用C语言进行重写,为后来Unix系统的广泛移植铺平了道路
Unix第六版(V6)被贝尔实验室以外广泛使用
1977年,贝尔实验室综合各种变体,推出了Unix SystemⅢ,其中最著名的为加州大学伯克利分校在1977年推出的第一个Unix演化版——1BSD(Berkeley Software Distribution)系统
1977年,加州大学伯克利分校推出第一个Unix演化版——1BSD(Berkeley Software Distribution)系统
1978年,伯克利推出2BSD,包含了csh、vi等软件
1979年,伯克利推出其独立开发的3BSD系统
1983年,AT&T推出system Ⅴ
20世纪80、90年代,许多工作站和服务器厂商在结合AT&T和伯克利发行版的基础上,结合自己的需要,推出自己的Unix系统,包括Digital Tru64、HP的HP-UX、IBM的AIX、SequentDYNIX/ptx等
2、主要特点
(1)简洁
(2)很多东西被表示成文件,这种抽象使对数据和对设备使用一套相同的系统调用接口来进行的open()、read()、write()、lseek()、close()
(3)Unix内核和相关系统工具软件是用C语言编写而成,便于移植
(4)进程创建十分迅速,并且有一个独特的fork()系统调用
二、关于操作系统和内核
1、操作系统
整个系统中负责完成最基本功能和系统管理的部分,包括内核、设备驱动程序、启动引导程序、命令行shell或者其他种类的用户界面基本的文件管理工具和系统工具。
2、内核
内核有时候被称为管理者或者是操作系统核心,通常由负责响应中断的中断服务程序,负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间的内存管理程序和网络、进程间通信等系统服务程序共同组成。内核独立于普通应用程序,一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限。这种内存态和被保护起来的内存空间统称为内核空间。
3、应用程序、内核和硬件的关系
在系统中运行的应用程序通过系统调用来与内核通信。
交互关系:应用程序通过系统调用界面陷入内核
应用程序被称为通过系统调用在内核空间运行;
内核被称为运行于进程上下文中。
每个处理器在任何时间点上的活动可以概括为下列三者之一:
4、单内核与微内核的比较
(1)单内核
从整体上作为一个单独的大过程来实现,同时也运行在一个单独的地址空间上,内核可以直接调用函数
优点:简单、性能高
缺点:一个功能损坏可能会造成整个内核无法正常使用
(2)微内核
功能被划分为多个独立的过程,每个过程叫做一个服务器。所有的服务器都保持独立并运行在各自的地址空间上,不能直接调用函数,通过消息传递处理微内核通信,系统采用进程间通信(IPC)机制。
优点:各自独立避免一个服务器失效祸及另一个,模块化的系统允许一个服务器为了另一个服务器而换出
缺点:服务器间的调用涉及进程间的通信,时间开销大,效率低
三、关于Linux
1、主要发展过程
1991年,Linus Torvalds为当时新推出的、使用intel 80386微处理器的计算机开发了一款全新的操作系统,Linux由此诞生。
2、内核
Linux基于单内核
(1)综合了微内核的精华——模块化设计、抢占式内核、支持内核线程以及动态装载内核模块的能力
(2)避免了微内核的弊端——所有事情运行在内核态,直接调用函数,无需消息传递
*Linux内核相比传统Unix内核的进步:
(1)支持动态加载内核模块
(2)支持对称多处理(SMP)
(3)内核可以抢占,允许内核运行的任务有优先执行的能力
(4)不区分线程和进程
3、版本
总的来说,Linux是类Unix系统,但它不是Unix,没有像其他Unix变种那样直接使用Unix源代码。Linux是一个互联网上的协作开发项目,任何人都可以开发内核。
第二章 从内核出发
一、获取内核源码
1、Git
2、安装内核源代码
如果压缩形式是bzip2,则运行:$tar xvjf linux-x.y.z.tar.bz2
如果压缩形式是GNU的zip,则运行:$tar xvzf linux-x.y.z.tar.gz (解压后的源代码位于linux-x.y.z.目录下)
3、使用补丁
从内部源码树开始,运行:$patch -pl < ../patch-x.y.z
二、内核源码树
三、编译内核
1、配置内核
当我们把需要把特定的功能和驱动编进内核前,需要配置相关选项。可以配置的各种选项以CONFIG_FEATURE形式表示,其前缀为CONFIG。这些配置选项要么二选一——yes或no,也可能是三选一——yes、no、module(module表示该配置项被选定了,但编译的时候这部分代码是以模块的形式生成),这些配置都会被存放在内核代码树根目录下的.config文件中。
*简化内核配置的工具:
$ make config 字符界面下的命令行工具,但会遍历所有配置选项,费时
$ make menuconfig 基于ncurse库编制的图形界面工具
$ make gconfig 基于gdk+的图形工具
$ make defconfig 基于默认的配置为你的体系结构创建一个配置
$ make oldconfig 验证和更新配置
配置选项CONFIG-IKCONFIG-PROC把完整的压缩过的内核配置文件存放在/prog/config.gz下,这样当编译一个新内核时就可以从/proc下复制出配置文件并使用它来编译一个新内核:
$ zcat /proc/config.gz > .config
$ make oldconfig
内核配置完毕后,编译:
$ make
2、减少编译的垃圾信息
$ make > ../detritue 尽量减少垃圾信息,又不会成错过错误报告与警告(用处不大)
$ make > /dev/null 把无用的输出信息重定向到永无返回值的黑洞/dev/null
3、衍生多个编译作业
$ make -jn 多个作业编译内核,n为要衍生出的作业数
4、安装新内核
以root身份运行:% make modules_install 就可以把所有已编译的模块安装到正确的主目录/lib/modules下
四、内核开发的特点
1、无libc库抑或无标准头文件
(1)原因:速度和大小
(2)头文件指组成内核源代码树的内核头文件,基本的头文件位于内核源代码树顶级目录下的include目录中;体系结构相关的头文件集位于内核源代码树的arch/<architecture>/include/asm目录下
(3)举例:printk()函数,与printf()几乎相同
printk("Hello world! A string:'%s' and an integer:'%d\n'",str,i);
*两者区别:
printk()允许你通过指定一个标志来设置优先级,例如:
printk(KERN_ERR "this is an error!\n");
在KERN_ERR和要打印的消息之间没有逗号,优先级标志是预处理程序定义的一个描述性字符串,在编译时优先级标志就要与要打印的消息绑定在一起处理。
2、GNU C
Linux内核使用C语言编写的
(1)内联函数
内联函数会在它所调用的位置上展开。但是如果一个函数较大,会被反复调用,且没有特别的时间上的限制,我们并不赞成把它做成内联函数。
定义一个内联函数时,需要使用static作为关键字,并且用inline限定,例:
(2)内联汇编
gcc编译器支持在C函数中嵌入汇编指令,通常使用asm()指令嵌入汇编代码,例,内联汇编指令用于执行x86处理器的rdtsc指令,返回时间戳(tsc)寄存器的值:
(3)分支说明
对于条件选择句,gcc内建了一条指令用于优化,在一个条件经常出现,或者该条件很少出现时,编译器可以根据这条指令对条件分支选择进行优化。例:
3、没有内存保护机制
(1)内核自己非法访问内存存在风险
(2)内核中的内存不分页:每用掉一个字节,物理内存都减少一个字节
4、不要轻易在内核中使用浮点数
(1)不建议使用
(2)使用浮点数,除了要人工保存和恢复浮点寄存器,还有其他一些琐碎的事情要做
5、容积小而固定的栈
内核栈的大小是两页——32位机的内核栈是8KB,64位机是16KB
6、注意同步和并发
(1)原因:
Linux是抢占多任务操作系统
Linux内核支持对称多处理器系统(SMP)
中断是异步到来的,完全不顾及当前正在执行的代码
Linux可以抢占
(2)常用的解决竞争方法:自旋锁和信号量
7、可移植的重要性
大部分C代码应该与体系结构无关,在许多不同体系结构的计算机上都能编译和执行,因此,必须把与体系结构相关的代码从内核代码树的特定目录中适当分离出来。