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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libevent源码学习-----统一事件源及信号绑定函数

發(fā)布時間:2024/4/19 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libevent源码学习-----统一事件源及信号绑定函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

libevent在對文件描述符,套接字進行監(jiān)控時直接放到event,這些event通過io多路復(fù)用函數(shù)進行監(jiān)控,然而對應(yīng)信號來說io復(fù)用函數(shù)卻無能為力,為了解決問題,libevent采用統(tǒng)一事件源的方式,即將信號也表現(xiàn)成event的形式,用到了socketpair套接字對

socketpair套接字對
套接字對也是通信方式的一種,在進程間通信時相比于管道和命名管道而言更簡單,也更安全
linux下使用socketpair函數(shù)創(chuàng)建一對套接字,函數(shù)原型

/**@param d: 協(xié)議族,通常為AF_UNIX*@param type: 套接字類型,如SOCK_STREAM*@param protocol: 協(xié)議,0即可*@param sv: 存放創(chuàng)建的兩個套接字*/ int socketpair(int d, int type, int protocol, int sv[2]);

創(chuàng)建的套接字對的每一端都可以進行讀寫,也就是sv[0]可以既作為讀端也可以作為寫端,sv[1]也是。
libevent中sv[1]為讀端,sv[0]為寫端。向sv[0]中寫入數(shù)據(jù)時sv[1]會變?yōu)榭勺x


對于信號的處理,其實用戶可以自己使用sigaction注冊信號處理函數(shù)然后自己提供回調(diào)函數(shù),但是既然想要交給libevent處理,就說明用戶只提供回調(diào)函數(shù),其他什么都不管。
也可以在內(nèi)部只調(diào)用sigaciton/signal注冊信號處理函數(shù),回調(diào)函數(shù)是用戶提供的那個,這樣也可以滿足需求,但是既然統(tǒng)一事件源,就需要把信號也當(dāng)成event處理。

libevent的做法是為

  • 讀端注冊到base中,提供一個內(nèi)部的回調(diào)函數(shù),該步驟僅僅調(diào)用一次
  • 信號值作為fd創(chuàng)建event,綁定內(nèi)部回調(diào)函數(shù),注冊到base中
  • 為信號綁定一個內(nèi)部的信號處理函數(shù),在信號處理函數(shù)中將發(fā)生的信號值寫入套接字對的寫端
  • 此時讀端變?yōu)榭勺x,調(diào)用這個讀端套接字綁定的回調(diào)函數(shù)
  • 讀端回調(diào)函數(shù)中讀取信號值,將信號值對應(yīng)的event添加到激活隊列中
  • 激活隊列處理

我覺得完全可以直接在內(nèi)部使用sigaction/signal綁定信號值和用戶的信號處理函數(shù)
但是既然libevent想要把所有東西都當(dāng)成event來處理,就需要將信號轉(zhuǎn)成event,把所有event都放到激活隊列中一起處理


復(fù)習(xí)一下linux下的信號處理機制

UNIX系統(tǒng)信號機制最簡單的接口是signal函數(shù),函數(shù)原型為

#include <signal.h> void (*signal(int signo, void (*func)(int)))(int);
  • signo表示用戶關(guān)心的信號類型,如終端信號,退出信號,SIGINT,SIGQUIT等
  • func可以是一個函數(shù)指針,也就是信號處理函數(shù),當(dāng)signno信號發(fā)生時,會調(diào)用這個函數(shù)。該函數(shù)有一個int類型參數(shù),通常是信號值。也可以是常量SIG_IGN表示內(nèi)核忽略該信號(SIGKILL和SIGSTOP不能被忽略),常量SIG_DFL表示執(zhí)行系統(tǒng)默認的處理動作,通常是終止當(dāng)前進程
  • 返回值是指向在此之前的信號處理函數(shù)的指針

signal的使用還是比較簡單的

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/types.h>void handler(int signo);int main() {signal(SIGINT,handler);for(;;)pause();return 0; }void handler(int signo) {printf("receive sig=%d\n", sig); }

程序首先注冊信號處理函數(shù),之后當(dāng)中斷發(fā)生后切換到內(nèi)核態(tài),在內(nèi)核的中斷處理程序執(zhí)行完后返回用戶態(tài)之前檢測到有信號SIGINT發(fā)生,內(nèi)核遍不恢復(fù)到main函數(shù)而是直接轉(zhuǎn)到handler函數(shù)中,在執(zhí)行完handler后由內(nèi)核轉(zhuǎn)到main函數(shù)中繼續(xù)執(zhí)行。main和handler是兩個獨立的存在


signal并不屬于POSIX標準,在UNIX中使用sigaction函數(shù)作為signal的替代品,signaction函數(shù)的功能是檢查或修改(或檢查并修改)與制定信號相關(guān)聯(lián)的處理動作,函數(shù)原型為

#include <signal.h> int sigaction(int signo, const struct sigaction *act,struct sigaction *oact);
  • signno是要檢測或修改其處理動作的信號編號,如SIGINT,SIGQUIT等
  • act為要修改的動作,本質(zhì)上是信號處理函數(shù)
  • oact為以前的信號處理動作,不關(guān)心時可以設(shè)置為NULL
  • 調(diào)用成功返回0,失敗返回-1(linux的系統(tǒng)調(diào)用返回值大多是這樣)

結(jié)構(gòu)體struct sigaction如下

struct sigaction {void (*sa_handler)(int);sigset_t sa_mask;int sa_flags;void (*sa_sigaction)(int, siginfo_t *, void *); }
  • sa_handler和signal的第二個參數(shù)相同,表示信號處理函數(shù),SIG_IGN表示忽略,SIG_DFL表示默認動作,參數(shù)為信號值
  • sa_mask是信號屏蔽字集,如果設(shè)置,那么在進行信號處理函數(shù)時,如果有在sa_mask中的信號到達,則不會通知進程,而是在信號處理函數(shù)執(zhí)行完后才通知。默認情況下,如果程序正在執(zhí)行信號處理函數(shù),那么對于當(dāng)前這個信號處理函數(shù)處理的信號不會再次送到進程。
  • 內(nèi)核維護著一個信號隊列,如果當(dāng)前有正在處理的信號處理函數(shù),會把其他到達進程的信號放到這個隊列中。若同一種信號多次發(fā)生,通常只會添加一次
  • sa_sigaction和sa_flags配合使用,與sa_handler相對應(yīng),通常使用sa_handler就不需要使用sa_sigaction,主要用于實時信號可以帶信息,使用sa_handler時sa_flags設(shè)為0即可

通常使用sa_handler和sa_mask就可以滿足需求了

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <sys/types.h>void handler(int signo);int main() {struct sigaction act;act.sa_handler = handler;/* 清空信號屏蔽集 */sigemptyset(&act.sa_mask);/* 在信號處理函數(shù)執(zhí)行期間屏蔽SIGQUIT,執(zhí)行完后送達當(dāng)前進程 */sigaddset(&act.sa_mask, SIGQUIT);act.sa_flags = 0;if(sigaction(SIGINT, &act, NULL) < 0){perror("sigaction error");exit(1);}for(;;)pause();return 0; }void handler(int signo) {printf("receive sig=%d\n", signo);sleep(5); }

先按ctrl+c發(fā)送中斷信號,馬上按ctrl+z發(fā)送終止信號,發(fā)現(xiàn)程序5秒后才終止,說明sa_mask中的信號如果發(fā)生了會在當(dāng)前信號處理函數(shù)完成后才送達當(dāng)前進程

總結(jié)

以上是生活随笔為你收集整理的libevent源码学习-----统一事件源及信号绑定函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。