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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android apr分析,APR分析信号篇

發布時間:2024/10/8 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android apr分析,APR分析信号篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

APR分析-信號篇

U know信號是Unix的重要系統機制。信號機制使用起來很簡單,但是理解起來有并不是那么Easy。APR

Signal的封裝也并不繁瑣,代碼量很少,所以分析APR Signal的過程其實就是學習Signal機制的過程。

一、信號介紹

1、Signal“歷史久遠”,在最初的Unix系統上就能看到它“偉岸”的身影。它的引入用來進行User

Mode進程間的交互,系統內核也可以利用它通知User Mode進程發生了哪些系統事件。從最開始引入到現在,信號只是做了很小的一些改動(不可靠信號模型到可靠信號模型)。

2、信號服務于兩個目的:

1)通知某進程某特定事件發生了;

2)強制其通知進程執行相應的信號處理程序。

二、基礎概念

1、信號的一個特性就是可以在任何時候發給某一進程,而無需知道該進程的狀態。如果該進程當前并未處于執行態,則該信號被內核Save起來,直到該進程恢復執行才傳遞給它;如果一個信號被進程設置為阻塞,則該信號的傳遞被延遲,直到其阻塞被取消它才被傳遞給進程。

2、系統內核嚴格區分信號傳送的兩個階段:

1) Signal Generation :系統內核更新目標進程描述結構來表示一個信號已經被發送出去。

2) Signal Delivery :內核強制目標進程對信號做出反應,或執行相關信號處理函數,或改變進程執行狀態。

信號的誕生和傳輸我們可以這樣理解:把信號作為“消費品”,其Generation狀態就是“消費品誕生”,其Delivery狀態就是理解為“被消費了”。這樣勢必存在這樣的一個情況:“消費品誕生了,但是還沒有被消費掉”,在信號模型中,這樣的狀態被稱為“pending”(懸而未決)。

任何時候一個進程只能有一個這樣的某類型的pending信號,同一進程的其他同類型的pending信號將不排隊,將被簡單的discard(丟棄)掉。

3、如何消費一個signal

1)忽略該信號;[注1]

2)響應該信號,執行一特定的信號處理函數;

3)響應該信號,執行系統默認的處理函數。包括:Terminate、Dump、Ignore、Stop、Continue等。

這里有特殊:SIGKILL和SIGSTOP兩個信號不能忽略、不能捕捉、不能阻塞,而只是執行系統默認處理函數。

三、APR Signal封裝

APR Signal源代碼的位置在$(APR_HOME)//threadproc目錄下,本篇blog著重分析unix子目錄下的signals.c文件內容,其相應頭文件為$(APR_HOME)/include/apr_signal.h。

1、apr_signal函數

Unix信號機制提供的最簡單最常見的接口是signal函數,用來設置某特定信號的處理函數。但是由于早期版本和后期版本處理信號方式的不同,導致現在直接使用signal函數在不同的平臺上可能得到不同的結果。

早期版本處理方式:進程每次處理信號后,隨即將信號的處理動作重置為默認值。

后期版本處理方式:進程每次處理信號后,信號的處理動作不被重置為默認值。

我們舉例測試一下:分別在Solaris9、Cygwin和RedHat Linux 9上。

例子:

E.G 1:

void siguser1_handler(int sig);

int main(void)

{

if (signal(SIGUSR1,siguser1_handler) == SIG_ERR) {

perror("siguser1_handler error");

exit(1);

}

while (1) {

pause();

}

}

void siguser1_handler(int sig)

{

printf("insiguser1_handler, %d/n", sig);

}

input:

kill -USR1 9122

kill -USR1 9122

output:(Solaris 9)

in siguser1_handler, 16

用戶信號1 (程序終止)

output:(Cygwin and RH9)

in siguser1_handler, 30

in siguser1_handler, 30

...

..

E.G 1結果表示在Solaris 9上,信號的處理仍然按照早期版本的方式,而Cygwin和RH9則都按照后期版本的方式。

那么有什么替代signal函數的辦法么?在最新的X/Open和UNIXspecifications中都推薦使用一個新的信號接口sigaction,該接口采用后期版本的信號處理方式。在《Unix高級環境編程》中就有使用sigaction實現signal的方法,而APR恰恰也是使用了該方法實現了apr_signal。其代碼如下:

APR_DECLARE(apr_sigfunc_t *) apr_signal(int signo, apr_sigfunc_t *func)

{

struct sigaction act, oact;

act.sa_handler = func;

sigemptyset(&act.sa_mask);?------------------(1)

act.sa_flags = 0;

#ifdefSA_INTERRUPT????????????/* SunOS */

act.sa_flags |= SA_INTERRUPT;

#endif

... ...

if (sigaction(signo, &act, &oact) <0)

return SIG_ERR;

return oact.sa_handler;

}

(1)這里有一個Signal Set(信號集)的概念,通過相關函數操作信號集以改變內核傳遞信號給進程時的行為。Unix用sigset_t結構來表示信號集。信號集總是和sigprocmask或sigaction一起使用。關于信號集和sigprocmask函數將在下面詳述。

2、apr_signal_block和apr_signal_unblock

這兩個函數分別負責阻塞和取消阻塞內核傳遞某信號給目標進程。其主要利用的就是sigprocmask函數來實現的。每個進程都有其對應的信號屏蔽字,它讓目標進程能夠通知內核“哪些傳給我的信號該阻塞,哪些暢通無阻”。在《Unix高級環境編程》中作者有這么一段說明“如果在調用sigprocmask后有任何未決的、不再阻塞的信號,則在sigprocmask返回前,至少將其中之一遞送給該進程?!蹦芾斫膺@句我想信號屏蔽字這塊兒也就沒什么問題了。在Unix高級環境編程》中作者舉了一個很不錯的例子,講解的也很詳細。這里想舉例說明的是:如果多次調用SET_BLOCK的sigprocmask設置屏蔽字,結果是什么呢?

E.G 3

int main(void)

{

sigset_t newmask,oldmask, pendmask;

/*設置進程信號屏蔽字,阻塞SIGQUIT */

sigemptyset(&newmask);

sigaddset(&newmask,SIGQUIT);

if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {

perror("SIG_BLOCK error");

}

printf("1st towait 30 seconds/n");

sleep(30);

/*第一次察看當前的處于pend狀態的信號*/

if(sigpending(&pendmask) < 0) {

perror("sigpending error");

}

if(sigismember(&pendmask, SIGQUIT)) {

printf("SIGQUIT pending/n");

} else {

printf("SIGQUIT unpending/n");

}

if(sigismember(&pendmask, SIGUSR1)) {

if(sigismember(&pendmask, SIGUSR1)) {

printf("SIGUSR1 pending/n");

} else {

printf("SIGUSR1 unpending/n");

}

/*重新設置屏蔽字,阻塞SIGUSR1 */

sigemptyset(&newmask);

sigaddset(&newmask,SIGUSR1);

if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {

perror("SIG_BLOCK error");

}

printf("2nd towait 30 seconds/n");

sleep(30);

/*再次察看當前的處于pend狀態的信號*/

if(sigpending(&pendmask) < 0) {

perror("sigpending error");

}

if(sigismember(&pendmask, SIGQUIT)) {

printf("SIGQUIT pending/n");

} else {

printf("SIGQUIT unpending/n");

}

if(sigismember(&pendmask, SIGUSR1)) {

printf("SIGUSR1 pending/n");

} else {

printf("SIGUSR1 unpending/n");

}

exit(0);

}

//output:

1st to wait 30 seconds

^/

SIGQUIT pending

SIGUSR1 unpending

2nd to wait 30 seconds --這之后發送kill -USR128821

SIGQUIT pending

SIGUSR1 pending

第一次輸出SIGUSR1unpending是因為并未發送USR1信號,所以自然為unpending狀態;我想說的是第二次重新sigprocmask時我們僅加入了SIGUSR1,并未顯示加入SIGQUIT,之后察看pending信號中SIGQUIT仍然為pending狀態,這說明兩次SET_BLOCK的sigprocmask調用是"或"的關系,第二次SET_BLOCK的sigprocmask調用不會將第一次SET_BLOCK的sigprocmask調用設置的阻塞信號變為非阻塞的。

四、總結

信號簡單而強大,如果想深入了解signal的實現,參考資料中的第二本書會給你滿意的答案。

五、參考資料:

1、《Unix高級環境編程》

2、《深入理解Linux內核》

[注1]

忽略信號和阻塞信號

前者相當于一個消費行為,該信號的狀態為“已消費”,而后者只是將信號做緩存,等待阻塞打開,再交給進程消費,其狀態為“未消費”,也相當于處于pending狀態。

總結

以上是生活随笔為你收集整理的android apr分析,APR分析信号篇的全部內容,希望文章能夠幫你解決所遇到的問題。

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