日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2023/12/1 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux多进程通过中断实现,Linux驱动中断上下文中会发生什么结果实验测试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

每一個Linux驅動工程師都知道這樣一個準則:在中斷上下文中不能睡眠。但是為什么interrupt context中不能調用導致睡眠的kernel API呢?如果驅動這么做會導致什么樣的后果呢?這就是本文探討的主題。為了理解這個主題,我們設計了一些非常簡單的驅動程序和用戶空間的程序,實際做實驗觀察實驗效果,最后給出了結果和分析。

BTW,本文的實驗在X86 64bit + 標準4.4內核上完成。

二、測試程序

1、cst驅動模塊

我們首先準備一個能夠在中斷上下文中睡眠的驅動程序,在這里我稱之Context schedule test module(后文簡稱cst模塊)。這個驅動程序類似潛伏在內核中的“搗蛋鬼”,每隔1秒隨機命中一個進程,然后引發調度。首先準備一個Makefile,代碼如下:

按理說代碼中的xxxx應該是我的名字,如果你愿意在你的環境中測試,可以修改成你的名字,當然,最重要的是需要某個版本的內核代碼。在內核升級文檔中,我已經編譯了/home/xxxx/work/linux-4.4.6目錄下的內核,并把我的計算機升級到4.4.6的內核上,如果你愿意可以按照那份文檔進行升級,否則可能會有一些版本問題需要處理。除了Makefile之外,還需要一個Kbuild文件:

obj-m := cst.o

當然,最重要的是cst模塊的源代碼:

代碼非常的簡單,無需多說,直接make就可以編譯得到cst.ko的內核模塊了。

2、用戶空間測試程序

為了更方便的測試,我們需要準備一個“受害者”,代碼如下:

這段代碼也很簡單:不斷的產生一個隨機數,并運算其平方根,在使得的時候,向用戶輸出一些字符,表明自己的狀態。當程序執行起來的時候,大部分時間在用戶態(運算),偶爾進入內核態(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了,對于內核開發者而言,這樣更好,可以盡早的發現問題。

總結

以上是生活随笔為你收集整理的linux多进程通过中断实现,Linux驱动中断上下文中会发生什么结果实验测试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。