当前位置: 首页 > news >正文

Linux内核与驱动面试经典“小”问题集锦(2)

接前一篇文章:Linux内核与驱动面试经典“小”问题集锦(1)

问题2

问:spin_lock和spin_lock_irq以及spin_lock_irqsave的区别是什么?也可以说它们之间有什么区别和联系?

备注:此题是自旋锁问题的进一步问题,一般都是在前边你回答出Linux内核的锁机制之后(上一回的问题1,参见Linux内核与驱动面试经典“小”问题集锦(1))的进一步提问、追问。这个问题在蔚来、比特大陆以及其它一些公司面试时问到过。

答:

spin_lock()/spin_unlock()是自旋锁机制的基础,其与关中断local_irq_disable()/开中断local_irq_enable()关中断并保存状态字local_irq_save()/开中断并恢复状态字local_irq_restore()关底半部local_bh_disable()/开底半部local_bh_enable()形成了整套自旋锁机制。其相互之间的关系如下:

  • spin_lock与spin_lock_irq的关系

spin_lock_irq() = spin_lock() + local_irq_disable()

即spin_lock_irq()是spin_lock()的同时关中断。与之相对应,

spin_unlock_irq() = spin_unlock() + local_irq_enable()

即spin_unlock_irq()是spin_unlock()的同时开中断。

  • spin_lock与spin_lock_irqsave的关系

spin_lock_irqsave() = spin_lock() + local_irq_save()

即spin_lock_irqsave()是spin_lock()的同时关中断并保存状态字。与之相对应,

spin_unlock_irqrestore() = spin_unlock() + local_irq_restore()

即spin_unlock_irqrestore()是spin_unlock()的同时开中断并恢复状态字。

  • spin_lock与spin_lock_bh的关系

spin_lock_bh() = spin_lock() + local_bh_disable()

即spin_lock_bh()是spin_lock()的同时关底半部。与之相对应,

spin_unlock_bh() = spin_unlock() + local_bh_enable()

即spin_unlock_bh()是spin_unlock()的同时开底半部。

spin_lock_irq()、spin_lock_irqsave()、spin_lock_bh()类似函数会为自旋锁的使用“系好安全带”,以避免突如其来的中断驶入对系统造成的伤害。

问题3

问:中断中应该使用自旋锁还是信号量或互斥锁?

备注:这个问题在百度、蔚来以及其它一些公司面试时问到过。

答:

自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分。自旋锁最多只能被一个内核任务持有。在单处理器上,自旋锁仅仅当作一个设置内核抢占的开关,内核不能被抢占。

信号量是一种睡眠锁。如果有一个任务试图获得一个已被持有的信号量时,信号量会将其推入等待队列,然后让其睡眠;当持有信号量的进程将信号量释放后,在等待队列中的一个任务将被唤醒,从而便可以获得这个信号量。信号量不同于自旋锁,它不会关闭内核抢占,所以持有信号量的代码可以被抢占。信号量只能在进程上下文中使用,因为中断上下文中是不能被调度的(即在中断上下文中释放时不能进行进程切换)。

综上,由于在中断中不能被调度,并且中断处理函数是不可重入的,因此中断中应该选择自旋锁而非信号量或互斥锁等。

额外:

这里要多说一点。如果做出上述回答后,面试官继续追问:为什么中断中不能休眠或进行调度?则原因如下:

(1)中断处理的时候不应该发生进程切换,因为在中断上下文中,唯一能打断当前中断handler的只有更高优先级的中断,它不会被进程打断。如果在中断上下文中休眠,则没有办法唤醒它,因为所有的wake_up_xxx都是针对某个进程而言的,而在中断上下文中,没有进程(task_struct)的概念,因此如果真的休眠,则内核几乎肯定会死。

(2)schedule()在切换进程时,保存当前的进程上下文(CPU寄存器的值、进程的状态以及堆栈中的内容),以便以后恢复此进程运行。中断发生后,内核会先保存当前被中断的进程上下文(在调用中断处理程序后恢复)。但在中断处理程序里,CPU寄存器的定已经变化了吧(最重要的程序计数器PC、堆栈SP等),如果此时因为睡眠或阻塞操作调用了schedule(),则保存的进程上下文就不是当前的进程上下文了。所以不可以在中断处理程序中调用schedule()以及引发schedule()的操作。

参考资料:

《Linux设备驱动开发详解 —— 基于最新的Linux 4.0内核》 宋宝华 编著,机械工业出版社

信号量和自旋锁的选择

为什么中断不能睡眠

http://www.lryc.cn/news/294210.html

相关文章:

  • windws安装mysql详细步骤
  • Linux的库文件
  • JAVA Web 学习(五)Nginx、RPC、JWT
  • Python编程的十大神奇依赖库
  • Java类的继承
  • 【DC渗透系列】DC-4靶场
  • 开源软件全景解析:驱动技术创新与行业革新的力量
  • 目标检测及相关算法介绍
  • 跟着cherno手搓游戏引擎【20】混合(blend)
  • leetcode 3.无重复字符的最长字串(滑动窗口) (C++)DAY2
  • Android Build 依赖项
  • SpringMVC精简知识点
  • 如何写好论文——(17)如何用批判性思维检阅文献
  • git将项目的某次签入遴选(Cherry-Pick)另一个项目
  • 开源节点框架STNodeEditor使用
  • 算法每日一题: Nim游戏 | 找规律
  • 分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别
  • Dockerfile保留字
  • Linux的7个运行级别
  • Linux期末总复习( 详解 )
  • 【Linux系统化学习】进程等待
  • 前端学习笔记 | HTML5+CSS3静态网页制作的技巧(持续更新)
  • docker安装-centos
  • Redis入门指南
  • K8s之configMap
  • 提高 NFS Azure 文件共享性能
  • 【Django-ninja】使用schema
  • 【TCP/IP】用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能
  • Unity 开发注意事项
  • [Unity Sentis] Unity Sentis 详细步骤工作流程