Linux内核及源码学习使用陈莉君老师的书《深入剖析Linux内核源代码》,内核源码版本为2.4.16。
1.Linux内核在整个操作系统中的位置
Linux的内核不是孤立的,必须把它放到整个系统中去研究,如图1.1所示,显示了Linux内核在整个操作系统的位置。
图1.1Linux内核在整个操作系统的位置
由图1.1可以看出,Linux操作系统由4个部份组成。
1)用户进程
用户应用程序是运行在Linux操作系统最高层的一个庞大的软件集合。当一个用户程序在操作系统之上运行时,它成为操作系统中的一个进程。
2)系统调用插口
在应用程序中,可通过系统调用来调用操作系统内核中特定的过程,以实现特定的服务。比如,在程序中安排一条创建进程的系统调用,则操作系统内核便会为之创建一个新进程。
系统调用本身也是由若干条指令构成的过程。但它与通常的过程不同,主要区别是:系统调用是运行在内核态(或叫系统态),而通常过程是运行在用户态。在Linux中,系统调用是内核代码的一部份。
3)Linux内核
内核是操作系统的灵魂,它负责管理c盘上的文件、内存,负责启动并运行程序,负责从网路上接收和发送数据包等。简言之,内核实际是具象的资源操作到具体硬件操作细节之间的插口。
4)硬件
这个子系统包括了Linux安装时须要的所有可能的化学设备。诸如,CPU、内存、硬盘、网络硬件等。
2.Linux内核的具象结构
Linux内核由5个主要的子系统组成,如图1.2所示。
图1.2Linux内核子系统及其之间的关系
(1)进程调度(SCHED)控制着进程对CPU的访问。当须要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际是仅等待CPU资源的进程,假如某个进程在等待其他资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。
(2)显存管理(MM)允许多个进程安全地共享主显存区域。Linux的显存管理支持虚拟显存,即在计算机中运行的程序linux多线程编程,其代码、数据和堆栈的总数可以超过实际显存的大小,操作系统只将当前使用的程序块保留在显存中,其余的程序块则保留在c盘上。必要时,操作系统负责在c盘和显存之间交换程序块。显存管理从逻辑上可以分为硬件无关的部份和硬件相关的部份。硬件无关的部份提供了进程的映射和虚拟显存的对换;硬件相关的部份为显存管理硬件提供了虚拟插口。
(3)虚拟文件系统(VirtulFileSystem,VFS)隐藏了各类不同硬件的具体细节,为所有设备提供了统一的插口,VFS还支持多达数十种不同的文件系统红旗linux6.0,这也是Linux较有特色的一部份。
虚拟文件系统可分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编撰的设备驱动程序模块。
(4)网路插口(NET)提供了对各类网路标准合同的存取和各类网路硬件的支持。网路插口可分为网路合同和网路驱动程序两部份。网路合同部份负责实现每一种可能的网路传输合同,网路设备驱动程序负责与硬件设备进行通讯,每一种可能的硬件设备都有相应的设备驱动程序。
(5)进程间通讯(IPC)支持进程间各类通讯机制。从图1.2所示可以看出,处于中心位置的是进程调度,所有其他的子系统都依赖于它,由于每位子系统都须要挂起或恢复进程。通常情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。诸如,当一个进程通过网路发送一条消息时,网路插口须要挂起发送进程,直至硬件成功地完成消息的发送,当消息被发送出去之后,网路插口给进程返回一个代码,表示操作的成功或失败。其他子系统(显存管理,虚拟文件系统及进程间通讯)以相像的理由依赖于进程调度。
各个子系统之间的依赖关系如下。
•进程调度与显存管理之间的关系:这两个子系统相互依赖。在多道程序环境下,程序要运行必须为之创建进程,而创建进程的第一件事,就是要将程序和数据放入显存。
•进程间通讯与显存管理的关系:进程间通讯子系统要依赖显存管理支持共享显存通讯机制,这些机制准许两个进程不仅拥有自己的私有显存,还可存取共同的显存区域。
•虚拟文件系统与网路插口之间的关系:虚拟文件系统借助网路插口支持网路文件系统(NFS),也借助显存管理支持RAMDISK设备。
•显存管理与虚拟文件系统之间的关系:显存管理借助虚拟文件系统支持交换,交换进程(swapd)定期地由调度程序调度,这也是显存管理依赖于进程调度的惟一缘由。当一个进程存取的显存映射被换出时,显存管理向文件系统发出恳求,同时,挂起当前正在运行的进程。
不仅如图1.2所示的依赖关系以外,内核中的所有子系统还要依赖一些共同的资源,但在图中并没有显示下来。这种资源包括所有子系统都用到的过程,比如分配和释放显存空间的过程,复印警告或错误信息的过程,还有系统的调试解释器等。
3.Linux内核源代码的结构
Linux内核源代码坐落/usr/src/linux目录下,其结构分布如图1.3所示,每一个目录或子目录可以看作一个模块,其目录之间的连线表示“子目录或子模块”的关系。下边是对每一个目录的简单描述。
include/目录包含了构建内核代码时所需的大部份包含文件,这个模块借助其他模块重建内核。
init/子目录包含了内核的初始化代码,这是内核开始工作的起点。
arch/子目录包含了所有硬件结构特定的内核代码,如图1.3所示,arch/子目录下有i386和alpha模块等。
drivers/目录包含了内核中所有的设备驱动程序,如块设备,scsi设备驱动程序等。
fs/目录包含了所有文件系统的代码,如:ext2,vfat模块的代码等。
net/目录包含了内核的连网代码。
mm/目录包含了所有的显存管理代码。
ipc/目录包含了进程间通讯的代码。
kernel/目录包含了主内核代码。
图1.3显示了8个目录,即init、kernel、mm、ipc、drivers、fs、arch及net的包含文件都在“include/”目录下。在Linux内核中包含了drivers、fs、arch及net模块,这就促使Linux内核既不是一个层次式结构,也不是一个微内核结构,而是一个“整体式”结构。由于系统调用可以直接调用内核层,因而,该结构促使整个系统具有较高的性能,其缺点是内核更改上去比较困难,除非遵守严格的规则和编码标准。
在图1.3中所示的模块结构,代表了一种工作分配单元。借助这些结构,我们期望LinusTorvalds能维护和提高内核的核心服务,即init/、kernel/、mm/及ipc/,其他的模块drivers、fs、arch及net也可以作为工作单元,比如,可以分配一组人对块文件系统进行维护和进一步地开发,而另一组人对scsi文件系统进行构建。图1.3所示类似于Linux的自愿者开发队伍一起工作来提高和扩充整个系统的框架。
图1.3Linux源代码的分布结构
4.从何处开始阅读源代码
像Linux内核这样庞大而复杂的程序看上去确实让人望而生畏,它像一个很大的球,没有起点和终点。在读源代码的过程中,你会遇见这样的情况,当读到内核的某一部分时又会涉及到其他更多的文件,当返回到原先的地方想继续往下读时,又忘了原先读的内容。在Internet上,好多人因此付出了很大的努力,制做出了源代码导航器,这为源代码阅读提供了挺好的条件,下载站点为。下边给出阅读源代码的一些线索。
1.系统的启动和初始化
在基于Intel的系统上,当loadlin.exe或LILO把内核放入到显存并把控制权传递给内核时,内核开始启动。关于这一部份,看arch/i386/kernel/head.S,head.S进行特定结构的设置,之后跳转到init/main.c的main()类库。
2.显存管理
显存管理的代码主要在/mm,但特定结构的代码在arch/*/mm。缺页中断处理的代码在mm/memory.c,而显存映射和页高速缓存器的代码在mm/filemap.c。缓冲器高速缓存是在mm/buffer.c中实现,而交换高速缓存是在mm/swap_state.c和mm/swapfile.c中实现。
3.内核
内核中linux 内核源码,特定结构的代码在arch/*/kernel,调度程序在kernel/sched.c,fork的代码在kernel/fork.c,task_struct数据结构在include/linux/sched.h中。
4.PCI
PCI伪驱动程序在drivers/pci/pci.c,其定义在include/linux/pci.h。每一种结构都有一些特定的PCIBIOS代码,Intel的在arch/alpha/kernel/bios32.c。
5.进程间通讯
所有SystemVIPC对象权限都包含在ipc_perm数据结构中,这可以在include/linux/ipc.h中找到SystemV消息是在ipc/msg.c中实现,共享显存在ipc/shm.c中,讯号量在ipc/sem.c中,管线在ipc/pipe.c中实现。
6.中断处理
内核的中断处理代码是几乎所有的微处理器所特有的。中断处理代码在arch/i386/kernel/irq.c中,其定义在include/asm-i386/irq.h中。
7.设备驱动程序
Linux内核源代码的好多行是设备驱动程序。Linux设备驱动程序的所有源代码都保存在/driver,按照类型可进一步界定为:
/block
块设备驱动程序如ide(在ide.c)。假如想看包含文件系统的所有设备是怎样被初始化的linux 内核源码,应该看drivers/block/genhd.c中的device_setup(),device_setup()除了初始化了硬碟,当一个网路安装nfs文件系统时,它也初始化网路。块设备包含了基于IDE和SCSI的设备。
/char
这是看字符设备(如tty,并口及键盘等)驱动程序的地方。
/cdrom
Linux的所有CDROM代码都在这儿,如在这里可以找到SoundblasterCDROM的驱动程序。注意ideCD的驱动程序是ide-cd.c,置于drivers/block;SCSICD的驱动程序是scsi.c,置于drivers/scsi。
/pci
这是PCI伪驱动程序的源代码,在这儿可以看见PCI子系统是怎样被映射和初始化的。
/scsi
在这儿可以找到所有的SCSI代码及Linux所支持的scsi设备的所有设备驱动程序。
/net
在这儿可以找到网路设备驱动程序,如DECChip21040PCI以太网驱动程序在tulip.c中。
/sound
这是所有声卡驱动程序的所在地。
8.文件系统
EXT2文件系统的源代码全部在fs/ext2/目录下,而其数据结构的定义在include/linux/ext2_fs.h,ext2_fs_i.h及ext2_fs_sb.h中。虚拟文件系统的数据结构在include/linux/fs.h中描述,而代码是在fs/*中。缓冲区高速缓存与更新内核的守护进程的实现是在fs/buffer.c中。
9.网路
网路代码保存在/net中,大部份的include文件在include/net下,BSD套节口代码在net/socket.c中,IP第4版本的套节口代码在net/ipv4/af_inet.c。通常的合同支持代码(包括sk_buff处理类库)在net/core下,TCP/IP联网代码在net/ipv4下,网路设备驱动程序在/drivers/net下。
10.模块
内核模块的代码部份在内核中,部份在模块包中,后者全部在kernel/modules.c中,而数据结构和内核守护进程kerneld的信息分别在include/linux/module.h和include/linux/kerneld.h中。假如想看ELF目标文件的结构,它坐落include/linux/elf.h中。
文章评论