libevent源码分析--event_init()函数

尝试着解释几个重要的函数,首先是event_inint()函数,这个函数式最初就需要使用的函数,此函数初始化了一个全局的变量current_base,也就是event_base,默认情况下所有的event都是在想这个变量中添加。

struct event_base *event_init(void)
  {
    struct event_base *base = event_base_new();

     if (base != NULL)
         current_base = base;
 
       return (base);
 }
函数体貌似很简单,也就是初始化了一个变量,current_base,这个是全局变量,这个函数也是提供给用户的接口函数,在应用程序中,可以使用它的返回值,也可以不用返回值,不用返回值的话,在以后的所有event变量都是天价到current_base变量中,有返回值的目的是应用程序中可以多次调用event_init()函数,也就是产生多个struct event_base,可以将不同的event添加到不同的evet_base中。这个函数中主要的是调用了event_base_new(),下面继续分析event_base_new()函数:

struct event_base *
 174 event_base_new(void)
 175 {   
 176     int i;
 177     struct event_base *base;
 178 
 179     if ((base = calloc(1, sizeof(struct event_base))) == NULL)
 180         event_err(1, "%s: calloc", __func__);
 181 
 182     event_sigcb = NULL;
 183     event_gotsig = 0;
 184 
 185     detect_monotonic();
 186     gettime(base, &base->event_tv);
 187     
 188     min_heap_ctor(&base->timeheap);
 189     TAILQ_INIT(&base->eventqueue);
 190     base->sig.ev_signal_pair[0] = -1;
 191     base->sig.ev_signal_pair[1] = -1;
 192     
 193     base->evbase = NULL;
 194     for (i = 0; eventops[i] && !base->evbase; i++) {
 195         
 196         base->evsel = eventops[i];
 197 
 198         base->evbase = base->evsel->init(base);
 199     }
 200 
 201     if (base->evbase == NULL)
 202         event_errx(1, "%s: no event mechanism available", __func__);
 203 
 204     if (getenv("EVENT_SHOW_METHOD"))
 205         event_msgx("libevent using: %s\n",
 206                base->evsel->name);
 207 
 208     /* allocate a single active event queue */
 209     event_base_priority_init(base, 1);
 210 
 211     return (base);
 212 }
这个函数很多中的很多处理都是为了为多次调用event_init()设计的,实现动态申请空间,(这里关于信号的一切都不多讲,在后面有专门的讲解),188行是小顶堆的初始化,189是事件队列的初始化(eventqueue是链表,保存了所有的注册事件event的指针,这个链表貌似是循环链表) 193~199选择合适的I/O复用机制,这个选择是系统在编译的时候已经设置好的,首先是给base->evbase设为空,然后查找eventops中不为空的选项,然后赋值,在以后只要evbase不为空,即使eventops不为空也不在修改evbase的值。这是因为eventop是有权限之分的。最后一部分呢:就是初始化base中的activequeues了: 同时还需要注意198行,这个是已经选择的I/O复用机制中所写的初始化函数,这里不介绍具体的内容,在稍后的更加详细的内容中介绍这个过程。

int
 321 event_base_priority_init(struct event_base *base, int npriorities)
 322 {
 323     int i;
 324 
 325     if (base->event_count_active)
 326         return (-1);
 327 
 328     if (base->nactivequeues && npriorities != base->nactivequeues) {
 329         for (i = 0; i < base->nactivequeues; ++i) {
 330             free(base->activequeues[i]);
 331         }
 332         free(base->activequeues);
 333     }
 334 
 335     /* Allocate our priority queues */
 336     base->nactivequeues = npriorities;
 337     base->activequeues = (struct event_list **)calloc(base->nactivequeues,
 338         npriorities * sizeof(struct event_list *));
 339     if (base->activequeues == NULL)
 340         event_err(1, "%s: calloc", __func__);
 341 
 342     for (i = 0; i < base->nactivequeues; ++i) {
 343         base->activequeues[i] = malloc(sizeof(struct event_list));
 344         if (base->activequeues[i] == NULL)
 345             event_err(1, "%s: malloc", __func__);
 346         TAILQ_INIT(base->activequeues[i]);
 347     }
 348 
 349     return (0);
 350 }

activequeues是一个二级指针,因为libevent支持事件优先级,可以把它看做是数组,其中的元素avtivequeues[priority]是一个链表,链表的每个节点指向一个优先级为priority的就绪事件event。

325行首先判断是够链表存在,如果存在就不再做一下的操作,event_count_active是事件活跃的数目,nactivequeues是队列的数目,其实这个数值就是优先级的数值,不如只用一个优先级,那么就只有一个队列,有三个优先级就必须初始化三个队列,但是avtivequeues永远都是只需要一个即可,328~333首先是释放原始的链表元素,是为了重新初始化新的链表初始化链表元素做准备。释放二级链表的时候的特色也需要注意。释放之后重新申请从336开始。

申请的队列个数就是优先级的个数,首先申请二级链表,然后再进行复制,每个元素都是以一个struct event_list,并且每申请好一个都需要做相应的初始化,也就是346行,函数体这么处理也是为了为应用程序重新修正优先级做准备,如果已经有被激活的事件,那么就不能再重新申请配置,如果尚且没有活跃事件,那么还可以继续调整优先级。一切从新开始,对外的接口函数可以是

int event_priority_init(int npriorities);这个函数体中只用一句话

int
 315 event_priority_init(int npriorities)
 316 {
 317   return event_base_priority_init(current_base, npriorities);
 318 }
关于event_init()函数已经基本结束,接下来是别的几个重要函数

你可能感兴趣的:(libevent)