まずは双方向リストについて解説する。
Linuxkernel内部ではlist_head
というデータ構造が用意されており、これが様々な場面で使用される。
このデータ構造はnext
とprev
の二つのメンバを持ち、データ構造に前後の概念を導入したいときに使用される。
list_headの定義
list_headは以下のように定義されている。
struct list_head { struct list_head *next, *prev; };
list_headの作成
list_headの作成にはLIST_HEAD
マクロを使用する。
#define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name)
このマクロを使用する際にはLIST_HEAD(list_name)
と宣言することで新しいlist_headを作成することができる
list_headの操作
list_headを操作するためにいくつかの関数が用意されている。
list_add(n, p)
: pが指す要素の直後に、nが指す要素を挿入するlist_add_tail(n, p)
: pが指す要素の直前に、nが指す要素を挿入するlist_del(p)
: pが指す要素を削除するlist_for_each(p)
: リストの先頭(h)で指定したリストの各要素を操作する。
プロセスリスト
存在するすべてのプロセスディスクリプタをリンクするためにも、list_head
は使われています。
struct task_struct { ... struct list_head tasks; ... }
それぞれのtask_struct
構造体は上記の通り、list_head
がたのtasks
メンバを持ち、このtasks
メンバのprev
メンバがひとつ前のtask_struct
要素を指し、next
メンバがひとつ後のtask_struct
要素を指しています。
プロセスリストの先頭には常にtask_struct
がたのinit_task
が格納されており、init_task
はいわゆるプロセス0、つまりswapperのプロセスディスクリプタとなります。