
《l深入理解Linux内核》
小_鱼
这个作者很懒,什么都没留下…
展开
-
Linux进程休眠和唤醒
当进程以阻塞的方式通信,在得到结果前进程会挂起休眠。为了将进程以一种安全的方式进入休眠,我们需要牢记两条规则:一、永远不要在原子上下文中进入休眠。二、进程休眠后,对环境一无所知。唤醒后,必须再次检查以确保我们等待的条件真正为真简单休眠完成唤醒任务的代码还必须能够找到我们的进程,这样才能唤醒休眠的进程。需要维护一个称为等待队列的数据结构。等待队列就是一个进程链表,其中包含了等转载 2013-08-27 23:35:07 · 2246 阅读 · 0 评论 -
linux2.6内核链表
一、 链表数据结构简介 链表是一种常用的组织有序数据的数据结构,它通过指针将一系列数据节点连接成一条数据链,是线性表的一种重要实现方式。相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入或删除数据。链表的开销主要是访问的顺序性和组织链的空间损失。 通常链表数据结构至少应包转载 2013-08-24 20:50:14 · 440 阅读 · 0 评论 -
Linux内核--异常和中断的区别
相信大家都知道非常著名的两个名词:异常和中断,不过,你真的理解这两个名词在说什么吗?它们之间有什么区别呢? 1.中断 大家都知道,当我们在敲击键盘的同时就会产生中断,当硬盘读写完数据之后也会产生中断,所以,我们需要知道,中断是由硬件设备产生的,而它们从物理上说就是电信号,之后,它们通过中断控制器发送给CPU,接着CPU判断收到的中断来自于哪个硬件设备(这定义在内核中),转载 2013-08-24 20:30:14 · 1833 阅读 · 0 评论 -
对 jiffies 溢出、回绕及 time_after 宏的理解
关于jiffies变量: 全局变量jiffies用来记录自启动以来产生的节拍的总数。系统启动时会将该变量初始化为0,此后,每当时钟中断产生时就会增加该变量的值。jiffies和另外一个变量息息相关:HZ。HZ是每秒系统产生的时钟中断次数,所以jiffies每秒增加的值也就是HZ;在x86体系结构中,内核版本在2.4以前的值为100,在2.6内核中被定义为1000。 jiffies的定转载 2013-08-24 15:53:41 · 773 阅读 · 0 评论 -
Linux2.6中的Slab层
还记得一个进程创建的时候是什么给它分配的“进程描述符”吗?没错,是slab分配器,那么,这个slab分配器是个什么东西呢? 分配和释放数据结构是所有内核中最普遍的操作之一。为了便于结构的频繁分配和回收,编程人员常常会用到空闲链表。空闲链表中包含可供使用的,已经分配好的数据结构块。当代码需要一个新的数据结构实例时,就可以从空闲链表中抓取一个,而不需要再去执行一些分配内存的代码,这样转载 2013-08-24 15:06:51 · 473 阅读 · 0 评论 -
Linux2.6内核--抢占
【摘要】本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核(Preemptive Kernel)的区别。接着分析Linux下有两种抢占:用户态抢占(User Preemption)、内核态抢占(Kernel Preemption)。然后分析了在内核态下:如何判断能否抢占内核(什么是可抢占的条件);何时触发重新调度(何时设置可抢占条件);抢占发生的时机(何时检查可抢转载 2013-08-24 22:56:44 · 994 阅读 · 1 评论 -
Linux系统调用的实现机制分析
【摘要】本文介绍了系统调用的一些实现细节。首先分析了系统调用的意义,它们与库函数和应用程序接口有怎样的关系。然后,我们考察了内核如何实现系统调用,以及执行系统调用的连锁反应:陷入内核,传递系统调用号和参数,执行正确的系统调用函数,并把返回值带回用户空间。最后讨论了如何增加系统调用,并提供了从用户空间访问系统调用的简单例子。1 系统调用意义linux内核中设置了一组用于实转载 2013-08-24 22:15:19 · 637 阅读 · 0 评论 -
直接内存访问(DMA)
1. 什么是DMA直接内存访问是一种硬件机制,它允许外围设备和主内存之间直接传输它们的I/O数据,而不需要系统处理器的参与。使用这种机制可以大大提高与设备通信的吞吐量。 2. DMA数据传输有两种方式引发数据传输:第一种情况:软件对数据的请求1. 当进程调用read,驱动程序函数分配一个DMA缓冲区,并让硬件将数据传输到这个缓转载 2013-08-24 15:41:24 · 570 阅读 · 0 评论 -
Linux内存映射--mmap函数
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明:头文件:原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize);返回值: 成功则返回转载 2013-08-24 13:54:11 · 556 阅读 · 0 评论 -
机制与策略
Unix/Linux的接口设计有一句通用的格言“提供机制而不是策略”。区别对待机制(mechanism)和策略(policy)是Unix设计中的一大亮点。大部分的编程问题都可以被切割成两个部分:“需要提供什么功能”(机制)和“怎样实现这些功能”(策略)。如果由程序中的独立部分分别负责机制和策略的实现,那么开发软件就更容易,也更容易适应不同的需求。 开源-展现在我们面前的是数以千计的转载 2013-08-24 20:55:06 · 476 阅读 · 0 评论 -
Linux上程序调试的基石(1)--ptrace
1.在Linux系统中,进程状态除了我们所熟知的TASK_RUNNING,TASK_INTERRUPTIBLE,TASK_STOPPED等,还有一个TASK_TRACED。这表明这个进程处于什么状态? 2.strace可以方便的帮助我们记录进程所执行的系统调用,它是如何跟踪到进程执行的? 3.gdb是我们调试程序的利器,可以设置断点,单步跟踪程序。它的实现原理又是什么? 所有这一切转载 2013-08-27 22:00:25 · 562 阅读 · 0 评论 -
Linux2.6 内核进程调度分析
进程的调度时机与引起进程调度的原因和进程调度的方式有关。在 2.6 中,除核心应用 主动调用调度器之外, 核心还在应用不完全感知的情况下在以下三种时机中启动调度器工作: 1>从中断或系统调用返回到用户态; 2>某个进程允许被抢占 CPU; 3>主动进入休眠状态; 调度策略: 在 Linux2.6 中,仍有三种调度策略: SCHE转载 2013-08-28 00:01:04 · 682 阅读 · 0 评论 -
Linux进程状态
在linux下,通过ps命令我们能够查看到系统中存在的进程,以及它们的状态:R (TASK_RUNNING),可执行状态。只有在该状态的进程才可能在CPU上运行。而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。进程调度器的任务就是从各个CPU的可执行队列中分别转载 2013-08-27 23:54:13 · 491 阅读 · 0 评论 -
Linux进程模型总结
一个进程在CPU上运行可以有两种运行模式(进程状态):用户模式和内核模式。如果当前运行的是用户程序(用户代码),那么对应进程就处于用户模式(用户态),如果出现系统调用或者发生中断,那么对应进程就处于内核模式(核心态)。Linux进程通过一个task_struct结构体描述,在linux/sched.h中定义,通过理解该结构,可更清楚的理解linux进程模型。转载 2013-08-27 23:25:55 · 524 阅读 · 0 评论 -
Linux中的中断处理
与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API request_irq()和free_irq(),request_irq()的原型为:int request_irq(unsigned int irq,void (*handler)(int irq, void *dev_id, struct pt_regs *regs),unsigned long irq转载 2013-08-27 23:08:57 · 686 阅读 · 0 评论 -
Linux系统调用
1 系统调用意义linux内核中设置了一组用于实现系统功能的子程序,称为系统调用。系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于核心态,而普通的函数调用由函数库或用户自己提供,运行于用户态。 一般的,进程是不能访问内核的。它不能访问内核所占内存空间也不能调用内核函数。CPU硬件决定了这些(这就是为什么它被称作"保护模式")。为了和用户空转载 2013-08-27 22:54:56 · 523 阅读 · 0 评论 -
Linux内核基础
Linux系统运行的应用程序通过系统调用来与内核通信。应用程序通常调用库函数(比如C库函数)再有库函数通过系统调用界面,让内核带其完成各种不同的任务。下面这张图显示的就是应用程序,内核和硬件之间的关系: 在任何时间点上我们都可以将每个处理器的活动概括为以下三者之一:1.运行于用户空间,执行用户进程2.运行于内核空间,处于转载 2013-08-27 22:35:17 · 482 阅读 · 0 评论 -
Linux上程序调试的基石(2)--GDB
3. GDB的实现 GDB是GNU发布的一个强大的程序调试工具,用以调试C/C++程序。可以使程序员在程序运行的时候观察程序在内存/寄存器中的使用情况。它的实现也是基于ptrace系统调用来完成的。 其原理是利用ptrace系统调用,在被调试程序和gdb之间建立跟踪关系。然后所有发送给被调试程序的信号(除SIGKILL)都会被gdb截 获,gdb根据截获的信号,查看被调试程序相应的内存地址转载 2013-08-27 22:16:57 · 598 阅读 · 0 评论 -
内存管理单元--MMU
现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持,本节简要介绍MMU的作用。首先引入两个概念,虚拟地址和物理地址。如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区转载 2013-08-24 15:18:43 · 579 阅读 · 0 评论 -
Linux2.6--虚拟文件系统
虚拟文件系统(有时也称作虚拟文件交换,更常见的是简称做VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口.系统中的所有文件系统不但依赖VFS共存,而且也依赖VFS系统协同工作.通过虚拟文件系统,程序可以利用标准的UNIX系统调用对不同的文件系统,甚至不同的介质上的文件系统进行读写操作,如下如图所示: 这幅图的含义是: VFS执行的动转载 2013-08-24 14:07:57 · 519 阅读 · 0 评论 -
Linux2.6--Linus电梯
内核为了处理来自IO层的请求,需要进行相应的优化,因为当请求很多时,且请求的块又都集中在一块,那么如果按照顺序处理这些请求无疑是很大的时间开销,所以,我们需要寻求方法来处理这种情况(当然,不只是这一种情况),这篇文章介绍的就是Linux中经典的IO调度程序--Linus电梯,这个是以Linux的发明者Linus自己的名字命名的。在2.4版的内核中,Linus电梯是默认的IO调度程序。虽然在后来的2转载 2013-08-24 14:02:20 · 758 阅读 · 0 评论 -
Linux2.6内核--VFS层中和进程相关的数据结构
系统中的每一个进程都有自己的一组打开的文件,像根文件系统,当前工作目录,安装点等。有三个数据结构将 VFS 层和系统的进程紧密的联系在一起,它们分别是:file_struct,fs_struct 和 namespace 结构体。 file_struct 结构体定义在文件 中。该结构体由进程描述符中的 files 目录项指向。所有的单个进程相关的信息(如打开的转载 2013-08-23 22:38:35 · 457 阅读 · 0 评论 -
LINUX自旋锁详解2
对于互斥, 旗标是一个有用的工具, 但是它们不是内核提供的唯一这样的工具. 相反, 大部分加锁是由一种称为自旋锁的机制来实现. 不象旗标,自旋锁可用在不能睡眠的代码中, 例如中断处理. 当正确地使用了, 通常自旋锁提供了比旗标更高的性能. 然而, 它们确实带来对它们用法的一套不同的限制.自旋锁概念上简单. 一个自旋锁是一个互斥设备, 只能有 2 个值:"上锁"和"解锁". 它常常实转载 2013-08-23 23:21:14 · 466 阅读 · 0 评论 -
Linux内核高端内存
Linux内核地址映射模型x86 CPU采用了段页式地址映射模型。进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存。段页式机制如下图。 Linux内核地址空间划分通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间。注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的。转载 2013-08-23 13:08:35 · 400 阅读 · 0 评论 -
用户级线程与内核级线程
线程有3种实现模型: 用户级或应用程序级线程 内核级线程 用户级和内核级混合线程 图6-1显示了3种线程实现模型。图6-1(a)显示了用户级线程,图6-1(b)显示了内核级线程,图6-1(c)则显示了用户线程和内核线程的混合。转载 2013-08-24 00:50:29 · 711 阅读 · 0 评论 -
浅析linux内核中的idr机制
idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制。这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁。现在,在内核的很多地方都可以找到idr的身影。 idr机制适用在那些需要把某个整数和特定指针关联在一起的地方。举个例子,在I2C总线中,每个设备都有自己的地址,要想在总线上找到特定的设备,就转载 2013-08-24 00:09:56 · 457 阅读 · 0 评论 -
Linux2.6内核--中断线被关闭的情况
中断系统是现代操作系统中不可获取的一个子系统,它由硬件主动触发并发送到CPU,最后由内核调用中断处理程序处理中断。 那么中断有时候需要关闭,这是为什么呢? 一般分为两种情况:1.内核或程序的某些操作需要关中断2.中断正在执行 下面,我来解释下第二种情况。 下面,首先看一张图: 可以转载 2013-08-23 23:56:40 · 477 阅读 · 0 评论 -
Linux2.6内核--内存管理(2)--区
由于硬件的限制,内核不能对所有的页一视同仁。有些页位于内存中的特定物理地址上,所以,不能将其用于一些特别的任务。(关于内存分页机制可以查看:http://blog.youkuaiyun.com/dlutbrucezhang/article/details/10181535)由于存在这种限制,所以内核会把页划分为不同的区。内核使用区对具有相似特性的页进行分组。Linux必须处理如下两种由于硬件存在缺陷而引起的内转载 2013-08-23 12:54:46 · 576 阅读 · 0 评论 -
LINUX自旋锁详解
加锁(locking)是一种广泛应用的同步技术。当内核控制路径必须访问共享数据结构或进入临界区时,就需要为自己获取一把“锁”。由锁机制保护的资源非常类似于限制于房间内的资源,当某人进入房间时,就把门锁上。如果内核控制路径希望访问资源,就试图获取钥匙“打开门”。当且仅当资源空闲时,它才能成功。然后,只要它还想使用这个资源,门就依然锁着。当内核控制路径释放了锁时,门就打开,另一个内核控制路径就可以进入转载 2013-08-23 23:09:10 · 1998 阅读 · 0 评论 -
Linux2.6内核--中断下半部实现方法 工作队列
工作队列子系统是一个用于创建内核线程的接口,通过它创建的线程负责执行由内核其他部分排到队列里的任务。它创建的这些内核线程称作工作者线程。工作队列可以让你的驱动程序创建一个专门的工作者线程来处理需要退后的工作。不过,工作队列子系统提供了一个缺省的工作者线程来处理这些工作。因此,工作队列最基本的表现形式,就转变成了一个把需要退后执行的任务交给特定的通用线程的这样一种接口。转载 2013-08-23 23:44:48 · 503 阅读 · 0 评论 -
Linux内核线程
内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程,与系统中其他进程“并行”执行(实际上,也并行于内核自身的执行),内核线程经常被称为内核“守护进程”。它们主要用于执行下列任务:l 周期性地将修改的内存页与页来源块设备同步。l 如果内存页很少使用,则写入交换区。l 管理延时动作l 实现文件系统的事务日志。 内核线程转载 2013-08-24 13:58:06 · 433 阅读 · 0 评论 -
linux下字节对齐
一,内存地址对齐的概念 计算机内存中排列、访问数据的一种方式,包含基本数据对齐和结构体数据对齐。 32位系统中,数据总线宽度为32,每次能够读取4字节数据。地址总线为32,最大寻址空间为4GB。但是由于最低位A[0]~A[1]是不用于寻址的,因此只能访问4的倍数的地址空间,但是寻址空间还是2^30*字长=4GB。 因此内存中除了结构体中成员变量之外的基本类型的开始转载 2013-08-24 13:48:29 · 3669 阅读 · 0 评论 -
Linux2.6--进程抢占和上下文切换
上下文切换,也就是从一个可执行进程切换到另一个可执行进程,由定义在kernel/sched.c中的context_switch()函数负责处理。每当一个新的进程被选出来准备投入运行的时候,schedule()就会调用该函数。它完成了两相基本工作: 1.调用声明在中的switch_mm(),该函数负责把虚拟内存从上一个进程映射切换到新的进程中去,其实就是切换到另一个进程的地址空间中转载 2013-08-24 13:21:41 · 463 阅读 · 0 评论 -
Linux系统调用中的参数验证
我们都知道,用户程序可以通过库函数来通知内核执行系统调用,由于是在内核空间中执行,所以,每一个步骤都需要非常小心,因为错误的操作随时可以导致系统崩溃。 系统调用必须仔细检查它们所有的参数是否合法有效。举例来说,与文件IO相关的系统调用必须检查文件描述符是否有效。与进程相关的函数必须检查提供的PID是否有效。必须检查每个参数,保证它们不但合法有效,而且正确。进程不应该让转载 2013-08-24 13:14:39 · 652 阅读 · 0 评论 -
linux内核 asmlinkage宏
asmlinkage是个宏,使用它是为了保持参数在stack中。看一下/usr/include/asm/linkage.h里面的定义:#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))其中 __attribute__是关键字,是gcc的C语言扩展。__attribute__机制是GNU C的转载 2013-08-24 00:35:40 · 587 阅读 · 0 评论 -
Linux2.6内核--对块IO层操作的讨论
当一个块被调入内存时(也就是说,在读入后或等待写出时),它要存储在缓冲区中。每个缓冲区与一个块对应,它相当于是磁盘块在内存中的表示。块包含一个或多个扇区,但大小不能超过一页,所以一页可以容纳一个或多个内存块。由于内核在处理数据时需要一些相关的控制信息(比如块属于哪个设备,块对应于哪个缓冲区),所以,每一个缓冲区都有一个对应的描述符。该描述符用 buffer_head 结构体表示,称作缓冲区头,转载 2013-08-23 22:24:28 · 416 阅读 · 0 评论 -
linux内存屏障浅析
内存屏障主要解决了两个问题:单处理器下的乱序问题和多处理器下的内存同步问题。为什么会乱序现在的CPU一般采用流水线来执行指令。一个指令的执行被分成:取指、译码、访存、执行、写回、等若干个阶段。然后,多条指令可以同时存在于流水线中,同时被执行。指令流水线并不是串行的,并不会因为一个耗时很长的指令在“执行”阶段呆很长时间,而导致后续的指令都卡在“执行”之前的阶段上。相反,流水线是并转载 2013-08-23 22:04:06 · 497 阅读 · 0 评论 -
Linux2.6内核中链表的实现
对于一个计算机专业的学生,链表这种数据结构对我们来说再熟悉不过了,毕竟在大学的《数据结构》中就讲解过,相信你也自己实现过,它实现起来可能是这个样子:(这里的例子都来自《Linux内核设计与实现》第三版) 假定我们有一个数据结构来描述犬科动物中的一员[cpp] view plaincopyprint?struct fox转载 2013-08-24 00:13:40 · 468 阅读 · 0 评论 -
Linux2.6内核--内存管理(1)--分页机制
在内核里分配内存可不像在其他地方分配内存那么容易。造成这种局面的因素很多。从根本上讲,是因为内核本身不能像用户空间那样奢侈的使用内存。内核与用户空间不同,它不具备这种能力,它不支持简单便捷的内存分配方式。比如,内核一般不能睡眠。此外,处理内存分配错误对于内核来说也绝非是一件简单的事。正式由于这些限制,再加上内存分配机制不能太复杂,所以在内核中获取内存要比在用户空间复杂的多。 首先转载 2013-08-23 12:46:17 · 591 阅读 · 0 评论