为什么不能在中断上半部休眠?
這是一個老生常談的問題。
我們先簡單說下什么是中斷「因為最近在群里看到有人竟然不懂什么是中斷」。中斷是計算機里面非常核心的東西,我們可以跑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」獲取學習資料網盤鏈接。
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~
總結
以上是生活随笔為你收集整理的为什么不能在中断上半部休眠?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为开始对嵌入式开发者下手了!
- 下一篇: 超全!0基础程序员从入门到工作(持续更新