Linux内核锁实现原理,linux 大内核锁原理
大内核锁(BKL)的设计是在kernel hacker们对多处理器的同步还没有十足把握时,引入的大粒度锁。
他的设计思想是,一旦某个内核路径获取了这把锁,那么其他所有的内核路径都不能再获取到这把锁。
自旋锁加锁的对象一般是一个全局变量,大内核锁加锁的对象是一段代码,里面可能包含多个全局变量。
那么他带来的问题是,虽然A只需要互斥访问全局变量a,但附带锁了全局变量b,从而导致B不能访问b了。
大内核锁最先的实现靠一个全局自旋锁,但大家觉得这个锁的开销太大了,影响了实时性,因此后来将自旋锁
改成了mutex,但阻塞时间一般不是很长,所以加锁失败的挂起和唤醒也是非常costly 所以后来又改成了自旋锁实现。
大内核锁一般是在文件系统,驱动等中用的比较多。目前kernel hacker们仍然在努力将大内核锁从linux里铲除。
下面来分析大内核锁的实现。
我们之前说了大内核锁有两种实现,分别是自旋锁和mutex锁。
如果是mutex锁实现,自然不能在中断环境下使用大内核锁,因为中断下禁止调度是金科玉律。
那么在大内核锁内调度是否可以?我们知道,如果一个内核流程获取到资源后就应该尽快完成操作释放资源,
以便下一个竞争者获取到资源。所以资源持有者不得睡眠是一个普遍共识。可是大内核锁不这么认为,
持有大内核锁的用户是允许睡眠的-虽然我们并不鼓励这样,但是内核的大内核锁的设计方案里,会在进程切换时,
检查当前进程是否持有大内核锁并释放,当重新获取到cpu后,再尝试抓这把大内核锁。也就是说,进程在
持有大内核锁时是可以睡眠的,这就带来资源starvation
来看基于自旋锁的大内核锁实现
static inline void __lock_kernel(void)
{
preempt_disable();
if (unlikely(!_raw_spin_trylock(&kernel_flag))) {
/*
* If preemption was disabled even before this
* was called, there's nothing we can be polite
* about - just spin.
*/
if (preempt_count() > 1) {
_raw_spin_lock(&kernel_flag);
return;
}
/*
* Otherwise, let's wait for the kernel lock
* with preemption enabled..
*/
do {
preempt_enable();
while (spin_is_locked(&kernel_flag))
cpu_relax();
preempt_disable();
} while (!_raw_spin_trylock(&kernel_flag));
}
}
void __lockfunc lock_kernel(void)
{
int depth = current->lock_depth+1;
if (likely(!depth))
__lock_kernel();
current->lock_depth = depth;
}
这段代码的意思是,
1) 如果当前进程如果不是重复加锁的话,就尝试去抓这把锁,
并把锁深度加1。这么做的目的是避免锁重入。
2)实际加锁的时候,先关抢占,如果尝试加锁失败,则会
根据调用lock_kernel之前关抢占与否,来决定是闷头死转,还是大开门户的轮询。
如果是mutex实现的大内核锁kernel_lock,则第2步直接mutex_lock--要么成功要么阻塞。
之前我们提到,在进程发生切换时,会检查当前进程是否持有大内核锁,这是在schedule
里做的。
asmlinkage void __sched schedule(void)
{
release_kernel_lock(prev);
context_switch();
reacquire_kernel_lock(current);
}
release_kernel_lock会判断如果当前进程持有大内核锁,则释放锁。
reacquire_kernel_lock在进程再次被调度回来后,检查当前进程在切换之前是否
因为持有大内核锁。如果有的话,说明在进程切换时,当前进程的大内核锁被强行释放了,
需要再次获取。
需要说明的是自旋锁版本:
release_kernel_lock在释放锁之后还会开抢占,因为获取到大内核锁之后会关闭;
reacquire_kernel_lock在重新获取到锁之后,会关闭抢占。
重点关注__reacquire_kernel_lock的实现
自旋锁的实现版本:
成功抓到锁之后关抢占,如果抓不到锁,则一直遍历need resched标志直至退出。注意和lock_kernel比较。
mutex版本就比较扯淡了:
int __lockfunc __reacquire_kernel_lock(void)
{
int saved_lock_depth = current->lock_depth;
BUG_ON(saved_lock_depth < 0);
current->lock_depth = -1;
preempt_enable_no_resched();
mutex_lock(&kernel_sem);
preempt_disable();
current->lock_depth = saved_lock_depth;
return 0;
}
我们之前看到kernel_lock的mutex实现就是一句mutex_lock 而这里的__reacquire_kernel_lock
有些细节差别。
1)首先将当前进程的加锁深度设置为-1,代表无人加锁。这么做的意义是,第2步的mutex_lock如果产生调度,
再次进入shedule时,不会重复释放大内核锁,因为__reacquire_kernel_lock之前已经释放锁了。
2)接着临时强行开抢占后执行mutex_lock
因为在schedule里是关抢占的,此时不能发生进程切换。
3)如果抓到锁则关抢占
恢复到schedule里调__reacquire_kernel_lock之前的抢占状态
4)将加锁深度恢复到__reacquire_kernel_lock之前的深度
恢复到schedule里调__reacquire_kernel_lock之前的大内核锁持有状态
总而言之,关于大内核锁,记住两点就可以了:
1)由spinlock或者mutex_lock锁住一个全局变量来实现
2)进程切换时会检查当前进程是否持有大内核锁,而采取释放和重获的操作,以支持持有大内核锁的用户代码睡眠。
Linux内核锁实现原理,linux 大内核锁原理相关推荐
- 大数据全样而非抽样原理_大数据思维原理,你了解多少?
原标题:大数据思维原理,你了解多少? 随着大数据的深入人心,很多大数据技术的专家.战略专家.未来学学者等开始提出.解读并丰富大数据思维概念的内涵和外延.总体来说,大数据思维包括全样思维.容错思维和相关 ...
- linux内核中锁有哪些,Linux内核中有哪些锁
Linux内核中的各种锁 在LInux操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需 ...
- 精品网摘:大内核锁将何去何从
精品网摘:大内核锁将何去何从 注:本文转载自CSDN博客universus的专栏:http://blog.csdn.net/universus/article/details/5623971 大内核锁 ...
- Linux内核中的同步原语:自旋锁,信号量,互斥锁,读写信号量,顺序锁
Linux内核中的同步原语 自旋锁,信号量,互斥锁,读写信号量,顺序锁 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. Linux 内核中的同步原 ...
- 不属于linux内核锁的是,Linux内核中的锁
1. 为什么要保证原子性 处理器分两种:cisc(复杂指令集,可以直接在内存上进行操作,如x86,一条汇编指令可以原子的完整读内存.计算.写内存)和rics(精简指令集,所有操作都必须是在CPU内部进 ...
- 大话Linux内核中锁机制之原子操作、自旋锁【转】
转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...
- Linux 内核同步(二):自旋锁(Spinlock)
自旋锁 内核当发生访问资源冲突的时候,可以有两种锁的解决方案选择: 一个是原地等待 一个是挂起当前进程,调度其他进程执行(睡眠) Spinlock 是内核中提供的一种比较常见的锁机制,自旋锁是&quo ...
- 透明大页相关内核参数_Alibaba Cloud Linux 2系统中与透明大页THP相关的性能调优方法...
免责声明:本文档可能包含第三方产品信息,该信息仅供参考.阿里云对第三方产品的性能.可靠性以及操作可能带来的潜在影响,不做任何暗示或其他形式的承诺. 概述 本文主要介绍在Alibaba Cloud Li ...
- linux内核中分配4M以上大内存的方法
在内核中, kmalloc能够分配的最大连续内存为2的(MAX_ORDER-1)次方个page(参见alloc_pages函数, "if (unlikely(order >= ...
最新文章
- 关于 Twing Hot Link 的一些事
- html5新年网页做给父母的,春节回家,要陪父母做这十件小事
- JQuery 如何选择带有多个class的元素
- HP LoadRunner 11.00 新鲜尝
- pandas 数据分析使用
- SQL 语法参考手册
- leetcode1046. 最后一块石头的重量(堆)
- Elasticsearch集群监控工具bigdesk插件安装
- 架构设计系列(一)——架构设计概述
- MySQL镜像下载及启动
- Go实战--golang中defer的使用
- jni数组使用(一)
- 开店软件透彻分析推荐
- Pyqt之exec()和show()与弹出自定义对话框
- 即时通讯工具的优缺点分别是什么
- 计算机无法装补丁,win7系统安装不了SP1补丁包怎么办 win7电脑SP1补丁包安装失败的解决方法...
- 用户画像项目两大核心内容之一“one_id”(含SQL实现代码)
- EFCore-脚手架Scaffold发生Build Failed问题的终极解决
- YOLOX: Exceeding YOLO Series in 2021
- easy connect无法卸载干净,后台sangfor文件一直在运行的卸载方法
热门文章
- java 中map_Java中Map集合
- 新手上路之django项目开发(二)-----引入静态文件
- linux下安装pm2
- 机器学习算法系列(一)-基础机器学习算法入门
- 远程修改linux文件内容,用VS Code连接远程Linux服务器实时修改代码
- 组态王怎么做超级曲线_鸭肉怎么做?大叔教你红烧鸭块,香气扑鼻,简单易做,超级好吃...
- linux怎么才能算telnet成功_怎么表白才算成功呢
- mysql联合查询语句详解_实例讲解MySQL联合查询
- JQ css3 导航栏到底部上移
- checkbox 最多选两项