当前位置: 首页 > 科技观察

Linux内核设计与实现读书笔记

时间:2023-03-15 16:17:06 科技观察

Unix强大的根本原因:Unix简洁,提供数百个系统调用,设计目的明确。Unix中的一切都被视为一个文件。Unix内核和相关的系统工具都是用C语言开发的,具有很强的可移植性。Unix进程可以快速创建并具有独特的fork机制Unix提供了简单稳定的进程间通信原语Linux是一个类Unix系统,它借鉴了Unix设计并实现了UnixAPI。应用程序通常调用库函数(如C库函数),然后库函数被系统接口调用,让内核代为完成各种任务。Linux支持内核模块的动态加载。Linux支持对称多处理(SMP)机制。设备模型、热插拔事件和用户控制的设备文件系统中断和中断处理中断是处理器和速度差异的解决方案,并且仅在硬件需要时才向内核发出信号。中断本质上是一种特殊的电信号。内核响应特定的中断,然后内核调用特定的中断处理程序。终端处理程序是设备驱动程序的一部分。linux中的terminalhandler是不可重入的,不会同时调用同一个中断处理程序中断上下文不能休眠(我的理解是当前被中断的程序需要在中断处理完成后继续执行)中断处理程序不在进程上下文中执行,它们不能阻止中断处理。分为两部分,上半部分是中断处理程序,要求尽快执行,下半部分(用于减少中断处理程序的工作量)执行与中断处理密切相关但未执行的工作由中断处理程序本身。后半部分的实现方式是软中断,tasklet,工作队列,中断机制的实现:设置产生中断,通过电信号向处理器的特定引脚发送信号,处理器监听当前处理工作,关闭中断系统,然后转移到内存中预定义的位置(中断处理程序的入口点)开始执行。计算终端号,do_IRQ()响应接收到的中断,禁止中断在该线上传输。内核同步对于共享资源,如果同时被多个线程访问和操作,可能会出现线程间相互覆盖共享数据,导致访问数据不一致的情况。同步实现通过主锁机制锁定共享资源。只有持有锁的线程才能操作共享资源,其他线程休眠(或轮询)。资源操作完成后,持有锁的线程释放锁,锁被等待线程获取。内核同步方式:原子操作自旋锁,特点是当线程获取不到锁时,会一直忙循环(busywaiting)等待锁再次可用,适合短时间的轻量级锁读/写自旋锁(共享/排他锁),一个或多个任务可以并发持有读锁,写锁只能由一个写任务持有。信号量(睡眠锁),如果一个任务试图获取一个已占用的信用时,信号量会将其推入等待队列,然后让它休眠。当信号量可用时,等待队列中的任务将被唤醒。适用于锁被占用时间较长的情况。mutex(计数为1的信号量),这个在编程中最常见。顺序锁屏障(barriers),用于保证指令顺序和读写的执行顺序,在内核中引起并发:中断,几乎可以随时异步发生,随时可能被中断当前正在执行的代码软中断和tasklets,内核可以随时唤醒或调度软中断或tasklets,中断当前正在执行的代码内核抢占睡眠和与用户空间同步对称多处理,多个处理器同时执行代码内存管理内核把物理页作为内存管理的基本单元。内存管理单元(MMU,管理内存,将虚拟地址转换为物理地址)通常以页为单位管理系统中的页表。内核也将其划分为不同的区域(zone),利用区域对具有相似特征的页面进行分组//该函数分配2个连续的`物理页面`为顺序的幂,并返回页面结构指向第一页Bodystaticinlinestructpage*alloc_pages(gfp_tgfp_mask,unsignedinterder)//释放物理页externvoidfree_pages(unsignedlongaddr,unsignedinterder);//按字节分配一块内核内存(物理连续)static__always_inlinevoid*kmalloc(size_tsize,gfp_tflags)//释放kmalloc分配的内存块voidkfree(constvoid*);虚拟文件系统虚拟文件系统为用户控制程序提供文件和文件系统相关的接口。文件的元数据存储在一个单独的数据结构中,称为inode(Inode)虚拟文件系统(VFS)有四种主要的对象模型:superblockobject,代表一个特定安装的文件系统,存储特定文件系统的信息;一个inode对象,代表一个具体的文件,包含了内核在操作文件时所需要的所有目录或目录的信息,一个index节点代表文件系统中的一个文件,一个目录项对象代表一个目录项,是acomponentofapath,VFS把目录当做文件,目录项对象没有对应的磁盘数据结构文件对象,代表进程打开的文件,进程直接处理文件的数据结构//文件对象structfile{union{structllist_nodefu_llist;structrcu_headfu_rcuhead;}??f_u;structpathf_path;structinode*f_inode;/*缓存值*/conststructfile_operations*f_op;/**Protectsf_ep_links,f_flags。*不得从IRQ上下文中获取。*/spinlock_tf_lock;atomic_long_tf;fmode_tf_mode;structmutexf_pos_lock;loff_tf_pos;structfown_structf_owner;conststructcred*f_cred;structfile_ra_statef_ra;u64f_version;#ifdefCONFIG_SECURITYvoid*f_security;#endif/*neededforttydriver,andmaybeothers*/void*private_data;#ifdefCONFIG_EPOLL/*Usedbyfs/eventpoll.ctolinkallthehookstothisfile*/structlist_headf_ep_links;structlist_headf_tfile_llink;#endif/*#ifdefCONFIG_EPOLL*/structaddress_space*f_mapping;}__attributeed(4)));/*lessomethingweirddecidesthat2isOK*/块I/O层系统能够随机访问固定大小的数据块(chunks)的硬件设备称为块设备,比如硬盘。它是按照字符流顺序访问一个硬件设备称为字符设备,比如keyboard#I/O设备的基本容器用bio结构体表示。I/O调度器用于管理一个块设备的请求队列,决定请求在队列中的顺序以及何时将请求调度到挂起的设备上。这有利于减少磁盘寻道时间,从而提高全局吞吐量。linux实际使用的I/O调度器包括linuxelevator、deadlineI/Oscheduler和predictiveI/Oscheduler,空操作的I/O调度器进程地址空间内核需要管理进程中的内存用户空间。该内存称为进程地址空间。系统中的所有进程以虚拟的方式共享内存。进程地址空间是进程可寻址的每个进程都有一个32位或64位的地址空间。虚拟地址空间,可以访问的合法地址空间称为内存区:可执行文件代码的内存映射,称为可执行文件的代码段初始化全局变量的内存映射,称为数据段包含未初始化的全局变量,bss(blockstartedbysymbol)段的零页内存映射用于进程用户空间栈的零页内存映射,如C库或动态链接的代码段、数据段和程序等共享库的bss会被加载到进程的地址空间任何内存映射文件任何共享内存段任何匿名内存映射,如malloc分配的内存内核使用内存描述符结构来表示地址在进程空间中,内存描述符由mm_struct()结构表示。内核线程没有进程地址空间,也没有相关的内存描述符,所有没有用户上下文应用操作的内核线程都映射到物理内存上的虚拟内存,而处理器对物理内存进行操作,Linux使用了三级页表完成地址转换,每个虚拟地址作为索引指向页表,页表入口指向下一级页表。在多级页表中,TLB(translatelookasidebuffer)作为缓存,将虚拟地址映射到物理地址