libevent的Select事件
2020-03-28 本文已影响0人
混世太保
libevent的Select事件
收获
- 特别大的收获,好像也没有。就只是看懂了它写的代码是什么意思。
- 程序结果的设计会有点意思。其他没什么特别的印象。
结构体
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 信号集。用于检测是否有信号发送过来。
} sop;
结构体说明
selectop含有成员变量
evsigmask是用于检测select时,有信号发送的。
成员函数
select类的成员函数。
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++的多态实现
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
- 初始化结构体和信号集
void *
select_init(void)
{
memset(&sop, 0, sizeof(sop));
sigemptyset(&sop.evsigmask);
return (&sop);
}
select_recalc
- 重新申请,存储监听信号集的变量的大小。(事件是安位监听的。)
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所需要的位数。
*/
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
注册到信号事件里的函数为signal_handler。
该事件,只是在数组里对应的字段加一。
因为信号事件,只有64个。所以这其实就是个信号数组。表示该信号发生了几次。
*/
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
事件处理函数
/*
下发任务,发起一次,select。等待信号发送。
*/
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);
/*
调用select函数,等待事件发送。
tv如果有值,则超时自动返回。
*/
res = select(sop->event_fds + 1, sop->event_readset,
sop->event_writeset, NULL, tv);
/*
select函数完后。需再重新注册信号事件。
如果select中有事件发生,需要再重新注册一遍事件。或者select中,是事件触发select结束
会导致程序未处理接下来的信号事件
*/
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));
/*
监听读事件,或者写事件,是否有事件发生。
*/
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的监听事件集里。
*/
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));
}