libevent源码学习(一)event事件
来源:互联网 发布:linux 禁用显卡 驱动 编辑:程序博客网 时间:2024/05/16 07:16
接触libevent断续有近一个月,准备开始系统学习源码,参考资料《libevent源码深度剖析》张亮
先看看事件结构体
#define TAILQ_ENTRY(type) \struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \}struct event { TAILQ_ENTRY (event) ev_next; TAILQ_ENTRY (event) ev_active_next; TAILQ_ENTRY (event) ev_signal_next; unsigned int min_heap_idx; /* for managing timeouts */ struct event_base *ev_base; int ev_fd; short ev_events; short ev_ncalls; short *ev_pncalls; /* Allows deletes in callback */ struct timeval ev_timeout; int ev_pri; /* smaller numbers are higher priority */ void (*ev_callback)(int, short, void *arg); void *ev_arg; int ev_res; /* result passed to event callback */ int ev_flags;};
看一下里面的成员:
1. 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 */
libevent通过struct event
这一个结构体,将IO事件,信号,超时事件统一管理
2. 事件链表
ev_next
、ev_active_next
、ev_signal_next
都是双向链表节点指针;它们是libevent对不同事件类型和在不同的时期,对事件管理时使用到的字段
3. 超时事件管理
min_heap_idx
和ev_timeoout
,如果是timeout事件
,则分别保存该超时事件在小根堆中的索引,和超时值。
4. ev_fd
对于IO事件,它绑定了一个文件描述符,对于signal事件,绑定的信号
5. ev_callback 事件回调
void (*ev_callback)(int fd,short events,void *arg)//fd对应ev_fd events对应ev_events arg对应ev_arg
事件设置的接口函数
通过event_new
为struct event
分配空间,并进行赋值
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);}
进而进入,event_assign
里面看看赋值:
intevent_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) { /* by default, we put new events into the middle priority */ ev->ev_pri = base->nactivequeues / 2; } _event_debug_note_setup(ev); return 0;}
libevent有一个全局的event_base
指针current_base
,默认情况下,event将被注册到这个默认的current_base
上,如果用户没有特别指定base
设置完成之后,调用event_add
来注册这个事件,来看看这个函数
intevent_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); res = event_add_internal(ev, tv, 0);//真正的add操作 EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock); return (res);}
event_add_internal
是一个比较复杂的函数:
首先,他会在小根堆中为超时事件预留一个hole
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 */ }
然后,针对I/O事件和信号,分别处理
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);//IO else if (ev->ev_events & EV_SIGNAL)//信号 res = evmap_signal_add(base, (int)ev->ev_fd, ev); if (res != -1) event_queue_insert(base, ev, EVLIST_INSERTED);//插入到队列中 if (res == 1) { /* evmap says we need to notify the main thread. */ notify = 1; res = 0; } }
最后,如果是超时事件,当事件插入完毕之后,需要将超时时间插入到之前预留的hole中去,代码略:
if (res != -1 && tv != NULL) { //... }
1 0
- libevent源码学习(一)event事件
- libevent事件(二)---event源码
- libevent源码学习-----event操作
- Libevent源码剖析——事件event
- 【libevent】源码学习(一)--开篇
- Libevent 编程- 定时器事件(timer event)
- libevent源码分析-event
- libevent高性能网络库源码分析——事件(event)及其接口(三)
- QT学习记录(一)事件 (event)
- libevent源码学习(二)事件循环event_base
- libevent源码深度剖析五 ——libevent的核心:事件event
- Libevent源码学习(二) 事件的概念
- libevent源码学习-----事件驱动流程分析
- libevent源码学习-----event_base事件循环
- libevent源码学习研究(libevent-0.1)
- libevent库源码学习-kqueue( freebsd) ,evport(Event ports)(Solaris 10)
- libevent库源码学习-evport(Event ports)(Solaris 10)
- Libevent源码分析(四)--- libevent事件机制
- VS2013 许可证
- 监听器接口(三)
- Spring AOP 实现原理----AspectJ与CGLIB介绍
- 有return的情况下try catch finally的执行顺序(最有说服力的总结)
- 比较分析 Spring AOP 和 AspectJ 之间的差别
- libevent源码学习(一)event事件
- Java中的字符串连接符(+)
- 字段串日期进行比较
- 【MapReduce Java】简单的平均距离计算
- Tomcat7用户配置
- 表单无法提交设为disabled的input
- spring之依赖注入之理解
- 请写一段 PHP 代码 ,确保多个进程同时写入同一个文件成功
- Sparse Graph HDU