作 ?者:道哥,10 年嵌入式開發(fā)老兵,專注于:C/C 、嵌入式、Linux 。關(guān)注下方公眾號 ,回復【書籍 】,獲取 Linux、嵌入式領(lǐng)域經(jīng)典書籍;回復【PDF 】,獲取所有原創(chuàng)文章( PDF 格式)。 目錄 kill 命令和信號 使用 kill 命令發(fā)送信號 多線程中的信號 信號注冊和處理函數(shù) 驅(qū)動程序 代碼示例:發(fā)送信號功能需求 驅(qū)動程序代碼 驅(qū)動模塊 Makefile 編譯和加載 應(yīng)用程序 代碼示例:接收信號別人的經(jīng)驗,我們的階梯! 大家好,我是道哥,今天我為大伙兒解說的技術(shù)知識點是:
【驅(qū)動層中,如何發(fā)送信號給應(yīng)用程序】 。在上一篇文章中,我們討論的是:在應(yīng)用層如何發(fā)送指令來控制驅(qū)動層的
GPIO
Linux驅(qū)動實踐:如何編寫【 GPIO 】設(shè)備的
驅(qū)動程序 ???刂频姆较蚴?span>從應(yīng)用層到驅(qū)動層:
那么,如果想讓程序的執(zhí)行路徑
從下往上 ,也就是從
驅(qū)動層傳遞到應(yīng)用層 ,應(yīng)該如何實現(xiàn)呢?
最容易、最簡單的方式,就是通過
發(fā)送信號 !這篇文章繼續(xù)以
完整的代碼實例 來演示如何實現(xiàn)這個功能。
kill 命令和信號 使用 kill 命令發(fā)送信號 關(guān)于
Linux
操作系統(tǒng)的信號,每位程序員都知道這個指令:使用
kill 工具來“殺死”一個進程:
$ kill -9 <進程的 PID>
這個指令的功能是:
向指定的某個進程發(fā)送一個信號 9 ,這個信號的默認功能是:是停止進程。雖然在應(yīng)用程序中沒有主動處理這個信號,但是
操作系統(tǒng)默認的處理動作 是終止應(yīng)用程序的執(zhí)行。除了發(fā)送信號
9
,
kill
命令還可以發(fā)送其他的任意信號。在
Linux
系統(tǒng)中,所有的信號都使用一個
整型 數(shù)值來表示,可以打開文件
/usr/include/x86_64-linux-gnu/bits/signum.h
(你的系統(tǒng)中可能位于其它的目錄) 查看一下,比較常見的幾個信號是:
/* Signals. */ #define SIGINT 2 /* Interrupt (ANSI). */ #define SIGKILL 9 /* Kill, unblockable (POSIX). */ #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ #define SIGSEGV 11 /* Segmentation violation (ANSI). */ #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ ... ... #define SIGSYS 31 /* Bad system call. */ #define SIGUNUSED 31 #define _NSIG 65 /* Biggest signal number 1 (including real-time signals). */ /* These are the hard limits of the kernel. These values should not be used directly at user level. */ #define __SIGRTMIN 32 #define __SIGRTMAX (_NSIG - 1)
信號
9
對應(yīng)著
SIGKILL
,而信號
11
(
SIGSEGV
)就是最令人討厭的
Segmentfault !這里還有一個地方需要注意一下:
實時信號和非實時信號 ,它倆的主要區(qū)別是:
非實時信號:操作系統(tǒng)不確保應(yīng)用程序一定能接收到(即:信號可能會丟失); 實時信號:操作系統(tǒng)確保應(yīng)用程序一定能接收到; 如果我們的程序設(shè)計,通過信號機制來完成一些功能,那么為了確保信號
不會丟失 ,肯定是使用實時信號的。從文件
signum.h
中可以看到,實時信號從
__SIGRTMIN
(數(shù)值:
32
) 開始。
多線程中的信號 我們在編寫應(yīng)用程序時,雖然沒有接收并處理
SIGKILL
這個信號,但是一旦別人發(fā)送了這個信號,我們的程序就被操作系統(tǒng)停止掉了,這是默認的動作。那么,在應(yīng)用程序中,應(yīng)該可以
主動 聲明接收并處理指定的信號,下面就來寫一個最簡單的實例。
在一個應(yīng)用程序中,可能存在多個線程;當有一個信號發(fā)送給此進程時,所有的線程都可能接收到,但是只能有一個線程來處理;在這個示例中,只有一個主線程來接收并處理信號; 信號注冊和處理函數(shù) 按照慣例,所有
應(yīng)用程序 文件都創(chuàng)建在
~/tmp/App
目錄中。
// 文件:tmp/App/app_handle_signal/app_handle_signal.c #include #include #include #include #include // 信號處理函數(shù) static void signal_handler(int signum, siginfo_t *info, void *context) { // 打印接收到的信號值 printf("signal_handler: signum = %d \n", signum); } int main(void) { int count = 0; // 注冊信號 處理函數(shù) struct sigaction sa; sigemptyset(