ubuntu內核list.h 的分析與應用


內核list (雙向循環鏈表)

類型:
struct list_head {

 struct list_head *next, *prev;
};


鏈表的初始化(兩種方式):
1. LIST_HEAD 定義一個頭,並且初始化為循環鏈表
2. INIT_LIST_HEAD(內聯函數)初始化為循環鏈表

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
 struct list_head name = LIST_HEAD_INIT(name)

static inline void INIT_LIST_HEAD(struct list_head *list)
{
 list->next = list;
 list->prev = list;
}


添加元素(兩種方式):
1. 頭插(list_add) :__list_add(new, head, head->next);
2. 尾插(list_add_tail) :__list_add(new, head->prev, head);
       兩中方式本質相同往兩個元素中間插入元素。
     (雙向循環鏈表特點的體現)

刪除元素(一種方式):
1. (list_del): __list_del(entry->prev, entry->next) 讓兩邊元素相互指向
       讓被刪除元素指向LIST_POISON隊列,讓系統銷毀
2. (list_del_init):將被刪除元素初始化為新的雙向循環列表

替換節點:
1. list_replace:修改新元素的指向即可
2. list_replace_init:修改新元素的指向即可,並將舊元素初始化為新的雙向循環列表


list_move: 刪除一個頭部元素,在向頭部插入一個新元素

判斷是否為最后一個元素:list_is_last
判空:list_empty 和 list_empty_careful

list_entry(找到某個節點的起始位置): 分析
#define list_entry(ptr, type, member) \
 container_of(ptr, type, member)

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

// 將值賦值給變量,並且用const修飾,可以防止無意修改變量的值
// offset也做了改動
#define container_of(ptr, type, member) ({   \
 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
 (type *)( (char *)__mptr - offsetof(type,member) );})

之前版本使用的是:
#define list_entry(ptr, type, member) \
 ((type*)((char*)ptr – (unsigned long)(((type*)0)->member)))


 

一. 鏈表的for 循環頭部:

0. 遍歷時使用到的工具

    1. list_entry 通過節點的指針域找到節點的起始地址
      #define container_of(ptr, type, member) ({ \
            const typeof( ((type *)0)->member ) *__mptr = (ptr); \
            (type *)( (char *)__mptr - offsetof(type,member) );})
    2. 

1. 向后遍歷

    1. 普通的for 循環,只適合遍歷,
        注意pos的類型是struct list_head
        list_for_each(pos, head) \
            for (pos = (head)->next; pos != (head); pos = pos->next)

    2. 在釋放的時候使用,其中的n 可以指向已釋放節點的下一個節點,
       注意pos 和n 的類型都是struct list_head
 list_for_each_safe(pos, n, head) \
            for (pos = (head)->next, n = pos->next; pos != (head); \
                  pos = n, n = pos->next)

    3. 普通的for 循環,只適合遍歷,
        注意pos 的類型是用戶定義的結構體
      list_for_each_entry (pos, head, member) \
 for (pos = list_first_entry(head, typeof(*pos), member);
                  &pos->member != (head);  \
                  pos = list_next_entry(pos, member))
    4. 繼續遍歷鏈表,從pos 的下一個開始</span>
        注意和3 中的一樣pos 的初始值是鏈表中的某個節點
       #define list_for_each_entry_continue(pos, head, member)
     for (pos = list_next_entry(pos, member);
            &pos->member != (head);
            pos = list_next_entry(pos, member))


    5. 遍歷鏈表從pos 開始
        和4 基本相似,
        #define list_for_each_entry_from(pos, head, member)
              for (; &pos->member != (head);
            pos = list_next_entry(pos, member))

    其他的就是給以上的加個safe
2. 向前遍歷
    和上邊的一樣,實質將next 改成prev 即可


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com