Linux Kernel(2.6)の実装に関するメモ書き

プロセス


Rev.19を表示中。最新版はこちら

1.データ構造

プロセスはtask_structにより管理される。


表1 task_structの内容(一部)
フィールド
意味
prio
動的優先度。effective_prio()によりstatic_prioをベースに計算される。
topで表示されているPrioはこの動的優先度(100-139)を0-39にバイアスして表示している。
static_prio
静的優先度(小さいほうが優先度高)。動的優先度を計算するための元ネタとして使われる。
0-99     リアルタイムプロセス用
100-139  通常プロセス用(nice値により値が決まる)
sleep_avg
動的優先度の計算に使用される。sleep_avgが大きい程、動的優先度が小さくなる。

RUNNING状態になってRunQueueに追加される時にsleepしていた時間が加算される(最初は動的優先度が小さくなる)。

schedule()で切替えられる時、動作していた時間分だけ減算される(動的優先度が大きくなっていく)。
time_slice
残りのCPU時間

CPUを使っているとscheduler_tick()で減算されていき、0になると Runqueueのactiveリストからexpireリストに移動される。(activeのままでいる場合もある)

nice値(static_prioと同義)から以下の値に初期設定される。
(優先度が高い程、割り当て時間が長くなる)

nice値            -20       19
p->static_prio    100   ... 139
p->time_slice     200ms ... 10ms

task_timeslice()でnice値をtime_slice値に変換している。
mm
プロセスのアドレス空間
カーネルプロセスの場合は、ユーザアドレス空間を持たないのでNULL。
active_mm
Active(実際にCR3に設定されて動作中)なアドレス空間。ユーザプロセスにおいてはtask->mmと同じものを指す。

カーネルプロセス等のようにアドレス空間を持たない(task->mm==NULL)プロセスの場合は、TLB Flushを最小限にするため、前のプロセスのアドレス空間をそのまま引き継ぐ(前のプロセスのactive_mmがcurrent->active_mmとなっている)。

もしcurrent->active_mm == NULLなら、なにかがおかしい。カレントのプロセスは、カーネルスレッド(current->mm == NULL)であったとしても、正しいtask->active_mmを常に持っていなければならない。



2.静的優先度と動的優先度

優先度には静的優先度と動的優先度がある。静的優先度は設定により固定的に割り当てられる。0〜99がリアルタイムプロセス用に使われ、100〜139が通常のプロセスに用いられる。通常プロセスの静的優先度はnice値により決定される。niceの取りうる値 -20〜19 が静的優先度 100〜139にマップされている(nice値 -20なら静的優先度は100、19なら139)。この、静的優先度をベースに動的優先度が計算される。

動的優先度は、実際にプロセスのスケジュールに使用される優先度。静的優先度を元に計算される。CPU時間を使うほど優先度が下がる(値が大きくなる)。この計算はeffective_prio()で行われる。

静的優先度と動的優先度の値の確認

静的優先度と動的優先度はtopコマンドで確認できる。静的優先度はnice値(NIフィールド)の値から算出でき、動的優先度はPRフィールドで確認できる。PRフィールドは動的優先度の生の値100〜139を100減算して0〜39にシフトして表示している。値の範囲を他のUnixシステムと同じようにするためか。


優先度はprocファイルシステムの以下のファイルでも確認できる。

ファイルの場所 - /proc/<pid>/stat
実装場所 - fs/proc/array.c

18番目の値が動的優先度。実際には (p->prio - MAX_RT_PRIO) の計算をして100-139を0-39にシフトして表示している。topコマンドのPRに表示されている優先度もこのシフトされた値。

19番目の値がnice値(-20〜19)


3.task_structとカーネルスタック

task_structはthread_union内のthread_infoからポインタが張ってある。thread_unionはthread_infoとstackの共用体で、thread_info以外の部分はカーネルスタックとして使われる。THREAD_SIZEは通常8192なので、カーネルスタックは8KB弱ということになる。CONFIG_4KSTACKSを使用すると4192になる。


task_structとカーネルスタック
union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};

thread_union
+------------+ task_struct
|thread_info | --> +-------+
| | | |
+------------+ +-------+
| |
: <-esp
| | KernelStack先頭
+------------+
捕捉: Linux2.4ではthread_infoの場所にtask_sturctが格納されていた。


[関連関数など]

current
現在のプロセスのtask_structを指すマクロ。

include/asm-i386/current.h で定義。

本マクロはカーネルモードでのスタックespからカレントプロセスのtask_structをしている(andl %%esp,8192でthread_infoのアドレスを求めてtask_structを取得)。このため、espを切替えることはcurrentを切替えることにもつながる。currentにtask_structのアドレスを代入しているような処理はない。

init_task
pid 0のtask_struct

全プロセスのリストはinit_taskを先頭にtask->tasks.nextでたどることができる。

nr_processes()
総プロセス数を取得

for_each_process(p)
全プロセスをなめるマクロ



最終更新 2006/06/26 20:53:05 - kztomita
(2006/06/24 20:24:29 作成)


リンク
最近更新したページ
検索