《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代码应该与体系结构无关,在许多不同体系结构的计算机上都能编译和执行,因此,必须把与体系结构相关的代码从内核代码树的特定目录中适当分离出来。

《Linux内核设计与实现》第一、二章学习笔记的更多相关文章

  1. 《Linux内核设计与实现》 第一二章学习笔记

    <Linux内核设计与实现> 第一二章学习笔记 第一章 Linux内核简介 1.1 Unix的历史 Unix的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆 ...

  2. 《java编程思想(第四版)》第一二章学习笔记

    目录 一.Introduction 1.抽象过程 2.面向对象语言(包括Java)的五个基本特性 3.每个对象都提供服务 4.public.private.protected三者的区别 5.Java的 ...

  3. 《Linux内核设计与实现》第四周读书笔记——第五章

    <Linux内核设计与实现>第四周读书笔记--第五章 20135301张忻 估算学习时间:共1.5小时 读书:1.0 代码:0 作业:0 博客:0.5 实际学习时间:共2.0小时 读书:1 ...

  4. LINUX内核设计与实现第三周读书笔记

    LINUX内核设计与实现第三周读书笔记 第一章 LINUX内核简介 1.1 Unix的历史 1969年的夏天,贝尔实验室的程序员们在一台PDR-7型机上实现了Unix这个全新的操作系统. 1973年, ...

  5. 《Linux内核设计与实现》Chapter 3 读书笔记

    <Linux内核设计与实现>Chapter 3 读书笔记 进程管理是所有操作系统的心脏所在. 一.进程 1.进程就是处于执行期的程序以及它所包含的资源的总称. 2.线程是在进程中活动的对象 ...

  6. 《Linux内核设计与实现》Chapter 1 读书笔记

    <Linux内核设计与实现>Chapter 1 读书笔记 一.Unix的特点 Unix从Multics中产生,是一个强大.健壮和稳定的操作系统. 特点 1.很简洁 2.在Unix系统中,所 ...

  7. 《Linux内核设计与实现》Chapter 2 读书笔记

    <Linux内核设计与实现>Chapter 2 读书笔记 一.获取内核源码 1.使用Git 我们曾经在以前的学习中使用过Git方法 $ git clone git://git.kernel ...

  8. 《Linux内核设计与实现》Chapter 5 读书笔记

    <Linux内核设计与实现>Chapter 5 读书笔记 在现代操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口的作用是: 使应用程序受限地访问硬件设备 提供创建新进程与已 ...

  9. 《Linux内核设计与实现》Chapter 18 读书笔记

    <Linux内核设计与实现>Chapter 18 读书笔记 一.准备开始 一个bug 一个藏匿bug的内核版本 知道这个bug最早出现在哪个内核版本中. 相关内核代码的知识和运气 想要成功 ...

随机推荐

  1. 团队作业——Beta冲刺2

    团队作业--Beta冲刺 冲刺任务安排 杨光海天 今日任务:根据冲刺内容,具体分配个人任务,对于冲刺内容做准备 明日任务:图片详情界面的开发 吴松青 今日任务:学习熟悉安卓开发,跟随组员快速了解其代码 ...

  2. JAVA-最常用的A题语法

    输出 System.out.println(""); if 语句 if(布尔表达式) { //如果布尔表达式为true将执行的语句 } if...else... 语句 if(布尔表 ...

  3. libco协程库上下文切换原理详解

    缘起 libco 协程库在单个线程中实现了多个协程的创建和切换.按照我们通常的编程思路,单个线程中的程序执行流程通常是顺序的,调用函数同样也是 “调用——返回”,每次都是从函数的入口处开始执行.而li ...

  4. 「2017 山东一轮集训 Day5」字符串

    题目 比较神仙的操作啊 首先先考虑一个串的做法,我们有两种:SA或SAM,其中SAM又有两种,拓扑图上的\(dp\)和\(parent\)上随便统计一下 显然这道题\(SA\)和\(parent\)树 ...

  5. VC++环境下单文档SDI与OpenGL多视图分割窗口的实现-类似3DMAX的主界面

    本文主要讲述如何在VC++环境下实现单文档SDI与OpenGL多视图分割窗口,最终的界面类似3DMAX的主界面.首先给出我实现的效果图: 整个实现过程网络上有很多零散的博文,请各位自行搜索,在基于对话 ...

  6. jq插件封装格式

    (function($) { // closure $.fn.hilight = function( options ) { //将方法定义在$的fn上 var defaults = { textCo ...

  7. js 动态声明变量(eval)

    eval()可以将一段字符串当作js代码来执行. 动态声明变量(字符串)可通过eval(字符串)来实现.举例如下: var Thread_num=5; for(var i=1;i<=Thread ...

  8. array_multisort函数,以及多维数组下排序的应用,并与usort函数对比

    以前比较少用这个函数,大部分自己接触的业务里,处理稍微大一些的数组的时候几乎都是从db里取出来的,在db里就order by了. 最近倒是用了次,这个函数用来排序很强大,有点类似于sql中的order ...

  9. 在main函数前后执行的函数之 C语言

    在gcc中,可以使用attribute关键字,声明constructor和destructor,来指定了函数在main之前或之后运行,代码如下: #include <stdio.h> __ ...

  10. tomcat-在cmd窗口启动Tomcat

    平时,一般使用tomcat/bin/startup.bat目录在windows环境启动Tomcat,或者使用IDE配置后启动. 下面来简单介绍下如果在cmd窗口直接输入命令启动Tomcat: 1.将t ...