# 2021q1 Homework2 (quiz2) contributed by < [`lofoz`](https://github.com/lofoz) > ###### tags: `linux2021` > [2021 年第 2 週隨堂測驗題目](https://hackmd.io/@sysprog/linux2021-quiz2) --- ## 測驗 1 ### 程式碼解析 [include/linux/list.h](https://github.com/torvalds/linux/blob/master/include/linux/list.h) ### Structure #### list_head :::spoiler Code ```cpp struct list_head { struct list_head *prev, *next; }; ``` ::: :::spoiler 圖例 ```graphviz digraph list_head { node[shape=Mrecord] list_head [label="prev|next", xlabel="list_head"] } ``` ::: ### Functions #### INIT_LIST_HEAD :::spoiler Code ```cpp static inline void INIT_LIST_HEAD(struct list_head *head) { head->next = head; head->prev = head; } ``` ::: :::spoiler 圖例 ```graphviz digraph list_head { node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head"] head:f0 -> head head:f1 -> head } ``` ::: #### list_add_tail 新增 node 到 list :::warning 需要清楚新增節點的擺放位置,參照 Linux 核心原始程式碼裡頭的註解來說明 :notes: jserv ::: :::spoiler Code ```cpp static inline void list_add_tail(struct list_head *node, struct list_head *head) { struct list_head *prev = head->prev; prev->next = node; node->next = head; node->prev = prev; head->prev = node; } ``` ::: :::spoiler 圖例(一個節點) ```graphviz digraph list_head { nodesep=1.0 rankdir="TB" node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head|prev"] t [label="<f0> prev|<f1> next", xlabel="node", fillcolor="lightblue", style="filled, bold"] head:f1 -> t [color="red"] t:f1 -> head [color="lightblue"] t:f0 -> head [color="lightblue"] head:f0 -> t [color="orange"] } ``` ::: :::spoiler 圖例(兩個節點以上) ```graphviz digraph list_head { nodesep=1.0 rankdir="LR" node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head"] t1 [label="<f0> prev|<f1> next", xlabel="t1|prev"] head:f1 -> t1 t1:f1 -> head [color="red"] t1:f0 -> head head:f0 -> t1 [color="orange"] } ``` ```graphviz digraph list_head { nodesep=1.7 rankdir="LR" node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head"] t1 [label="<f0> prev|<f1> next", xlabel="t1|prev"] t2 [label="<f0> prev|<f1> next", xlabel="node", fillcolor="lightblue", style="filled, bold"] head:f1 -> t1 t1:f1 -> t2 [color="red"] t2:f1 -> head [color="lightblue"] head:f0 -> t2 [color="orange"] t2:f0 -> t1 [color="lightblue"] t1:f0 -> head } ``` ::: #### list_del 將 node 從 list 刪除 :::spoiler Code ```cpp static inline void list_del(struct list_head *node) { struct list_head *next = node->next, *prev = node->prev; next->prev = prev; prev->next = next; } ``` ::: :::spoiler 圖例 ```graphviz digraph list_head { nodesep=1.7 rankdir="LR" node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head|prev"] t1 [label="<f0> prev|<f1> next", xlabel="t1|node", fillcolor="lightblue", style="filled, bold"] t2 [label="<f0> prev|<f1> next", xlabel="t2|next"] head:f1 -> t1 [color="orange"] t1:f1 -> t2 t2:f1 -> head head:f0 -> t2 t2:f0 -> t1 [color="red"] t1:f0 -> head } ``` ```graphviz digraph list_head { nodesep=1.0 rankdir="LR" node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head|prev"] t2 [label="<f0> prev|<f1> next", xlabel="t2|next"] t2:f1 -> head head:f0 -> t2 head:f1 -> t2 [color="orange"] t2:f0 -> head [color="red"] } ``` ::: #### list_splice_tail 將 list 接到 head 尾端 :::spoiler Code ```cpp static inline void list_splice_tail(struct list_head *list, struct list_head *head) { struct list_head *head_last = head->prev; struct list_head *list_first = list->next, *list_last = list->prev; if (list_empty(list)) return; head->prev = list_last; list_last->next = head; list_first->prev = head_last; head_last->next = list_first; } ``` ::: ::: spoiler 圖例(未連接) ```graphviz digraph list_head { nodesep=0.2 rankdir="LR" node[shape=Mrecord] list [label="<f0> prev|<f1> next", xlabel="list"] l1 [label="<f0> prev|<f1> next", xlabel="l1|\nlist_first ", style="filled, bold", fillcolor="#42AB91"] l2 [label="<f0> prev|<f1> next", xlabel="l2|\nlist_last ", style="filled, bold", fillcolor="#F19C9F"] list:f1 -> l1 l1:f1 -> l2 l2:f1 -> list [color="orange"] list:f0 -> l2 l2:f0 -> l1 l1:f0 -> list [color="green"] head [label="<f0> prev|<f1> next", xlabel="head"] h1 [label="<f0> prev|<f1> next", xlabel="h1"] h2 [label="<f0> prev|<f1> next", xlabel="h2|\nhead_last", style="filled, bold", fillcolor="#C4D700"] head:f1 -> h1 h1:f1 -> h2 h2:f1 -> head [color="#7BB99B"] head:f0 -> h2 [color="red"] h2:f0 -> h1 h1:f0 -> head } ``` ::: :::spoiler 圖例(連接) ```graphviz digraph list_head { nodesep=0.2 rankdir="LR" node[shape=Mrecord] head [label="<f0> prev|<f1> next", xlabel="head"] h1 [label="<f0> prev|<f1> next", xlabel="h1"] h2 [label="<f0> prev|<f1> next", xlabel="h2|\nhead_last", style="filled, bold", fillcolor="#C4D700"] l1 [label="<f0> prev|<f1> next", xlabel="l1|\nlist_first ", style="filled, bold", fillcolor="#42AB91"] l2 [label="<f0> prev|<f1> next", xlabel="l2|\nlist_last ", style="filled, bold", fillcolor="#F19C9F"] head:f1 -> h1 h1:f1 -> h2 h2:f1 -> l1 [color="#7BB99B"] head:f0 -> l2 [color="red"] h2:f0 -> h1 h1:f0 -> head l1:f1 -> l2 l2:f0 -> l1 l2:f1 -> head [color="orange"] l1:f0 -> h2 [color="green"] } ``` ::: #### list_cut_position 把 head_from 在 node 的位置分成兩半。 將 head_from_first 到 node 連接到 head_to,head_from 連接 node 後的節點。 :::spoiler Code ```cpp static inline void list_cut_position(struct list_head *head_to, struct list_head *head_from, struct list_head *node) { struct list_head *head_from_first = head_from->next; if (list_empty(head_from)) return; if (head_from == node) { INIT_LIST_HEAD(head_to); return; } head_from->next = node->next; head_from->next->prev = head_from; head_to->prev = node; node->next = head_to; head_to->next = head_from_first; head_to->next->prev = head_to; } ``` ::: :::spoiler 圖例(未切割) ```graphviz digraph list_head { nodesep=0.7 rankdir="LR" node[shape=Mrecord] head_to [label="<f0> prev|<f1> next", xlabel="head_to"] head_from [label="<f0> prev|<f1> next", xlabel="head_from"] h1 [label="<f0> prev|<f1> next", xlabel="h1|head_from_first"] h2 [label="<f0> prev|<f1> next", xlabel="h2|node", style="filled, bold", fillcolor="#F19C9F"] h3 [label="<f0> prev|<f1> next", xlabel="h3"] h4 [label="<f0> prev|<f1> next", xlabel="h4"] head_from:f1 -> h1 [color="red"] h1:f1 -> h2 h2:f1 -> h3 [color="green"] h3:f1 -> h4 h4:f1 -> head_from head_from:f0 -> h4 h4:f0 -> h3 h3:f0 -> h2 [color="orange"] h2:f0 -> h1 h1:f0 -> head_from [color="#7BB99B"] } ``` ::: :::spoiler 圖例(切割後) ```graphviz digraph list_head { nodesep=0.1 rankdir="LR" node[shape=Mrecord] head_to [label="<f0> prev|<f1> next", xlabel="head_to"] head_from [label="<f0> prev|<f1> next", xlabel="head_from"] h1 [label="<f0> prev|<f1> next", xlabel="h1|head_from_first"] h2 [label="<f0> prev|<f1> next", xlabel="h2|node", style="filled, bold", fillcolor="#F19C9F"] h3 [label="<f0> prev|<f1> next", xlabel="h3"] h4 [label="<f0> prev|<f1> next", xlabel="h4"] head_from:f1 -> h3 [color="red"] h1:f1 -> h2 h2:f1 -> head_to [color="green"] h3:f1 -> h4 h4:f1 -> head_from head_to:f1 -> h1 head_from:f0 -> h4 h4:f0 -> h3 h3:f0 -> head_from [color="orange"] h2:f0 -> h1 h1:f0 -> head_to [color="#7BB99B"] head_to:f0 -> h2 } ``` ::: --- ### 運作原理 : merge sort ( doubly-linked list version ) ### Structures #### queue_t :::spoiler {state="open"} Code ```cpp typedef struct { list_ele_t *head; /* Linked list of elements */ list_ele_t *tail; size_t size; struct list_head list; } queue_t; ``` ::: :::spoiler {state="open"} 圖例 ```graphviz digraph queue_t { nodesep=0.1 rankdir="LR" node[shape=Mrecord] queue_t [label="{<f0> head|<f1> tail}|<f2> size|<f3> list", xlabel="queue_t", style="filled, bold", fillcolor="#F19C9F"] } ``` ::: #### list_ele_t :::spoiler {state="open"} Code ```cpp typedef struct __element { char *value; struct __element *next; struct list_head list; } list_ele_t; ``` ::: :::spoiler {state="open"} 圖例 ```graphviz digraph list_ele_t { nodesep=0.1 rankdir="LR" node[shape=Mrecord] __element [label="<f0> value|<f1> next|<f2> list", xlabel="list_ele_t", style="filled, bold", fillcolor="lightblue"] } ``` ::: ### Functions #### q_new :::spoiler {state="open"} Code ```cpp static queue_t *q_new() { queue_t *q = malloc(sizeof(queue_t)); if (!q) return NULL; q->head = q->tail = NULL; q->size = 0; INIT_LIST_HEAD(&q->list); return q; } ``` ::: :::spoiler {state="open"} 圖例 ```graphviz digraph q_new { nodesep=0.5 rankdir="TB" node[shape=Mrecord] q [label="{{<f0> head|<f1> tail}|{<f2> size = 0}|{<f3> list}}", xlabel="q", style="filled, bold", fillcolor="#F19C9F"] list_ele_t_1 [label="<f0> NULL", color="white"] list_ele_t_2 [label="<f0> NULL", color="white"] q:f0 -> list_ele_t_1 q:f1 -> list_ele_t_2 head [label="<f0> prev|<f1> next", xlabel="q->list"] head:f0 -> head head:f1 -> head q:f3 -> head } ``` ::: #### q_insert_head 將字串 s 放到 queue q->head (以 list_ele_t 而言,從 head 插入),並將其放到 list_head (以 list_head 而言,從 tail 插入)。 :::spoiler Code ```cpp bool q_insert_head(queue_t *q, char *s) { if (!q) return false; list_ele_t *newh = malloc(sizeof(list_ele_t)); if (!newh) return false; char *new_value = strdup(s); if (!new_value) { free(newh); return false; } newh->value = new_value; newh->next = q->head; q->head = newh; if (q->size == 0) q->tail = newh; q->size++; list_add_tail(&newh->list, &q->list); return true; } ``` ::: :::spoiler 圖例 ( size = 0 插入 ) ```graphviz digraph q_new { nodesep=1.0 rankdir="TB" node[shape=Mrecord] q [label="{{<f0> head|<f1> tail}|{<f2> size = 1}|{<f3> prev|<f4> next}}", xlabel="q", style="filled, bold", fillcolor="#F19C9F"] NULL [label="<f0> NULL", color="white"] q:f0 -> newh q:f1 -> newh q:f3 -> newh q:f4 -> newh newh [label="{<f0> value = s|<f1> next|{<f2> prev|<f3> next}}", xlabel="newh", style="filled, bold", fillcolor="lightblue"] newh:f1 -> NULL newh:f2 -> q:f2 newh:f3 -> q:f2 } ``` ::: :::spoiler 圖例 ( size = 1 插入 ) ```graphviz digraph q_new { nodesep=1.0 rankdir="LR" node[shape=Mrecord] q [label="{{<f0> head|<f1> tail}|{<f2> size = 2}|{<f3> prev|<f4> next}}", xlabel="q", style="filled, bold", fillcolor="#F19C9F"] NULL [label="<f0> NULL", color="white"] q:f0 -> newh q:f1 -> t1 q:f3 -> newh q:f4 -> t1 t1 [label="{<f0> value = s|<f1> next|{<f2> prev|<f3> next}}", xlabel="t1"] t1:f1 -> NULL t1:f2 -> q:f2 t1:f3 -> newh newh [label="{<f0> value = s|<f1> next|{<f2> prev|<f3> next}}", xlabel="newh", style="filled, bold", fillcolor="lightblue"] newh:f1 -> t1 newh:f2 -> t1 newh:f3 -> q:f2 } ``` ::: #### list_merge_sort :::spoiler Code ```cpp void list_merge_sort(queue_t *q) { if (list_is_singular(&q->list)) return; queue_t left; struct list_head sorted; INIT_LIST_HEAD(&left.list); list_cut_position(&left.list, &q->list, &(get_middle(&q->list)->list)); list_merge_sort(&left); list_merge_sort(q); list_merge(&left.list, &q->list, &sorted); INIT_LIST_HEAD(&q->list); list_splice_tail(&sorted, &q->list); } ``` ::: #### get_middle :::spoiler Code ```cpp= static list_ele_t *get_middle(struct list_head *list) { struct list_head *fast = list->next, *slow; list_for_each (slow, list) { if (fast->next == list || fast->next->next == list) break; fast = fast->next->next; } return list_entry(slow, list_ele_t, list); } ``` ::: --- ### 改進空間 #### 1. struct list_ele_t 中的 next 為**無用處**之變數。 研 gdb追蹤code