乐趣区

关于内核:读书笔记Linux内核设计与实现2

从内核登程

原以为这章能够飞快跳过,但还是发现很多新的有意思的点。

获取源码

  1. https://www.kernel.org 压缩源码或者增量补丁

    • bz2
      tar xvjf linux-x-y-z.tar.bz2
    • gz
      tar xvzf linux-x-y-x.tar.gz
  2. https://github.com/torvalds/l…

装置源码

/usr/src/linux
不要把这个源码树用于开发,因为编译用的 C 库所用的内核版本就链接到这棵树。
正确:建设本人的主目录,而后仅用 root 进行装置。
对于补丁:
patch -p1 < ../patch-x.y.z

内核源码树

目录 形容
arch 特定体系结构的源码
block 块设施 io 层
crypto 秘密 API
Documents 内核源码文档
drivers 设施驱动程序
firmware 应用某些驱动程序而须要的设施固件
fs VFS 和各种文件系统
include 内核同文件
init 内核疏导和初始化
ipc 过程间通信
kernel 外围子系统
lib 通用内核函数
mm 内存管理子系统和 VM
net 网络子系统
samples 实例
scripts 编译内核所用的脚本
security Linux 平安模块
sound 语音子系统
usr 晚期用户空间代码
tools Linux 开发工具
virt 虚拟化体系

编译

编译 Linux 之前须要进行配置:CONFIG_XXXX: yes|no|module;

  1. 决定哪些文件能够被编译进内核;module 意味着该配置选项被选定,但编译的时候这部分性能的实现代码是以模块的模式生成的(动静装置的独立代码块)。
  2. 通过预处理的命令解决代码;配置选项能够为字符串和证书,指定内核源码能够拜访的值,以预处理宏的模式;如制订动态调配数组的大小。
    配置命令:
  3. 逐个遍历
    make config
  4. 图形界面工具
    make menuconfig
  5. gtk+ 图形工具
    make gconfig
  6. 默认配置
    make defconfig
    配置选项会被放在根目录下.config 文件中;每次编译前,更新配置
    make oldconfig
    能够配置 CONFIG_IKCONFIG_PROC,把配置压缩放入 /proc/config.gz 下,能够从 /proc 下复制出配置文件并且应用它来编译一个新内核:
    zcat /proc/config.gz > .config
    make oldconfig
    配置实现后: make > /dev/null
    进步 make 效率多核,如 16 核:
    make -j32 > /dev/null

装置

  1. 查阅启动疏导工具的阐明,将内核映像拷贝到 /boot 目录下,按启动要求装置。
  2. 内核模块的装置是主动的,make modules_install,装到 /lib/modules 下
  3. 编译时也会在内核代码树的根目录下创立一个 System.map 文件,符号对照表,将内核符号和他们的起始地址对应,须要把内存地址翻译成容易了解的函数名以及变量名。

内核开发

内核编译时不能拜访 c 库文件 (libc) 和规范 c 头文件

lib/string.c => <linux/string.h>

  1. 内核开发头文件根本都在源码 include 目录下,头文件 <linux/inotify.h>
  2. 体系相干的头文件 arch/x86/include/asm 上面 <asm/ioctl.h>
    没有实现的 printf() -> prink 将格式化的字符串拷贝到日志缓冲区中,syslog 程序就能够通过读取该缓冲区来获取内核信息。能够指定一个优先级标志符,相似于宏定义
    prink(KERN_ERR "this is an error.\n")

应用 GNU C

  1. gcc 工具蕴含了多种 GNU 编译器,能够编译内核。
  2. 内核 C 语言蕴含了 ISO C99 规范和 GNU C 扩大个性。与规范 c 语言不同的大多是 GNU C 的扩大上。

    • 内联函数 inline:

      • 函数在调用地位扩大,打消函数调用和返回的开销,代码变长,占用内存空间或者指令缓存更多;
      • 函数较大,被重复调用,没有工夫要求不举荐应用
      • 与 static 合用
        static inline void wolf(unsigned long tail_size)
      • 应用前定义,举荐在头文件中定义,优先应用 inline 函数而不是宏
    • 内联汇编

      • 只有晓得体系结构才能够应用,偏近底层或对执行工夫要求严格
      • asm()
        unsigned int low, hight
        asm volatile("rdtsc" : "=a" (low), "=d" (high));
    • 分支申明

      • gcc 优化分支,经常出现 likely, unlikely
        if (unlikely (error))
      • 肯定要弄清是否真的有偏差,对性能影响微小

    没有内存保护机制

  3. 用户程序非法内存拜访,内核会发现,发送 SIGSEGV 信号,完结过程
  4. 内核中产生内存拜访谬误导致 oops

    • 非法内存拜访
    • 援用空指针
  5. 内核中内存不分页,用一个字节,物理内存就少一个

不要轻易应用浮点数

  1. 用户空间操作浮点数,内核须要从整数模式切换成内核模式,具体实现与体系相干
  2. 在内核中应用浮点数时,须要人工保留和回复浮点寄存器,还要有其余简单工作

内核只有小而固定的栈

  1. 用户空间能够动态分配大容积的栈,内核不行
  2. 内核栈大小随体系变动,x86,在编译时确定,4KB 或者 8KB;历史上内核栈大小两页,32 位 8KB, 64 位 16KB

留神同步和并发

起因:

  1. Linux 是抢占多任务操作系统,调度过程中内核必须和工作同步
  2. 反对对称多处理器零碎 SMP;两个或多个以上的处理器上执行的内核代码可能同时访问共享的同一个资源
  3. 中断异步到来,可能在拜访资源时到来,中断程序可能解决同一个资源
  4. Linux 内核能够抢占,内核中正在执行的代码可能被同一段代码抢占,从而导致几段代码同时拜访雷同的资源。

办法:

  1. 自旋锁
  2. 信号量

可移植性很重要

退出移动版