三言两语聊Kernel:从Linux到FreeBSD

TL;DR

总的来说,FreeBSD Kernel比Linux Kernel要简洁的多。我感觉可能是以下两个原因:

  • linux考虑的场景多,所实现的功能也更多一些,所以linux比freebsd在编译时的配置要灵活。
  • FreeBSD是个中央集权式的组织结构,linux则是民主式组织结构,所以freebsd的很多改进都是有组织有计划,代码看起来就很清晰,而linux是自底向上的改进,代码看起来就散乱些。

下面来看下linux kernel 和freebsd kernel在代码上的主要差异:

编译

Linux和FreeBSD都是使用Makefile来管理整个工程的。
二者在编译上最大的差异是configuration的不同。

Linux为了灵活配置,在内核编译配置上使用了Kconfig机制,使用该机制能够很方便的选择编译哪些功能。Kconfig也是使用Makefile来控制的,使用make menuconfig这个命令。

FreeBSD则是使用了一个专门的工具config来配置需要编译的内核代码。

内核启动

bootstrap之后是OS的启动,这对于所有的操作系统都是一致的。

二者在启动过程主要是如下的不同。

  • linux内核使用了镜像压缩机制,在从bootloarder跳转到内核后先执行的是一个压缩的镜像,然后进行自解压。FreeBSD则没有这个压缩机制。
  • linux模块的初始化是分层级进行,每个优先级都对应于一个section。
    linux首先初始化高优先级的initcall,再去初始化低优先级的initcall,在某个优先级内,比如A模块和B模块都属于优先级1,那么A模块和B模块的初始化顺序则是由链接过程决定的,哪个模块先被链接到section的前面,自然要先执行哪个模块。
    FreeBSD的模块初始化是使用的SYSINIT,SYSINIT会在编译时首先定义好各个模块的初始化顺序,然后内核就按照这个顺序来初始化各个模块。
  • swapper/init/idle线程
    不同在于SMP系统。linux内核的每个CPU都有自己的swapper线程(0号线程),init线程(1号线程)则只有主核有,对于linux而言,swapper线程就是idle线程,即在CPU空闲的时候会去唤醒idle线程。 FreeBSD的内核swapper线程和idle线程是不同的线程,只有主核有swapper线程(0核线程)和init线程(1号线程),每个核都有自己的idle线程,在CPU空闲的时候会唤醒该idle线程。

 Task Management 和 Scheduling Algorithm

  • 主要数据结构
    Linux kernel使用task_struct这个结构体(include/linux/sched.h)来描述进程, 使用thread_info结构体(arch/arm/include/asm/thread_info.h)来描述线程状态信息,thread_info是和architecture强相关的,所以定义在了arch目录下。调度是以task_struct为基本单位来进行的,每个线程/进程都有自己的task_struct,线程和进程的区别主要在于,进程有自己独立地址空间,而线程则是共享进程的地址空间。
    FreeBSD使用proc这个结构体(sys/sys/proc.h)来描述进程,使用thread结构体(sys/sys/proc.h)来描述线程信息,FreeBSD的调度单位是thread,对于单线程的进程而言,它有一个proc结构体和一个thread结构体,对于多线程的进程而言,则是每个线程都有自己的thread结构体,多线程共用一个proc结构体。 线程和进程的主要区别也是线程没有自己的独立地址空间。
  • 调度机制
    Linux的进程分为实时进程和普通进程两种,实时进程有FIFO和RR两种调度策略, 普通进程则是CFS调度算法。 每个CPU都维护着自己的运行队列/等待队列链表。
    FreeBSD则是将进程分为以下几种调度类型:ITHD/KERN/REALTIME/TIMESHARE/IDLE,从左往右优先级递减。其中,ITHD是针对中断下半部的线程(FreeBSD用线程来处理中断,这是和linux的一个很大的区别),所以优先级最高;接着是内核线程;然后是实时用户态线程;接着是分时线程;CPU空闲的时候再唤醒idle线程。FreeBSD有三种调度算法:实时调度,针对实时进程;分时调度,针对普通进程;ULE调度算法,针对SMP系统的负载均衡。 每个CPU都维护着自己的idle队列/curren队列/next队列这三个链表。

Memory Management

  • 主要数据结构
    Linux kernel使用mm_struct这个结构体(include/linux/mm_types.h)来描述进程的地址空间。
    FreeBSD使用vmspace这个结构体(sys/vm/vm_map.h)来描述进程的地址空间。
  •  内存管理策略
    二者并无明显的差异。都是分页机制+访问权限控制。

Filesystem

都是使用的VFS机制。差异在于具体文件系统上。

linux kernel支持:

  • 磁盘文件系统(EXT系列)
  • 块设备文件系统(yaffs2/jffs2)
  • 网络文件系统(NFS)
  • 虚拟文件系统(pseudo filesystem,例如procfs/devfs) 。

FreeBSD在具体实现上跟linux略有不同,FreeBSD的具体存储机制是Filestore,filestore有三种管理方式:

  • 针对块设备:FFS
  • 针对内存:MFS
  • 日志文件系统

FreeBSD也支持NFS。FreeBSD也支持虚拟文件系统,略有不同的是,FreeBSD的procfs是指process filesystem,就类似于内核提供给用户态一个sysctl接口来查看进程信息。

Interrupt

FreeBSD的中断下半部对应于一个内核线程,是由内核线程来处理中断服务程序。Linux的中断下半部则没有所谓的线程,直接由中断向量表进入中断中断服务程序。

Sync Mechanism

二者的同步机制基本一样,都是spinlock/mutex/semaphore这些机制以及衍生。

Debug

  • 用户态
    linux和FreeBSD都支持GDB,GDB的实现在两个OS上也是一致的,都是通过ptrace系统调用。
    linux有个很强大的工具strace来跟踪系统调用,FreeBSD上没有该利器,不过FreeBSD可以使用ktrace+kdump来实现strace的功能。
  • 内核态调试
    linux的kgdb可以分析crash dump,也可以对内核进行live debug。
    FreeBSD则是使用kgdb来分析crash dump,然后使用ddb工具来进行 live debug。
  • 杂项调试工具
    大同小异,半斤八两。

P.S.:对FreeBSD代码看的还不多,很多地方也许写的不对。后续会继续完善。

Ref.

[1] Understanding the Linux Kernel

[2]The Design and Implementation of the FreeBSD Operation System

Comments