**列表基本结构
libevent**列表使用双向链表数据结构实现,其按优先级存放活跃事件,具体结构如下图:
libevent在结构体struct event_base中维护了优先级双向队列头struct evcallback_list *activequeues数组,其下标越小表示优先级越高。各数组成员指向了双向链表的头和尾如下图所示:
**列表基本操作
该宏用于声明一个表示双向列表头的结构体,该结构体指向了双向列表的头和尾。
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
该宏用户声明双向列表的节点。
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
注意下述结构体入口处使用了宏TAILQ_ENTRY,不难看出TAILQ_ENTRY的成员变量 struct type *tqe_next的地址就是结构体struct event_callback 的首地址,这一点很重要。
struct event_callback {
TAILQ_ENTRY(event_callback) evcb_active_next;
//、、、、、、、、
};
插入操作
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm);/* 其实就是将插入前最后一个元素的field.tqe_next设置为要插入的元素 */ \
(head)->tqh_last = &(elm)->field.tqe_next; /* 其实就是结构体的首地址,因为是第一个元素tqe_next为一级指针取地址为2级指针 */ \
} 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; /*注意对二级指针解引用其实得到的是一级指针next,因为该指针在结构体的第一个位置*/ \
} while (0)