libevent源码分析之信号处理
int called = 0;- static void
signal_cb(int fd, short event, void *arg){struct event *signal = arg;printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal));if (called >= 2)event_del(signal);called++;}intmain (int argc, char **argv){struct event signal_int;//这里我们把它称为事件2/* Initalize the event library */event_init();/* 初始化事件2,设置相关信号,回调函数 */event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,&signal_int);event_add(&signal_int, NULL);//激活信号event_dispatch();//等待事件的触发return (0);}
evsignal_init(base);
struct evsignal_info {struct event ev_signal;//向event_base注册读事件使用的event结构体,这里我们称为事件1int ev_signal_pair[2];//sock pair对,也就是clientfd跟servfdint ev_signal_added;//记录ev_signal信号是否已经注册volatile sig_atomic_t evsignal_caught;//是否有信号发生struct event_list evsigevents[NSIG];//注册到信号的事件链表的一个标志sig_atomic_t evsigcaught[NSIG];//记录每个信号的触发的次数#ifdef HAVE_SIGACTIONstruct sigaction **sh_old;//记录旧的信号处理函数#elseev_sighandler_t **sh_old;#endifint sh_old_max;};
intevsignal_init(struct event_base *base){int i;/** Our signal handler is going to write to one end of the socket* pair to wake up our event loop. The event loop then scans for* signals that got delivered.*///创建一个socketpairif (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {#ifdef WIN32/* Make this nonfatal on win32, where sometimes peoplehave localhost firewalled. */event_warn("%s: socketpair", __func__);#elseevent_err(1, "%s: socketpair", __func__);#endifreturn -1;}////子进程不能访问该socketpairFD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);base->sig.sh_old = NULL;base->sig.sh_old_max = 0;base->sig.evsignal_caught = 0;memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);/* initialize the queues for all events */for (i = 0; i < NSIG; ++i)TAILQ_INIT(&base->sig.evsigevents[i]);//设置为非阻塞evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);//可读事件设置与fd相关(但还缺乏注册到base注册链表中,需要在event_add中才会被注册到链表中去)event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);base->sig.ev_signal.ev_base = base;//把信号对应的事件跟base相关联base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;return 0;}
//添加事件static intepoll_add(void *arg, struct event *ev){struct epollop *epollop = arg;//获取epoll管理结构体struct epoll_event epev = {0, {0}};//epoll事件struct evepoll *evep;//读写事件指针int fd, op, events;if (ev->ev_events & EV_SIGNAL)//是否注册了信号return (evsignal_add(ev));//是的话,添加信号到此事件fd = ev->ev_fd;//获取对应的描述符if (fd >= epollop->nfds) {//判断描述符是否大于最大值,是的话,扩充/* Extent the file descriptor array as necessary */if (epoll_recalc(ev->ev_base, epollop, fd) == -1)return (-1);}evep = &epollop->fds[fd];//获取事件指针op = EPOLL_CTL_ADD;//默认是添加,其实还有修改等events = 0;if (evep->evread != NULL) {//这里epoll的修改与添加设置到一起了,如果不为空,说明本身已有事件了,那就只是修改器读写而已events |= EPOLLIN;//修改op = EPOLL_CTL_MOD;//设置为默认}if (evep->evwrite != NULL) {//为空events |= EPOLLOUT;op = EPOLL_CTL_MOD;}if (ev->ev_events & EV_READ)//是否可读events |= EPOLLIN;//events设置为可读if (ev->ev_events & EV_WRITE)//是否可写events |= EPOLLOUT;//设置为可写,注意events只是int类型epev.data.fd = fd;//epoll事件设置fdepev.events = events;//epoll事件设置为是否可读可写if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)return (-1);/* Update events responsible */if (ev->ev_events & EV_READ)//更新ev_events是否可读可写,如果是,那就更新evep读写事件指针,表示此事件可读可写evep->evread = ev;if (ev->ev_events & EV_WRITE)evep->evwrite = ev;return (0);}
intevsignal_add(struct event *ev){int evsignal;struct event_base *base = ev->ev_base;struct evsignal_info *sig = &ev->ev_base->sig;//获取信号事件结构体if (ev->ev_events & (EV_READ|EV_WRITE))//信号事件不可以是读写event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);evsignal = EVENT_SIGNAL(ev);//信号的fd就是信号的numberassert(evsignal >= 0 && evsignal < NSIG); // //信号不能超过NSIG这个数if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {////如果说该信号链表为空event_debug(("%s: %p: changing signal handler", __func__, ev));if (_evsignal_set_handler( //设置信号处理函数,同时,保存原来的信号处理函数到ev_base->sh_old中去base, evsignal, evsignal_handler) == -1)return (-1);/* catch signals if they happen quickly */evsignal_base = base;if (!sig->ev_signal_added) {//判断是否已加入if (event_add(&sig->ev_signal, NULL))//正式注册,添加到epoll_wait中去return (-1);sig->ev_signal_added = 1;//表示已经添加了}}//把ev->ev_signal_next加入到sig->evsigevents[evsignal]的链表末端/* multiple events may listen to the same signal */TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);return (0);}
static intepoll_dispatch(struct event_base *base, void *arg, struct timeval *tv){struct epollop *epollop = arg; //获取管理epoll的结构struct epoll_event *events = epollop->events;//epoll的事件数组struct evepoll *evep;int i, res, timeout = -1;if (tv != NULL)timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;//设置超时事件if (timeout > MAX_EPOLL_TIMEOUT_MSEC) {//不可以大于最大超时事件/* Linux kernels can wait forever if the timeout is too big;* see comment on MAX_EPOLL_TIMEOUT_MSEC. */timeout = MAX_EPOLL_TIMEOUT_MSEC;}res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);if (res == -1) {if (errno != EINTR) {event_warn("epoll_wait");return (-1);}evsignal_process(base);//处理信号事件return (0);} else if (base->sig.evsignal_caught) {evsignal_process(base);//处理信号事件}event_debug(("%s: epoll_wait reports %d", __func__, res));for (i = 0; i < res; i++) {int what = events[i].events;struct event *evread = NULL, *evwrite = NULL;int fd = events[i].data.fd;if (fd < 0 || fd >= epollop->nfds)continue;evep = &epollop->fds[fd];if (what & (EPOLLHUP|EPOLLERR)) {evread = evep->evread;evwrite = evep->evwrite;} else {if (what & EPOLLIN) {//可读evread = evep->evread;}if (what & EPOLLOUT) {//可写evwrite = evep->evwrite;}}if (!(evread||evwrite))continue;if (evread != NULL)//插入就绪链表event_active(evread, EV_READ, 1);if (evwrite != NULL)//插入就绪链表event_active(evwrite, EV_WRITE, 1);}if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {/* We used all of the event space this time. We shouldbe ready for more events next time. */int new_nevents = epollop->nevents * 2;struct epoll_event *new_events;new_events = realloc(epollop->events,new_nevents * sizeof(struct epoll_event));if (new_events) {epollop->events = new_events;epollop->nevents = new_nevents;}}return (0);}
voidevsignal_process(struct event_base *base)//遍历信号链表,是否有事件2挂载{struct evsignal_info *sig = &base->sig;//获取信号管理结构体struct event *ev, *next_ev;sig_atomic_t ncalls;int i;base->sig.evsignal_caught = 0;for (i = 1; i < NSIG; ++i) {ncalls = sig->evsigcaught[i];//是否有触发if (ncalls == 0)//没有就可以滚了continue;sig->evsigcaught[i] -= ncalls;//有的话。。。清空for (ev = TAILQ_FIRST(&sig->evsigevents[i]);ev != NULL; ev = next_ev) {next_ev = TAILQ_NEXT(ev, ev_signal_next);if (!(ev->ev_events & EV_PERSIST))//没设置这个位,就只使用一次了event_del(ev);event_active(ev, EV_SIGNAL, ncalls);//插入就绪链表}}}
libevent源码分析之信号处理的更多相关文章
- 【转】libevent源码分析
libevent源码分析 转自:http://www.cnblogs.com/hustcat/archive/2010/08/31/1814022.html 这两天没事,看了一下Memcached和l ...
- Libevent源码分析 (1) hello-world
Libevent源码分析 (1) hello-world ⑨月份接触了久闻大名的libevent,当时想读读源码,可是由于事情比较多一直没有时间,现在手头的东西基本告一段落了,我准备读读libeven ...
- libevent源码分析
这两天没事,看了一下Memcached和libevent的源码,做个小总结. 1.入门 1.1.概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络 ...
- Libevent源码分析系列【转】
转自:https://www.cnblogs.com/zxiner/p/6919021.html 1.使用libevent库 源码那么多,该怎么分析从哪分析呢?一个好的方法就是先用起来,会用了 ...
- Libevent源码分析系列
1.使用libevent库 源码那么多,该怎么分析从哪分析呢?一个好的方法就是先用起来,会用了,然后去看底层相应的源码,这样比较有条理,自上向下掌握.下面用libevent库写个程序,每隔1秒 ...
- Libevent源码分析—event_base_dispatch()
我们知道libevent是一个Reactor模式的事件驱动的网络库. 到目前为止,我们已经看了核心的event和event_base结构体的源码,看了初始化这两个结构体的源码,看了注册event的 ...
- libevent源码分析二--timeout事件响应
libevent不仅支持io事件,同时还支持timeout事件与signal事件,这篇文件将分析libevent是如何组织timeout事件以及如何响应timeout事件. 1. min_heap ...
- libevent源码分析一--io事件响应
这篇文章将分析libevent如何组织io事件,如何捕捉事件的发生并进行相应的响应.这里不会详细分析event与event_base的细节,仅描述io事件如何存储与如何响应. 1. select l ...
- Libevent源码分析—event_init()
下面开始看初始化event_base结构的相关函数.相关源码位于event.c event_init() 首先调用event_init()初始化event_base结构体 struct event_b ...
随机推荐
- 读json文件发生错误,所遇到的坑
当我们生产者生产json 文件的时候 消费时用JSON读文件时,如下: val values = kafkardd.map(t=>JSON.parseObject(t._2)) 如果发生以下 ...
- grunt简记
grunt和gulp都是前端自动化的工具,grunt更成熟,插件社区全.大:gulp比较年轻,性能更好,更简单容易.具体使用哪种可根据实际项目组来决定. 创建任务 grunt默认执行的是default ...
- 《Cracking the Coding Interview》——第1章:数组和字符串——题目7
2014-03-18 01:55 题目:给定一个MxN矩阵,如果某个元素为0,则将对应的整行和整列置为0. 解法:单独挑出一行和一列作为标记数组.因为某元素为0就全部置为0,所以不论A[i][j]为0 ...
- 使用Html5shiv.js让ie支持html5
ie低版本不支持html5标签,可以引入一段脚本,在ie浏览器中创建html5的标签. 1,可以在网上下载html5shiv的压缩包,引入压缩版的html5shiv.min.js即可. 脚本引用要在h ...
- CSS系列(8) CSS后代选择器和子选择器详解
一.CSS后代选择器详解 1, 生动介绍基本概念 一个标签嵌B在另一个标签A内部,B就是A的后代. 而且,B的后代也是A的后代,这就叫“子子孙孙无穷尽也”. 比如: <div> < ...
- 如何在乌班图上配置java开发环境
不想说的那么细,每条命令都说一下,在现在这个浮躁的时代,很少有人能看的下去,我就直接上命令,最简单的快捷的方式. 1:安装软件 2:设置root密码 3:配置mysql远程登录 4:安装java运行环 ...
- 聊聊、Mybatis API
API Mybatis 到底解决了什么问题,持久化框架是什么,没出现 Mybatis 之前我们又是怎么来操作数据库的呢?对于 Java语言 来说,JDBC标准 是比较底层的了,但并非最底层的,可以说 ...
- Kd-Tree&Ransac笔记
关于sift资源总结: http://blog.csdn.net/masibuaa/article/details/9191309 两个比较好的资源: https://my.oschina.net/k ...
- java作业 2017.10.14
课后作业一 1.设计思想: (1)通过组合数公式计算:分别输入中的n和k的值.定义一个计算n!的方法,然后调用方法分别计算出n!,k!,(n-k)!,然后通过公式=n!/(k!*(n-k)!)算出的值 ...
- jQuery基础知识点(上)
jQuery是一个优秀的.轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF1.5+, Safari 2.0+, Opera 9.0+),而jQuery2.0及后续版本将不再支 ...