近日在學習Binder驅動的binder_work
時,發現了以下結構:git
struct binder_work{ struct list_head entry; enum { ... } type;
發現其中引入了list_head
鏈表節點,如此一來binder_work
類型也能夠看作是個鏈表了。那麼對binder_work
也能夠加入鏈表中了,以binder_enqueue_work_ilocked
方法爲例:github
static void binder_enqueue_work_ilocked(struct binder_work *work, struct list_head *target_list) { BUG_ON(target_list == NULL); BUG_ON(work->entry.next && !list_empty(&work->entry)); list_add_tail(&work->entry, target_list);//將binder_work的entry成員加入target_list中 }
由此先熟悉kernel中list的實現以及經常使用方法,以幫助學習Binder內容。多線程
#define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name)
這種方式構造方法十分巧妙,當調用LIST_HEAD(name)
時,即爲ide
struct list_head name = { &(name), &(name) }
因爲list_head
結構體的定義爲:oop
struct list_head { struct list_head *next, *prev; };
即把next,prev都指向自身。學習
我的以爲這種方式更容易看懂:測試
static inline void INIT_LIST_HEAD(struct list_head *list) { WRITE_ONCE(list->next, list);//等同於list->net = list; list->prev = list; }
INIT_LIST_HEAD
初始化鏈表時,實質將頭部節點的next以及prev都指向本身。this
至於WRITE_ONCE
第一次見,stackoverflow的解釋是:google
1.Read/write "tearing" : replacing a single memory access with many smaller ones. GCC may (and does!) in certain situations replace something like p = 0x01020304; with two 16-bit store-immediate instructions -instead of presumably placing the constant in a register and then a memory access, and so forth. WRITE_ONCE would allow us to say to GCC, "don't do that", like so: WRITE_ONCE(p, 0x01020304);
編譯器有可能對讀,寫操做分割成多條指令,經過該WRITE_ONCE
可以將保證這些操做只有一次。
2.C compilers have stopped guaranteeing that a word access is atomic. Any program which is non-race-free can be miscompiled with spectacular results. Not only that, but a compiler may decide to not keep certain values in registers inside a loop, leading to multiple references that can mess up code like this:
C的編譯器不可以保證對一個word的訪問是原子的。全部可致使多線程競爭的程序都有可能由於編譯致使出現不一樣的結果。
詳細的內容能夠參考READ_ONCE and WRITE_ONCEatom
簡單而言,有三點好處:
list_add
list_add
(struct list_head new, struct list_head head); 將節點插入到鏈表頭部static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { if (!__list_add_valid(new, prev, next)) return; next->prev = new; new->next = next; new->prev = prev; WRITE_ONCE(prev->next, new); } static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); }
list_add_tail
list_add_tail
(struct list_head new, struct list_head head); 將節點插入到鏈表尾部static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); }
尾部加入節點與頭部加入節點都是使用了__list_add
方法。能夠將__list_add
參數理解爲:
list_del
list_del(struct list_head *entry);
刪除一個節點,並將他的指針清除0static inline void list_del(struct list_head *entry) { __list_del_entry(entry); entry->next = LIST_POISON1;//LIST_POISINO1和LIST_POISON2是兩個無效的地址區 entry->prev = LIST_POISON2; } static inline void __list_del_entry(struct list_head *entry) { if (!__list_del_entry_valid(entry)) return; __list_del(entry->prev, entry->next); } static inline bool __list_del_entry_valid(struct list_head *entry) { return true; } static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; WRITE_ONCE(prev->next, next); }
list_del_init
list_del_init(struct list_head *entry);
刪除一個節點,並將他的指針再次指向本身自己static inline void list_del_init(struct list_head *entry) { __list_del_entry(entry); INIT_LIST_HEAD(entry); }
list_replace
list_replace(struct list_head *old, struct list_head *new);
替換鏈表中的某個節點, old須要被替換的節點, new新的節點static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; }
list_replace_init
list_replace_init(struct list_head *old, struct list_head *new);
和上面的區別在於,把替換以後的老的節點進行初始化static inline void list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); }
list_is_last
int list_is_last(const struct list_head *list, const struct list_head *head);
測試一個節點是否爲鏈表尾節點,list是要測試的節點,head是一個鏈表頭static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; }
list_empty
int list_empty(const struct list_head *head);
測試鏈表是否爲空static inline int list_empty(const struct list_head *head) { return READ_ONCE(head->next) == head; }