プロセス
1.データ構造
プロセスはtask_structにより管理される。表1 task_structの内容(一部)
フィールド | 意味 |
---|---|
state | プロセスの状態 TASK_RUNNING: 実行可能 TASK_INTERRUPTIBLE: Sleep中(シグナルを受信するとWakeupする) TASK_UNINTERRUPTIBLE: Sleep中(シグナルを受信してもWakeupしない) TASK_STOPPED:SIGSTOPなどを受けて停止中 TASK_NONINTERACTIVEは少し特殊で、Sleep時にTASK_INTERRUPTIBLEなどと組み合わされて使用される。このフラグがセットされているとWakeup時にsleep_avgが更新されない。 |
prio | 動的優先度。effective_prio()によりstatic_prioをベースに計算される。 topで表示されているPrioはこの動的優先度(100-139)を0-39にバイアスして表示している。 |
static_prio | 静的優先度(小さいほうが優先度高)。動的優先度を計算するための元ネタとして使われる。 0-99 リアルタイムプロセス用 100-139 通常プロセス用(nice値により値が決まる) |
sleep_avg | プロセスのSleep量を表す値(0〜NS_MAX_SLEEP_AVG)。 動的優先度の計算に使用される。sleep_avgが大きい程、動的優先度が小さくなる。 |
timestamp | 以下のタイミングで時間が記録される ・RunqueueのActiveリストにつながれたとき ・コンテキスイッチされた時 ・スケジューラで実行プロセスに選ばれた時 |
activated | プロセスがどのようにWakeupされたかを示す。schedule()で実行プロセスに選ばれると0にクリアされる。このため!=0の場合、Wakeupされたがまだ実行はされていないことを示す。スケジューリングのパラメータの調整に使用されている。 -1:TASK_UNINTERRUPTIBLE状態からWakeupされた。 1:通常コンテキストからWakeupされた 2:割り込みコンテキストからWakeupされた |
time_slice | 残りのCPU時間(jiffies) CPUを使っているとscheduler_tick()で減算されていき、0になると Runqueueのactiveリストからexpireリストに移動される。(activeのままでいる場合もある) nice値(static_prioと同義)から以下の値に初期設定される。 (優先度が高い程、割り当て時間が長くなる) nice値 -20 19 p->static_prio 100 ... 139 p->time_slice 200ms ... 5ms 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
優先度はprocファイルシステムの以下のファイルでも確認できる。
ファイルの場所 - /proc/<pid>/stat
実装場所 - fs/proc/array.c
18番目の値が動的優先度。実際には (p->prio - MAX_RT_PRIO)
の計算をして100-139を0-39にシフトして表示している。topコマンドのPRに表示されている優先度もこのシフトされた値。
19番目の値がnice値(-20〜19)
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)
全プロセスをなめるマクロ