libevent源码分析(一)-event事件

在使用时,我们知道了libevent的几个模块。这篇来讲event。

event结构体

#define TAILQ_ENTRY(type)
struct {
    struct type *tqe_next;
    struct type **tqe_prev;//双向链表
}

struct event {
    TAILQ_ENTRY (event) ev_next;//下一个事件
    TAILQ_ENTRY (event) ev_active_next;//下一个活动事件
    TAILQ_ENTRY (event) ev_signal_next;//下一个信号
    unsigned int min_heap_idx;//最小堆

    struct event_base *ev_base;//下一章讲

    int ev_fd;//描述符或信号
    short ev_events;//事件类型
    short ev_ncalls;//事件就绪后回调函数调用次数,一般为1
    short *ev_pncalls;//指向ncall或null

    struct timeval ev_timeout;//保存超时时间

    int ev_pri;//数越小优先级越高

    void (*ev_callback)(int, short, void *arg);//回调函数
    void *ev_arg;//上面的void参数,设置时指定

    int ev_res;//激活事件类型
    int ev_flags;//event信息
};

下面分块阐述event结构体:

  1. 首先是事件链表,ev_next,ev_active_next,ev_signal_next,都是双向链表的节点指针,是事件管理的索引。
    在这里插入图片描述
  2. min_heap_idx和timeout:进行超时事件管理,保存的是超时事件在小根堆的索引和超时值。
  3. ev_fd:对于IO事件绑定文件描述符,对于signal保存信号。
  4. short ev_events:event关注的事件类型:
//超时事件
#define EV_TIMEOUT  0x01
//io事件
#define EV_READ     0x02
#define EV_WRITE    0x04
//信号
#define EV_SIGNAL   0x08
//辅助选项
#define EV_PERSIST  0x10    /* Persistant event */
  1. ev_callback:事件回调,fd对应ev_fd,short对应events,arg对应ev_arg。
  2. ev_flag:
	#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已被初始化         

event_new()

struct event *
event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
{
    struct event *ev;
    ev = mm_malloc(sizeof(struct event));//分配空间
    if (ev == NULL)
        return (NULL);
    if (event_assign(ev, base, fd, events, cb, arg) < 0) {
        mm_free(ev);//分配失败释放内存
        return (NULL);
    }
    return (ev);
}

base结构体下一章再讲。我们继续来看event的接口函数,怎么来为event提供new接口。
首先是定义结构体,然后为他分配内存。分配失败就释放内存,成功就返回这个结构体指针。
里面的event_assign():

int event_assign(struct event *ev, struct event_base *base, evutil_socket_t fd, short events, void (*callback)(evutil_socket_t, short, void *), void *arg)
{
//设置event_base
    if (!base)
        base = current_base;//默认注册位置

    _event_debug_assert_not_added(ev);

    //参数分配
    ev->ev_base = base;
    ev->ev_callback = callback;
    ev->ev_arg = arg;
    ev->ev_fd = fd;
    ev->ev_events = events;
    ev->ev_res = 0;
    ev->ev_flags = EVLIST_INIT;
    ev->ev_ncalls = 0;
    ev->ev_pncalls = NULL;

    if (events & EV_SIGNAL) {//信号事件
        if ((events & (EV_READ|EV_WRITE)) != 0) {
            event_warnx("%s: EV_SIGNAL is not compatible with "
                "EV_READ or EV_WRITE", __func__);
            return -1;
        }
        ev->ev_closure = EV_CLOSURE_SIGNAL;
    } else {
        if (events & EV_PERSIST) {
            evutil_timerclear(&ev->ev_io_timeout);
            ev->ev_closure = EV_CLOSURE_PERSIST;
        } else {
            ev->ev_closure = EV_CLOSURE_NONE;
        }
    }

    //初始化小根堆
    min_heap_elem_init(ev);

    if (base != NULL) {
        ev->ev_pri = base->nactivequeues / 2;//优先级默认为中等
    }

    _event_debug_note_setup(ev);

    return 0;
}

这个函数就是个分配参数的过程,event设置好后,就是注册

event_add()

int event_add(struct event *ev, const struct timeval *tv)
{
    int res;

    if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
        event_warnx("%s: event has no event_base set.", __func__);
        return -1;
    }

    EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);//lock

    res = event_add_internal(ev, tv, 0);//add

    EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);//unlock

    return (res);
}

里面又真正的add函数:event_add_internal();
这其实就是对事件和时间的处理:

if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
	//最小堆size+1,为超时事件留空
    if (min_heap_reserve(&base->timeheap,1 + min_heap_size(&base->timeheap)) == -1)
        return (-1); //分配失败返回errno
    }
    //处理事件
    if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&//IO或者信号
        !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
        if (ev->ev_events & (EV_READ|EV_WRITE))
            res = evmap_io_add(base, ev->ev_fd, ev);//添加到IOmap
        else if (ev->ev_events & EV_SIGNAL)
            res = evmap_signal_add(base, (int)ev->ev_fd, ev);//添加到信号map
        if (res != -1)
            event_queue_insert(base, ev, EVLIST_INSERTED);//插入到队列中
        if (res == 1) {
            notify = 1;//通知主线程
            res = 0;
        }
    }
    //超时的话就插入预留的空位
    	if (res != -1 && tv != NULL) {
		struct timeval now;
		// EVLIST_TIMEOUT表明event已经在定时器堆中了,删除旧的
		if (ev->ev_flags & EVLIST_TIMEOUT)
			event_queue_remove(base, ev, EVLIST_TIMEOUT);
		// 如果事件已经是就绪状态则从激活链表中删除
		if ((ev->ev_flags & EVLIST_ACTIVE) &&
			(ev->ev_res & EV_TIMEOUT)) {
				// 将ev_callback调用次数设置为0
				if (ev->ev_ncalls && ev->ev_pncalls) {
					*ev->ev_pncalls = 0;
				}
				event_queue_remove(base, ev, EVLIST_ACTIVE);
		}
		// 计算时间,并插入到timer小根堆中
		gettime(base, &now);
		evutil_timeradd(&now, tv, &ev->ev_timeout);
		event_queue_insert(base, ev, EVLIST_TIMEOUT);
	}
	return (res);

event_queue_insert():

 
void event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
	// ev可能已经在激活列表中了,避免重复插入
	if (ev->ev_flags & queue) {
		if (queue & EVLIST_ACTIVE)
			return;
	}
	// ...
	ev->ev_flags |= queue; // 记录queue标记
	switch (queue) {
	case EVLIST_INSERTED: // I/O或Signal事件,加入已注册事件链表
		TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
		break;
	case EVLIST_ACTIVE: // 就绪事件,加入激活链表
		base->event_count_active++;
		TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], ev, ev_active_next);
		break;
	case EVLIST_TIMEOUT: // 定时事件,加入堆
		min_heap_push(&base->timeheap, ev);
		break;
	}
}

这也不是event的全部源码,只是源码的搭建框架,后续用到的会讲。event是libevent的重要模块,关于优先级什么的,可以自己看源码,比较简单。
参考:
libevent源码深度剖析——张亮

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值