libevent-signal

Posted 大老虎打老虎

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libevent-signal相关的知识,希望对你有一定的参考价值。

现在已经知道,libevent有三种事件类型,分别是时钟事件,信号事件,i/o事件。今天就分析一下信号事件,下面是一个简单的信号事件demo

#include <sys/types.h>

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
#else
#include <windows.h>
#endif
#include <signal.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event.h>

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++;
}

int
main (int argc, char **argv)
{
	struct event signal_int;

	/* Initalize the event library */
	struct event_base* base = event_base_new();

	/* Initalize one event */
	event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,
	    &signal_int);
	event_base_set(base, &signal_int);

	event_add(&signal_int, NULL);

	event_base_dispatch(base);
	event_base_free(base);

	return (0);
}

  从代码看,这里event_set第二个参数是一个中断类型的信号(ctrl+c可触发),第三个参数代表这是一个信号事件并长存

  event_add的代码如下

 

 1 int
 2 event_add(struct event *ev, const struct timeval *tv)
 3 {
 4     struct event_base *base = ev->ev_base;
 5     const struct eventop *evsel = base->evsel;
 6     void *evbase = base->evbase;
 7     int res = 0;
 8 
 9     event_debug((
10          "event_add: event: %p, %s%s%scall %p",
11          ev,
12          ev->ev_events & EV_READ ? "EV_READ " : " ",
13          ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
14          tv ? "EV_TIMEOUT " : " ",
15          ev->ev_callback));
16 
17     assert(!(ev->ev_flags & ~EVLIST_ALL));
18 
19     /*
20      * prepare for timeout insertion further below, if we get a
21      * failure on any step, we should not change any state.
22      */
23     if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) 
24     {
25         if (min_heap_reserve(&base->timeheap,
26             1 + min_heap_size(&base->timeheap)) == -1)
27             return (-1);  /* ENOMEM == errno */
28     }
29 
30     if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
31         !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
32         res = evsel->add(evbase, ev);
33         if (res != -1)
34             event_queue_insert(base, ev, EVLIST_INSERTED);
35     }
36 
37     /* 
38      * we should change the timout state only if the previous event
39      * addition succeeded.
40      */
41     if (res != -1 && tv != NULL) {
42         struct timeval now;
43 
44         /* 
45          * we already reserved memory above for the case where we
46          * are not replacing an exisiting timeout.
47          */
48         if (ev->ev_flags & EVLIST_TIMEOUT)
49             event_queue_remove(base, ev, EVLIST_TIMEOUT);
50 
51         /* Check if it is active due to a timeout.  Rescheduling
52          * this timeout before the callback can be executed
53          * removes it from the active list. */
54         if ((ev->ev_flags & EVLIST_ACTIVE) &&
55             (ev->ev_res & EV_TIMEOUT)) {
56             /* See if we are just active executing this
57              * event in a loop
58              */
59             if (ev->ev_ncalls && ev->ev_pncalls) {
60                 /* Abort loop */
61                 *ev->ev_pncalls = 0;
62             }
63             
64             event_queue_remove(base, ev, EVLIST_ACTIVE);
65         }
66 
67         gettime(base, &now);
68         evutil_timeradd(&now, tv, &ev->ev_timeout);
69 
70         event_debug((
71              "event_add: timeout in %ld seconds, call %p",
72              tv->tv_sec, ev->ev_callback));
73 
74         event_queue_insert(base, ev, EVLIST_TIMEOUT);
75     }
76 
77     return (res);
78 }

  第五行,代表的是当前系统所支持的后端模式,base->evsel和base->evbase先不要纠结,都是用在一个地方

  第23行关于最小堆的逻辑先跳过

  第30行,当事件ev不在已注册或者激活链表中,则调用evbase注册事件,这里的ev_events,ev_flags分别代表event关注的事件类型与当前的状态

ev_events有四种类型

  I/O事件: EV_WRITE和EV_READ
  定时事件:EV_TIMEOUT
  信号:    EV_SIGNAL
  辅助选项:EV_PERSIST,表明是一个永久事件

ev_flags有以下几种状态

#define EVLIST_TIMEOUT 0x01 // event在time堆中  
#define EVLIST_INSERTED 0x02 // event在已注册事件链表中  
#define EVLIST_SIGNAL 0x04 // 未见使用  
#define EVLIST_ACTIVE 0x08 // event在激活链表中  
#define EVLIST_INTERNAL 0x10 // 内部使用标记  
#define EVLIST_INIT     0x80 // event已被初始化  

  重点分析一下res = evsel->add(evbase, ev);我所在为win32平台,实际调用的是int win32_insert(void *op, struct event *ev)

 1 int
 2 win32_insert(void *op, struct event *ev)
 3 {
 4     struct win32op *win32op = op;
 5     struct event_entry *ent;
 6 
 7     if (ev->ev_events & EV_SIGNAL) {
 8         if (win32op->signals_are_broken)
 9             return (-1);
10         return (evsignal_add(ev));
11     }
12     if (!(ev->ev_events & (EV_READ|EV_WRITE)))
13         return (0);
14     ent = get_event_entry(win32op, ev->ev_fd, 1);
15     if (!ent)
16         return (-1); /* out of memory */
17 
18     event_debug(("%s: adding event for %d", __func__, (int)ev->ev_fd));
19     if (ev->ev_events & EV_READ) {
20         if (do_fd_set(win32op, ent, 1)<0)
21             return (-1);
22         ent->read_event = ev;
23     }
24     if (ev->ev_events & EV_WRITE) {
25         if (do_fd_set(win32op, ent, 0)<0)
26             return (-1);
27         ent->write_event = ev;
28     }
29     return (0);
30 }

今天先看到这,接下来看调用win32_init() 内部初始化了socket_pair,win32_dispatch(),内部调用了select

以上是关于libevent-signal的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段——CSS选择器

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

VSCode自定义代码片段——.vue文件的模板

VSCode自定义代码片段6——CSS选择器

VSCode自定义代码片段——声明函数