libevent的Select事件
收獲
- 特別大的收獲阵赠,好像也沒有数初。就只是看懂了它寫的代碼是什么意思拷况。
- 程序結(jié)果的設計會有點意思作煌。其他沒什么特別的印象。
結(jié)構(gòu)體
struct selectop {
/* 最大的文件句柄赚瘦。*/
int event_fds; /* Highest fd in fd set */
int event_fdsz;
fd_set *event_readset;/* 讀信號事件集合*/
fd_set *event_writeset;/* 寫信號事件集合*/
sigset_t evsigmask;// linux 信號集粟誓。用于檢測是否有信號發(fā)送過來。
} sop;
結(jié)構(gòu)體說明
selectop含有成員變量
evsigmask是用于檢測select時起意,有信號發(fā)送的鹰服。
成員函數(shù)
select類的成員函數(shù)。
void *select_init (void);
int select_add (void *, struct event *);
int select_del (void *, struct event *);
int select_recalc (void *, int);
int select_dispatch (void *, struct timeval *);
select類揽咕,類似于c++的多態(tài)實現(xiàn)
struct eventop {
char *name;
void *(*init)(void);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
int (*recalc)(void *, int);
int (*dispatch)(void *, struct timeval *);
};//基類
struct eventop selectops = {
"select",
select_init,
select_add,
select_del,
select_recalc,
select_dispatch
};
select_recalc
- 初始化結(jié)構(gòu)體和信號集
void *
select_init(void)
{
memset(&sop, 0, sizeof(sop));
sigemptyset(&sop.evsigmask);
return (&sop);
}
select_recalc
- 重新申請悲酷,存儲監(jiān)聽信號集的變量的大小。(事件是安位監(jiān)聽的亲善。)
int
select_recalc(void *arg, int max)
{
struct selectop *sop = arg;
fd_set *readset, *writeset;
struct event *ev;
int fdsz;
/*
設置event_fds為最大值
*/
if (sop->event_fds < max)
sop->event_fds = max;
/*
如果event_fds不存在设易,則遍歷隊列,取最大值蛹头。
*/
if (!sop->event_fds) {
TAILQ_FOREACH(ev, &eventqueue, ev_next)
if (ev->ev_fd > sop->event_fds)
sop->event_fds = ev->ev_fd;
}
/*
計算存儲event_fds所需要的位數(shù)顿肺。
*/
fdsz = howmany(sop->event_fds + 1, NFDBITS) * sizeof(fd_mask);
if (fdsz > sop->event_fdsz) {
if ((readset = realloc(sop->event_readset, fdsz)) == NULL) {
log_error("malloc");
return (-1);
}
if ((writeset = realloc(sop->event_writeset, fdsz)) == NULL) {
log_error("malloc");
free(readset);
return (-1);
}
memset((char *)readset + sop->event_fdsz, 0,
fdsz - sop->event_fdsz);
memset((char *)writeset + sop->event_fdsz, 0,
fdsz - sop->event_fdsz);
sop->event_readset = readset;
sop->event_writeset = writeset;
sop->event_fdsz = fdsz;
}
return (signal_recalc());
}
signal_recalc
/*
重新計算,并重新注冊信號事件渣蜗。只注冊signalqueue里的even
注冊到信號事件里的函數(shù)為signal_handler屠尊。
該事件,只是在數(shù)組里對應的字段加一耕拷。
因為信號事件知染,只有64個。所以這其實就是個信號數(shù)組斑胜。表示該信號發(fā)生了幾次控淡。
*/
static void
signal_handler(int sig)
{
evsigcaught[sig]++;
}
int
signal_recalc(void)
{
struct sigaction sa;
struct event *ev;
if (sigprocmask(SIG_BLOCK, &sop.evsigmask, NULL) == -1)
return (-1);
/* Reinstall our signal handler. */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler;
sa.sa_mask = sop.evsigmask;
sa.sa_flags |= SA_RESTART;
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
return (-1);
}
return (0);
}
select_dispatch
事件處理函數(shù)
/*
下發(fā)任務嫌吠,發(fā)起一次,select掺炭。等待信號發(fā)送辫诅。
*/
int
select_dispatch(void *arg, struct timeval *tv)
{
int maxfd, res;
struct event *ev, *next;
struct selectop *sop = arg;
memset(sop->event_readset, 0, sop->event_fdsz);
memset(sop->event_writeset, 0, sop->event_fdsz);
/*
再初始化,信號集涧狮。
*/
TAILQ_FOREACH(ev, &eventqueue, ev_next) {
if (ev->ev_events & EV_WRITE)
FD_SET(ev->ev_fd, sop->event_writeset);
if (ev->ev_events & EV_READ)
FD_SET(ev->ev_fd, sop->event_readset);
}
/*
先注冊信號炕矮。
*/
if (signal_deliver() == -1)
return (-1);
/*
調(diào)用select函數(shù),等待事件發(fā)送者冤。
tv如果有值肤视,則超時自動返回。
*/
res = select(sop->event_fds + 1, sop->event_readset,
sop->event_writeset, NULL, tv);
/*
select函數(shù)完后涉枫。需再重新注冊信號事件邢滑。
如果select中有事件發(fā)生,需要再重新注冊一遍事件愿汰±Ш螅或者select中,是事件觸發(fā)select結(jié)束
會導致程序未處理接下來的信號事件
*/
if (signal_recalc() == -1)
return (-1);
if (res == -1) {
if (errno != EINTR) {
log_error("select");
return (-1);
}
/*
處理信號衬廷。
*/
signal_process();
return (0);
}
LOG_DBG((LOG_MISC, 80, __FUNCTION__": select reports %d",
res));
/*
監(jiān)聽讀事件摇予,或者寫事件,是否有事件發(fā)生吗跋。
*/
maxfd = 0;
for (ev = TAILQ_FIRST(&eventqueue); ev != NULL; ev = next) {
next = TAILQ_NEXT(ev, ev_next);
res = 0;
if (FD_ISSET(ev->ev_fd, sop->event_readset))
res |= EV_READ;
if (FD_ISSET(ev->ev_fd, sop->event_writeset))
res |= EV_WRITE;
res &= ev->ev_events;
if (res) {
if (!(ev->ev_events & EV_PERSIST))
event_del(ev);
event_active(ev, res, 1);
} else if (ev->ev_fd > maxfd)
maxfd = ev->ev_fd;
}
sop->event_fds = maxfd;
return (0);
}
select_add
/*
添加事件侧戴。
如果只是select的信號事件,就增加到信號事件集里跌宛。
如果不是select的信號事件救鲤。就增加最大的文件fd
這樣,自然就添加到了select的監(jiān)聽事件集里秩冈。
*/
int
select_add(void *arg, struct event *ev)
{
struct selectop *sop = arg;
if (ev->ev_events & EV_SIGNAL) {
int signal;
if (ev->ev_events & (EV_READ|EV_WRITE))
errx(1, "%s: EV_SIGNAL incompatible use",
__FUNCTION__);
signal = EVENT_SIGNAL(ev);
sigaddset(&sop->evsigmask, signal);
return (0);
}
/*
* Keep track of the highest fd, so that we can calculate the size
* of the fd_sets for select(2)
*/
if (sop->event_fds < ev->ev_fd)
sop->event_fds = ev->ev_fd;
return (0);
}
select_del
/*
* Nothing to be done here.
文件句柄,擴大了就沒有再縮小了斥扛。
刪除信號事件入问。
*/
int
select_del(void *arg, struct event *ev)
{
struct selectop *sop = arg;
int signal;
if (!(ev->ev_events & EV_SIGNAL))
return (0);
signal = EVENT_SIGNAL(ev);
sigdelset(&sop->evsigmask, signal);
return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
}