Libevent的事件驱动源码分析(一)

前言

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

正文

libevent 大致创建使用流程图

libevent 事件分发的流程图

一, event_base_new

event_base_new 设置io类型和 event通知类型

struct event_base *event_base_new(void)
{
	struct event_base *base = NULL;
	struct event_config *cfg = event_config_new();
	if (cfg) 
	{
		// 设置event的通知事件
		base = event_base_new_with_config(cfg);
		// 释放配置文件分配的内存
		event_config_free(cfg);
	}
	return base;
}


struct event_config *event_config_new(void)
{
	struct event_config *cfg = mm_calloc(1, sizeof(*cfg));

	if (cfg == NULL)
	{
		return (NULL);
	}

	TAILQ_INIT(&cfg->entries);

	return (cfg);
}



struct event_base *event_base_new_with_config(const struct event_config *cfg)
{
	int i;
	struct event_base *base;
	int should_check_environment;

#ifndef _EVENT_DISABLE_DEBUG_MODE
	event_debug_mode_too_late = 1;
	if (_event_debug_mode_on && !_event_debug_map_lock) 
	{
		EVTHREAD_ALLOC_LOCK(_event_debug_map_lock, 0);
	}
#endif

	if ((base = mm_calloc(1, sizeof(struct event_base))) == NULL) 
	{
		event_warn("%s: calloc", __func__);
		return NULL;
	}
	detect_monotonic();
	gettime(base, &base->event_tv);
	// 1. 设置反应堆为0
	min_heap_ctor(&base->timeheap);
	// 2. 设置队列中节点
	TAILQ_INIT(&base->eventqueue);
	// 3. 设置event的事件的本地通信 socket
	base->sig.ev_signal_pair[0] = -1;
	base->sig.ev_signal_pair[1] = -1;
	// 4. notify 通知事件
	base->th_notify_fd[0] = -1;
	base->th_notify_fd[1] = -1;
	
	// 5. 回调函数的初始化 
	event_deferred_cb_queue_init(&base->defer_queue);
	// 6. 设置事件通知回调函数
	base->defer_queue.notify_fn = notify_base_cbq_callback;
	base->defer_queue.notify_arg = base;
	if (cfg)
	{
		base->flags = cfg->flags;
	}
	// 7. 初始化 io 中map事件
	evmap_io_initmap(&base->io);
	// 8. 初始化 信号map
	evmap_signal_initmap(&base->sigmap);
	// 9. 初始化 链表中文件描述符初始化
	event_changelist_init(&base->changelist);

	base->evbase = NULL;

	should_check_environment =
	    !(cfg && (cfg->flags & EVENT_BASE_FLAG_IGNORE_ENV));
	// 10. eventops 是对 epoll, select, poll 和iocp等等封装  io的的初始化
	for (i = 0; eventops[i] && !base->evbase; i++) 
	{
		if (cfg != NULL) 
		{
			// 10.1 获取配置文件中io 类型 epoll, select, poll 和iocp
			/* determine if this backend should be avoided */
			if (event_config_is_avoided_method(cfg,
				eventops[i]->name))
			{
				continue;
			}
			// 10.2 获取配置文件中 设置io 的文件描述符的通知 使用边缘触发(LT)模式和水平触发(ET)模式 
			if ((eventops[i]->features & cfg->require_features)
				!= cfg->require_features) 
			{
				continue;
			}
		}

		/* also obey the environment variables */
		if (should_check_environment &&
			event_is_method_disabled(eventops[i]->name))
		{
			continue;
		}
		// 10.3 设置 io的类型 epoll , select
		base->evsel = eventops[i];
		// 10.4 初始化 io模式
		base->evbase = base->evsel->init(base);
	}

	if (base->evbase == NULL) 
	{
		event_warnx("%s: no event mechanism available",
		    __func__);
		event_base_free(base);
		return NULL;
	}

	if (evutil_getenv("EVENT_SHOW_METHOD"))
	{
		event_msgx("libevent using: %s", base->evsel->name);
	}

	/* allocate a single active event queue */
	if (event_base_priority_init(base, 1) < 0) 
	{
		event_base_free(base);
		return NULL;
	}

	/* prepare for threading */

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
	if (!cfg || !(cfg->flags & EVENT_BASE_FLAG_NOLOCK)) 
	{
		int r;
		EVTHREAD_ALLOC_LOCK(base->th_base_lock,
		    EVTHREAD_LOCKTYPE_RECURSIVE);
		base->defer_queue.lock = base->th_base_lock;
		EVTHREAD_ALLOC_COND(base->current_event_cond);
		// 11. 设置 本地 event通知事件
		r = evthread_make_base_notifiable(base);
		if (r<0) 
		{
			event_base_free(base);
			return NULL;
		}
	}
#endif

#ifdef WIN32
	if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
		event_base_start_iocp(base, cfg->n_cpus_hint);
#endif

	return (base);
}



int evthread_make_base_notifiable(struct event_base *base)
{
	void (*cb)(evutil_socket_t, short, void *) = evthread_notify_drain_default;
	int (*notify)(struct event_base *) = evthread_notify_base_default;

	/* XXXX grab the lock here? */
	if (!base)
	{
		return -1;
	}

	if (base->th_notify_fd[0] >= 0)
	{
		return 0;
	}

#if defined(_EVENT_HAVE_EVENTFD) && defined(_EVENT_HAVE_SYS_EVENTFD_H)
#ifndef EFD_CLOEXEC
#define EFD_CLOEXEC 0
#endif
	base->th_notify_fd[0] = eventfd(0, EFD_CLOEXEC);
	if (base->th_notify_fd[0] >= 0) 
	{
		evutil_make_socket_closeonexec(base->th_notify_fd[0]);
		notify = evthread_notify_base_eventfd;
		cb = evthread_notify_drain_eventfd;
	}
#endif
#if defined(_EVENT_HAVE_PIPE)
	if (base->th_notify_fd[0] < 0) 
	{
		if ((base->evsel->features & EV_FEATURE_FDS)) 
		{
			if (pipe(base->th_notify_fd) < 0) 
			{
				event_warn("%s: pipe", __func__);
			}
			else 
			{
				evutil_make_socket_closeonexec(base->th_notify_fd[0]);
				evutil_make_socket_closeonexec(base->th_notify_fd[1]);
			}
		}
	}
#endif

#ifdef WIN32
#define LOCAL_SOCKETPAIR_AF AF_INET
#else
#define LOCAL_SOCKETPAIR_AF AF_UNIX
#endif
	if (base->th_notify_fd[0] < 0) {
		if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0,
			base->th_notify_fd) == -1) {
			event_sock_warn(-1, "%s: socketpair", __func__);
			return (-1);
		} else {
			evutil_make_socket_closeonexec(base->th_notify_fd[0]);
			evutil_make_socket_closeonexec(base->th_notify_fd[1]);
		}
	}

	evutil_make_socket_nonblocking(base->th_notify_fd[0]);

	base->th_notify_fn = notify;

	/*
	  Making the second socket nonblocking is a bit subtle, given that we
	  ignore any EAGAIN returns when writing to it, and you don't usally
	  do that for a nonblocking socket. But if the kernel gives us EAGAIN,
	  then there's no need to add any more data to the buffer, since
	  the main thread is already either about to wake up and drain it,
	  or woken up and in the process of draining it.
	*/
	if (base->th_notify_fd[1] > 0)
	{
		evutil_make_socket_nonblocking(base->th_notify_fd[1]);
	}

	/* prepare an event that we can use for wakeup */
	event_assign(&base->th_notify, base, base->th_notify_fd[0],
				 EV_READ|EV_PERSIST, cb, base);

	/* we need to mark this as internal event */
	base->th_notify.ev_flags |= EVLIST_INTERNAL;
	event_priority_set(&base->th_notify, 0);

	return event_add(&base->th_notify, NULL);
}



2, 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);
}

/** 
* 赋值的操作得到 事件struct event
**/
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;
	}

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


3, event_add 添加事件到反应堆中

  1. 事件添加到io事件中
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);

	res = event_add_internal(ev, tv, 0);

	EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);

	return (res);
}



static inline int event_add_internal(struct event *ev, const struct timeval *tv,
    int tv_is_absolute)
{
	struct event_base *base = ev->ev_base;
	int res = 0;
	int notify = 0;

	EVENT_BASE_ASSERT_LOCKED(base);
	_event_debug_assert_is_setup(ev);

	event_debug((
		 "event_add: event: %p (fd %d), %s%s%scall %p",
		 ev,
		 (int)ev->ev_fd,
		 ev->ev_events & EV_READ ? "EV_READ " : " ",
		 ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
		 tv ? "EV_TIMEOUT " : " ",
		 ev->ev_callback));

	EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL));

	/*
	 * prepare for timeout insertion further below, if we get a
	 * failure on any step, we should not change any state.
	 */
	// 1. 添加计时器到哈希表中
	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 */
		}
	}

	/* If the main thread is currently executing a signal event's
	 * callback, and we are not the main thread, then we want to wait
	 * until the callback is done before we mess with the event, or else
	 * we can race on ev_ncalls and ev_pncalls below. */
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
	// 2. listen的描述符
	if (base->current_event == ev && (ev->ev_events & EV_SIGNAL)
	    && !EVBASE_IN_THREAD(base)) 
	{
		++base->current_event_waiters;
		EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock);
	}
#endif
	// 3. 根据read 或者write 事件 把文件描述符添加到io map集合中
	if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) 
	{
		if (ev->ev_events & (EV_READ | EV_WRITE))
		{
			res = evmap_io_add(base, ev->ev_fd, ev);
		}
		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;
		}
	}

	/*
	 * we should change the timeout state only if the previous event
	 * addition succeeded.
	 */
	if (res != -1 && tv != NULL)
	{
		struct timeval now;
		int common_timeout;

		/*
		 * for persistent timeout events, we remember the
		 * timeout value and re-add the event.
		 *
		 * If tv_is_absolute, this was already set.
		 */
		if (ev->ev_closure == EV_CLOSURE_PERSIST && !tv_is_absolute)
		{
			ev->ev_io_timeout = *tv;
		}

		/*
		 * we already reserved memory above for the case where we
		 * are not replacing an existing timeout.
		 */
		if (ev->ev_flags & EVLIST_TIMEOUT) 
		{
			/* XXX I believe this is needless. */
			if (min_heap_elt_is_top(ev))
			{
				notify = 1;
			}
			event_queue_remove(base, ev, EVLIST_TIMEOUT);
		}

		/* Check if it is active due to a timeout.  Rescheduling
		 * this timeout before the callback can be executed
		 * removes it from the active list. */
		if ((ev->ev_flags & EVLIST_ACTIVE) &&
		    (ev->ev_res & EV_TIMEOUT))
		{
			if (ev->ev_events & EV_SIGNAL) 
			{
				/* See if we are just active executing
				 * this event in a loop
				 */
				if (ev->ev_ncalls && ev->ev_pncalls) 
				{
					/* Abort loop */
					*ev->ev_pncalls = 0;
				}
			}

			event_queue_remove(base, ev, EVLIST_ACTIVE);
		}

		gettime(base, &now);

		common_timeout = is_common_timeout(tv, base);
		if (tv_is_absolute) 
		{
			ev->ev_timeout = *tv;
		}
		else if (common_timeout) 
		{
			struct timeval tmp = *tv;
			tmp.tv_usec &= MICROSECONDS_MASK;
			evutil_timeradd(&now, &tmp, &ev->ev_timeout);
			ev->ev_timeout.tv_usec |=
			    (tv->tv_usec & ~MICROSECONDS_MASK);
		}
		else 
		{
			evutil_timeradd(&now, tv, &ev->ev_timeout);
		}

		event_debug((
			 "event_add: timeout in %d seconds, call %p",
			 (int)tv->tv_sec, ev->ev_callback));

		event_queue_insert(base, ev, EVLIST_TIMEOUT);
		if (common_timeout) 
		{
			struct common_timeout_list *ctl =
			    get_common_timeout_list(base, &ev->ev_timeout);
			if (ev == TAILQ_FIRST(&ctl->events)) 
			{
				common_timeout_schedule(ctl, &now, ev);
			}
		}
		else 
		{
			/* See if the earliest timeout is now earlier than it
			 * was before: if so, we will need to tell the main
			 * thread to wake up earlier than it would
			 * otherwise. */
			if (min_heap_elt_is_top(ev))
			{
				notify = 1;
			}
		}
	}

	/* if we are not in the right thread, we need to wake up the loop */
	if (res != -1 && notify && EVBASE_NEED_NOTIFY(base))
	{
		// @@@ 这个回调 有点意思
		evthread_notify_base(base);
	}

	_event_debug_note_add(ev);

	return (res);
}

4, event_base_dispatch 事件分发

  1. io 事件反应
  2. 添加事件队列中
int event_base_dispatch(struct event_base *event_base)
{
	return (event_base_loop(event_base, 0));
}

int event_base_loop(struct event_base *base, int flags)
{
	const struct eventop *evsel = base->evsel;
	struct timeval tv;
	struct timeval *tv_p;
	int res, done, retval = 0;

	/* Grab the lock.  We will release it inside evsel.dispatch, and again
	 * as we invoke user callbacks. */
	EVBASE_ACQUIRE_LOCK(base, th_base_lock);

	if (base->running_loop) 
	{
		event_warnx("%s: reentrant invocation.  Only one event_base_loop"
		    " can run on each event_base at once.", __func__);
		EVBASE_RELEASE_LOCK(base, th_base_lock);
		return -1;
	}

	base->running_loop = 1;

	clear_time_cache(base);

	if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
	{
		evsig_set_base(base);
	}

	done = 0;

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
	base->th_owner_id = EVTHREAD_GET_ID();
#endif

	base->event_gotterm = base->event_break = 0;

	while (!done) 
	{
		/* Terminate the loop if we have been asked to */
		if (base->event_gotterm) 
		{
			break;
		}

		if (base->event_break) 
		{
			break;
		}

		timeout_correct(base, &tv);

		tv_p = &tv;
		if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) 
		{
			timeout_next(base, &tv_p);
		}
		else 
		{
			/*
			 * if we have active events, we just poll new events
			 * without waiting.
			 */
			evutil_timerclear(&tv);
		}

		/* If we have no events, we just exit */
		if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) 
		{
			event_debug(("%s: no events registered.", __func__));
			retval = 1;
			goto done;
		}

		/* update last old time */
		gettime(base, &base->event_tv);

		clear_time_cache(base);
		// epoll_wait active
		res = evsel->dispatch(base, tv_p);

		if (res == -1) 
		{
			event_debug(("%s: dispatch returned unsuccessfully.",
				__func__));
			retval = -1;
			goto done;
		}

		update_time_cache(base);
		// 处理 超时的文件描述符 删除io的事件 提交到事件中 给业务队列中
		timeout_process(base);

		if (N_ACTIVE_CALLBACKS(base))
		{
			// 处理队列中的事件
			int n = event_process_active(base);
			if ((flags & EVLOOP_ONCE)
				&& N_ACTIVE_CALLBACKS(base) == 0
				&& n != 0)
			{
				done = 1;
			}
		}
		else if (flags & EVLOOP_NONBLOCK)
		{
			done = 1;
		}
	}
	event_debug(("%s: asked to terminate loop.", __func__));

done:
	clear_time_cache(base);
	base->running_loop = 0;

	EVBASE_RELEASE_LOCK(base, th_base_lock);

	return (retval);
}

/* Activate every event whose timeout has elapsed. */
static void timeout_process(struct event_base *base)
{
	/* Caller must hold lock. */
	struct timeval now;
	struct event *ev;

	if (min_heap_empty(&base->timeheap)) 
	{
		return;
	}

	gettime(base, &now);

	while ((ev = min_heap_top(&base->timeheap))) 
	{
		if (evutil_timercmp(&ev->ev_timeout, &now, > ))
		{
			break;
		}

		/* delete this event from the I/O queues */
		event_del_internal(ev);

		event_debug(("timeout_process: call %p",
			 ev->ev_callback));
		event_active_nolock(ev, EV_TIMEOUT, 1);
	}
}


/*
 * Active events are stored in priority queues.  Lower priorities are always
 * process before higher priorities.  Low priority events can starve high
 * priority ones.
 */

static int event_process_active(struct event_base *base)
{
	/* Caller must hold th_base_lock */
	struct event_list *activeq = NULL;
	int i, c = 0;

	for (i = 0; i < base->nactivequeues; ++i) 
	{
		if (TAILQ_FIRST(&base->activequeues[i]) != NULL) 
		{
			activeq = &base->activequeues[i];
			c = event_process_active_single_queue(base, activeq);
			if (c < 0)
			{
				return -1;
			}
			else if (c > 0)
			{
				break; /* Processed a real event; do not
					   * consider lower-priority events */
					   /* If we get here, all of the events we processed
					   * were internal.  Continue. */
			}
		}
	}

	event_process_deferred_callbacks(&base->defer_queue,&base->event_break);
	return c;
}

/*
  Helper for event_process_active to process all the events in a single queue,
  releasing the lock as we go.  This function requires that the lock be held
  when it's invoked.  Returns -1 if we get a signal or an event_break that
  means we should stop processing any active events now.  Otherwise returns
  the number of non-internal events that we processed.
*/
static int event_process_active_single_queue(struct event_base *base,
    struct event_list *activeq)
{
	struct event *ev;
	int count = 0;

	EVUTIL_ASSERT(activeq != NULL);

	for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) 
	{
		if (ev->ev_events & EV_PERSIST)
		{
			event_queue_remove(base, ev, EVLIST_ACTIVE);
		}
		else
		{
			event_del_internal(ev);
		}
		if (!(ev->ev_flags & EVLIST_INTERNAL))
		{
			++count;
		}

		event_debug((
			 "event_process_active: event: %p, %s%scall %p",
			ev,
			ev->ev_res & EV_READ ? "EV_READ " : " ",
			ev->ev_res & EV_WRITE ? "EV_WRITE " : " ",
			ev->ev_callback));

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
		base->current_event = ev;
		base->current_event_waiters = 0;
#endif

		switch (ev->ev_closure) 
		{
		case EV_CLOSURE_SIGNAL:
			event_signal_closure(base, ev);
			break;
		case EV_CLOSURE_PERSIST:
			event_persist_closure(base, ev);
			break;
		default:
		case EV_CLOSURE_NONE:
			EVBASE_RELEASE_LOCK(base, th_base_lock);
			(*ev->ev_callback)(
				(int)ev->ev_fd, ev->ev_res, ev->ev_arg);  //  调用业务的回调函数 
			break;
		}

		EVBASE_ACQUIRE_LOCK(base, th_base_lock);
#ifndef _EVENT_DISABLE_THREAD_SUPPORT
		base->current_event = NULL;
		if (base->current_event_waiters)
		{
			base->current_event_waiters = 0;
			EVTHREAD_COND_BROADCAST(base->current_event_cond);
		}
#endif

		if (base->event_break)
		{
			return -1;
		}
	}
	return count;
}



5, event_base_free 是否event基类

void event_base_free(struct event_base *base)
{
	int i, n_deleted=0;
	struct event *ev;
	/* XXXX grab the lock? If there is contention when one thread frees
	 * the base, then the contending thread will be very sad soon. */

	if (base == NULL && current_base)
	{
		base = current_base;
	}
	if (base == current_base)
	{
		current_base = NULL;
	}

	/* XXX(niels) - check for internal events first */
	EVUTIL_ASSERT(base);

#ifdef WIN32
	event_base_stop_iocp(base);
#endif

	/* threading fds if we have them */
	if (base->th_notify_fd[0] != -1) 
	{
		event_del(&base->th_notify);
		EVUTIL_CLOSESOCKET(base->th_notify_fd[0]);
		if (base->th_notify_fd[1] != -1)
		{
			EVUTIL_CLOSESOCKET(base->th_notify_fd[1]);
		}
		base->th_notify_fd[0] = -1;
		base->th_notify_fd[1] = -1;
		event_debug_unassign(&base->th_notify);
	}

	/* Delete all non-internal events. */
	for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) 
	{
		struct event *next = TAILQ_NEXT(ev, ev_next);
		if (!(ev->ev_flags & EVLIST_INTERNAL)) 
		{
			event_del(ev);
			++n_deleted;
		}
		ev = next;
	}
	while ((ev = min_heap_top(&base->timeheap)) != NULL) 
	{
		event_del(ev);
		++n_deleted;
	}
	for (i = 0; i < base->n_common_timeouts; ++i) 
	{
		struct common_timeout_list *ctl =
		    base->common_timeout_queues[i];
		event_del(&ctl->timeout_event); /* Internal; doesn't count */
		event_debug_unassign(&ctl->timeout_event);
		for (ev = TAILQ_FIRST(&ctl->events); ev; ) 
		{
			struct event *next = TAILQ_NEXT(ev,
			    ev_timeout_pos.ev_next_with_common_timeout);
			if (!(ev->ev_flags & EVLIST_INTERNAL)) 
			{
				event_del(ev);
				++n_deleted;
			}
			ev = next;
		}
		mm_free(ctl);
	}
	if (base->common_timeout_queues)
	{
		mm_free(base->common_timeout_queues);
	}

	for (i = 0; i < base->nactivequeues; ++i) 
	{
		for (ev = TAILQ_FIRST(&base->activequeues[i]); ev; ) 
		{
			struct event *next = TAILQ_NEXT(ev, ev_active_next);
			if (!(ev->ev_flags & EVLIST_INTERNAL)) 
			{
				event_del(ev);
				++n_deleted;
			}
			ev = next;
		}
	}

	if (n_deleted)
	{
		event_debug(("%s: %d events were still set in base",
			__func__, n_deleted));
	}

	if (base->evsel != NULL && base->evsel->dealloc != NULL)
	{
		base->evsel->dealloc(base);
	}

	for (i = 0; i < base->nactivequeues; ++i)
	{
		EVUTIL_ASSERT(TAILQ_EMPTY(&base->activequeues[i]));
	}

	EVUTIL_ASSERT(min_heap_empty(&base->timeheap));
	min_heap_dtor(&base->timeheap);

	mm_free(base->activequeues);

	EVUTIL_ASSERT(TAILQ_EMPTY(&base->eventqueue));

	evmap_io_clear(&base->io);
	evmap_signal_clear(&base->sigmap);
	event_changelist_freemem(&base->changelist);

	EVTHREAD_FREE_LOCK(base->th_base_lock, EVTHREAD_LOCKTYPE_RECURSIVE);
	EVTHREAD_FREE_COND(base->current_event_cond);

	mm_free(base);
}


结语

个人博客地址

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
luotuo44是一个GitHub上的开源项目,其主要目的是分析libevent源码libevent是一个使用C语言编写的事件驱动库,可以用于开发高性能的网络服务器和客户端应用程序。 在分析libevent源码时,luotuo44首先研究了libevent的基本结构和使用方法。他深入研究了libevent的事件循环机制、事件触发方式以及事件回调函数的实现原理。通过仔细阅读源代码,他详细解释了libevent是如何利用系统底层的IO多路复用技术(如select、epoll等)来实现高效的事件处理。 此外,luotuo44还分析libevent的缓冲区管理和事件优先级处理机制。他对libevent的缓冲区数据结构和操作进行了详细解读,包括如何实现缓冲区的读写以及缓冲区事件的触发和处理。他还深入探讨了libevent的事件优先级机制,介绍了如何设置和管理不同优先级的事件,并解释了事件优先级对事件处理效率的影响。 除了基本功能外,luotuo44还分析libevent的线程安全性和性能优化策略。他详细讲解了libevent的线程安全机制,包括互斥锁、条件变量等,并提供了一些最佳实践指南,以确保多线程环境下的稳定性和性能。此外,他还分享了一些他自己的性能优化经验,包括使用合适的数据结构、避免频繁内存分配与释放等。 总的来说,luotuo44的libevent源码分析为那些想深入了解libevent内部原理和如何正确使用libevent的开发者提供了很大的帮助。通过他的分析,读者可以更好地理解libevent的工作原理,并从中学习到一些编程技巧和优化策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值