Linux 2.6 内核阅读笔记 内核同步

2014年7月26日 内核抢占和内核控制路径的设计

内核抢占的一种定义:如果进程正在内核态执行内核函数时,允许发生内核切换(就是被替换的进程是内核函数所在进程),这个内核就是抢占的。

linux内核提供了内核抢占的开启和关闭功能,在current_thread_info的preempt_count字段大于0时,内核就是不能抢占的。可以通过preempt_disable和preempt_enable来增加这个字段来控制这个开关。

中断和软中断和抢占的控制主要使用到current_thread_info->preempt_count字段,这个字段被分成了4部分:0-7位为抢占计数器,8-15位为软中断计数器,16-27位为硬中断计数器,28位为PREEMPT_ACTIVE标志。

内核设计上的选择子某种程度上简化了内核控制路径的同步:

1.所有的中断处理程序相应来自于pic的中断并且禁用IRQ线。此外在中断处理程序结束前,不允许产生相同的中断事件。

2.中断处理程序、软中断和tasklet既不可以被抢占也不能被阻塞,所以它们不可能长时间处于挂起状态。在最坏的情况下,它们的执行将会有轻微的延迟,因为在执行过程中可能发生其他的中断(内核控制路径的嵌套执行)。

3.执行中断处理的内核控制路径不能被执行可延迟函数或系统调用服务例程的内核控制路径中断。

4.软中断和tasklet不能一个给定的cpu上交错执行。

5.同一个tasklet不能同时在几个cpu上执行,但是不同类型的tasklet可以在几个cpu上同时执行。

2014年7月26日 同步原语

内核使用的各种同步技术:

技术

说明 适用范围
每cpu变量 在多个cpu之间复制数据 所有cpu
原子操作 对一个计数器原子地“读-修改-写”操作 所有cpu
内存屏障 避免指令重新排序 本地cpu或者所有cpu
自旋锁 加锁时忙等 所有cpu
信号量 加锁时阻塞等待(睡眠) 所有cpu
顺序锁 基于访问计数器的锁 所有cpu
本地中断的禁止 禁止单个cpu上的中断处理 本地cpu
本地软中断的禁止 禁止单个cpu上的可延迟函数的执行 本地cpu
读-拷贝-写 通过指针而不是锁来访问共享数据结构 所有cpu

每cpu变量:主要做法是声明一个nr_cpus大小的变量数组,每个cpu都使用其自己的变量。要注意不要访问属于其他cpu的变量,可以使用get_cpu_var()(禁止了抢占)宏来获得这个变量,用put_cpu_var()(启动抢占)宏来结束使用这个变量。

原子操作:通过lock,inc,dec等等原子性汇编指令来实现整型值的原子操作。

内存屏障:避免编译器、cpu对指令进行重新排序,当然这样可能会失去指令重排带来的优化。

自旋锁:在进入临界区之前尝试去获得锁,如果不能获得就一直在那空等。其实在底层还是通过lock,inc,dec等等原子性的汇编指令来实现。由于自旋锁浪费cpu周期,只适合临界区比较小的同步场景。

信号量:在进入临界区之前尝试去获得信号量 ,如果不能获得就把当前进程放到信号量的等待队列里面睡眠。底层是通过自旋锁来实现的。信号量不能在中断处理程序和可延迟函数(tasklets)中使用,因为它们不允许睡眠。

顺序锁:类似于读写锁,但是不同于读写锁的读写操作拥有相同优先级,顺序锁中写操作拥有更高的优先级。

本地中断的禁止:通过cli和sti来关闭和打开本地中断。内核提供了local_irq_disable和local_irq_enable来实现这些功能。内核还提供了local_irq_save和local_irq_restore在前面两个宏的功能基础上实现eflags寄存器的保存和恢复功能,这对中断嵌套执行非常重要。

本地软中断的禁止:通过local_bh_disable和local_bh_enable来实现本地软中断的关闭和开启功能。宏展开其实也就是对current_thread_info->preempt_count的软中断部分进行加减操作。

读-拷贝-写:为了提高内核的并发度而引入的一种技术,主要场景适合于指针数据,读操作不需要同步,写操作时,先复制一份副本,再在副本上修改,最后在合适的时候(因为其他读操作可能正在进行中 )将原数据的指针指向副本的地址。

时间: 2024-08-25 00:33:48

Linux 2.6 内核阅读笔记 内核同步的相关文章

Linux 2.6 内核阅读笔记 信号

2014年8月3日 信号处理程序调用过程 当一个进程接收到一个信号时,需要暂停进程执行转去执行专门的信号处理函数(如果定义了这个信号的专门处理函数的话),然后再继续执行进程代码. 所有的信号处理都是通过内核函数do_signal进行的,do_signal如果发现需要处理的信号,并且这个信号有专门的处理函数,就需要调用这个用户态的函数,这是通过handle_signal来处理的.执行信号处理函数是非常复杂的任务,因为在用户态和内核态来回切换需要特别谨慎地处理栈里的内容,在当前进程恢复"正常&quo

Linux 2.6 内核阅读笔记 中断和异常

2014年7月24日 中断门.陷阱门及中断门 中断是可以禁止的,可以通过告诉PIC停止对某个中断的发布.被禁止的中断是不会丢失的,在解除禁止后又会发送到CPU上. 禁止中断和屏蔽(mask)中断的不同之处是屏蔽是忽略掉某个中断,而禁止相当于延迟发送. Intel提供了三种类型的中断描述符:任务门.中断门及陷阱门描述.linux使用与inten稍有不同的细分分类和术语,把他们进行如下分类: 中断门:用户态进程不能访问的一个intel中断门(DPL为0),所有的linux中断处理程序都通过中断门在内

Linux 2.6 内核阅读笔记 内存管理

2014年7月29日 buddy分配算法 内核需要为分配一组连续的页框提供一种健壮.高效的分配策略.分配连续的页框必须解决内存管理中的外碎片(external fragmentation).频繁的请求和释放不同大小的一组连续页框,必然导致分配页框的块分算来许多小块的空闲页框无法被一次性大量分配使用. linux内核采用著名的伙伴系统算法来解决外碎片问题.该算法的核心思想是把所有的空闲页框分成11个链块表.每个链块表的大小分别为1,2,4,8,16,32,64,128,256,512和1024个连

Linux内核学习笔记——内核内存管理方式

一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页大小8KB 内核用相应的数据结构表示系统中的每个物理页: <linux/mm_types.h> struct page {} 内核通过这样的数据结构管理系统中所有的页,因此内核判断一个页是否空闲,谁有拥有这个页 ,拥有者可能是:用户空间进程.动态分配的内核数据.静态内核代码.页高速缓存…… 系统中

Linux概念与体系阅读笔记

[Linux概念与体系教程http://www.cnblogs.com/vamei/archive/2012/10/10/2718229.html] 1.Linux开机启动(bootstrap) 启动顺序:BIOS -> MBR -> boot loader -> kernel -> init process -> login BIOS:Basic Input/Output System MBR :Master Boot Record 2.Linux文件管理 (1)文件附件信

《Linux权威指南》阅读笔记(4)

第十五章  TCP/IP和PPP <DNS与BIND>,见转帖的读书笔记. TCP和UDP数据单位被称为分组包(packet),包头中指定了目的和源端口地址. 互联网协议(IP)在协议层次中位于TCP和UDP下面,将TCP和UDP分组包封装在另一个分组包中(被称为IP报文),

《Linux权威指南》阅读笔记(3)

第十三章 程序设计语言 Linux共享函数库使用一种叫跳跃表格(jump table)的数据结构 gcc -o 执行链接,指定文件名,-c不执行链接,-O优化,-g调试信息放入目标文件, 建立和使用静态函数库的方法: 先gcc -c将含目标函数源码(多个文件也可以)编译为.o文件,然后用ar程序 ar -r 建立.a静态库, 然后用ranlib命令产生索引,然后为该函数库建立头文件 gcc  -I../include -L../lib  -o  wibble  wibble.c  -lstuff

Linux kernel源码阅读笔记2-2.6版本调度器sched.c功能

来自:http://www.ibm.com/developerworks/cn/linux/l-scheduler/ 2.6 版本调度器的源代码都很好地封装到了 /usr/src/linux/kernel/sched.c 文件中.我们在表 1 中对在这个文件中可以找到的一些有用的函数进行了总结. 表 1. Linux 2.6 调度器的功能 函数名 函数说明 schedule 调度器主函数.调度优先级最高的任务执行. load_balance 检查 CPU,查看是否存在不均衡的情况,如果不均衡,就

【转】linux 用户线程、LWP、内核线程学习笔记

[好文转发---linux 用户线程.LWP.内核线程学习笔记] 在现代操作系统中,进程支持多线程.进程是资源管理的最小单元:而线程是程序执行的最小单元.一个进程的组成实体可以分为两大部分:线程集合资源集.进程中的线程是动态的对象:代表了进程指令的执行.资源,包括地址空间.打开的文件.用户信息等等,由进程内的线程共享. 线程有自己的私有数据:程序计数器,栈空间以及寄存器. Why Thread?(传统单线程进程的缺点) 1. 现实中有很多需要并发处理的任务,如数据库的服务器端.网络服务器.大容量