Linux 开关中断系列函数探究

简介:

Linux 开关中断系列函数探究

中断与锁

中断是Linux响应异步事件的一种方式,区别于陷阱、异常指令和出错等在指令执行完后产生的异常,它往往发生在处理器的外部,通常由外设触发,可以在指令执行完成的瞬间产生,也可能在指令执行的过程中产生,因而不可预测。从外设的角度看,中断是设备请求CPU响应的方式;而从调度的视角来看,中断是驱动系统心跳和调度的手段。而为了实现同步互斥机制,内核还基于处理器提供的原子指令实现了锁的机制,在进入临界段时需要上锁,而在退出时需要解锁,这样就保证了其他处理器不会也进入临界区。通过关本地中断,保重了当前运行的处理器不会再去执行其他内核线程,而是沿着当前上下文继续执行下去;而在临界段之前上锁,则防止其他处理器也执行即将要被执行的代码。那么在什么时候需要上锁,什么时候要关中断,什么时候二者都需要呢?下文结合Linux内核已经提供的几组相关函数进行了分析。

三组相关函数

Spin_lock 与spin_unlock

Spin_lock() 与 spin_unlock(),顾名思义,是内核提供的分别上锁和解锁的函数,值得一提的是这组函数在单处理器系统中,都退化成空操作,因为单处理器系统上只有一个处理器,所以任何当前正在执行的临界段,不可能被其他处理器再次进入。

Spin_lock_irq与spin_unlock_irq

与上面的spin_lock和spin_unlock这组函数的不同,spin_lock_irq()在执行的过程中,会先关本地中断,然后上锁;spin_unlock_irq()相反,会先解锁,然后打开本地中断。注意这里两个函数是互逆对称的操作过程。读者可以思考一下,spin_lock_irq()先上锁后关中断是否可以?答案是不可以,否则对应的spin_unlock_irq()执行的顺序就是开中断先然后解锁,在解锁和开中断的瞬间,如果有同一中断再被当前CPU响应,它就会再次调用spin_lock_irq(),里面先执行spin_lock(),可是这时该锁已经被它上次申请,并且没有来得及释放,这样它就会译制在这里死等。虽然它还可以响应其他类型的中端请求,但是该CPU无法再正确处理当前的中断类型。用户将会看到对应的设备好像停止了工作。

Spin_lock_irqsave 与spin_unlock_irqrestore

Spin_lock_irqsave()与spin_unlock_irqsrestore()除了分别包含spin_lock_irq()和spin_unlock_irq()所执行的所有操作之外,还会分别保存中断使能与否的状态、恢复中断使能的状态。因为有的中断可以以嵌套的方式执行,当前的中端可能正是嵌套进入的,这种情况下在unlockspin 锁后,内核不能贸然使能本地中断,而应恢复之前的中断使能状态,否则相当于在嵌套中断返回之前提前执行了本地中断使能的工作。这组函数具体的伪码如下:

Spin_lock_irqrestore()

{

…………

Save_local_irq_state(&flag);

Local_irq_disable()

Spin_lock();

 

…………

}

 

Spin_unlock_irqrestore()

{

Spin_unlock()

Restore_local_irq_state(flag);

Enable_local_irq()

}

使用场景对比

通过上面描述的对比可以看到,三组函数既有共同的地方,那就是上锁和解锁,也有不同的地方,那就是关于中断是否关闭、是否保存。所实现功能的不同,也就决定了三组函数应用场景的不同,下表给出了对比和说明:

wKiom1W_gcKzYiLtAAEv1CN9beI335.jpg

总结

内核提供了看似差不多实则有不小差别的中断、自旋锁相关的函数,我们需要根据不同的应用场景和需求谨慎选择,否则很容易出现意想不到的问题。














本文转自存储之厨51CTO博客,原文链接:http://blog.51cto.com/xiamachao/1681431 ,如需转载请自行联系原作者




相关文章
|
存储 Linux
linux中的目录操作函数
本文详细介绍了Linux系统编程中常用的目录操作函数,包括创建目录、删除目录、读取目录内容、遍历目录树以及获取和修改目录属性。这些函数是进行文件系统操作的基础,通过示例代码展示了其具体用法。希望本文能帮助您更好地理解和应用这些目录操作函数,提高系统编程的效率和能力。
430 26
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
858 19
|
Linux Android开发 开发者
linux m、mm、mmm函数和make的区别
通过理解和合理使用这些命令,可以更高效地进行项目构建和管理,特别是在复杂的 Android 开发环境中。
840 18
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
661 13
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
904 6
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
508 3
在Linux内核中根据函数指针输出函数名称
在Linux内核中根据函数指针输出函数名称
|
Linux PHP
Linux CentOS 宝塔 Suhosin禁用php5.6版本eval函数详细图文教程
【8月更文挑战第27天】本文介绍两种禁用PHP执行的方法:使用`PHP_diseval_extension`禁用和通过`suhosin`禁用。由于`suhosin`不支持PHP8,仅适用于PHP7及以下版本,若服务器安装了PHP5.6,则需对应安装`suhosin-0.9.38`版本。文章提供了详细的安装步骤,并强调了宝塔环境下与普通环境下的PHP路径差异。安装完成后,在`php.ini`中添加`suhosin.so`扩展并设置`executor.disable_eval = on`以禁用执行功能。最后通过测试代码验证是否成功禁用,并重启`php-fpm`服务生效。
471 2
|
Shell Linux C语言
Linux0.11 execve函数(六)
Linux0.11 execve函数(六)
747 1
|
Linux API
Linux源码阅读笔记07-进程管理4大常用API函数
Linux源码阅读笔记07-进程管理4大常用API函数