ユーザランドでは、プロセス、スレッドと区別していますが、kernelではいずれも"task struct"で管理されます。スレッドは、libc実装ではプロセス空間を共有するtaskと考えるとよいでしょう。forkするときは注意が必要なのですが、これはまた別の機会があればそちらで。。。
本題のプロセス情報、以下のディレクトリ配下にあるファイルから取得ができます。
/proc/<id>/
このファイルを通して読み書きされるコードは、procfsのところでも触れたとおり、kernelのフレームワークを利用すると簡潔なコードになります。とりあえずソースコードを見てみましょう:
FILE: fs/proc/base.c
static const struct pid_entry tid_base_stuff[] = {
ONE("stat", S_IRUGO, proc_tid_stat),
ONE("statm", S_IRUGO, proc_pid_statm),
REG("maps", S_IRUGO, proc_tid_maps_operations),
statにpsで表示するための情報がたくさん含まれているようです(busybox版psコマンドソースコードより):
int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
return do_task_stat(m, ns, pid, task, 0);
}
FILE: fs/proc/array.c
static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task, int whole)
ここをざーっと眺めていくと、なにを表示しているのかがわかりますね!(ブン投げ
/proc/PID/statの表示コード(変数はこの手前に代入されている)
seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state);
seq_put_decimal_ll(m, ' ', ppid);
seq_put_decimal_ll(m, ' ', pgid);
seq_put_decimal_ll(m, ' ', sid);
seq_put_decimal_ll(m, ' ', tty_nr);
seq_put_decimal_ll(m, ' ', tty_pgrp);
seq_put_decimal_ull(m, ' ', task->flags);
seq_put_decimal_ull(m, ' ', min_flt);
seq_put_decimal_ull(m, ' ', cmin_flt);
seq_put_decimal_ull(m, ' ', maj_flt);
seq_put_decimal_ull(m, ' ', cmaj_flt);
seq_put_decimal_ull(m, ' ', cputime_to_clock_t(utime));
seq_put_decimal_ull(m, ' ', cputime_to_clock_t(stime));
seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cutime));
seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cstime));
seq_put_decimal_ll(m, ' ', priority);
seq_put_decimal_ll(m, ' ', nice);
seq_put_decimal_ll(m, ' ', num_threads);
seq_put_decimal_ull(m, ' ', 0);
seq_put_decimal_ull(m, ' ', start_time);
seq_put_decimal_ull(m, ' ', vsize);
seq_put_decimal_ull(m, ' ', mm ? get_mm_rss(mm) : 0);
seq_put_decimal_ull(m, ' ', rsslim);
seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->start_code : 1) : 0);
seq_put_decimal_ull(m, ' ', mm ? (permitted ? mm->end_code : 1) : 0);
seq_put_decimal_ull(m, ' ', (permitted && mm) ? mm->start_stack : 0);
seq_put_decimal_ull(m, ' ', esp);
seq_put_decimal_ull(m, ' ', eip);
/* The signal information here is obsolete.
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
seq_put_decimal_ull(m, ' ', task->pending.signal.sig[0] & 0x7fffffffUL);
seq_put_decimal_ull(m, ' ', task->blocked.sig[0] & 0x7fffffffUL);
seq_put_decimal_ull(m, ' ', sigign.sig[0] & 0x7fffffffUL);
seq_put_decimal_ull(m, ' ', sigcatch.sig[0] & 0x7fffffffUL);
seq_put_decimal_ull(m, ' ', wchan);
seq_put_decimal_ull(m, ' ', 0);
seq_put_decimal_ull(m, ' ', 0);
seq_put_decimal_ll(m, ' ', task->exit_signal);
seq_put_decimal_ll(m, ' ', task_cpu(task));
seq_put_decimal_ull(m, ' ', task->rt_priority);
seq_put_decimal_ull(m, ' ', task->policy);
seq_put_decimal_ull(m, ' ', delayacct_blkio_ticks(task));
seq_put_decimal_ull(m, ' ', cputime_to_clock_t(gtime));
seq_put_decimal_ll(m, ' ', cputime_to_clock_t(cgtime));
if (mm && permitted) {
seq_put_decimal_ull(m, ' ', mm->start_data);
seq_put_decimal_ull(m, ' ', mm->end_data);
seq_put_decimal_ull(m, ' ', mm->start_brk);
seq_put_decimal_ull(m, ' ', mm->arg_start);
seq_put_decimal_ull(m, ' ', mm->arg_end);
seq_put_decimal_ull(m, ' ', mm->env_start);
seq_put_decimal_ull(m, ' ', mm->env_end);
} else
seq_printf(m, " 0 0 0 0 0 0 0");
if (permitted)
seq_put_decimal_ll(m, ' ', task->exit_code);
else
seq_put_decimal_ll(m, ' ', 0);
seq_putc(m, '\n');
if (mm)
mmput(mm);
pid_nr_ns()では、namespaceで管理しているpidに変換する関数のようです。namespaceも、不勉強なため説明できるような理解はできていません。
ぼちぼち調べながら見ていきましょう...
schedulerが参照するようなcpu timeとかあるので、ここだけ見ても意味は理解できない雰囲気ですね。
format | vars | description | In the kernel space |
%d | pid | プロセスID | pid_nr_ns(pid, ns) |
%s | tcomm | COMM名 | (task_struct*)->comm |
%c | state | 状態フラグのうち最も若いフラグの立っているところ([RSDTtXz]:左が若い) | get_task_state()の1文字目 |
(ll) | ppid | 親プロセスID | task_tgid_nr_ns(task->real_parent, ns) |
(ll) | pgid | プロセスグループID | task_pgrp_nr_ns(task, ns) |
(ll) | sid | グループリーダID(?) | task_session_nr_ns(task, ns), task->group_leaderのpid |
(ll) | tty_nr | ttyに属していれば、tty drviceのidを入れる.なければ0 | ((minor & ~0xFF)<<12) or (major << 8) or ((minor&0xFF) |
(ll) | tty_pgrp | ttyのプロセスグループ | - |
(ull) | task->flags | プロセス状態を示すビットマップ(後述) | - |
(ull) | min_flt | minor faultカウントの総和 | (struct task_struct*)->min_flt |
(ull) | cmin_flt | signal.minor faultカウントの総和 | (struct signal_struct)->cmin_flt |
(ull) | maj_flt | major faultカウントの総和 | (struct task_struct*)->maj_flt |
(ull) | cmaj_flt | signal.major faultカウントの総和 | (struct signal_struct)->cmaj_flt |
(ull) | utime | ユーザランドに費やしたcpu time | cputime_to_clock_t(utime) |
(ull) | stime | システムに費やしたcpu time | cputime_to_clock_t(stime) |
(ll) | cutime | 亡くなった子プロセスを含めたユーザランドに費やしたcpu time | cputime_to_clock_t((struct signal_struct)->cutime) |
(ll) | cstime | 亡くなった子プロセスを含めたシステムに費やしたcpu time | cputime_to_clock_t((struct signal_struct)->cstime) |
(ll) | priority | task priority() | (->prio - 100) |
(ll) | nice | nice値 | (->static_prio - 120(DEFAULT_PRIO)) |
(ll) | num_threads | スレッド数 | tsk->signal->nr_threads |
(ull) | 0 (fixed.) | - | - |
(ull) | start_time | boot based time in ticks, copy_proces()された時 | nsec_to_clock_t(task->real_start_time) |
(ull) | vsize | マップされたサイズ[Bytes] | PAGE_SIZE * mm->total_vm |
(ull) | mm->rss_stat.count[ MM_FILEPAGES,MM_ANONPAGES]の和 | プロセスに割り当てられている物理ページ数 | (mm ? get_mm_rss(mm) : 0) |
(ull) | rsslim | max resident set size | sig->rlim[RLIMIT_RSS].rlim_cur |
(ull) | | このプロセスのコード領域の先頭アドレス | mm ? (permitted ? mm->start_code : 1) : 0 |
(ull) | | このプロセスのコード領域の終了アドレス | mm ? (permitted ? mm->end_code : 1) : 0 |
(ull) | | スタックアドレスの先頭(スタックの底?) | (permitted && mm) ? mm->start_stack : 0 |
(ull) | esp | stack pointer | -(arch依存) |
(ull) | eip | index pointer? | -(arch依存) |
(ull) | | ペンディングされているシグナルのビットマップ | task->pending.signal.sig[0] & 0x7fffffffUL |
(ull) | | (確認中) | task->blocked.sig[0] & 0x7fffffffUL |
(ull) | | (確認中) | sigign.sig[0] & 0x7fffffffUL |
(ull) | | (確認中) | sigcatch.sig[0] & 0x7fffffffUL |
(ull) | wchan | 待ち状態に入った関数名(名前なし設定だとアドレス) | get_wchan(task) |
(ull) | 0 (fixed) | - | - |
(ull) | 0 (fixed) | - | - | |
(ll) | task->exit_signal | (確認中) | - |
(ll) | task_cpu(task) | (確認中) | - |
(ull) | task->rt_priority | (確認中) | - |
(ull) | task->policy | (確認中) | - |
(ull) | delayacct_blkio_ticks(task) | (確認中) | - |
(ull) | cputime_to_clock_t(gtime) | (確認中) | - |
(ll) | cputime_to_clock_t(cgtime) | (確認中) | - |
(ull) | mm->start_data | (確認中) | - |
(ull) | mm->end_data | (確認中) | - |
(ull) | mm->start_brk | (確認中) | - |
(ull) | mm->arg_start | (確認中) | - |
(ull) | mm->arg_end | (確認中) | - |
(ull) | mm->env_start | (確認中) | - |
(ull) | mm->env_end | (確認中) | - |
(ll) | task->exit_code | 0 if !permitted | (確認中) |
コメントも面白いですね。RT-signalは statusを見ろって書いてます。
/* The signal information here is obsolete.
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
※per proces flags
/*
* Per process flags
*/
#define PF_EXITING 0x00000004 /* getting shut down */
#define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */
#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
#define PF_MCE_PROCESS 0x00000080 /* process policy on mce errors */
#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
#define PF_DUMPCORE 0x00000200 /* dumped core */
#define PF_SIGNALED 0x00000400 /* killed by a signal */
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
#define PF_NPROC_EXCEEDED 0x00001000 /* set_user noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */
#define PF_USED_ASYNC 0x00004000 /* used async_schedule*(), used by module init */
#define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */
#define PF_FROZEN 0x00010000 /* frozen for system suspend */
#define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */
#define PF_KSWAPD 0x00040000 /* I am kswapd */
#define PF_MEMALLOC_NOIO 0x00080000 /* Allocating memory without IO involved */
#define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
#define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK 0x80000000 /* this thread called freeze_processes and should not be frozen */
cmin_fltとかの説明。統計情報ですね...
/*
* The resource counters for the group leader are in its
* own task_struct. Those for dead threads in the group
* are in its signal_struct, as are those for the child
* processes it has previously reaped. All these
* accumulate in the parent's signal_struct c* fields.
*
* We don't bother to take a lock here to protect these
* p->signal fields because the whole thread group is dead
* and nobody can change them.
*
* psig->stats_lock also protects us from our sub-theads
* which can reap other children at the same time. Until
* we change k_getrusage()-like users to rely on this lock
* we have to take ->siglock as well.
*
* We use thread_group_cputime_adjusted() to get times for
* the thread group, which consolidates times for all threads
* in the group including the group leader.
*/
prio : RT[0..99], user [100..140], 120がnice=0, user-nice = -20..+19 => 100..139