編寫Linux驅動的過程中,需要考慮與應用程序交互的情況。當設備驅動完成某項任務或者達到某種狀態的時候(如設備文件可以寫入或讀取),此時可以讓驅動程序主動通知應用程序進行相應的處理(個人感覺類似于Android應用程序中的廣播)。這種在Linux內核中使用的“廣播”就是本文要詳細介紹的“信號”。
1. Linux信號類型
使用信號進行進程間通信(IPC)是LInux系統的重要通信機制。在Linux系統中,異步通知使用信號來實現。以下是Linux系統支持的信號及其含義:(asm/signal.h)
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
#define SIGPWR 30
#define SIGSYS 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX _NSIG
#define SIGSWI 32
注:以上除了SISSTOP和SIGKILL兩個信號外,進程可以忽略或捕獲其他的全部信號。
如果其中一個信號被捕獲,說明在應用程序中為該信號指定了一個處理函數。如果一個信號沒有被某個進程捕獲,Linux內核會對該信號采用默認處理方式進行處理。
2. 接收Linux信號
在用戶程序中,為了捕捉信號,需要使用signal函數來設置信號接收的回調函數:
void (*signal(int signum, void (* handler)(int)))(int);
從signal函數原型上看有些復雜, 但主要有兩個參數:signum和handler,signum表示信號代碼,handler表示回調函數。
在應用程序中捕獲信號比較簡單,如下例子:
void signal_handler(int signo)
{
printf("捕獲到%d信號\n",signo);
}
main()
{
printf("信號ID是%d\n",getpid());
signal(SIGINT, signal_handler); //設置SIGINT信號的處理函數
signal(SIGHUP, signal_handler); //設置SIGHUP信號的處理函數
signal(SIGQUIT, signal_handler); //設置SIGQUIT信號的處理函數
getchar();
}
以上代碼示例了如何捕捉信號,并設置相應的處理函數。
3、發送信號
在設備驅動和應用程序的異步通知過程中,驅動程序需要向應用程序發出信號,為了完成發送信號的任務,需要完成以下工作:
- 支持F_SETDOWN命令。通過這個命令可以設置file_f_owner為對應進程的ID。
- 支持F_SETFL命令的處理。每當FASYNC標志改變時,驅動程序中的fasync函數就會執行。
- 再滿足條件時,調用kill_fasync函數發送相應的信號。
接收信號可以用signal函數和sigaction函數來完成,他們之間有以下幾個區別:
signal函數
1、signal在調用handler之前先把信號的handler指針恢復;sigaction調用之后不會恢復handler指針,直到再次調用sigaction修改handler指針。
:這樣,(1)signal就會丟失信號,而且不能處理重復的信號,而sigaction就可以。因為signal在得到信號和調用handler之間有個時間把handler恢復了,這樣再次接收到此信號就會執行默認的handler。(雖然有些調用,在handler的以開頭再次置handler,這樣只能保證丟信號的概率降低,但是不能保證所有的信號都能正確處理)
2、signal在調用過程不支持信號block;sigaction調用后在handler調用之前會把屏蔽信號(屏蔽信號中自動默認包含傳送的該信號)加入信號中,handler調用后會自動恢復信號到原先的值。
(2)signal處理過程中就不能提供阻塞某些信號的功能,sigaction就可以阻指定的信號和本身處理的信號,直到handler處理結束。這樣就可以阻塞本身處理的信號,到handler結束就可以再次接受重復的信號。
在驅動程序編寫過程中與應用程序進行交互是非常重要的,他可以確保用戶程序能夠順利執行,也能保證驅動能夠更好地服務于用戶。以上是本人學習中的一些總結,希望對大家有幫助~~