qemu中的singly-linkedlists, lists, simple queues, and tail queues
qemu/include/qemu/qeueu.h
该文件定义了4种数据结构:singly-linkedlists, lists, simple queues, and tail queues.
Singly-linkedlists单向列表
单链表由一个向前指针引导。元素是单独链接的最小空间和指针操作开销在牺牲O(N)去除任意元素。新元素可以在现有元素或列表头部添加到列表中。从列表头部移除的元素应该使用显式宏来达到最佳效率。单链表只能在向前方向遍历。单链表用于大型数据集和很少或没有清除或实现一个后进先出队列的应用的理想选择。
Lists 列表
列表由单向前指针(或用于哈希表头的前向指针数组)引导。元素是双向链接的,这样就可以删除任意元素而不需要遍历列表。新元素可以添加到列表之前或之后的现有元素或在列表的头。只能在向前方向遍历列表。
Simple queues 简单队列
简单队列由一对指针组成,一个是列表的头,另一个是列表的尾部。元素单独链接以节省空间,所以元素只能从列表的头中移除。新元素可以添加到列表后的现有元素,在列表的头,或在列表的结尾。一个简单的队列只能向前单向遍历。
Tailqueue 尾队列
尾队列由一对指针引导,一个指向列表的头,另一个指向列表的尾部。元素是双向链接的,这样就可以删除任意元素而不需要遍历列表。新的元素可以添加到列表之前或之后的现有元素,在列表的头,或在列表的结尾。可以沿着任一方向遍历尾队列。
List definitions:
#define QLIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element下一个元素 */ \
struct type **le_prev; /* address of previous next element 前一个元素的le_next变量的地址,le_next算是一个地址,因此le_prev中保存的是一个存放地址的变量的地址,即指向指针的指针*/ \
}
List functions:
QLIST_SWAP(dstlist,srclist, field):将dstlist和srclist指向的列表交换
QLIST_INSERT_AFTER(listelm,elm, field):将elm插入到llistelm之后
QLIST_INSERT_BEFORE(listelm,elm, field):将elm插入到listelm之前,其中*(listelm)->field.le_prev =(elm);表示将listelm前一个元素的le_next指针指向elm
QLIST_INSERT_HEAD(head,elm, field):将elm插入到head之后
QLIST_FOREACH_SAFE(var,head, field, next_var):不懂((next_var)= ((var)->field.le_next), 1)
Singly-linkedList definitions:
#define QSLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#defineQSLIST_ENTRY(type) \
struct{ \
struct type *sle_next; /* next element */ \
}
Singly-linkedList functions:
QSLIST_INSERT_HEAD_ATOMIC(head,elm, field):
QSLIST_MOVE_ATOMIC(dest,src):
QSLIST_REMOVE_HEAD(head,field):移除头部的元素
QSLIST_INSERT_HEAD_ATOMIC(head,elm, field):将elm插入单链表头部的原子操作;atomic_cmpxchg(&(head)->slh_first,save_sle_next, (elm))其中,函数的原型staticinline int atomic_cmpxchg(atomic_t *ptr, int old, intnew),它是把旧值同atomic_t类型的值相比较,如果相同,就把新值存入atomic_t类型的值中,返回atomic_t类型变量中原有的值。其中第一个参数是指向该值的一个指针,因此需要&符号
QSLIST_MOVE_ATOMIC(dest,src):将src链表移至dest链表中。src置为空,atomic_xchg则是将新值存入atomic_t类型的变量,并将变量的旧值返回。
Simple queue definitions:
#define QSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element最后一个下一个元素的地址*/ \
}
#define QSIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define QSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
Simple queue functions:
QSIMPLEQ_INSERT_HEAD(head, elm,field):将elm插入队列头部,注意((elm)->field.sqe_next= (head)->sqh_first) ==NULL,只有在head队列为空时,将head的尾指针指向elm的sqe_next的地址
QSIMPLEQ_SPLIT_AFTER(head, elm, field,removed):将elm从head队列中移除,并且将elm另起一个队列,为removed
QSIMPLEQ_REMOVE(head, elm, type, field):遍历head队列,移除elm
QSIMPLEQ_CONCAT(head1, head2):将head2队列连接到head1尾部,并将head2置空
Tail queue definitions:
#define Q_TAILQ_HEAD(name, type, qual) \
struct name { \
qual type *tqh_first; /* first element */ \
qual type *qual *tqh_last; /* addr of last nextelement 最后一个元素的tqe_next项的地址*/\
}
#define QTAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define Q_TAILQ_ENTRY(type, qual) \
struct { \
qual type *tqe_next; /* next element */ \
qual type *qual *tqe_prev; /* address of previousnext element 前一个元素的tqe_next项的地址*/\
}
#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,)
#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,)
由于后两句,qualtype *qual其实在使用的时候等价于structtype *,qual被去掉了
Tail queue functions:
QTAILQ_INSERT_HEAD(head, elm,field):将elm插入到head队列的头部,在head为空时,需要改变head->tqh_last指针,将之指向elm的tqe_next的地址,否则改变原来的队首的tqe_prev指针,将之指向elm的tqe_next的地址
QTAILQ_FOREACH(var, head, field):正向遍历
QTAILQ_FOREACH_REVERSE(var, head, headname,field):反向遍历,参考http://www.blogjava.net/bacoo/archive/2010/08/08/328235.html;注意tqe_next是放在tqe_prev之前,所以强制转化时,可以从struct的第一个元素寻找第二个元素