为什么不能在中断上半部休眠?

这是一个老生常谈的问题。

我们先简单说下什么是中断「因为最近在群里看到有人竟然不懂什么是中断」。中断是计算机里面非常核心的东西,我们可以跑OS,可以多任务运行都因为中断的存在。

假设你是一个CPU,你正在睡觉。

你突然觉得肚子疼,「这个事情就是一个中断你睡觉的事情」,然后你就去上厕所了。

然后你又回到床上睡觉。

你突然又觉得肚子饿了,「这个事情也是一个中断你睡觉的事情」,然后你就去吃了个汉堡。

中断可以认为是突发的事情,并且时间不是特别长,如果时间非常久,那就不能叫中断了,就叫主业了。

CPU怎么用中断做到多任务运行呢?

CPU不是普通的人,CPU比普通的人快得多得多。

就拿我手上最差的新唐单片机举例子,他的主频是24M,那执行一条指令周期的时间就是

1/24000000 = 41.6 纳秒

假设你现在有两个事情要做,玩王者荣耀和扫地

你在第一个时钟周期,拿着手机玩王者荣耀,第二个时钟周期扫地,第三个时钟周期玩王者荣耀,第四个时钟周期扫地……

这样,你会发现,CPU是一个闪电侠,可能比闪电侠还要快,根据这个方法,可以裂变出很多很多个人做很多很多件事情。

Linux 内核中断上文为什么不能休眠呢?

现在的Linux 内核中断是不能嵌套的,所以我们就只讨论单中断的问题。

进中断的第一件事情,就是关中断,这个是关所有中断。

然后就在中断里面干事情了,具体做什么事情,我也不知道。

做完事情然后就开中断,去做其他事情了。

如果休眠会引起什么呢?

比如这样的代码

static irqreturn_t tpd_eint_interrupt_handler(unsigned irq, struct irq_desc *desc)
{TPD_DEBUG_PRINT_INT;tpd_flag = 1;/* enter EINT handler disable INT, make sure INT is disable when handle touch event including top/bottom half *//* use _nosync to avoid deadlock */spin_lock(&irq_lock);if (tpd_irq_flag) {tpd_irq_flag = 0;disable_irq_nosync(tpd_touch_irq);}spin_unlock(&irq_lock);ssleep(1);//系统会死掉wake_up_interruptible(&waiter);return IRQ_HANDLED;
}

这个代码的问题在ssleep(1)上,ssleep(1)是OS里面的休眠函数,这个函数会让任务休眠,休眠的意思就是让这个任务睡觉不执行,CPU去执行其他的任务。

因为CPU是按时间片执行的,等下一次调度到这个中断的时候,就有可能再获取一次spin_lock自旋锁,两次获取锁的操作,肯定就引起系统挂壁了。

具体的可以去看看ssleep的代码

/*** msleep - sleep safely even with waitqueue interruptions* @msecs: Time in milliseconds to sleep for*/
void msleep(unsigned int msecs)
{unsigned long timeout = msecs_to_jiffies(msecs) + 1;while (timeout)timeout = schedule_timeout_uninterruptible(timeout);
}EXPORT_SYMBOL(msleep);

系统宕机日志

[    1.564767] <3>.(3)[139:kworker/u8:2]<<GTP-INF>>[tpd_irq_registration:484] Device Tree Tpd_irq_registration!
[    1.566520] <3>.(3)[139:kworker/u8:2]gpiod_set_debounce: invalid GPIO
[    1.567319] <3>.(3)[139:kworker/u8:2]<<GTP-INF>>[tpd_irq_registration:495] Device gt1x_int_type = 1!
[    1.568484] <0>-(0)[0:swapper/0]BUG: scheduling while atomic: swapper/0/0/0x00010002
[    1.568493] <0>.(3)[139:kworker/u8:2]<<GTP-INF>>[tpd_irq_registration:514] irq:119, debounce:0-0:
[    1.570534] Modules linked in:
[    1.570912] <0>-(0)[0:swapper/0]CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.146 #41
[    1.571879] <0>-(0)[0:swapper/0]Hardware name: Generic DT based system
[    1.572689] Backtrace: 
[    1.572989] <0>-(0)[0:swapper/0][<c010d5d4>] (dump_backtrace) from [<c010d7fc>] (show_stack+0x18/0x1c)
[    1.574143]  r6:60000193 r5:c1136bc8 r4:00000000 r3:dc8ba692
[    1.574841] <0>-(0)[0:swapper/0][<c010d7e4>] (show_stack) from [<c041b4c4>] (dump_stack+0x94/0xa8)
[    1.575950] <0>-(0)[0:swapper/0][<c041b430>] (dump_stack) from [<c0155350>] (__schedule_bug+0x58/0x6c)
[    1.577104]  r6:c1101ce8 r5:c1085b40 r4:00000000 r3:60000193
[    1.577802] <0>-(0)[0:swapper/0][<c01552f8>] (__schedule_bug) from [<c0b6dc88>] (__schedule+0x59c/0x808)
[    1.578978]  r4:c110bcf8 r3:00010002
[    1.579418] <0>-(0)[0:swapper/0][<c0b6d6ec>] (__schedule) from [<c0b6df48>] (schedule+0x54/0xc4)
[    1.580507]  r10:00000000 r9:c1102100 r8:dfedfb80 r7:c1103948
[    1.581216] <0>-(0)[0:swapper/0][<c0b6def4>] (schedule) from [<c0b712c4>] (schedule_timeout+0x148/0x264)
[    1.582391]  r4:fffea370 r3:c1100000
[    1.582831] <0>-(0)[0:swapper/0][<c0b7117c>] (schedule_timeout) from [<c01ad8f8>] (msleep+0x34/0x40)
[    1.583964]  r10:c1100000 r9:00000000 r8:00000000 r7:00000077
[    1.584673] <0>-(0)[0:swapper/0][<c01ad8c4>] (msleep) from [<c081e0d0>] (tpd_eint_interrupt_handler+0x2c/0xd8)
[    1.585913]  r5:ced00000 r4:cec8d540
[    1.586353] <0>-(0)[0:swapper/0][<c081e0a4>] (tpd_eint_interrupt_handler) from [<c0199684>] (handle_irq_event_percpu+0x6c/0x268)
[    1.587787]  r5:d0344ae0 r4:cec8d540
[    1.588227] <0>-(0)[0:swapper/0][<c0199618>] (handle_irq_event_percpu) from [<c01998c0>] (handle_irq_event+0x40/0x64)
[    1.589542]  r10:c0c487cc r9:00000077 r8:00000000 r7:00000000
[    1.590251] <0>-(0)[0:swapper/0][<c0199880>] (handle_irq_event) from [<c019d388>] (handle_level_irq+0xb4/0x16c)
[    1.591502]  r6:d0344a90 r5:d0344ae0 r4:d0344a80 r3:00020002
[    1.592201] <0>-(0)[0:swapper/0][<c019d2d4>] (handle_level_irq) from [<c0198b64>] (generic_handle_irq+0x2c/0x3c)
[    1.593462]  r6:d030e6d0 r5:02000000 r4:00000019 r3:c019d2d4
[    1.594161] <0>-(0)[0:swapper/0][<c0198b38>] (generic_handle_irq) from [<c045d7e4>] (mtk_eint_irq_handler+0x288/0x36c)
[    1.595486] <0>-(0)[0:swapper/0][<c045d55c>] (mtk_eint_irq_handler) from [<c0198b64>] (generic_handle_irq+0x2c/0x3c)
[    1.596790]  r10:00000001 r9:00000000 r8:00010001 r7:00000000
[    1.597499] <0>-(0)[0:swapper/0][<c0198b38>] (generic_handle_irq) from [<c0198e7c>] (__handle_domain_irq+0xc0/0x25c)
[    1.598802] <0>-(0)[0:swapper/0][<c0198dbc>] (__handle_domain_irq) from [<c01015ec>] (gic_handle_irq+0x50/0x94)
[    1.600053]  r9:e1003000 r8:e1002000 r7:c1101eb0 r6:e100200c
[    1.600752] <0>-(0)[0:swapper/0][<c010159c>] (gic_handle_irq) from [<c010e314>] (__irq_svc+0x54/0x90)
[    1.601893] <0>-(0)[0:swapper/0]Exception stack(0xc1101eb0 to 0xc1101ef8)
[    1.602736] <0>-(0)[0:swapper/0]1ea0:                                     00000000 ffffffff 1ee35000 00000000
[    1.603965] <0>-(0)[0:swapper/0]1ec0: c11ac9b4 cfbdf800 5cc9dbdf 00000000 5ccecf4c 00000000 00000001 c1101f44
[    1.605192] <0>-(0)[0:swapper/0]1ee0: c1101f00 c1101f00 c08a2380 c08a2390 60000013 ffffffff
[    1.606224]  r9:00000000 r8:5ccecf4c r7:c1101ee4 r6:ffffffff
[    1.606922] <0>-(0)[0:swapper/0][<c08a2220>] (cpuidle_enter_state) from [<c08a2670>] (cpuidle_enter+0x1c/0x20)
[    1.608162]  r10:c1103a1c r9:c1187308 r8:cfbdf800 r7:c11ac9b4
[    1.608872] <0>-(0)[0:swapper/0][<c08a2654>] (cpuidle_enter) from [<c0183334>] (cpu_startup_entry+0x1e0/0x3d8)
[    1.610110] <0>-(0)[0:swapper/0][<c0183154>] (cpu_startup_entry) from [<c0b6ac18>] (rest_init+0x90/0x94)
[    1.611285]  r7:ffffffff
[    1.611596] <0>-(0)[0:swapper/0][<c0b6ab88>] (rest_init) from [<c1000e44>] (start_kernel+0x418/0x468)
[    1.612739]  r4:c11b1040 r3:dc8ba692
[    1.613179] <0>-(0)[0:swapper/0]Backtrace aborted due to bad pc <c1000a30>
[    1.614040] <0>-(0)[0:swapper/0]------------[ cut here ]------------
[    1.614816] <0>-(0)[0:swapper/0]Kernel BUG at c0155360 [verbose debug info unavailable]
[    1.615807] <0>-(0)[0:swapper/0]Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
[    1.616746] <0>-(0)[0:swapper/0][LY]rtc_mark_aee_kernel_panic!!!
[    1.617551] disable aee kernel api
[    1.617935] <0>-(0)[0:swapper/0]Kernel Offset: disabled
[    1.618603] Modules linked in:

Linux 内核中断函数能不能执行malloc函数?

这个是之前已经发过的文章

可以在中断服务程序执行malloc吗?

内核里面分配内存的函数是kmalloc ,其他不废话,我直接测试了下面的代码

static irqreturn_t tpd_eint_interrupt_handler(unsigned irq, struct irq_desc *desc)
{char *rbuff = NULL;rbuff = kmalloc(1024, GFP_KERNEL);TPD_DEBUG_PRINT_INT;tpd_flag = 1;/* enter EINT handler disable INT, make sure INT is disable when handle touch event including top/bottom half *//* use _nosync to avoid deadlock */spin_lock(&irq_lock);if (tpd_irq_flag) {tpd_irq_flag = 0;disable_irq_nosync(tpd_touch_irq);}spin_unlock(&irq_lock);ssleep(1);//系统会死掉wake_up_interruptible(&waiter);kfree(rbuff);return IRQ_HANDLED;
}

系统是没有挂掉的,然后去看看kmalloc的实现。

/*** kmalloc - allocate memory* @size: how many bytes of memory are required.* @flags: the type of memory to allocate.** kmalloc is the normal method of allocating memory* for objects smaller than page size in the kernel.** The @flags argument may be one of:** %GFP_USER - Allocate memory on behalf of user.  May sleep.** %GFP_KERNEL - Allocate normal kernel ram.  May sleep.** %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools.*   For example, use this inside interrupt handlers.** %GFP_HIGHUSER - Allocate pages from high memory.** %GFP_NOIO - Do not do any I/O at all while trying to get memory.** %GFP_NOFS - Do not make any fs calls while trying to get memory.** %GFP_NOWAIT - Allocation will not sleep.** %__GFP_THISNODE - Allocate node-local memory only.** %GFP_DMA - Allocation suitable for DMA.*   Should only be used for kmalloc() caches. Otherwise, use a*   slab created with SLAB_DMA.** Also it is possible to set different flags by OR'ing* in one or more of the following additional @flags:** %__GFP_COLD - Request cache-cold pages instead of*   trying to return cache-warm pages.** %__GFP_HIGH - This allocation has high priority and may use emergency pools.** %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail*   (think twice before using).** %__GFP_NORETRY - If memory is not immediately available,*   then give up at once.** %__GFP_NOWARN - If allocation fails, don't issue any warnings.** %__GFP_REPEAT - If allocation fails initially, try once more before failing.** There are other flags available as well, but these are not intended* for general use, and so are not documented here. For a full list of* potential flags, always refer to linux/gfp.h.*/
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{if (__builtin_constant_p(size)) {if (size > KMALLOC_MAX_CACHE_SIZE)return kmalloc_large(size, flags);
#ifndef CONFIG_SLOBif (!(flags & GFP_DMA)) {int index = kmalloc_index(size);if (!index)return ZERO_SIZE_PTR;return kmem_cache_alloc_trace(kmalloc_caches[index],flags, size);}
#endif}return __kmalloc(size, flags);
}

代码里面没有看到引起调度的代码,但是注释里面有说会引起休眠。

这个函数跟微信微信公众号留言提到的gfp一致。

推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

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

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

相关文章

j.u.c系列(08)---之并发工具类:CountDownLatch

写在前面 CountDownLatch所描述的是”在完成一组正在其他线程中执行的操作之前&#xff0c;它允许一个或多个线程一直等待“&#xff1a;用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法&#xff0c;所以在当前计数到达零之前&#xff0c;await 方法会一直受…

巧用1个GPIO控制2个LED显示4种状态

很多电子产品有状态指示灯&#xff0c;比如电视机&#xff1a;待机状态亮红灯开机状态亮绿灯实现起来很简单&#xff0c;微控制器MCU的两个GPIO分别控制就行&#xff1a;不过资源总是紧张的&#xff0c;有时候会碰到GPIO不够用的情况。如果只用1个GPIO&#xff0c;可不可以实现…

大大大大数怎么求余?C语言

问题&#xff1a;一个特别大的数除以23求余数用C语言应该怎么算啊&#xff1f;比如23232323232323232323232323232323232323232323232323232323233除以23&#xff0c;怎么算余数&#xff1f;数据类型在计算机的存储是有大小限制的&#xff0c;所以才出现了大数求余这种问题&…

程序员因拒绝带电脑回家工作被开除!获赔19.4万元

近日&#xff0c;男子拒绝春节带电脑回家工作被开除的消息&#xff0c;成为了不少网友关注的焦点&#xff0c;引发网友共鸣。因为春节拒绝带工作电脑回家被开除&#xff0c;上海一位软件工程师起诉公司获赔19.4万元。2月2日&#xff0c;据上海浦东法院公众号消息&#xff0c;该…

随便写写(5)

也许是今年发生的事情太多了&#xff0c;所以比以前要更关注时事&#xff0c;虽然面对一些既成的事实&#xff0c;难免要进行痛心的思考。 昨天晚上关注了一下东方卫视播出的9.8特大尾矿库溃坝事故的后续报道&#xff0c;这起特大人为事故已经得到了认定&#xff0c;相关的责任…

利用C语言中的setjmp和longjmp,来实现异常捕获和协程

一、前言二、函数语法介绍与 goto 语句比较与 fork 函数比较与 Python 语言中的 yield/resume 比较三、利用 setjmp/longjmp 实现异常捕获四、利用 setjmp/longjmp 实现协程五、总结一、前言 在 C 标准库中&#xff0c;有两个威力很猛的函数&#xff1a;setjmp 和 longjmp&…

centos6.9系列LNMP环境的安装

一、Nginx 1.先解决Nginx的依赖关系&#xff1a; yum install -y pcre-devel openssl-devel 2.安装wget&#xff1a;sudo yum -y install wget 3.下载nginx的安装包&#xff1a;wget http://nginx.org/download/nginx-1.10.3.tar.gz 4.解压nginx文件包&#xff1a;tar xf nginx…

Linux 修改 ELF 解决 glibc 兼容性问题

转自&#xff1a;Soul Of Free Loophttps://zohead.com/archives/mod-elf-glibc/Linux glibc 问题相信有不少 Linux 用户都碰到过运行第三方&#xff08;非系统自带软件源&#xff09;发布的程序时的 glibc 兼容性问题&#xff0c;这一般是由于当前 Linux 系统上的 GNU C 库&am…

VS2010创建ATL工程及使用C++测试COM组件

VS2010创建ATL工程及使用C测试COM组件 1.创建ATL项目&#xff0c;取名MyCom 2. ATL 项目向导&#xff0c;勾选 【支持COM 1.0】和【支持部件注册器】&#xff0c;其他默认&#xff0c;点击完成。 3.在该项目中添加类 4.添加一个ATL简单对象 5. ATL 简单对象向导&#xff0c…

芯片IC附近为啥要放0.1uF的电容?看完秒懂~

数字电路要运行稳定可靠&#xff0c;电源一定要”干净“&#xff0c;并且能量补充一定要及时&#xff0c;也就是滤波去耦一定要好。什么是滤波去耦&#xff0c;简单的说就是在芯片不需要电流的时候存储能量&#xff0c;在需要电流的时候又能及时地补充能量。有读者看到这里会说…

无线中继蹭网(转)

随着无线技术的逐渐成熟&#xff0c;无线设备的价格也越来越低&#xff0c;已经有不少的家庭开始在自己的家中建立无线网络&#xff0c;利用笔记本&#xff0c;具备WiFi功能的手机连接无线网络享受冲浪乐趣&#xff0c;很多时候为了节约网费可能几家人一起共用一个ADSL上网帐号…

深入掌握Linux操作系统,其实也没你想象那么难

曹政大家应该都不陌生吧&#xff0c;众多IT人的偶像&#xff0c;数据、技术、业务&#xff0c;无一不精&#xff0c;被大家称为曹大。在曹大的一篇文章中&#xff0c;他曾经提到过&#xff0c;1998年&#xff0c;自己的第一份工作接手的是一个Windows系统下的人才网站系统&…

WSS页面定制系列(1)--如何启用表单页面的编辑模式

wss的大多数页面右上角的“站点操作”菜单都有一个编辑网页菜单项&#xff0c;用这个菜单项&#xff0c;可以启用当前页面的设计模式&#xff0c;修改或添加webpart。但是奇怪的是&#xff0c;所有的表单页面&#xff08;用来新建&#xff0c;编辑&#xff0c;查看列表项的页面…

单片机检测220V交流电通断电路

我们在topemic网站上分享过一篇题为"单片机检测220V交流电通断电路"的文章&#xff0c;目前有近万次阅读&#xff0c;在这里做个总结分享给没有读过该文的公众号朋友。废话不多说&#xff0c;直接上图&#xff1a;该电路工作原理如下&#xff1a;当220V断开时&#x…

Qt值得学习吗?详解Qt的几种开发方式

qt值得学习吗&#xff1f;嵌入式要学的东西真的很多&#xff0c;我们可能会说不写界面的话就不用学qt了&#xff1f;我不赞同。Qt的实现主要是采用p-impl手法&#xff0c;实现接口与实现分离&#xff0c;它有很好的消息循环机制&#xff0c;有的对象与线程的相关性&#xff0c;…

技术QA:如何安装并启用BITS和WebDAV?

引子&#xff1a; 在安装SCCM 2007 SP1时&#xff0c;必须要安装并启用BITS和WebDAV&#xff0c;否则在SCCM 2007 SP1安装先决条件检查时将会报错。它们以前都是IIS的功能组件&#xff0c;但是在IIS 7中变动很大&#xff0c;特别是在 Windows Server 2008 操作系统中现在已经不…

C语言,谁都能看得懂的归并排序

喜欢看排序算法动态效果的&#xff0c;可以看看这个网站https://visualgo.net/zh/sorting里面很多算法的动画解释&#xff0c;可以看到算法的排序效果&#xff0c;而且还附带了伪代码的实现过程。本来想录制几张动图放上来&#xff0c;但是因为图片较大&#xff0c;传不上来&am…

内核链表list.h文件剖析

内核链表list.h文件剖析 一、内核链表的结构【双向循环链表】 内核链表的好主要体现为两点&#xff0c;1是可扩展性&#xff0c;2是封装。可以将内核链表复用到用户态编程中&#xff0c;以后在用户态下编程就不需要写一些关于链表的代码了&#xff0c;直接将内核中list.h中的代…

CAN总线很难吗?CAN总线看不懂是不可能的!

CAN&#xff08;Controller Area Network&#xff09;即控制器局域网&#xff0c;是一种能够实现分布式实时控制的串行通信网络。想到CAN就要想到德国的Bosch公司&#xff0c;因为CAN就是这个公司开发的&#xff08;和Intel&#xff09;CAN有很多优秀的特点&#xff0c;使得它能…

C语言必须写main函数?最简单的 Hello world 你其实一点都不懂!

我们在刚写程序的时候&#xff0c;第一个都是 hello world&#xff0c;而在这里&#xff0c;完整的代码就是&#xff1a;我们打眼一看&#xff0c;其实很简单&#xff0c;就是引入头文件&#xff0c;写一个主函数&#xff0c;然后输出一句话&#xff0c;但是当我们编译出来ELF的…