contributed by <bauuuu1021
>
為何 Linux 採用 macro 來實作 linked list?一般的 function call 有何成本?
Linux 應用 linked list 在哪些場合?舉三個案例並附上對應程式碼,需要解說,以及揣摩對應的考量
在 linux Kernel 2.6 中,每個處理器都有兩個 Task Queue,當 Active Task Queue 中的 task 執行完畢,就會依據 Priority level 及 Time Slice 放到 Expired Task Queue中。當 Active Task Queue 執行完畢後,就 Switch 這兩個 Task Queue,開始執行經過計算後的新Active Task Queue。如下圖:
task_struct 中的 run_list 是以呼叫 list_head 的方式使用 linux 中的 doubly-linked list 把同一個 Task Priority 的行程串起來,對應的程式碼下
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
struct thread_info *thread_info;
atomic_t usage;
unsigned long flags; /* per process flags, defined below */
unsigned long ptrace;
int lock_depth; /* Lock depth */
int prio, static_prio;
struct list_head run_list;
………
}
GNU extension 的 typeof 有何作用?在程式碼中扮演什麼角色?
int a;
typeof(a) b; //即 int b;
typeof(&a) c; //即 int* c;
/*
* Check at compile time that something is of a particular type.
* Always evaluates to 1 so you may use it easily in comparisons.
*/
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
/*
* Check at compile time that 'function' is a certain type, or is a pointer
* to that type (needs to use typedef for the function type.)
*/
#define typecheck_fn(type,function) \
({ typeof(type) __tmp = function; \
(void)__tmp; \
})
TODO:實驗程式
#define container_of(ptr, type, member) \
__extension__({ const __typeof__(((type *) 0)->member) *__pmember = (ptr); \
(type *) ((char *) __pmember - offsetof(type, member)); \
})
offsetof()
的定義如下
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#include <stdio.h>
#include <stddef.h>
typedef struct {
char name[16];
int age;
char studentId[12];
} idCard;
int main () {
idCard myData = {"bauuuu1021",21,"f74041145"};
printf("offset of studentId %d\n", offsetof(idCard,studentId)); //output 20
}
#include <stdio.h>
#include <stddef.h>
typedef struct {
char name[16];
int age;
char studentId[12];
} idCard;
int main () {
idCard myData = {"bauuuu1021",21,"f74041145"};
printf("addr of stutentId %p\n", &myData.studentId);
printf("offset of studentId %d\n", offsetof(idCard, studentId));
printf("addr of name %p\n", &myData.name);
printf("addr of myData(struct) %p\n", container_of(&myData.studentId,idCard, studentId));
}
不知道為什麼最後一行有錯誤@@
container_of.c:15:73: error: expected expression before ‘struct’
printf("addr of myData(struct) %p\n", container_of(&(myData.studentId),struct idCard, studentId));
^
在以上程式碼加上 #define container_of 之定義即可解決問題bauuuu1021
list.h
還定義一系列操作,為什麼呢?這些有什麼益處?
LIST_POISONING
這樣的設計有何意義?
/*
...
* LIST_POISONING can be enabled during build-time to provoke an invalid memory
* access when the memory behind the next/prev pointer is used after a list_del.
* This only works on systems which prohibit access to the predefined memory
* addresses.
*/
...
#ifdef LIST_POISONING
node->prev = (struct list_head *) (0x00100100);
node->next = (struct list_head *) (0x00200200);
#endif
LIST_POISONING
是將被刪除的節點的 prev & next 先指向一個定義好的節點以避免這種狀況。list_for_each_safe
和 list_for_each
的差異在哪?“safe” 在執行時期的影響為何?
TODO
程式註解裡頭大量存在 @
符號,這有何意義?你能否應用在後續的程式開發呢?
tests/
目錄底下的 unit test 的作用為何?就軟體工程來說的精神為何?
tests/
目錄的 unit test 可如何持續精進和改善呢?
tests/
中所有 unit test 的 target 或寫一個 script 來執行全部檔案。因為如果對某個功能做修改,而這個功能又會被其他功能使用的話,嚴謹一點的作法應該要每個 unit test 都執行看看以確保其他功能不會受影響,手動輸入會蠻花時間的。如果要這樣改善的話應該還要在 assert() 中加上 file 名以方便 debug研讀 A Comparative Study Of Linked List Sorting Algorithms
examples
裡頭有兩種排序實作 (insertion 和 quick sort),請簡述其原理examples/insert-sort.c
和 examples/quick-sort.c
的實作方式,實作 merge sort,並且在 tests/
目錄提供新的 unit testinclude/list.h
的實作考量 (在上述檢查清單已提及部分)
#define NTH_IN_LIST(head,n) \
for(;n>0; head=head->next,n--);
error: expected expression before ‘for’
for(;n>0; head=head->next,n--);
^
bauuuu1021
, sysprog
, 2018spring