linux多进程通过中断实现,Linux驱动中断上下文中会发生什么结果实验测试

一、前言

每一个Linux驱动工程师都知道这样一个准则:在中断上下文中不能睡眠。但是为什么interrupt context中不能调用导致睡眠的kernel API呢?如果驱动这么做会导致什么样的后果呢?这就是本文探讨的主题。为了理解这个主题,我们设计了一些非常简单的驱动程序和用户空间的程序,实际做实验观察实验效果,最后给出了结果和分析。

BTW,本文的实验在X86 64bit + 标准4.4内核上完成。

二、测试程序

1、cst驱动模块

我们首先准备一个能够在中断上下文中睡眠的驱动程序,在这里我称之Context schedule test module(后文简称cst模块)。这个驱动程序类似潜伏在内核中的“捣蛋鬼”,每隔1秒随机命中一个进程,然后引发调度。首先准备一个Makefile,代码如下:

262e788a104bd13b258179764e9215f2.png

按理说代码中的xxxx应该是我的名字,如果你愿意在你的环境中测试,可以修改成你的名字,当然,最重要的是需要某个版本的内核代码。在内核升级文档中,我已经编译了/home/xxxx/work/linux-4.4.6目录下的内核,并把我的计算机升级到4.4.6的内核上,如果你愿意可以按照那份文档进行升级,否则可能会有一些版本问题需要处理。除了Makefile之外,还需要一个Kbuild文件:

obj-m := cst.o

当然,最重要的是cst模块的源代码:

7d408a02c39c0fa360b78982ca4f2148.png

代码非常的简单,无需多说,直接make就可以编译得到cst.ko的内核模块了。

2、用户空间测试程序

为了更方便的测试,我们需要准备一个“受害者”,代码如下:

90794b058e8f9d7ba4e9c7ea90917617.png

这段代码也很简单:不断的产生一个随机数,并运算其平方根,在使得的时候,向用户输出一些字符,表明自己的状态。当程序执行起来的时候,大部分时间在用户态(运算),偶尔进入内核态(printf)。这个进程并不知道在内核态有一个cst的模块,每隔一秒就发射一只休眠之箭,可能命中用户态,也可能命中内核态,看运气吧,但是无论怎样,该进程被射中之后都会进入睡眠。

三、执行测试并观察结果

1、先把用户空间的测试程序跑起来

要想测试导弹(呵呵~~我们的cst模块就是一个捣蛋) 的性能,必须要有靶机或者靶舰。当然也可以不用“靶机”程序,只不过捣蛋鬼cst总是命中swapper进程,有点无趣,因此这里需要把我们用户空间的那个测试程序跑起来,让CPU先活跃起来。

需要注意的是,在多核cpu上,我们需要多跑几个“靶机”进程才能让系统不会always进入idle状态。例如我的T450是4核cpu,因此我需要运行4个靶机程序才能让系统中的4个cpu core都燥起来。可以通过下面的命令确认:

ps –eo comm,psr | grep cst

BTW,靶机程序是cst_test。通过上面的命令,可以看到系统中运行了四个cst_test进程,分别在4个cpu上。

2、插入内核模块

靶机已经就绪,是时候发射捣蛋了,命令如下:

sudo insmod ./cst.ko

一旦插入了cst内核模块,捣蛋鬼就开始运作了,每隔1秒钟发射一次,总有一个倒霉蛋被命中,被调度。当然,在我们的测试中,一般总是cst_test这个进程被命中。

3、观察结果

一切准备就绪,是时候搬个小板凳坐下来看好戏了。当然,我们需要一个观察的工具,输入如下命令:

sudo tail –f /var/log/messages

在上面的cst模块中,输出并没有直接到控制台,因此我们需要通过内核日志来看看cst的运行情况。

四、结果和分析

1、结果

很奇怪,一切都是正常的,系统没有死,cst模块也运行正常,cst_test进程也始终保持alive状态,不断的运行在无聊的平方根、打印着无聊的字符串。唯一异常的是日志,每隔1秒钟就会dump stack一次。

2、分析

当cst模块命中cst_test进程,无论是userspace还是kernel space,都会在内核栈上保存中断发生那一点的上下文,唯一不同是如果发生在userspace,那么发生中断那一刻,内核栈是空的,而如果在kernel space,内核栈上已经有了cst_test通过系统调用进入内核的现场以及该系统调用各个函数的stack frame,当中断发生的时候,在当前内核栈的栈顶上继续压入了中断现场,之后就是中断处理的各个函数的stack frame,最后是cst_timer_handler的stack frame,由于调用了schedule函数,cst_test进程的现场被继续压入内核栈,调度器决定下一个调度的进程。

cst_test进程虽然被调度了,但是仍然在runqueue中,调度器一定会在适当的时机调度cst_test进程重新进入执行态,这时候恢复其执行就OK了,cpu执行cst_TImer_handler函数schedule之后的代码,继续未完的中断上下文的执行,然后从内核栈恢复中断现场,一切又按照原路返回了。

当然,这里的测试看起来一切OK,但这并不是说可以自由的在中断上下文中调用导致睡眠的内核API,因为我们这里给出了一个简单的例子,实际上也有可能导致系统死锁。例如在内核态持有锁的时候被中断,然后发生调度。有兴趣的同学可以自己修改上面的代码实验这种情况。

3、why

最后还是回到这个具体的技术问题:为什么interrupt context中不能调用导致睡眠的kernel API?

我的看法是这样的:调度器是每一个OS的必备组件,在编码阶段之前,我们往往要制定下我们的设计概念。对于Linux 调度器,它的目标就是调度一个线程,一个线程就是调度实体(暂不考虑group sched)。中断上下文是不是调度实体呢?当然不是,它没有专属的task struct,内核无从调度。这是调度器设计者的决定,这样的决定让调度器设计起来简洁而美丽。

基于上面的设计概念,中断上下文(hard irq和sofTIrq context)并不参与调度(暂不考虑中断线程化),它们是异步事件的处理机制,目标就是尽快完成处理,返回现场。因此,所有中断上下文的优先级都是高于进程上下文的,也就是说,对于用户进程(无论内核态还是用户态)或者内核线程,除非disable了CPU的本地中断,否则一旦中断发生,它们是没有任何能力阻挡中断上下文抢占当前进程上下文的执行的。

因此,Linux kernel的设计者制定了规则:

1、中断上下文不是调度实体

2、中断上下文的优先级高于进程上下文

而在中断上下文中调度毫无疑问会打破规则,因此不能在硬中断、软中断环境中调用阻塞函数。不过,在linux调度器的具体实现的时候,检测到了在中断上下文中调度schedule函数也并没有强制linux进入panic,可能是linux的开发者认为一个好的内核调度器无论如何也尽自己最大的努力让系统运行下去吧。但是,在厂商自己提供的内核中,往往修改调度器行为,在中断上下文中检测到调度就直接panic了,对于内核开发者而言,这样更好,可以尽早的发现问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/380521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

'unsigned char'-C编程中的声明,赋值和用法

char is a data type in C programming language which can store value from -128 to 127. It generally used to store character values. char是C编程语言中的数据类型,可以存储从-128到127的值 。 它通常用于存储字符值。 unsigned is a qualifier which is us…

cmp指令

功能:比较 格式: CMP destination,sourceCMP 指令比较整数。字符代码也是整数,因此可以用 CMP 指令。 如果比较的是两个无符号数,则零标志位和进位标志位表示的两个操作数之间的关系 如果比较的是两个有符号数,则符…

游戏后的迷茫

9月份花了很多时间耐下心的玩了一个游戏——三国志11,这个是我继三国5以后耐下心玩得最多的一个游戏了,也是2年来耐下心玩得最多的游戏。现在是不是真的太浮躁了。连玩游戏都耐不下心。每天的泡论坛,看电影,下载,刻录的…

linux下获取时间的函数

相关函数 time,ctime,gmtime,localtime //--------------------------------------------------------------------------------------------------------------------------------------------------------// asctime(将时间和日…

linux 内核配置 dns,linux bind dns简单配置

操作系统版本:[roottest ~]# cat /etc/issueRed Hat Enterprise Linux AS release 4 (Nahant Update 4)Kernel r on an m内核:[roottest ~]# uname -aLinux test 2.6.9-42.EL #1 Wed Jul 12 23:16:43 EDT 2006 i686 i686 i386 GNU/Linux[roottest ~]#需要…

鸡兔同笼问题

已知鸡兔的总数量为n,总腿数为m。输入n和m,依次输出鸡的数目和兔的数目。如果无解,则输出No answer。 样例输入:①14 32 ② 10 16 样例输出:①12 2 ②No answer 【分析】 设鸡有a只,兔有b只&#xff0c…

两个人 三声叹 一钵泪

寂寞的人,流下的泪珠是单数的 转载于:https://www.cnblogs.com/aque1984/archive/2006/10/02/520282.html

散列碰撞_散列中的碰撞和碰撞解决技术

散列碰撞Prerequisite: Hashing data structure 先决条件: 哈希数据结构 碰撞 (Collisions) Hash functions are there to map different keys to unique locations (index in the hash table), and any hash function which is able to do so is known as the per…

call和ret(f)指令

call指令 CPU执行call指令时,进行两步操作 将当前的ip(eip)或者cs和ip(ecs和eip)压入栈中跳转到标号处 call 标号 将当前的IP压栈后,转到标号处执行指令 相当于: push ip jmp near ptr 标号…

天翼云linux远程密码不对,天翼云主机远程连接

天翼云主机如何进行远程连接?操作系统不同自然连接方式也是不一样,今天我们分别介绍一下天翼云Windows主机远程连接和Linux云主机远程连接的方法。一、Windows云主机远程连接(1)在电脑连接网络的情况下,点击桌面左下角的windows图标&#xff…

pku2503 Babelfish

额&#xff0c;跟hdu的1075很像&#xff0c;不过比那题简单多了&#xff0c;就是读入时有点麻烦&#xff0c;用到了一个函数 具体看代码吧&#xff0c;这题没什么&#xff0c;不过我的内存开了太多了&#xff0c;不解…… #include<stdio.h> #include<string.h> #i…

JAVA JDK环境渲染

①&#xff08;随便在哪个盘里都行&#xff09;创建一个文件夹名称&#xff1a;Java&#xff1b; ②在文件夹Java下创建一个子文件夹 名称&#xff1a;jdk&#xff1b; ③在子文件夹jdk下再创建一个子文件夹 名称jre&#xff1b; &#xff08;文件夹名称随便&#xff0c;我这…

英语单词 搞笑着背

背单词的过程是枯燥的&#xff0c;一天紧张的学习用下面的方法检查一下今天记住了多少&#xff1a;&#xff09; 根据中英文的谐音&#xff0c;不知对大家背单词是否有用&#xff01;  peevish------"劈为尸体"------暴躁的  hermit-------"何处觅她"---…

linux查看网卡硬件 lsw,linux系统配置管理小测试试卷答案

广东岭南职业技术学院Linux操作系统试题卷一、选择题&#xff1a;(每题2分&#xff0c;共64分)1&#xff0e;Linux操作系统内核创始人是( C )。A. Bill GatesB. Richard StallmanC. Linus TorvaldsD. Dennis MRitchie、Ken Thompson2、下面哪个Linux命令可以一次显示一页内容&a…

turbo c填充图形_C / C ++中的图形:Turbo C编译器中的简介和图形模式

turbo c填充图形In this advanced learning tutorial, you will learn more about the C/C feature "Graphics" by using which you can make your C program even more interactive and attractive. Graphics in C/C can be used to draw different shapes, animati…

使用C和汇编实现一个加法操作

在C/C嵌入汇编指令格式&#xff1a; __asm{;汇编指令 }代码&#xff1a; #include "stdio.h"int main() {int a1;int b2;int c0;__asm{mov eax,amov ebx,badd eax,ebxmov c,eax}printf("ab%d\n",c);return 0; }结果&#xff1a;

神话人物的现代版简历

她丈夫在河北当建筑工人&#xff0c;工程塌方&#xff0c;被砸死在下面。她要求赔偿&#xff0c;包工头不肯。她起诉到法院&#xff0c;败诉。她上诉&#xff0c;再次败诉。她只好上访&#xff0c;从山东一次次来到河北&#xff0c;当局抓她&#xff0c;关她&#xff0c;在精神…

restrict(TextField.restrict 属性)

restrict&#xff08;TextField.restrict 属性&#xff09; public restrict : String 指示用户可输入到文本字段中的字符集。如果 restrict 属性的值为 null&#xff0c;则可以输入任何字符。如果 restrict 属性的值为空字符串&#xff0c;则不能输入任何字符。如果 restrict …

字符串 charat_Java | String.charAt(index)| 从字符串中按索引获取字符

字符串 charatString.charAt() function is a library function of String class, it is used to get/retrieve the specific character from a string. Where, the index starts from 0 and ends to String.lenght-1. String.charAt()函数是String类的库函数&#xff0c;用于…