4、libevent队列分析

struct event_base {
	/* evsel和evbase这两个字段你可以把evsel和evbase看作是类和静态函数的关系,
	比如添加事件时的调用行为:evsel->add(evbase, ev),实际执行操作的是evbase;
	这相当于class::add(instance, ev),instance就是class的一个对象实例。
	evsel指向了全局变量static const struct eventop *eventops[]中的一个;
	libevent将系统提供的I/O demultiplex机制统一封装成了eventop结构;
	因此eventops[]包含了select、poll、kequeue和epoll等其中的若干个全局实例对象。
	evbase实际上是一个eventop实例对象;先来看看eventop结构体,
	它的成员是一系列的函数指针, 在event-internal.h文件中:
	struct eventop {
		const char *name;
		void *(*init)(struct event_base *); // 初始化
		int (*add)(void *, struct event *); // 注册事件
		int (*del)(void *, struct event *); // 删除事件
		int (*dispatch)(struct event_base *, void *, struct timeval *); // 事件分发
		void (*dealloc)(struct event_base *, void *); // 注销,释放资源 
		int need_reinit;// set if we need to reinitialize the event base 
	};
	也就是说,在libevent中,每种I/O demultiplex机制的实现都必须提供这五个函数接口,
	来完成自身的初始化、销毁释放;对事件的注册、注销和分发。
	比如对于epoll,libevent实现了5个对应的接口函数,并在初始化时并将eventop的5个函数指针指向这5个函数,
	那么程序就可以使用epoll作为I/O demultiplex机制了 */
	const struct eventop *evsel;
	/** Pointer to backend-specific data. */
	void *evbase;

	/** List of changes to tell backend about at next dispatch.  Only used
	 * by the O(1) backends. */
	struct event_changelist changelist;

	/** Function pointers used to describe the backend that this event_base
	 * uses for signals */
	const struct eventop *evsigsel;
	/** Data to implement the common signal handelr code. */
	struct evsig_info sig;

	/** Number of virtual events */
	int virtual_event_count;
	/** Number of total events added to this event_base */
	int event_count;
	/** Number of total events active in this event_base */
	int event_count_active;

	/** Set if we should terminate the loop once we're done processing
	 * events. */
	int event_gotterm;//处理完当前所有的事件之后退出
	/** Set if we should terminate the loop immediately */
	int event_break;//立即退出
	/** Set if we should start a new instance of the loop immediately. */
	int event_continue;//立即启动一个新的事件循环

	/** The currently running priority of events */
	int event_running_priority;//当前运行事件的优先级

	/** Set if we're running the event_base_loop function, to prevent
	 * reentrant invocation. */
	int running_loop;//是否正在进行事件循环

	/* Active event management. */
	/** An array of nactivequeues queues for active events (ones that
	 * have triggered, and whose callbacks need to be called).  Low
	 * priority numbers are more important, and stall higher ones.
	 */
	struct event_list *activequeues;//活跃事件的链表
	/** The length of the activequeues array */
	int nactivequeues;//活跃事件的个数

	/* common timeout logic */

	/** An array of common_timeout_list* for all of the common timeout
	 * values we know. */
	struct common_timeout_list **common_timeout_queues;
	/** The number of entries used in common_timeout_queues */
	int n_common_timeouts;
	/** The total size of common_timeout_queues. */
	int n_common_timeouts_allocated;

	/** List of defered_cb that are active.  We run these after the active
	 * events. */
	struct deferred_cb_queue defer_queue;

	/** Mapping from file descriptors to enabled (added) events */
	struct event_io_map io;

	/** Mapping from signal numbers to enabled (added) events. */
	struct event_signal_map sigmap;

	/** All events that have been enabled (added) in this event_base */
	struct event_list eventqueue;

	/** Stored timeval; used to detect when time is running backwards. */
	struct timeval event_tv;

	/** Priority queue of events with timeouts. */
	struct min_heap timeheap;

	/** Stored timeval: used to avoid calling gettimeofday/clock_gettime
	 * too often. */
	struct timeval tv_cache;

#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
	/** Difference between internal time (maybe from clock_gettime) and
	 * gettimeofday. */
	struct timeval tv_clock_diff;
	/** Second in which we last updated tv_clock_diff, in monotonic time. */
	time_t last_updated_clock_diff;
#endif

#ifndef _EVENT_DISABLE_THREAD_SUPPORT
	/* threading support */
	/** The thread currently running the event_loop for this base */
	unsigned long th_owner_id;
	/** A lock to prevent conflicting accesses to this event_base */
	void *th_base_lock;
	/** The event whose callback is executing right now */
	struct event *current_event;
	/** A condition that gets signalled when we're done processing an
	 * event with waiters on it. */
	void *current_event_cond;
	/** Number of threads blocking on current_event_cond. */
	int current_event_waiters;
#endif

#ifdef WIN32
	/** IOCP support structure, if IOCP is enabled. */
	struct event_iocp_port *iocp;
#endif

	/** Flags that this base was configured with */
	enum event_base_config_flag flags;

	/* Notify main thread to wake up break, etc. */
	/** True if the base already has a pending notify, and we don't need
	 * to add any more. */
	int is_notify_pending;
	/** A socketpair used by some th_notify functions to wake up the main
	 * thread. */
	evutil_socket_t th_notify_fd[2];//用于线程通信的pair
	/** An event used by some th_notify functions to wake up the main
	 * thread. */
	struct event th_notify;
	/** A function used to wake up the main thread from another thread. */
	int (*th_notify_fn)(struct event_base *base);
};

(1)libevent的队列结构体:

#define TAILQ_HEAD(name, type)						\
struct name {								\
    struct type *tqh_first;	/* first element */			\
    struct type **tqh_last;	/* addr of last next element */		\
}
 
//和前面的TAILQ_HEAD不同,这里的结构体并没有name.即没有结构体名。
//所以该结构体只能作为一个匿名结构体。所以,它一般都是另外一个结构体或者共用体的成员
#define TAILQ_ENTRY(type)						\
struct {								\
    struct type *tqe_next;	/* next element */			\
    struct type **tqe_prev;	/* address of previous next element */	\
}

由这两个结构体构造出来的队列如下图所示:
4、libevent队列分析_第1张图片
在这里插入图片描述
(2)队列操作宏

#define	TAILQ_FIRST(head)		((head)->tqh_first)
 
#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
 
#define	TAILQ_INIT(head) do {						\
    (head)->tqh_first = NULL;					\
    (head)->tqh_last = &(head)->tqh_first;				\
} while (0)
 
#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.tqe_next = NULL;					\
    (elm)->field.tqe_prev = (head)->tqh_last;			\
    *(head)->tqh_last = (elm);					\
    (head)->tqh_last = &(elm)->field.tqe_next;			\
} while (0)
 
#define TAILQ_REMOVE(head, elm, field) do {				\
    if (((elm)->field.tqe_next) != NULL)				\
        (elm)->field.tqe_next->field.tqe_prev =			\
            (elm)->field.tqe_prev;				\
    else								\
        (head)->tqh_last = (elm)->field.tqe_prev;		\
    *(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
} while (0)

案例:

#include  


#define TAILQ_HEAD(name, type)						\
struct name {								\
    struct type *tqh_first;	/* first element */			\
    struct type **tqh_last;	/* addr of last next element */		\
}
 
//和前面的TAILQ_HEAD不同,这里的结构体并没有name.即没有结构体名。
//所以该结构体只能作为一个匿名结构体。所以,它一般都是另外一个结构体
//或者共用体的成员
#define TAILQ_ENTRY(type)						\
struct {								\
    struct type *tqe_next;	/* next element */			\
    struct type **tqe_prev;	/* address of previous next element */	\
}


#define	TAILQ_FIRST(head)		((head)->tqh_first)
#define	TAILQ_END(head)			NULL
#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname)					\
	(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field)				\
	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define	TAILQ_EMPTY(head)						\
	(TAILQ_FIRST(head) == TAILQ_END(head))

#define TAILQ_FOREACH(var, head, field)					\
	for((var) = TAILQ_FIRST(head);					\
	    (var) != TAILQ_END(head);					\
	    (var) = TAILQ_NEXT(var, field))

#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
	for((var) = TAILQ_LAST(head, headname);				\
	    (var) != TAILQ_END(head);					\
	    (var) = TAILQ_PREV(var, headname, field))
 
#define	TAILQ_INIT(head) do {						\
	(head)->tqh_first = NULL;					\
	(head)->tqh_last = &(head)->tqh_first;				\
} while (0)

#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
	if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
		(head)->tqh_first->field.tqe_prev =			\
		    &(elm)->field.tqe_next;				\
	else								\
		(head)->tqh_last = &(elm)->field.tqe_next;		\
	(head)->tqh_first = (elm);					\
	(elm)->field.tqe_prev = &(head)->tqh_first;			\
} while (0)

#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
	(elm)->field.tqe_next = NULL;					\
	(elm)->field.tqe_prev = (head)->tqh_last;			\
	*(head)->tqh_last = (elm);					\
	(head)->tqh_last = &(elm)->field.tqe_next;			\
} while (0)

#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
	if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
		(elm)->field.tqe_next->field.tqe_prev =			\
		    &(elm)->field.tqe_next;				\
	else								\
		(head)->tqh_last = &(elm)->field.tqe_next;		\
	(listelm)->field.tqe_next = (elm);				\
	(elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
} while (0)

#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
	(elm)->field.tqe_next = (listelm);				\
	*(listelm)->field.tqe_prev = (elm);				\
	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
} while (0)

#define TAILQ_REMOVE(head, elm, field) do {				\
	if (((elm)->field.tqe_next) != NULL)				\
		(elm)->field.tqe_next->field.tqe_prev =			\
		    (elm)->field.tqe_prev;				\
	else								\
		(head)->tqh_last = (elm)->field.tqe_prev;		\
	*(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
} while (0)

#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
	if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
		(elm2)->field.tqe_next->field.tqe_prev =		\
		    &(elm2)->field.tqe_next;				\
	else								\
		(head)->tqh_last = &(elm2)->field.tqe_next;		\
	(elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
	*(elm2)->field.tqe_prev = (elm2);				\
} while (0)


//队列中的元素结构体。它有一个值,并且有前向指针和后向指针
//通过前后向指针,把队列中的节点(元素)连接起来
struct queue_entry_t
{
    int value;
 
    //从TAILQ_ENTRY的定义可知,它只能是结构体或者共用体的成员变量
    TAILQ_ENTRY(queue_entry_t)entry;
};
 
//定义一个结构体,结构体名为queue_head_t,成员变量类型为queue_entry_t
//就像有头节点的链表那样,这个是队列头。它有两个指针,分别指向队列的头和尾
TAILQ_HEAD(queue_head_t, queue_entry_t);
 
int main(int argc, char **argv)
{
    struct queue_head_t queue_head;
    struct queue_entry_t *q, *p, *s, *new_item;
    int i;
 
    TAILQ_INIT(&queue_head);
 
    for(i = 0; i < 3; ++i)
    {
        p = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
        p->value = i;
 
        TAILQ_INSERT_TAIL(&queue_head, p, entry);//在队尾插入数据
    }
 
    q = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    q->value = 10;
    TAILQ_INSERT_HEAD(&queue_head, q, entry);//在队头插入数据
 
    //现在q指向队头元素、p指向队尾元素

    s = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    s->value = 20;
    //在队头元素q的后面插入元素
    TAILQ_INSERT_AFTER(&queue_head, q, s, entry);
 
 
    s = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    s->value = 30;
    //在队尾元素p的前面插入元素
    TAILQ_INSERT_BEFORE(p, s, entry);
 
    //现在进行输出
	//获取第一个元素
    s = TAILQ_FIRST(&queue_head);
    printf("the first entry is %d\n", s->value);
	
	//获取下一个元素
    s = TAILQ_NEXT(s, entry);
    printf("the second entry is %d\n\n", s->value);
 
    //删除第二个元素, 但并没有释放s指向元素的内存
    TAILQ_REMOVE(&queue_head, s, entry);
    free(s);
 
 
    new_item = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    new_item->value = 100;
 
    s = TAILQ_FIRST(&queue_head);
    //用new_iten替换第一个元素
    TAILQ_REPLACE(&queue_head, s, new_item, entry);
 
 
    printf("now, print again\n");
    i = 0;
    TAILQ_FOREACH(p, &queue_head, entry)//用foreach遍历所有元素
    {
        printf("the %dth entry is %d\n", i, p->value);
    }
 
    p = TAILQ_LAST(&queue_head, queue_head_t);
    printf("last is %d\n", p->value);
 
    p = TAILQ_PREV(p, queue_head_t, entry);
    printf("the entry before last is %d\n", p->value);
}

4、libevent队列分析_第2张图片

(3)宏函数展开
4、libevent队列分析_第3张图片

//队列中的元素结构体。它有一个值,并且有前向指针和后向指针
//通过前后向指针,把队列中的节点连接起来
struct queue_entry_t
{
    int value;
 
    struct
    {
        struct queue_entry_t *tqe_next;
        struct queue_entry_t **tqe_prev;
    }entry;
};
 
//就像有头节点的链表那样,这个是队列头,它有两个指针,分别指向队列的头和尾
struct queue_head_t
{
    struct queue_entry_t *tqh_first;
    struct queue_entry_t **tqh_last;
};
 
int main(int argc, char **argv)
{
    struct queue_head_t queue_head;
    struct queue_entry_t *q, *p, *s, *new_item;
    int i;
 
    //TAILQ_INIT(&queue_head);
    do
    {
        (&queue_head)->tqh_first = 0;
        //tqh_last是二级指针,这里指向一级指针
        (&queue_head)->tqh_last = &(&queue_head)->tqh_first;
    }while(0);
 
    for(i = 0; i < 3; ++i)
    {
        p = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
        p->value = i;
 
        //TAILQ_INSERT_TAIL(&queue_head, p, entry);在队尾插入数据
        do
        {
            (p)->entry.tqe_next = 0;
            //tqh_last存储的是最后一个元素(队列节点)tqe_next成员的地址。
            //所以tqe_prev指向了tqe_next。
            (p)->entry.tqe_prev = (&queue_head)->tqh_last;
 
            //tqh_last存储的是最后一个元素(队列节点)tqe_next成员
            //的地址,所以*(&queue_head)->tqh_last修改的是最后一个
            //元素的tqe_next成员的值,使得tqe_next指向*p(新的队列
            //节点)。
            *(&queue_head)->tqh_last = (p);
            //队头结构体(queue_head)的tqh_last成员保存新队列节点的
            //tqe_next成员的地址值。即让tqh_last指向tqe_next。
            (&queue_head)->tqh_last = &(p)->entry.tqe_next;
        }while(0);
    }
 
    q = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    q->value = 10;
 
    //TAILQ_INSERT_HEAD(&queue_head, q, entry);在队头插入数据
    do {
        //queue_head队列中已经有节点(元素了)。要对第一个元素进行修改
        if(((q)->entry.tqe_next = (&queue_head)->tqh_first) != 0)
            (&queue_head)->tqh_first->entry.tqe_prev = &(q)->entry.tqe_next;
        else//queue_head队列目前是空的,还没有任何节点(元素)。修改queue_head即可
            (&queue_head)->tqh_last = &(q)->entry.tqe_next;
 
        //queue_head的first指针指向要插入的节点*q
        (&queue_head)->tqh_first = (q);
        (q)->entry.tqe_prev = &(&queue_head)->tqh_first;
    }while(0);
 
    //现在q指向队头元素、p指向队尾元素
 
    s = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    s->value = 20;
 
    //TAILQ_INSERT_AFTER(&queue_head, q, s, entry);在队头元素q的后面插入元素
    do
    {
        //q不是最后队列中最后一个节点。要对q后面的元素进行修改
        if (((s)->entry.tqe_next = (q)->entry.tqe_next) != 0)
            (s)->entry.tqe_next->entry.tqe_prev = &(s)->entry.tqe_next;
        else//q是最后一个元素。对queue_head修改即可
            (&queue_head)->tqh_last = &(s)->entry.tqe_next;
 
        (q)->entry.tqe_next = (s);
        (s)->entry.tqe_prev = &(q)->entry.tqe_next;
    }while(0);
 
 
 
    s = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    s->value = 30;
 
    //TAILQ_INSERT_BEFORE(p, s, entry); 在队尾元素p的前面插入元素
    do
    {
        //无需判断节点p前面是否还有元素。因为即使没有元素,queue_head的两个
        //指针从功能上也相当于一个元素。这点是采用二级指针的一大好处。
        (s)->entry.tqe_prev = (p)->entry.tqe_prev;
        (s)->entry.tqe_next = (p);
        *(p)->entry.tqe_prev = (s);
        (p)->entry.tqe_prev = &(s)->entry.tqe_next;
    }while(0);
 
 
    //现在进行输出
 
    // s = TAILQ_FIRST(&queue_head);
    s = ((&queue_head)->tqh_first);
    printf("the first entry is %d\n", s->value);
 
    // s = TAILQ_NEXT(s, entry);
    s = ((s)->entry.tqe_next);
    printf("the second entry is %d\n\n", s->value);
 
    //删除第二个元素, 但并没有释放s指向元素的内存
    //TAILQ_REMOVE(&queue_head, s, entry);
    do
    {
        if (((s)->entry.tqe_next) != 0)
            (s)->entry.tqe_next->entry.tqe_prev = (s)->entry.tqe_prev;
        else (&queue_head)->tqh_last = (s)->entry.tqe_prev;
 
        *(s)->entry.tqe_prev = (s)->entry.tqe_next;
    }while(0);
 
    free(s);
 
 
    new_item = (struct queue_entry_t*)malloc(sizeof(struct queue_entry_t));
    new_item->value = 100;
 
    //s = TAILQ_FIRST(&queue_head);
    s = ((&queue_head)->tqh_first);
 
    //用new_iten替换第一个元素
    //TAILQ_REPLACE(&queue_head, s, new_item, entry);
    do
    {
        if (((new_item)->entry.tqe_next = (s)->entry.tqe_next) != 0)
            (new_item)->entry.tqe_next->entry.tqe_prev = &(new_item)->entry.tqe_next;
        else
            (&queue_head)->tqh_last = &(new_item)->entry.tqe_next;
 
        (new_item)->entry.tqe_prev = (s)->entry.tqe_prev;
        *(new_item)->entry.tqe_prev = (new_item);
    }while(0);
 
 
    printf("now, print again\n");
    i = 0;
    //TAILQ_FOREACH(p, &queue_head, entry)//用foreach遍历所有元素
    for((p) = ((&queue_head)->tqh_first); (p) != 0;
        (p) = ((p)->entry.tqe_next))
    {
        printf("the %dth entry is %d\n", i, p->value);
    }
 
    //p = TAILQ_LAST(&queue_head, queue_head_t);
    p = (*(((struct queue_head_t *)((&queue_head)->tqh_last))->tqh_last));
    printf("last is %d\n", p->value);
 
 
    //p = TAILQ_PREV(p, queue_head_t, entry);
    p = (*(((struct queue_head_t *)((p)->entry.tqe_prev))->tqh_last));
    printf("the entry before last is %d\n", p->value);
}

(4)C/C++中指针操作

#include
 
struct item_t
{
    int a;
    int b;
    int c;
};
 
struct entry_t
{
    int a;
    int b;
};
 
int main()
{
    struct item_t item = { 1, 2, 3};
 
    entry_t *p = (entry_t*)(&item.b);
    printf("a = %d, b = %d\n", p->a, p->b);
 
    return 0;
}

在这里插入图片描述
在这里插入图片描述

4、libevent队列分析_第4张图片

在这里插入图片描述

(5)队尾结点
4、libevent队列分析_第5张图片

4、libevent队列分析_第6张图片

其实此时
p = (*(((struct queue_head_t *)((&queue_head)->tqh_last))->tqh_last))
也就是((&queue_head)->tqh_last) + 4(32位系统指针大小4字节)

(6)前一个结点
4、libevent队列分析_第7张图片

4、libevent队列分析_第8张图片

4、libevent队列分析_第9张图片

你可能感兴趣的:(libevent)