[libevent源码分析] event_add

event_add 把event往当前event中的ev_base追加,如果需要定时,那么tv不能为空

  1. int  
  2. event_add(struct event *ev, const struct timeval *tv)  
  3. {  
  4.     struct event_base *base = ev->ev_base;      //event_add 会把event加入到他的ev_base成员里  
  5.     const struct eventop *evsel = base->evsel;  //对应linux的epoll相关函数  
  6.     void *evbase = base->evbase;                //对应linux为 struct epollop  
  7.     /* 
  8.      * struct epollop 
  9.      * { 
  10.      *      struct evepoll *fds;                //分配nfiles个evepoll对象 
  11.      *      int nfds;                           //支持的最大软限制数的句柄(上面的数组个数) 
  12.      *      struct epoll_event* events;         //分配nfiles(软限制数) epoll_event对象 
  13.      *      int nevents;                        //nevents保存着上面events个数 
  14.      *      int epfd;                           //保存着epoll_create的句柄 
  15.      * } 
  16.      */  
  17.     int res = 0;  
  18.   
  19.     event_debug((  
  20.          "event_add: event: %p, %s%s%scall %p",  
  21.          ev,  
  22.          ev->ev_events & EV_READ ? "EV_READ " : " ",  
  23.          ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",  
  24.          tv ? "EV_TIMEOUT " : " ",  
  25.          ev->ev_callback));  
  26.   
  27.     assert(!(ev->ev_flags & ~EVLIST_ALL));  
  28.   
  29.     if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {  
  30.         if (min_heap_reserve(&base->timeheap,  
  31.             1 + min_heap_size(&base->timeheap)) == -1)  
  32.             return (-1);  /* ENOMEM == errno */  
  33.     }  
  34.   
  35.     if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&  
  36.         !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {  
  37.         res = evsel->add(evbase, ev);           //注册or修改事件到epoll中去  
  38.         if (res != -1)  
  39.             event_queue_insert(base, ev, EVLIST_INSERTED);  //把ev插入到eventqeue中去  
  40.     }  
  41.   
  42.     /* 
  43.      * 如果说插入事件成功同时设置了超时时间 
  44.      */  
  45.     if (res != -1 && tv != NULL) {  
  46.         struct timeval now;  
  47.   
  48.         /*  
  49.          *如果已经存在了超时时间,那么就删除这个超时节点 
  50.          */   
  51.         if (ev->ev_flags & EVLIST_TIMEOUT)  
  52.             event_queue_remove(base, ev, EVLIST_TIMEOUT);  
  53.   
  54.         /* Check if it is active due to a timeout.  Rescheduling 
  55.          * this timeout before the callback can be executed 
  56.          * removes it from the active list. */  
  57.         if ((ev->ev_flags & EVLIST_ACTIVE) &&  
  58.             (ev->ev_res & EV_TIMEOUT)) {  
  59.             /* See if we are just active executing this 
  60.              * event in a loop 
  61.              */  
  62.             if (ev->ev_ncalls && ev->ev_pncalls) {  
  63.                 /* Abort loop */  
  64.                 *ev->ev_pncalls = 0;  
  65.             }  
  66.               
  67.             event_queue_remove(base, ev, EVLIST_ACTIVE);  
  68.         }  
  69.   
  70.         gettime(base, &now);  
  71.         evutil_timeradd(&now, tv, &ev->ev_timeout);  
  72.   
  73.         event_debug((  
  74.              "event_add: timeout in %ld seconds, call %p",  
  75.              tv->tv_sec, ev->ev_callback));  
  76.   
  77.         event_queue_insert(base, ev, EVLIST_TIMEOUT);//加入到最小超时堆中去  
  78.     }  
  79.   
  80.     return (res);  
  81. }  
int
event_add(struct event *ev, const struct timeval *tv)
{
	struct event_base *base = ev->ev_base;      //event_add 会把event加入到他的ev_base成员里
	const struct eventop *evsel = base->evsel;  //对应linux的epoll相关函数
	void *evbase = base->evbase;                //对应linux为 struct epollop
    /*
     * struct epollop
     * {
     *      struct evepoll *fds;                //分配nfiles个evepoll对象
     *      int nfds;                           //支持的最大软限制数的句柄(上面的数组个数)
     *      struct epoll_event* events;         //分配nfiles(软限制数) epoll_event对象
     *      int nevents;                        //nevents保存着上面events个数
     *      int epfd;                           //保存着epoll_create的句柄
     * }
     */
	int res = 0;

	event_debug((
		 "event_add: event: %p, %s%s%scall %p",
		 ev,
		 ev->ev_events & EV_READ ? "EV_READ " : " ",
		 ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
		 tv ? "EV_TIMEOUT " : " ",
		 ev->ev_callback));

	assert(!(ev->ev_flags & ~EVLIST_ALL));

	if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
		if (min_heap_reserve(&base->timeheap,
			1 + min_heap_size(&base->timeheap)) == -1)
			return (-1);  /* ENOMEM == errno */
	}

	if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
		res = evsel->add(evbase, ev);           //注册or修改事件到epoll中去
		if (res != -1)
			event_queue_insert(base, ev, EVLIST_INSERTED);  //把ev插入到eventqeue中去
	}

    /*
     * 如果说插入事件成功同时设置了超时时间
     */
	if (res != -1 && tv != NULL) {
		struct timeval now;

        /* 
         *如果已经存在了超时时间,那么就删除这个超时节点
         */ 
		if (ev->ev_flags & EVLIST_TIMEOUT)
			event_queue_remove(base, ev, EVLIST_TIMEOUT);

		/* Check if it is active due to a timeout.  Rescheduling
		 * this timeout before the callback can be executed
		 * removes it from the active list. */
		if ((ev->ev_flags & EVLIST_ACTIVE) &&
		    (ev->ev_res & EV_TIMEOUT)) {
			/* See if we are just active executing this
			 * event in a loop
			 */
			if (ev->ev_ncalls && ev->ev_pncalls) {
				/* Abort loop */
				*ev->ev_pncalls = 0;
			}
			
			event_queue_remove(base, ev, EVLIST_ACTIVE);
		}

		gettime(base, &now);
		evutil_timeradd(&now, tv, &ev->ev_timeout);

		event_debug((
			 "event_add: timeout in %ld seconds, call %p",
			 tv->tv_sec, ev->ev_callback));

		event_queue_insert(base, ev, EVLIST_TIMEOUT);//加入到最小超时堆中去
	}

	return (res);
}
如果新加的事件不为空,当前事件不是timeout时间,就为他在时间最小堆上分配一块可用空间(如果最小堆有空间,就不会重新分配)
关于最小堆可以连接我的githup,libevent用最小堆来管理定时事件,根节点永远是最小的而且算法时间最小



如果事件是EV_READ、EV_WRITE、EV_SIGNAL,并且事件不是插入or激活状态,那么就加入事件
以epoll为例

  1. static int  
  2. epoll_add(void *arg, struct event *ev)  
  3. {  
  4.     struct epollop *epollop = arg;  
  5.     struct epoll_event epev = {0, {0}};  
  6.     struct evepoll *evep;  
  7.     int fd, op, events;  
  8.   
  9.     /* 
  10.      * 信号的原理 
  11.      * 1 设置信号处理函数,保存原来的信号处理函数到event的ev_base->sh_old中去 
  12.      * 2 如果是首次添加信号,那么需要为所有信号追加一个信号事件来源自event->ev_base->ev_signal 
  13.      *   同时设置event->ev_base->ev_signal->ev_signal_added,表示信号回调事件已经设置了 
  14.      * 3 同时把事件追加到event->ev_base->ev_signal->evsigevents[signno]链表中去 
  15.      */  
  16.     if (ev->ev_events & EV_SIGNAL)  //如果是加入的信号  
  17.         return (evsignal_add(ev));  
  18.   
  19.     fd = ev->ev_fd;  
  20.     if (fd >= epollop->nfds) {  
  21.         /* Extent the file descriptor array as necessary */  
  22.         //如果说当前的epoll中已经满足不了新加入的句柄  
  23.         if (epoll_recalc(ev->ev_base, epollop, fd) == -1)  
  24.             return (-1);  
  25.     }  
  26.   
  27.     evep = &epollop->fds[fd];  
  28.     op = EPOLL_CTL_ADD;  
  29.     events = 0;  
  30.     //如果事件之前是可读  
  31.     if (evep->evread != NULL) {  
  32.         events |= EPOLLIN;  
  33.         op = EPOLL_CTL_MOD;  
  34.     }  
  35.     //如果事件之前是可写  
  36.     if (evep->evwrite != NULL) {  
  37.         events |= EPOLLOUT;  
  38.         op = EPOLL_CTL_MOD;  
  39.     }  
  40.   
  41.     //新加入事件设置的是可读事件  
  42.     if (ev->ev_events & EV_READ)  
  43.         events |= EPOLLIN;  
  44.     //新加入事件设置的是可写事件  
  45.     if (ev->ev_events & EV_WRITE)  
  46.         events |= EPOLLOUT;  
  47.   
  48.     epev.data.ptr = evep;  
  49.     epev.events = events;  
  50.     if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)  
  51.             return (-1);  
  52.   
  53.     /* Update events responsible */  
  54.     if (ev->ev_events & EV_READ)  
  55.         evep->evread = ev;  
  56.     if (ev->ev_events & EV_WRITE)  
  57.         evep->evwrite = ev;  
  58.   
  59.     return (0);  
  60. }  
static int
epoll_add(void *arg, struct event *ev)
{
	struct epollop *epollop = arg;
	struct epoll_event epev = {0, {0}};
	struct evepoll *evep;
	int fd, op, events;

    /*
     * 信号的原理
     * 1 设置信号处理函数,保存原来的信号处理函数到event的ev_base->sh_old中去
     * 2 如果是首次添加信号,那么需要为所有信号追加一个信号事件来源自event->ev_base->ev_signal
     *   同时设置event->ev_base->ev_signal->ev_signal_added,表示信号回调事件已经设置了
     * 3 同时把事件追加到event->ev_base->ev_signal->evsigevents[signno]链表中去
     */
	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 */
        //如果说当前的epoll中已经满足不了新加入的句柄
		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) {
		events |= EPOLLIN;
		op = EPOLL_CTL_MOD;
	}
    //如果事件之前是可写
	if (evep->evwrite != NULL) {
		events |= EPOLLOUT;
		op = EPOLL_CTL_MOD;
	}

    //新加入事件设置的是可读事件
	if (ev->ev_events & EV_READ)
		events |= EPOLLIN;
    //新加入事件设置的是可写事件
	if (ev->ev_events & EV_WRITE)
		events |= EPOLLOUT;

	epev.data.ptr = evep;
	epev.events = events;
	if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
			return (-1);

	/* Update events responsible */
	if (ev->ev_events & EV_READ)
		evep->evread = ev;
	if (ev->ev_events & EV_WRITE)
		evep->evwrite = ev;

	return (0);
}

信号追加,libevent对信号采用sockpair 创建两个互连socket,信号激发写可写sock,可读加入到事件循环中去
根据信号ev_base->sig.evsigcaught[signumber]来判断该信号是否发生,下面是信号追加函数

  1. int  
  2. evsignal_add(struct event *ev)  
  3. {  
  4.     int evsignal;  
  5.     struct event_base *base = ev->ev_base;          //信号event的base  
  6.     struct evsignal_info *sig = &ev->ev_base->sig;  //信号在ev_base的管理结构  
  7.   
  8.     if (ev->ev_events & (EV_READ|EV_WRITE))         //信号事件不支持可读可写事件  
  9.         event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);  
  10.     evsignal = EVENT_SIGNAL(ev);                    //信号的fd就是信号number  
  11.     assert(evsignal >= 0 && evsignal < NSIG);       //信号不能超过NSIG这个数  
  12.     if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) { //如果说该信号链表为空  
  13.         event_debug(("%s: %p: changing signal handler", __func__, ev));  
  14.         //设置信号处理函数,同时,保存原来的信号处理函数到ev_base->sh_old中去  
  15.         if (_evsignal_set_handler(  
  16.                 base, evsignal, evsignal_handler) == -1)  
  17.             return (-1);  
  18.   
  19.         /* catch signals if they happen quickly */  
  20.         evsignal_base = base;  
  21.   
  22.         if (!sig->ev_signal_added) {  
  23.             if (event_add(&sig->ev_signal, NULL))  
  24.                 return (-1);  
  25.             sig->ev_signal_added = 1;               //加入epoll_wait中去  
  26.         }  
  27.     }  
  28.   
  29.     //把ev->ev_signal_next加入到sig->evsigevents[evsignal]的链表末端  
  30.     /* multiple events may listen to the same signal */  
  31.     TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);  
  32.   
  33.     return (0);  
  34. }  
int
evsignal_add(struct event *ev)
{
	int evsignal;
	struct event_base *base = ev->ev_base;          //信号event的base
	struct evsignal_info *sig = &ev->ev_base->sig;  //信号在ev_base的管理结构

	if (ev->ev_events & (EV_READ|EV_WRITE))         //信号事件不支持可读可写事件
		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
	evsignal = EVENT_SIGNAL(ev);                    //信号的fd就是信号number
	assert(evsignal >= 0 && evsignal < NSIG);       //信号不能超过NSIG这个数
	if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) { //如果说该信号链表为空
		event_debug(("%s: %p: changing signal handler", __func__, ev));
        //设置信号处理函数,同时,保存原来的信号处理函数到ev_base->sh_old中去
		if (_evsignal_set_handler(
			    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))
				return (-1);
			sig->ev_signal_added = 1;               //加入epoll_wait中去
		}
	}

    //把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);
}

信号回调函数

  1. /* 
  2.  * 所有的信号都通用一个信号处理函数 
  3.  */  
  4. static void  
  5. evsignal_handler(int sig)  
  6. {  
  7.     int save_errno = errno;     //保存错误码  
  8.   
  9.     if (evsignal_base == NULL) {  
  10.         event_warn(  
  11.             "%s: received signal %d, but have no base configured",  
  12.             __func__, sig);  
  13.         return;  
  14.     }  
  15.   
  16.     evsignal_base->sig.evsigcaught[sig]++;  //引起的信号number++  
  17.     evsignal_base->sig.evsignal_caught = 1; //设置信号标志,表示信号已经触发  
  18.   
  19. #ifndef HAVE_SIGACTION  
  20.     signal(sig, evsignal_handler);  
  21. #endif  
  22.   
  23.     /* Wake up our notification mechanism */  
  24.     send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);  //通过写sockpair写数据来触发epoll_wait返回  
  25.     errno = save_errno;  
  26. }  
/*
 * 所有的信号都通用一个信号处理函数
 */
static void
evsignal_handler(int sig)
{
	int save_errno = errno;     //保存错误码

	if (evsignal_base == NULL) {
		event_warn(
			"%s: received signal %d, but have no base configured",
			__func__, sig);
		return;
	}

	evsignal_base->sig.evsigcaught[sig]++;  //引起的信号number++
	evsignal_base->sig.evsignal_caught = 1; //设置信号标志,表示信号已经触发

#ifndef HAVE_SIGACTION
	signal(sig, evsignal_handler);
#endif

	/* Wake up our notification mechanism */
	send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);  //通过写sockpair写数据来触发epoll_wait返回
	errno = save_errno;
}

定时事件采用最小堆,定时值+当前事件最为左后超时时间,加入到最小堆中去,主要在event_base_dispatch中使用

libeven 整个源码分析和sample都在我的 githup

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值