码迷,mamicode.com
首页 > 其他好文 > 详细

qemu数据结构分析

时间:2020-10-29 10:18:08      阅读:25      评论:0      收藏:0      [点我收藏+]

标签:struct   过多   lin   它的   地址   linked   backend   合并   block   

qemu数据结构分析
这里主要分析queue.h头文件中包含的四种数据结构:1.单链表 2.双链表 3.简单队列 4.尾队列

一、单链表
1.1 应用场景
适用于数据量大的集合并且没有过多删除动作的场景,也适用做LIFO(后进先出)队列。

1.2 定义
/*

  • Singly-linked List definitions.
    */

define QSLIST_HEAD(name, type) \

struct name {
struct type slh_first; / first element */
}

define QSLIST_HEAD_INITIALIZER(head) \

    { NULL }

define QSLIST_ENTRY(type) \

struct {
struct type sle_next; / next element */
}

1.3 元素插入

define QSLIST_INSERT_AFTER(slistelm, elm, field) do { \

    (elm)->field.sle_next = (slistelm)->field.sle_next;                 (slistelm)->field.sle_next = (elm);                             

} while (/CONSTCOND/0)
qemu代码中并没有使用该数据结构,这里简单分析一下该链表的元素插入方式。

插入流程比较简单,slistelm是待插入元素的前一个元素位置,elm是待插入元素,field是数据结构中的域名称,这里是next。

插入过程:1.将elm元素的next域的sle_next指向slistelm指向的下一个元素

2.将slistelm指向待插入元素elm

二、双向链表
2.1 应用场景
由于有前向指针,因此删除元素不需要遍历链表。新加入元素可以实现前插或后插。

2.2 定义

/*

  • List definitions.
    */

define QLIST_HEAD(name, type) \

struct name {
struct type lh_first; / first element */
}

define QLIST_HEAD_INITIALIZER(head) \

    { NULL }

define QLIST_ENTRY(type) \

struct {
struct type le_next; / next element */
struct type *le_prev; / address of previous next element */
}
2.3 插入操作分析

define QLIST_INSERT_AFTER(listelm, elm, field) do { \

    if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)              (listelm)->field.le_next->field.le_prev =                               &(elm)->field.le_next;                                  (listelm)->field.le_next = (elm);                                   (elm)->field.le_prev = &(listelm)->field.le_next;               

} while (/CONSTCOND/0)

插入过程:1. 首先待插入元素的le_next指针指向插入位置的下一个元素

  1. 待插入位置的下一个元素的le_prev指向待插入元素的le_next指针。注意这里的le_prev是一个指向指针的指针,因此le_prev保存的是指针le_next的地址,而不是它的值。如果是值的话就变成指向自身了。

  2. 前一个元素的le_next开始指向待插入元素

  3. 最后待插入元素的le_prev指向其前一个元素的le_next指针。

2.4 在qemu中的应用
双向链表在qemu中有大量使用,如block设备链(block-backend.c)。

三、简单队列
3.1 定义

/*

  • 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 */
}

2.3 元素插入

define QSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \

if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)        (head)->sqh_last = &(elm)->field.sqe_next;                      (listelm)->field.sqe_next = (elm);                                  

} while (/CONSTCOND/0

简单队列的插入过程也比较简单

插入过程:1. 首先将待插入元素的sqe_next指针指向待插入位置的下一个元素

  1. 最后将插入位置的前一个元素的sqe_next指针指向待插入元素

四、尾队列
4.1 应用场景
尾队列在链表头有一个头指针,在链表尾有一个尾指针。元素由前向指针和尾指针构成双向链表。可以在任意方向上进行遍历。

4.2 定义

/*

  • Tail queue definitions. The union acts as a poor man template, as if
  • it were QTailQLink.
    */

define QTAILQ_HEAD(name, type) \

union name {
struct type tqh_first; / first element /
QTailQLink tqh_circ; /
link for circular backwards list */
}

define QTAILQ_HEAD_INITIALIZER(head) \

    { .tqh_circ = { NULL, &(head).tqh_circ } }

define QTAILQ_ENTRY(type) \

union {
struct type tqe_next; / next element /
QTailQLink tqe_circ; /
link for circular backwards list */
}

4.3 插入过程

define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \

    if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)        (elm)->field.tqe_next->field.tqe_circ.tql_prev =                        &(elm)->field.tqe_circ;                                     else                                                                    (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ;             (listelm)->field.tqe_next = (elm);                                  (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ;    

} while (/CONSTCOND/0)

尾队列结构由于头结点有一个tqh_circ指针始终指向尾结点,因此可以以O(1)的复杂度在尾部插入元素。同时能够以O(1)的复杂度在头部删除元素。

尾队列结构在中间的插入过程比较复杂。

插入过程:1.将待插入元素elm的tqe_next指针指向插入位置的下一个元素

  1. 将插入位置下一个元素的tql_prev指针指向待插入元素的tqe_circ。这里和双向链表一样,tql_prev是一个指向指针的指针,保存的是前一个节点中tqe_circ指针的地址。

  2. 第一,二步实际上完成了插入元素与插入位置下一个元素之间的连接,构成了一个循环。现在开始的是与插入位置前一个元素之间的连接。首先将插入位置前一个元素的tqe_next指向待插入元素elm。

  3. 最后将待插入元素的tql_prev指向前一个元素。保存前一个元素tqe_circ指针的地址。

4.4 在qem中的应用
尾队列的应用十分广泛,在内核,libevent中都能看到它的身影。主要得益于它O(1)复杂度的插入和删除操作以及可以双向遍历。

在qemu中,如memory_mapping使用的就是QTAIL_LIST(memory_mapping.c)。

五、总结
在qemu中主要使用双向链表和尾队列这两种数据结构。对于这两种数据结构的初始化,插入,添加,删除操作都使用宏定义做了封装。理解了这两种数据结构,可以更好的理解qemu相关模块的代码。

qemu数据结构分析

标签:struct   过多   lin   它的   地址   linked   backend   合并   block   

原文地址:https://www.cnblogs.com/foxmai/p/13892334.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!