Linux内核的组成 - STEMHA's Blog

Linux内核的组成

概述

Linux内核主要由进程调度(SCHED)内存管理(MM)虚拟文件系统(VFS)网络接口(NET)进程间通信(IPC)5个子系统组成。

Linux内核的组成部分与关系

如果更具体一点就是下面这幅图:

Linux 内核子系统及其之间的关系

进程调度

  • 处于系统的中心位置,内核中其他的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。
  • 可运行进程实际是仅等待 CPU 资源的进程,如果某个进程在等待其他资源,则该进程是不可运行进程。

Linux进程状态转换

在设备驱动编程中,当请求的资源不能得到满足时,驱动一般会调度其他进程执行,并使本进程进入睡眠状态,直到它请求的资源被释放,才会被唤醒而进入就绪状态。

进程睡眠

睡眠的划分:

  • 可中断的睡眠(浅睡眠):在收到信号的时候会醒。其状态标志位为TASK_INTERRUPTIBLE;
  • 不可中断的睡眠(深睡眠):把信号传递到这种睡眠状态的进程不能改变它的状态,也就是说它不响应信号的唤醒。其状态标志位为TASK_UNINTERRUPTIBLE。

进程的描述

在Linux内核中,使用task_struct结构体来描述进程,该结构体中包含描述该进程内存资源、文件系统资源、文件资源、tty资源、信号处理等的指针。

Linux线程创建

Linux的线程采用轻量级进程模型来实现,在用户空间通过pthread_create()API创建线程的时候,本质上内核只是创建了一个新的task_struct,并将新task_struct的所有资源指针都指向创建它的那个task_struct的资源指针。

内核线程

绝大多数进程(以及进程中的多个线程)是由用户空间的应用创建的,当它们存在底层资源和硬件访问的需求时,会通过系统调用进入内核空间。
有时候,在内核编程中,如果需要几个并发执行的任务,可以启动内核线程,这些线程没有用户空间。启动内核线程的函数为:

1
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);

内存管理

内存管理的主要作用是控制多个进程安全地共享主内存区域。当CPU提供内存管理单元(MMU)时,Linux内存管理对于每个进程完成从虚拟内存到物理内存的转换。
内存管理从逻辑上可以分为硬件无关的部分和硬件相关的部分。

  • 硬件无关的部分( Architecture Independent Manager)提供了提供所有的内存管理机制,包括进程的映射(以进程为单位的memory mapping)和虚拟内存的对换(虚拟内存的Swapping)。
  • 硬件相关的部分( Architecture Specific Managers)为内存管理硬件提供了虚拟接口

Linux进程地址空间

一般而言,32位处理器的Linux的每个进程享有4GB的内存空间,0 ~ 3GB属于用户空间,3 ~ 4GB属于内核空间,内核空间对常规内存、I/O设备内存以及高端内存有不同的处理方式。当然,内核空间和用户空间的具体界限是可以调整的,在内核配置选项Kernel Features→Memory split下,可以设置界限为2GB或者3GB。

Linux进程地址空间

Linux内存管理的组成

Linux内存管理

  • Linux内核的内存管理总体比较庞大,包含底层的Buddy算法,它用于管理每个页的占用情况,内核空间的slab以及用户空间的C库的二次管理
  • 内核也提供了页缓存的支持,用内存来缓存磁盘
  • per-BDI flusher线程用于刷回脏的页缓存到磁盘。
  • Kswapd(交换进程)则是Linux中用于页面回收(包括file-backed的页和匿名页)的内核线程,它采用最近最少使用(LRU)算法进行内存回收。
  • slab是Linux操作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内存碎片,而且处理速度也太慢。
  • 在内核初始化完成之后, 内存管理的责任就由伙伴系统来承担. 伙伴系统是一个结合了2的方幂个分配器和空闲缓冲区合并计技术的内存分配方案, 其基本思想很简单. 内存被分成含有很多页面的大块, 每一块都是2个页面大小的方幂. 如果找不到想要的块, 一个大块会被分成两部分, 这两部分彼此就成为伙伴. 其中一半被用来分配, 而另一半则空闲. 这些块在以后分配的过程中会继续被二分直至产生一个所需大小的块. 当一个块被最终释放时, 其伙伴将被检测出来, 如果伙伴也空闲则合并两者.

虚拟文件系统

Linux虚拟文件系统隐藏了各种硬件的具体细节,为所有设备提供了统一的接口。而且,它独立于各个具体的文件系统,是对各种文件系统的一个抽象。

  • 它为上层的应用程序提供了统一的vfs_read()、vfs_write()等接口,并调用具体底层文件系统或者设备驱动中实现的file_operations结构体的成员函数。

VFS

网络接口

网络接口提供了对各种网络标准协议的存取和各种网络硬件的支持。
网络接口可分为网络协议和网络驱动程序两部分:

  • 网络协议部分负责实现每一种可能的网络传输协议
  • 网络设备驱动程序负责与硬件设备进行通信,每一种可能的硬件设备都有相应的设备驱动程序。

Linux网络体系结构

Linux内核支持的协议栈种类较多,如Internet、UNIX、CAN、NFC、Bluetooth、WiMAX、IrDA等,上层的应用程序统一使用套接字接口。

进程间通信

Linux支持进程间的多种通信机制,包含信号量共享内存消息队列管道UNIX域套接字等,这些机制可协助多个进程、多资源的互斥访问、进程间的同步和消息传
递。

在实际的Linux应用中,人们更多地趋向于使用UNIX域套接字,而不是System V IPC中的消息队列等机制。

Linux内核5个组成部分之间的依赖关系

  • 处于中心位置的是进程调度,所有其他的子系统都依赖于它,因为每个子系统都需要挂起或恢复进程。
    • 一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。
    • 例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。
    • 其他子系统(内存管理,虚拟文件系统及进程间通信)以相似的理由依赖于进程调度。
  • 进程调度与内存管理之间的关系:这两个子系统互相依赖。在多道程序环境下,程序要运行必须为之创建进程,而创建进程的第一件事,就是要将程序和数据装入内存。
  • 进程间通信与内存管理的关系:进程间通信子系统要依赖内存管理支持共享内存通信机制,这种机制允许两个进程除了拥有自己的私有内存,还可存取共同的内存区域。
  • 虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络文件系统(NFS),也利用内存管理支持RAMDISK 设备。
  • 内存管理与虚拟文件系统之间的关系内存管理利用虚拟文件系统支持交换,交换进程(swapd)定期地由调度程序调度,这也是内存管理依赖于进程调度的唯一原因。当一个进程存取的内存映射被换出时,内存管理向文件系统发出请求,同时,挂起当前正在运行的进程。

除了上面图示中的资源以外,内核中的所有子系统还要依赖一些共同的资源,但在图中并没有显示出来。这些资源包括所有子系统都用到的过程,例如分配和释放内存空间的过程,打印警告或错误信息的过程,还有系统的调试例程等。

参考资料

《Linux设备驱动开发详解:基于最新的Linux4.0内核》
slab-百度百科
伙伴系统之伙伴系统概述–Linux内存管理(十五) //很通俗的博客。
Linux内核的整体架构 //不错的英文图示
《深入分析Linux内核源代码》

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×