- 博客(25)
- 资源 (14)
- 收藏
- 关注
原创 写时复制
<br />第一代Unix系统实现了一种傻瓜式的进程创建:当发出fork()系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程。这种行为是非常耗时的,因为它需要:<br />- 为子进程的页表分配页框<br />- 为子进程的页分配页框<br />- 初始化子进程的页表<br />- 把父进程的页复制到子进程相应的页中<br /> <br />这种创建地址空间的方法涉及许多内存访问,消耗许多CPU周期,并且完全破坏了高速缓存中的内容。在大多数情况下,这样做常常是毫无意义的,因为许多子进
2010-05-31 20:27:00 3454 5
原创 请求调页
<br />上一篇博文引出了“请求调页”技术,术语“请求调页”指的是一种动态内存分配技术,它把页框的分配推迟到不能再推迟为止,也就是说,一直推迟到进程要访问的页不在物理RAM中时为止,由此引起一个缺页异常。<br /> <br />请求调页技术背后的动机是:进程开始运行的时候并不访问其线性地址空间中的全部地址。<br /> <br />事实上,有一部分地址也许永远不被进程使用。此外,程序的局部性原理保证了在程序执行的每个阶段,真正引用的进程页只有一小部分,因此临时用不着的页所在的页框可以由其他进程来使用。因
2010-05-31 20:24:00 3957 1
原创 处理地址空间内的错误地址
<br />如果addr地址属于进程的地址空间,则do_page_fault()转到good_area标记处的语句执行:<br />/*<br /> * Ok, we have a good vm_area for this memory access, so<br /> * we can handle it..<br /> */<br />good_area:<br /> si_code = SEGV_ACCERR;<br /> write = 0;<br /> switch (error_code &
2010-05-31 20:20:00 4084
原创 处理地址空间以外的错误地址
<br />前面博文提到了,如果address不属于进程的地址空间,那么do_page_fault()函数继续执行bad_area标记处的语句。如果错误发生在用户态,则发送一个SIGSEGV信号给current进程并结束函数:<br /><br />/*<br /> * Something tried to access memory that isn't in our memory map..<br /> * Fix it, but check if it's kernel or user first..
2010-05-31 20:16:00 2859
原创 缺页异常处理程序
<br />我们在中断专题中提到,Linux的缺页(Page Fault)异常处理程序必须区分以下两种情况:由编程错误所引起的异常,及由引用属于进程地址空间但还尚未分配物理页框的页所引起的异常。<br /> <br />线性区描述符可以让缺页异常处理程序非常有效地完成它的工作。do_page_fault()函数是80x86上的缺页中断服务程序,它把引起缺页的线性地址和当前进程的线性区相比较,从而能够根据和下图所示的方案选择适当的方法处理这个异常。<br /> <br /><br /> <br /> <br
2010-05-31 20:14:00 12583 7
原创 释放线性地址区间
<br />内核使用do_munmap()函数从当前进程的地址空间中删除一个线性地址区间。<br /> 1 do_munmap()函数<br /> <br />该参数为:进程内存描述符的地址mm,地址区间的起始地址start和它的长度len。要删除的区间并不总是对应一个线性区,它或许是一个线性区的一部分,或许跨越两个或多个线性区。<br /> <br />该函数经过两个主要的阶段。第一阶段(第1一6步),扫描进程所拥有的线性区链表,并把包含在进程地址空间的线性地址区间中的所有线性区从链表中解除链接。第二阶段
2010-05-31 18:49:00 3945 3
原创 分配线性地址区间
<br />前面讲了那么多线性区底层分配的细节,现在让我们讨论怎样分配一个新的线性地址区间。为了做到这点,do_mmap()函数为当前进程创建并初始化一个新的线性区。不过,分配成功之后,可以把这个新的线性区与进程已有的其他线性区进行合并。<br /><br />static inline unsigned long do_mmap(struct file *file, unsigned long addr,<br /> unsigned long len, unsigned long prot,<br />
2010-05-31 18:46:00 2600 1
原创 线性区的底层处理
<br />在上一篇博文对控制内存处理所用的数据结构和状态信息有了基本理解以后,我们来看一组对线性区描述符进行操作的低层函数。这些函数应当被看作简化了do_map()和do_unmap()实现的辅助函数。这两个函数将在后面的相关博文中进行描述,它们分别扩大或者缩小进程的地址空间。这两个函数所处的层次比我们这里所考虑函数的层次要高一些,它们并不接受线性区描述符作为参数,而是使用一个线性地址区间的起始地址、长度和访问限权作为参数。<br /> 1 查找给定地址的最邻近区<br /> <br />find_vma
2010-05-31 18:39:00 2330 2
原创 线性区的数据结构
<br />上一篇博文我们会看到,内核使用一种新的资源成功实现了对进程动态内存的推迟分配。当用户态进程请求动态内存时,并没有获得请求的页框,而仅仅获得对一个新的线性地址区间的使用权,而这一线性地址区间就成为进程地址空间的一部分。这一区间就叫做“线性区”。本博,我们就来详细讨论这个线性区。<br /> 1 线性区数据结构<br /> <br />Linux通过类型为vm_area_struct的对象实现线性区,它的字段如下所示:<br />struct vm_area_struct {<br /> struc
2010-05-31 18:30:00 3629 1
原创 内存描述符
<br />在前面的系列博文中我们已经看到,内核中的函数以相当直截了当的方式获得动态内存:__get_free_pages()或alloc_pages()通过伙伴算法从分区页框分配器中获得页框,kmem_cache_alloc()或kmalloc()使用slab分配器为专用或通用对象分配内存,而vmalloc()或vmalloc_32()获得一块非连续的内存区。如果所请求的内存区得以满足,这些函数都返回一个页描述符或线性地址(即所分配动态内存区的起始地址)。<br /> <br />使用这些简单方法是基于以
2010-05-31 16:37:00 3565
原创 内核同步与互斥的总结
前面讲了那么多内核同步与互斥的技术,现在我们就来做一个总结。我们可以随意使用前面所述的同步技术保护共享数据结构避免竞争条件。当然,系统性能可能随所选择同步原语种类的不同而有很大变化。通常情况下,内核开发者采用下述由经验得到的法则:把系统中的并发度保持在尽可能高的程度。系统中的并发度又取决于两个主要因素:(1)同时运转的I/O设备数(2)进行有效工作的CPU数为了使I/O吞吐量最大化,应该使中断禁止保持在很短的时间。因为,当中断被禁止时,由I/O设备产生的IRQ被PIC暂时忽略,因此,就没
2010-05-31 15:34:00 2220
原创 一些避免竞争条件的实例
<br />人们总是期望内核开发者确定和解决由内核控制路径的交错执行所引起的同步问题。但是,避免竞争条件是一项艰巨的任务,因为这需要对内核的各个成分如何相互作用有一个清楚的理解。为了直观地认识内核内部到底是什么样子,需要提及前面博文中所定义同步技术的几种典型应用场景。<br />1 引用计数器<br /><br />引用计数器广泛地用在内核中以避免由于资源的并发分配和释放而产生的竞争条件。引用计数器(reference counter)只不过是一个atomic_t计数器,与特定的资源,如内存页、模块或文
2010-05-31 14:51:00 1679
原创 禁止本地中断
<br />禁止本地CPU中断是确保一组内核语句被当作一个临界区处理的主要机制。这个机制的意义是:即使当硬件设备产生了一个IRQ信号时,中断禁止也让内核控制路径继续执行,因此,这就提供了一种有效的方式,确保内核控制路径中的一些中断处理程序能访问的数据结构也受到保护。<br />1 禁止本地中断<br /><br />然而,禁止本地中断并不保护运行在另一个CPU上的中断处理程序对该数据结构的并发访问,因此,在多处理器系统上,禁止本地中断经常与自旋锁结合使用。<br /><br />宏local_irq
2010-05-31 14:32:00 4180 1
原创 信号量
信号量这个东西,从本质上说,它实现了一个加锁原语,即让等待者睡眠,直到等待的资源变为空闲。实际上,Linux提供两种信号量:- 内核信号量,由内核控制路径使用- System V IPC信号量,由用户态进程使用在本专题,我们集中讨论内核信号量,而IPC信号量将有专门的专题来讲。内核信号量类似于自旋锁,因为当锁关闭着时,它不允许内核控制路径继续进行。然而,当内核控制路径试图获取内核信号量所保护的忙资源时,相应的进程被挂起,其task_struck结构被从rq上脱链。只有在资源被释放时,
2010-05-31 14:27:00 2296 3
原创 RCU机制
读-拷贝-更新(RCU)是为了保护在多数情况下被多个CPU读的数据结构而设计的另一种同步技术。RCU允许多个读者和写者并发执行(相对于只允许一个写者执行的顺序锁有了改进)。而且,RCU是不使用锁的,就是说,它不使用被所有CPU共享的锁或计数器,在这一点上与读/写自旋锁和顺序锁(由于高速缓存行窃用和失效而有很高的开销)相比RCU具有更大的优势。RCU是如何不使用共享数据结构而令人惊讶地实现多
2010-05-19 14:46:00 3994
原创 顺序锁
当使用读/写自旋锁时,内核控制路径发出的执行read_lock或write_lock操作的请求具有相同的优先权:读者必须等待,直到写操作完成。同样地,写者也必须等待,直到读操作完成。Linux 2.6中引入了顺序锁(seqlock),它与读/写自旋锁非常相似,只是它为写者赋予了较高的优先级:事实上,即使在读者正在读的时候也允许写者继续运行。这种策略的好处是写者永远不会等待读(除非另外一个写
2010-05-19 14:14:00 2894 2
原创 读写自旋锁
读/写自旋锁同样是在保护SMP体系下的共享数据结构而引入的,它的引入是为了增加内核的并发能力。只要内核控制路径没有对数据结构进行修改,读/写自旋锁就允许多个内核控制路径同时读同一数据结构。如果一个内核控制路径想对这个结构进行写操作,那么它必须首先获取读/写锁的写锁,写锁授权独占访问这个资源。这样设计的目的,即允许对数据结构并发读可以提高系统性能。下图显示有两个受读/写锁保护的临界区(CI和
2010-05-18 20:24:00 2093 1
原创 自旋锁
加锁(locking)是一种广泛应用的同步技术。当内核控制路径必须访问共享数据结构或进入临界区时,就需要为自己获取一把“锁”。由锁机制保护的资源非常类似于限制于房间内的资源,当某人进入房间时,就把门锁上。如果内核控制路径希望访问资源,就试图获取钥匙“打开门”。当且仅当资源空闲时,它才能成功。然后,只要它还想使用这个资源,门就依然锁着。当内核控制路径释放了锁时,门就打开,另一个内核控制路径就可以进入
2010-05-18 19:59:00 3477 3
原创 优化屏障和内存壁垒
当使用指令优化的编译器时,你千万不要认为指令会严格按它们在源代码中出现的顺序执行。例如,编译器可能重新安排汇编语言指令以使寄存器以最优的方式使用。此外,现代CPU通常并行地执行若干条指令,且可能重新安排内存访问。这种重新排序可以极大地加速程序的执行。然而,当处理同步时,必须避免指令重新排序。因为如果放在同步及原语之后的一条指令在同步原语本身之前执行,事情很快就会变得失控。所以,所有的同步技
2010-05-18 19:56:00 2724
原创 原子操作
若干汇编语言指令都具有“读-修改-写”特点 —— 也就是说,它们访问存储器单元两次,第一次读原值,第二次写新值。假定运行在两个CPU上的两个内核控制路径试图通过执行非原子操作来同时“读-修改-写”同一存储器单元,如n++。首先,两个CPU都试图读同一单元,比如n=5。但是存储器仲裁器(对访问RAM芯片的操作进行串行化的硬件电路)插手,只允许其中的一个访问而让另一个延迟。然而,当第一个读操作
2010-05-18 19:51:00 2209
原创 每CPU变量
最好的同步技术是把设计不需要同步的临界资源放在首位,这是一种思维方法,因为每一种显式的同步原语都有不容忽视的性能开销。最简单也是最重要的同步技术包括把内核变量或数据结构声明为每CPU变量(per-cpu variable)。每CPU变量主要是数据结构的数组,系统的每个CPU对应数组的一个元素。一个CPU不应该访问与其他CPU对应的数组元素,另外,它可以随意读或修改它自己的元素而不用
2010-05-18 19:47:00 5738
原创 内核抢占
为了更好地理解内核代码是如何执行的,我们借用ULK-3中的思想,把内核看作必须满足两种请求的侍者:一种请求来自顾客,另一种请求来自数量有限的几个不同的老板。对不同的请求,侍者采用如下的策略:1. 老板提出请求时,如果侍者正空闲,则侍者开始为老板服务,这是空闲情况。2. 如果老板提出请求时侍者正在为顾客服务,那么侍者停止为顾客服务,开始为老板服务,这是高优先级抢占低优先级情况。
2010-05-18 18:52:00 2627
转载 rpm安装出现问题,提示lock
故障现象:[root@localhost Mysql4.1.14.Rhel3]# rpm -ivh MySQL*warning: waiting for transaction lock on /var/lib/rpm/__db.000解决方法: 因为prm数据库出现损坏导致,可能导致多数rpm软件的升级、安装或者删除都会有问题。此错误,请以root身份输入
2010-05-13 16:43:00 4736 1
原创 linux下网卡网络流量监控工具
个人比较喜欢iftop,它能动态的用简单的ASC图标识网卡当前流量首行是网络流量刻度,中间是与其它机器的流量,有个白底的bar直观的标识流量变化,后三列数据分别表示:1. preceding 2 seconds 过去两秒钟的流量(traffic)2. around half that amount over the preceding 10s 过去十秒钟流量的一半
2010-05-12 12:00:00 3052
原创 制作rpm包
菜菜最近做了一个Hello,World的RPM包,由于什么都不懂,所以做了一整天,有点感想,在这里把我的制作方案和经验和大家分享一下。RPM是Redhat Package Manage的缩写,将Source Code简单地包装成档案,在最终生成的RPM包中有两个档案文件,一个是ix86.rpm,另外一个是src.rpm,ix86文件包含软件发布者选择发布的应用必须的文件,而src文件则包含
2010-05-12 09:23:00 2981 1
NFS文件系统
2012-04-08
[数据结构(C语言版)].严蔚敏_吴伟民扫描版
2012-01-12
数据结构与算法——面向对象C++设计模式
2011-11-27
高性能分布式监控系统Ganglia详解
2011-07-10
疯狂内核之——内核初始化
2011-05-30
疯狂内核之——Linux虚拟内存
2011-05-30
疯狂内核之——虚拟文件系统
2011-05-30
疯狂内核之——进程管理子系统
2011-05-30
疯狂内核之——Linux预备知识.pdf
2011-05-30
23种GoF设计模式Java版.pdf
2011-05-29
基于C++语言的GoF23种设计模式
2011-05-29
从8086到Pentium Ⅲ微型计算机及接口技术3
2010-09-24
Linux sysfs 文件系统机制详解
2009-12-14
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人