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

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.kler.cn/a/229825.html

相关文章:

  • 面试:C++类成员初始化顺序
  • 【LeetCode】力扣刷题热题100道(21-25题)附源码 接雨水 合并区间 字母异位词 滑动窗口 覆盖子串(C++)
  • 音视频入门基础:MPEG2-PS专题(6)——FFmpeg源码中,获取PS流的视频信息的实现
  • 代码随想录算法训练营day23
  • 测试ip端口-telnet开启与使用
  • 云安全博客阅读(三)
  • 优化elemen-ui的el-table的tree树结构因数据过多卡顿问题
  • 20240202在WIN10下使用whisper.cpp
  • 17:数据库连接池与Servlet整合-Java Web
  • Spring Cloud Stream解密:流式数据在微服务中的魔力
  • PyTorch的10个基本张量操作
  • 护眼灯色温多少合适?推荐五款合适色温的护眼台灯
  • springboot157基于springboot的线上辅导班系统的开发与设计
  • 深度学习:数据驱动的人工智能革命
  • 消息中间件之RocketMQ源码分析(六)
  • 数据结构刷题 -- 客房预约
  • 【Langchain+Streamlit】打造一个旅游问答AI
  • Flink SQL Client 安装各类 Connector、Format 组件的方法汇总(持续更新中....)
  • 数据结构:单链表
  • LeetCode 0292.Nim 游戏:脑筋急转弯
  • 【经典例子】Java实现2048小游戏(附带源码)
  • 【自然语言处理-工具篇】spaCy<1>--介绍及安装指南
  • 8个国外顶尖设计网站,设计师必备!
  • re:从0开始的CSS学习之路 2. 选择器超长大合集
  • Java锁到底是个什么东西
  • 92.网游逆向分析与插件开发-游戏窗口化助手-显示游戏数据到小助手UI