linux中斷信號
1. 在SMP系統中,linux定義的處理機間中斷RESCEDULE_VECTOR:使被中斷CPU重新調
摘要 中斷讓外設能夠通知CPU他需要獲得服務(讓CPU執行指定的中斷服務常式ISR)。為了達到這個目的,首先要為中斷執行做好准備,完成初始化相關的操作。包括:
2. Linux內核中斷之中斷申請介面
本文基於 RockPI 4A 單板Linux4.4內核介紹中斷申請的常用介面函數。
1、文件
2、定義
說明:
1)、 irq :要申請的中斷號,可通過 platform_get_irq() 獲取,見「Linux內核中斷之獲取中斷號」。
2)、 handler :中斷處理函數,發生中斷時,先處理中斷處理函數,然後返回 IRQ_WAKE_THREAD 喚醒中斷處理線程。中斷處理函數盡可能簡單。
中斷處理函數定義: typedef irqreturn_t (*irq_handler_t)(int, void *);
中斷返回值如下:
3)、 thread_fn :中斷處理線程,該參數可為NULL。類似於中斷處理函數的下半部分。
4)、 irqflags :中斷類型標志。
定義文件: include/linux/interrupt.h ,內容如下:
5)、 devname :中斷名稱,可使用 cat /proc/interrupts 命令查看。
6)、 dev_id :設備ID,該值唯一。
在使用共享中斷時(即設置 IRQF_SHARED ),必須傳入 dev_id ,在中斷處理和釋放函數中都會使用該參數。
註:
1、 request_threaded_irq() 函數可替代 request_irq 加 tasklet 或 workqueue 的方式。
2、對應的中斷釋放函數為: void free_irq(unsigned int, void *) ,需要和中斷申請函數成對出現。
1、文件
2、定義
說明:
1)、 __must_check :指調用函數一定要處理函數的返回值,否則編譯器會給出警告。
2)、 request_irq() 函數本質上是中斷處理線程 thread_fn 為空的 request_threaded_irq() 函數。
注 :
對應的中斷釋放函數為: void free_irq(unsigned int, void *) ,需要和中斷申請函數成對出現。
1、文件
2、定義
說明 :
devm_request_threaded_irq() 本質上還是使用 request_threaded_irq() 函數實現中斷申請。
兩者區別:
1)多了一個 dev 參數;
2)在設備驅動卸載時,中斷會自動釋放;
3)如果想單獨釋放中斷,可使用 void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) 函數。
1、文件
2、定義
devm_request_irq() 函數本質上是中斷處理線程 thread_fn 為空的 devm_request_threaded_irq() 函數。
1、獲取中斷號
2、申請中斷
3、中斷處理函數
4、中斷處理線程
5、查看中斷
3. Linux下通過哪個命令怎麼查看中斷
與Linux設備驅動中中斷處理相關的首先是申請與釋放IRQ的API request_irq()和free_irq()。
C++是一種面向對象的計算機程序設計語言,由美國AT&T貝爾實驗室的本賈尼·斯特勞斯特盧普博士在20世紀80年代初期發明並實現,最初它被稱作「C with Classes」(包含類的C語言)。
它是一種靜態數據類型檢查的、支持多重編程範式的通用程序設計語言,支持過程化程序設計、數據抽象、面向對象程序設計、泛型程序設計等多種程序設計風格。
在C基礎上,一九八三年又由貝爾實驗室的Bjarne Strou-strup推出了C++,C++進一步擴充和完善了C語言,成為一種面向 對象的程序設計語言。
C++目前流行的編譯器最新版本是Borland C++ 4.5,Symantec C++ 6.1,和Microsoft Visual C++ 2012。
4. linux系統中的中斷指令是什麼
什麼是中斷
Linux 內核需要對連接到計算機上的所有硬體設備進行管理,毫無疑問這是它的份內事。如果要管理這些設備,首先得和它們互相通信才行,一般有兩種方案可實現這種功能:
輪詢(polling) 讓內核定期對設備的狀態進行查詢,然後做出相應的處理;中斷(interrupt) 讓硬體在需要的時候向內核發出信號(變內核主動為硬體主動)。
第一種方案會讓內核做不少的無用功,因為輪詢總會周期性的重復執行,大量地耗用 CPU 時間,因此效率及其低下,所以一般都是採用第二種方案 。
對於中斷的理解我們先看一個生活中常見的例子:QQ。第一種情況:你正在工作,然後你的好友突然給你發送了一個窗口抖動,打斷你正在進行的工作。第
二種情況:當然你有時候也會每隔 5 分鍾就去檢查一下 QQ
看有沒有好友找你,雖然這很浪費你的時間。在這里,一次窗口抖動就可以被相當於硬體的中斷,而你就相當於 CPU,你的工作就是 CPU
這在執行的進程。而定時查詢就被相當於 CPU 的輪詢。在這里可以看到:同樣作為 CPU 和硬體溝通的方式,中斷是硬體主動的方式,較輪詢(CPU
主動)更有效些,因為我們都不可能一直無聊到每隔幾分鍾就去查一遍好友列表。
CPU
有大量的工作需要處理,更不會做這些大量無用功。當然這只是一般情況下。好了,這里又有了一個問題,每個硬體設備都中斷,那麼如何區分不同硬體呢?不同設
備同時中斷如何知道哪個中斷是來自硬碟、哪個來自網卡呢?這個很容易,不是每個 QQ 號碼都不相同嗎?同樣的,系統上的每個硬體設備都會被分配一個
IRQ 號,通過這個唯一的 IRQ 號就能區別張三和李四了。
從物理學的角度看,中斷是一種電信號,由硬體設備產生,並直接送入中斷控制器(如
8259A)的輸入引腳上,然後再由中斷控制器向處理器發送相應的信號。處理器一經檢測到該信號,便中斷自己當前正在處理的工作,轉而去處理中斷。此後,
處理器會通知 OS 已經產生中斷。這樣,OS
就可以對這個中斷進行適當的處理。不同的設備對應的中斷不同,而每個中斷都通過一個唯一的數字標識,這些值通常被稱為中斷請求線。
5. Linux內核中斷如何避
首先我闡明一下,用鎖的情況只有兩種:
線程
文件
內核程序在使用的時候也脫離不了這兩種鎖的概念。
中斷,是信號,是否要處理中斷信號?或者產生中斷信號?
對信號來說只有:
信號屏蔽、信號捕捉、信號排隊、可重如函數等概念。
你想問的問題,我沒猜測,在處理某個信號時,不想讓其他信號中斷,那麼使用信號屏蔽字:
先設置要屏蔽的信號集,要保存的信號集,初始信號集,可供協調使用的函數有幾個:
#include <signal.h>
signal(這個不建議使用,應為有些老的實現是有問題的),設置信號處理程序
sig_atomic_t 數據類型
sigprocmask,設置信號屏蔽字
sigaction,設置信號處理程序,功能跟強悍,可控性更好
sigsuspend,以原子性方式,等待某些信號發生,然後返回
你具體要做啥不清楚,但使用上面的信號相關的函數,肯定能實現你的功能。參考APUE的論述。
6. Linux幾種中斷信號的區別:HUP,INT,KILL,TERM,TSTP
Linux的HUP,INT,KILL,TERM,TSTP中斷信號區別為:鍵入不同、對應操作不同、啟用不同。
一、鍵入不同
1、HUP中斷信號:HUP中斷信號是當用戶鍵入<Ctrl+X>時由終端驅動程序發送的信號。
2、INT中斷信號:INT中斷信號是當用戶鍵入<Ctrl+I>時由終端驅動程序發送的信號。
3、KILL中斷信號:KILL中斷信號是當用戶鍵入<Ctrl+Z>時由終端驅動程序發送的信號。
4、TERM中斷信號:TERM中斷信號是當用戶鍵入<Ctrl+>時由終端驅動程序發送的信號。
5、TSTP中斷信號:TSTP中斷信號是當用戶鍵入<Ctrl+T>時由終端驅動程序發送的信號。二、對應操作不同
1、HUP中斷信號:HUP中斷信號的對應操作為讓進程掛起,睡眠。
2、INT中斷信號:INT中斷信號的對應操作為正常關閉所有進程。
3、KILL中斷信號:KILL中斷信號的對應操作為強制關閉所有進程。
4、TERM中斷信號:TERM中斷信號的對應操作為正常的退出進程。
5、TSTP中斷信號:TSTP中斷信號的對應操作為暫時停用進程。
三、啟用不同
1、HUP中斷信號:HUP中斷信號發送後,可以重新被用戶再次輸入恢復啟用進程。
2、INT中斷信號:INT中斷信號發送後,不可以重新被用戶再次輸入恢復啟用進程。
3、KILL中斷信號:KILL中斷信號發送後,不可以重新被用戶再次輸入恢復啟用進程。
4、TERM中斷信號:TERM中斷信號發送後,可以重新被用戶再次輸入啟用進程。
5、TSTP中斷信號:TSTP中斷信號發送後,可以重新被用戶再次輸入繼續使用進程。
7. Linux如何及時響應外部中斷
FPGA每隔100us給運行linux的ARM一個中斷,要求在20us內響應中斷,並讀走2000*16bit的數據。
目前主要的問題是,當系統同時發生多個中斷時,會嚴重影響linux對FPGA中斷的響應時間。如何解決?
1、首先想到了ARM的FIQ,它可以打斷IRQ中斷服務程序,保證對外部FIQ的及時響應。但是發現linux只實現了IRQ,沒有顯示FIQ。
linux是從devicetree讀取中斷號,加入中斷向量表的。
interrupts = <0x0 0x32 0x0>;中的第一個欄位0表示非共享中斷,非零表示共享中斷,SDK產生的dts統一為0,此時第二欄位的值比XPS中的小32;如果第一欄位非零,則第二欄位比XPS小16.
最後欄位表示中斷的觸發方式。
IRQ_TYPE_EDGE_RISING =0x00000001,
IRQ_TYPE_EDGE_FALLING =0x00000002,
IRQ_TYPE_LEVEL_HIGH =0x00000004,
IRQ_TYPE_LEVEL_LOW =0x00000008,
很明顯,devicetree根本沒有提供通知linux有FIQ的渠道。
2、再來看linux的IRQ
linux的中斷分為上半部和下半部,上半部運行在IRQ模式,會屏蔽所有中斷,下半部運行在SVC模式,會重新打開中斷。
也就是說,當一個中斷的上半部正在運行時(不能再次響應中斷),FPGA的中斷是不能被linux響應的;
反過來,當FPGA中斷的上半部正在運行時(不能再次響應中斷),其他的中斷也不能被linux響應;
unsigned long flags;
...
local_irq_save(flags);
....
local_irq_restore(flags);
3.
ARM有七種模式,我們這里只討論SVC、IRQ和FIQ模式。
我們可以假設ARM核心有兩根中斷引腳(實際上是看不見的),一根叫 irq pin, 一根叫fiq pin.
在ARM的cpsr中,有一個I位和一個F位,分別用來禁止IRQ和FIQ的。
先不說中斷控制器,只說ARM核心。正常情況下,ARM核都只是機械地隨著pc的指示去做事情,當CPSR中的I和F位為1的時候,IRQ和FIQ全部處於禁止狀態。無論你在irq
pin和fiq pin上面發什麼樣的中斷信號,ARM是不會理你的,你根本不能打斷他,因為他耳聾了,眼也瞎了。
在I位和F位為0的時候,當irq
pin上有中斷信號過來的時候,就會打斷arm的當前工作,並且切換到IRQ模式下,並且跳到相應的異常向量表(vector)位置去執行代碼。這個過程是自動的,但是返回到被中斷打斷的地方就得您親自動手了。當你跳到異常向量表,處於IRQ的模式的時候,這個時候如果irq
pin上面又來中斷信號了,這個時候ARM不會理你的,irq
pin就跟秘書一樣,ARM核心就像老闆,老闆本來在做事,結果來了一個客戶,秘書打斷它,讓客戶進去了。而這個時候再來一個客戶,要麼秘書不斷去敲門問,要麼客戶走人。老闆第一個客戶沒有會見完,是不會理你的。
但是有一種情況例外,當ARM處在IRQ模式,這個時候fiq pin來了一個中斷信號,fiq
pin是什麼?是快速中斷呀,比如是公安局的來查刑事案件,那才不管你老闆是不是在會見客戶,直接打斷,進入到fiq模式下,並且跳到相應的fiq的異常向量表處去執行代碼。那如果當ARM處理FIQ模式,fiq
pin又來中斷信號,又就是又一批公安來了,那沒戲,都是執法人員,你打不斷我。那如果這個時候irq
pin來了呢?來了也不理呀,正在辦案,還敢來妨礙公務。
所以得出一個結論: IRQ模式只能被FIQ模式打斷,FIQ模式下誰也打不斷。
在打不斷的情況下,irq pin 或 fiq pin隨便你怎麼發中斷信號,都是白發。
所以除了fiq能打斷irq以外,根本沒有所謂中斷嵌套的情況。
Linux不用FIQ,只用到了IRQ。但是我們有時候一個中斷需要處理很長時間,那我們就需要佔用IRQ模式那麼長的時間嗎?沒有,linux在IRQ模式下只是簡單的記錄是什麼中斷,馬上就切換回了SVC模式,換句話說,Linux的中斷處理都是在SVC模式下處理的。
只不過SVC模式下的ISR上半部關閉了當前中斷線,下半部才重新打開
8. Linux中斷補充
在系統結構中,CPU工作的模式有兩種,一種是中斷,由各種設備發起;一種是輪詢,由CPU主動發起。
中斷IRQ:
中斷允許讓設備(如鍵盤,串口卡,並口等設備)表明它們需要CPU。一旦CPU接收了中斷請求,CPU就會暫時停止執行正在運行的程序,並且調用一個稱為中斷處理器或中斷服務程序(interrupt service routine)的特定程序。CPU處理完中斷後,就會恢復執行之前被中斷的程序。
中斷分類:
硬中斷+軟中斷
硬中斷:
①非屏蔽中斷:不能被屏蔽,硬體發生的錯誤:內存錯誤,風扇故障,溫度感測器故障等。
②可屏蔽中斷:可被CPU忽略或延遲處理。當緩存控制器的外部針腳被觸發的時候就會產生這種類型的中斷,而中斷屏蔽寄存器就會將這樣的中斷屏蔽掉。我們可以將一個比特位設置為0,來禁用在此針腳觸發的中斷。
軟中斷:
是軟體實現的中斷,也就是程序運行時其他程序對它的中斷;而硬中斷是硬體實現的中斷,是程序運行時設備對它的中斷。
CPU之間的中斷處理(IPI)
處理器間中斷允許一個CPU向系統其他的CPU發送中斷信號,處理器間中斷(IPI)不是通過IRQ線傳輸的,而是作為信號直接放在連接所有CPU本地APIC的匯流排上。
CALL_FUNCTION_VECTOR (向量0xfb)
發往所有的CPU,但不包括發送者,強制這些CPU運行發送者傳遞過來的函數,相應的中斷處理程序叫做call_function_interrupt(),例如,地址存放在群居變數call_data中來傳遞的函數,可能強制其他所有的CPU都停止,也可能強制它們設置內存類型範圍寄存器的內容。通常,這種中斷發往所有的CPU,但通過smp_call_function()執行調用函數的CPU除外。
RESCHEDULE_VECTOR (向量0xfc)
當一個CPU接收這種類型的中斷時,相應的處理程序限定自己來應答中斷,當從中斷返回時,所有的重新調度都自動運行。
INVALIDATE_TLB_VECTOR (向量0xfd)
發往所有的CPU,但不包括發送者,強制它們的轉換後援緩沖器TLB變為無效。相應的處理程序刷新處理器的某些TLB表項。
9. LINUX軟中斷通信
我驗證下阿...一不小心就fork多了..
剛開始我把kill的參數弄反了,信號和pid位置弄錯了,調了半個小時,很郁悶..
你只是忽略了一點...,我也給忽略了。。。後來才想起來
你按下ctrl+C的時候,另外兩個fork出來的進程,他們也會接到SIGINT。。。就退出了。。所以你要先在子進程裡面忽略這個SIGINT信號,用signal(SIGINT,SIG_IGN)就OK了....
程序如下...
有解釋,你可以自己看看...
#include"stdio.h"
#include"unistd.h"
#include"signal.h"
#include"sys/types.h"
#include"stdlib.h"
int k=0;
pid_t child1=0,child2=0;
void func_main(int sig);
void func_child1(int sig);
void func_child2(int sig);
int main()
{
while((child1=fork())==-1);
if(child1==0)
{
printf("child1 OK\n");
signal(SIGINT,SIG_IGN);
signal(SIGUSR1,func_child1);
sleep(60);
}
else if(child1 >0)
{
while((child2=fork())==-1);
if(child2==0)
{
printf("child 2 OK\n");
signal(SIGINT,SIG_IGN);//你按下ctrl+C,子進程也會接受到ctrl的信號...所以,子進程忽略
//所提子進程要忽略掉這個SIGINT信號
signal(SIGUSR2,func_child2);
sleep(60); //這里為了驗證,如果進程沒退出,40妙之後自動會退出的
//不然就得手動在終端裡面kill掉這個進程了...
//有時候成了僵屍進程需要kill -9 才能殺死
}
else if(child2 >0)
{
signal(SIGINT,func_main);
printf("children forked OK...\n");
wait(0);
printf("child return...\n");
sleep(100);
return 0;
}
}
}
void func_main(int sig)
{
k++;
printf("to send signal\n");
//printf("child1=%d,child2=%d\n",child1,child2);
//if(k==1)
kill(child1,SIGUSR1);
//if(k==2) 加上這句,再按一次ctrl C,子進程2才會退出
就是你想要的效果了
kill(child2,SIGUSR2);
signal(SIGINT,SIG_DFL); //這里恢復ctrl+C的效果
//子進程退出之後,我們再按一次ctrl+C,當前的父進程就會像平常一樣,退出。
}
void func_child1(int sig)
{
printf("child1 is killed by parent!\n");
exit(0);
}
void func_child2(int sig)
{
printf("child2 is killed by parent!\n");
exit(0);
}