libevent源码分析(8)--2.1.8--事件申请与释放

一、event_new

主要用来创建事件结构体,根据监听事件类型,文件描述符,以及回调函数,回调函数参数等创建,可以看成是事件的初始化过程,主要是设定事件的初始状态,此时事件结构体刚刚创建出来还没有添加到event_base的激活或者等待列表中,是孤立存在的,需要调用event_add函数将此事件添加到event_base中。

/**
  Allocate and asssign a new event structure, ready to be added.
  The function event_new() returns a new event that can be used in
  future calls to event_add() and event_del().  The fd and events
  arguments determine which conditions will trigger the event; the
  callback and callback_arg arguments tell Libevent what to do when the
  event becomes active.

  If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then
  fd is a file descriptor or socket that should get monitored for
  readiness to read, readiness to write, or readiness for either operation
  (respectively).  If events contains EV_SIGNAL, then fd is a signal
  number to wait for.  If events contains none of those flags, then the
  event can be triggered only by a timeout or by manual activation with
  event_active(): In this case, fd must be -1.

  The EV_PERSIST flag can also be passed in the events argument: it makes
  event_add() persistent until event_del() is called.
  The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported
  only by certain backends.  It tells Libevent to use edge-triggered
  events.
  The EV_TIMEOUT flag has no effect here.
  It is okay to have multiple events all listening on the same fds; but
  they must either all be edge-triggered, or all not be edge triggerd.
  When the event becomes active, the event loop will run the provided
  callbuck function, with three arguments.  The first will be the provided
  fd value.  The second will be a bitfield of the events that triggered:
  EV_READ, EV_WRITE, or EV_SIGNAL.  Here the EV_TIMEOUT flag indicates
  that a timeout occurred, and EV_ET indicates that an edge-triggered
  event occurred.  The third event will be the callback_arg pointer that
  you provide.

  @param base the event base to which the event should be attached.
  @param fd the file descriptor or signal to be monitored, or -1.
  @param events desired events to monitor: bitfield of EV_READ, EV_WRITE,
      EV_SIGNAL, EV_PERSIST, EV_ET.
  @param callback callback function to be invoked when the event occurs
  @param callback_arg an argument to be passed to the callback function
  @return a newly allocated struct event that must later be freed with
    event_free().
  @see event_free(), event_add(), event_del(), event_assign()
 */
// 分配新的event结构,并准备好添加。函数event_new返回新的事件,可以用在
// event_add和event_del函数中。fd和events参数决定了什么条件可以触发这个事件;
// 回调函数和回调函数参数告诉libevent当event激活时需要做什么。
// 如果events包括EV_READ,EV_WRITE,EV_READ|EV_WRITE之一,那么fd是文件描述符或者socket,
// 这两个都是可以在读、写条件下被监控的。如果events包含EV_SIGNAL,那么fd是等待的信号值。
// 如果events不包含上述任何一种,那么事件是定时事件或者通过event_active进行人工触发:如果是
// 这种情况,fd必需是-1。
// EV_PERSIST可以通过events参数传递:它使得event_add永久生效,直到event_del调用;
// EV_ET与EV_READ以及EV_WRITE是兼容的,并且只能被部分后台方法支持。它告诉libevent使用边沿触发事件;
// EV_TIMEOUT此处没有影响;
// 在同一个fd上监听多个events是合法的;但是它们必需都是边沿触发,或者都不是边沿触发。
// 当事件激活时,event loop将运行提供的回调函数,就使用这三个参数:第一个就是提供的fd;
// 第二个是触发的events,EV_READ,EV_WRITE,EV_SIGNAL,EV_TIMEOUT表示超时事件发生,EV_ET
// 表示边沿触发事件发生;第三个参数是提供的callback_arg指针。
// base:需要绑定的base
// fd:需要监听的文件描述符或者信号,或者为-1,如果为-1则是定时事件
// events:事件类型,信号事件和IO事件不能同时存在
// callback:回调函数,信号发生或者IO事件或者定时事件发生时
// callback_arg:传递给回调函数的参数,一般是base
// 返回值:是指事件结构体,必须由event_free释放
// 相关查看event_free,event_add,event_del,event_assign
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
准备将新创建的event添加到event_base中,注意,这里的添加到event_base中只是将事件和event_base关联起来,并不是加入到event_base的激活队列或者等待队列中。

/**
  Prepare a new, already-allocated event structure to be added.
  The function event_assign() prepares the event structure ev to be used
  in future calls to event_add() and event_del().  Unlike event_new(), it
  doesn't allocate memory itself: it requires that you have already
  allocated a struct event, probably on the heap.  Doing this will
  typically make your code depend on the size of the event structure, and
  thereby create incompatibility with future versions of Libevent.
  The easiest way to avoid this problem is just to use event_new() and
  event_free() instead.
  A slightly harder way to future-proof your code is to use
  event_get_struct_event_size() to determine the required size of an event
  at runtime.
  Note that it is NOT safe to call this function on an event that is
  active or pending.  Doing so WILL corrupt internal data structures in
  Libevent, and lead to strange, hard-to-diagnose bugs.  You _can_ use
  event_assign to change an existing event, but only if it is not active
  or pending!
  The arguments for this function, and the behavior of the events that it
  makes, are as for event_new().
  @param ev an event struct to be modified
  @param base the event base to which ev should be attached.
  @param fd the file descriptor to be monitored
  @param events desired events to monitor; can be EV_READ and/or EV_WRITE
  @param callback callback function to be invoked when the event occurs
  @param callback_arg an argument to be passed to the callback function
  @return 0 if success, or -1 on invalid arguments.
  @see event_new(), event_add(), event_del(), event_base_once(),
    event_get_struct_event_size()
  */
// 准备新的已经分配的事件结构体以添加到event_base中;
// 函数event_assign准备事件结构体ev,以备将来event_add和event_del调用。
// 不像event_new,他没有自己分配内存:他需要你已经分配了一个事件结构体,应该是在堆上分配的;
// 这样做一般会让你的代码依赖于事件结构体的尺寸,并且会造成与未来版本不兼容。
// 避免自己分配出现问题的最简单的办法是使用event_new和event_free来申请和释放。
// 让代码未来兼容的稍微困难的方式是使用event_get_struct_event_size来确定运行时事件的尺寸。
// 注意,如果事件处于激活或者未决状态,调用这个函数是不安全的。这样会破坏libevent内部数据结构,
// 导致一些奇怪的,难以调查的问题。你只能使用event_assign来改变一个存在的事件,但是事件状态不能
// 是激活或者未决的。
// ev:需要修正的事件结构体
// base: 将ev添加到的event_base
// fd: 需要监控的文件描述符
// events: 需要监控的事件类型;可以是EV_READ或者EV_WRITE
// callback:当事件发生时的回调函数
// callback_arg: 传递给回调函数的参数,一般是event_base句柄
// 如果成功则返回0,如果失败则返回-1
// 相关查看 event_new,event_add,event_del,event_base_once,event_get_struct_event_size

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)
{
    if (!base)
        base = current_base;
    if (arg == &event_self_cbarg_ptr_)
        arg = ev;

    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) {
          // 信号事件与IO事件不能同时存在
        if ((events & (EV_READ|EV_WRITE|EV_CLOSED)) != 0) {
            event_warnx("%s: EV_SIGNAL is not compatible with "
                "EV_READ, EV_WRITE or EV_CLOSED", __func__);
            return -1;
        }
          // 设置事件关闭时执行回调函数的类型:evcb_callback
        ev->ev_closure = EV_CLOSURE_EVENT_SIGNAL;
    } else {
     // 如果是其它类型的事件:IO事件、定时事件

          // 如果事件是永久事件,即每次调用之后不会移除出事件列表
          // 清空IO超时控制,并设置事件关闭时回调函数类型:evcb_callback
        if (events & EV_PERSIST) {
            evutil_timerclear(&ev->ev_io_timeout);
            ev->ev_closure = EV_CLOSURE_EVENT_PERSIST;
        } else {
               // 设置事件回调函数类型:evcb_callback
            ev->ev_closure = EV_CLOSURE_EVENT;
        }
    }

     // 事件超时控制最小堆初始化
    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;
}


三、event_free

释放由event_new申请的事件,可以看出源码中是调用事件删除函数event_del将事件从event_base中删除,然后调用内部空间释放函数mm_free释放事件结构体的空间。

/**
   Deallocate a struct event * returned by event_new().
   If the event is pending or active, first make it non-pending and
   non-active.
 */
// 释放event_new创建的事件结构体;如果事件正处于未决或者激活状态,首先需要将事件
// 变为非未决或者非活跃状态
void
event_free(struct event *ev)
{
    /* This is disabled, so that events which have been finalized be a
     * valid target for event_free(). That's */
    // event_debug_assert_is_setup_(ev);

    /* make sure that this event won't be coming back to haunt us. */
     // 调用实际执行函数
    event_del(ev);
    event_debug_note_teardown_(ev);
    mm_free(ev);

}





你可能感兴趣的:(libevent,libevent)