# 2018q3 Homework3 (list) contributed by < [`letticee`](https://github.com/letticee) > - [ ] 自我檢查事項: * 為何 Linux 採用 macro 來實作 linked list?一般的 function call 有何成本? * 若在程式中使用到多次 macro ,在進行編譯前,前置處理器會進行取代的動作,因此較費時一點 * 呼叫函式在執行時,必須跳到函式所在處,待執行完再返回原呼叫處的下一個敘述,花時間在 stack 的 pop 和 push * macro 執行時間較快,但程式空間加長 * Linux 應用 linked list 在哪些場合?舉三個案例並附上對應程式碼,需要解說,以及揣摩對應的考量 1. [linux/mm/page_alloc.c](https://github.com/torvalds/linux/blob/bab5c80b211035739997ebd361a679fa85b39465/mm/page_alloc.c#L2789) ```Clike /* * Free a list of 0-order pages */ void free_unref_page_list(struct list_head *list) { struct page *page, *next; unsigned long flags, pfn; int batch_count = 0; /* Prepare pages for freeing */ list_for_each_entry_safe(page, next, list, lru) { pfn = page_to_pfn(page); if (!free_unref_page_prepare(page, pfn)) list_del(&page->lru); set_page_private(page, pfn); } local_irq_save(flags); list_for_each_entry_safe(page, next, list, lru) { unsigned long pfn = page_private(page); set_page_private(page, 0); trace_mm_page_free_batched(page); free_unref_page_commit(page, pfn); /* * Guard against excessive IRQ disabled times when we get * a large list of pages to free. */ if (++batch_count == SWAP_CLUSTER_MAX) { local_irq_restore(flags); batch_count = 0; local_irq_save(flags); } } local_irq_restore(flags); } ``` * 0-order pages ([Allocating Pages](https://www.kernel.org/doc/gorman/html/understand/understand009.html#tab:%20Physical%20Pages%20Allocation%20API)) * 只有單個(2^0) page * 這個函式用來 free 掉一串的 page,這串 page 是以一個 list 儲存 2. 123 3. 233 * GNU extension 的 [typeof](https://gcc.gnu.org/onlinedocs/gcc/Typeof.html) 有何作用?在程式碼中扮演什麼角色? * 當程式可接收多種型態的資料時,typeof 可以用來取得變數的型態 * typeof 的參數可以是兩種形式 * an expression * typeof (a) * a type * typeof (int *) * e.g. typeof (*x) y; 將 y 宣告為 x 指到的型態 * 解釋以下巨集的原理 ```Clike #define container_of(ptr, type, member) \ __extension__({ \ const __typeof__(((type *) 0)->member) *__pmember = (ptr); \ (type *) ((char *) __pmember - offsetof(type, member)); \ }) ``` * 除了你熟悉的 add 和 delete 操作,`list.h` 還定義一系列操作,為什麼呢?這些有什麼益處? * `list.h` 中還定義了以下的操作: * list_add_tail:在 list 的尾端插入新節點 * list_del_init:刪除節點並將其初始化,可以避免之後錯誤的操作 * list_empty:回傳 list 是否是空的 * list_is_singular:回傳是否只有一個節點 ??* list_splice:把一個 list 的所有節點插入到另一個 list 開頭 * list_splice_tail:把一個 list 的所有節點插入到另一個 list 結尾 * list_splice_init:把一個 list 的所有節點移到另一個 list 開頭,並且把第一個 list 的 head 做 INIT_LIST_HEAD * list_splice_tail_init:把一個 list 的所有節點移到另一個 list 結尾,並且把第一個 list 的 head 做 INIT_LIST_HEAD * list_cut_position:將一個 list 的開頭的一部分節點移到另一個 list * list_move:把一個指定的節點移到 list 的開頭 * list_move_tail:把一個指定的節點移到 list 的尾端 * `LIST_POISONING` 這樣的設計有何意義? * linked list 採用環狀是基於哪些考量? * * `list_for_each_safe` 和 `list_for_each` 的差異在哪?"safe" 在執行時期的影響為何? * `list_for_each_safe` ```C #define list_for_each_safe(node, safe, head) \ for (node = (head)->next, safe = node->next; node != (head); \ node = safe, safe = node->next) ``` * `list_for_each` ```C #define list_for_each(node, head) \ for (node = (head)->next; node != (head); node = node->next) ``` * for_each 風格的開發方式對程式開發者的影響為何? * 提示:對照其他程式語言,如 Perl 和 Python * 程式註解裡頭大量存在 `@` 符號,這有何意義?你能否應用在後續的程式開發呢? * 提示: 對照看 Doxygen * `tests/` 目錄底下的 unit test 的作用為何?就軟體工程來說的精神為何? * `tests/` 目錄的 unit test 可如何持續精進和改善呢?