proc プロバイダは、プロセスの作成と終了、軽量プロセス (LWP) の作成と終了、新しいプログラムイメージの実行、およびシグナルの送信と処理に関連するプローブを使用できるようにします。
表 25–1 では、proc プローブについて説明します。
表 25–1 proc プローブ|
プローブ |
説明 |
|---|---|
|
create |
fork(2)、forkall(2)、fork1(2)、vfork(2) のいずれかを使ってプロセスが作成されたときに起動するプローブ。args[0] は、新しい子プロセスの psinfo_t をポイントしています。vfork とその他の fork のバリエーションとの違いは、フォークスレッドの lwpsinfo_t で、pr_flag メンバー内の PR_VFORKP を調べるとわかります。fork1 と forkall との違いは、親プロセスの psinfo_t (curpsinfo) と子プロセスの psinfo_t (args[0]) の両方の pr_nlwp メンバーを調べるとわかります。create プローブはプロセスが正常に作成されてから起動します。また、LWP はプロセスの作成時に作成されます。このため、まずプロセス作成時に作成された LWP に対して lwp-create が起動し、その後、新しいプロセスに対して create プローブが起動します。 |
|
exec |
exec(2) システムコールのバリエーション、exec(2)、execle(2)、execlp(2)、execv(2)、execve(2)、execvp(2) のいずれかを使って、プロセスが新しいプロセスイメージをロードするときに起動するプローブ。exec プローブは、プロセスイメージがロードされる前に起動します。したがって、execname、curpsinfo などのプロセス変数には、イメージがロードされる前のプロセス状態が格納されます。exec プローブの起動後しばらくすると、同じスレッド内で exec-failure プローブか exec-success プローブが起動します。args[0] は、新しいプロセスイメージのパスをポイントします。 |
|
exec-failure |
exec(2) のバリエーションのいずれかが失敗したときに起動するプローブ。exec-failure プローブは、同じスレッド内で exec プローブが起動したあとでのみ起動します。args[0] には、errno(3C) の値が入ります。 |
|
exec-success |
exec(2) のバリエーションのいずれかが成功したときに起動するプローブ。exec-success も、exec-failure プローブと同じように、同じスレッド内で exec プローブが起動したあとでのみ起動します。exec-success プローブが起動したときにはすでに、execname、curpsinfo などのプロセス変数には、新しいプロセスイメージがロードされたあとのプロセス状態が格納されています。 |
|
exit |
現在のプロセスが終了する直前に起動するプローブ。終了理由を表す SIGCHLD siginfo.h(3HEAD) コードが、args[0] に格納されます。 |
|
fault |
スレッドがマシンフォルトを検出したときに起動するプローブ。args[0] には、proc(4) に定義されているようにフォルトコードが格納されます。args[1] は、このフォルトの siginfo 構造体をポイントします。fault プローブをトリガーできるのは、シグナルを発行するフォルトだけです。 |
|
lwp-create |
LWP の作成時に起動するプローブ。LWP は、通常、thr_create(3C) の結果として作成されます。args[0] は、新しいスレッドの lwpsinfo_t をポイントしています。args[1] は、このスレッドが含まれているプロセスの psinfo_t をポイントしています。 |
|
lwp-start |
新しく作成された LWP のコンテキストで起動するプローブ。lwp-start プローブは、ユーザーレベルの命令が実行される前に起動します。LWP がプロセス内の最初の LWP である場合は、まず start プローブが起動し、続いて lwp-start プローブが起動します。 |
|
lwp-exit |
シグナル、または thr_exit(3C) の明示的な呼び出しによって、LWP が終了する直前に起動するプローブ。 |
|
signal-discard |
シングルスレッドプロセスに送信されたシグナルが、プロセスによってブロックされず、かつ無視されたときに、起動するプローブ。この条件下では、シグナルは作成後すぐに破棄されます。ターゲットプロセスとスレッドの lwpsinfo_t と psinfo_t は、それぞれ args[0] と args[1] に格納されます。シグナル番号は args[2] に格納されます。 |
|
signal-send |
スレッドまたはプロセスにシグナルが送信されたときに起動するプローブ。signal-send プローブは、送信側のプロセスとスレッドのコンテキストで起動します。受信側のプロセスとスレッドの lwpsinfo_t と psinfo_t は、それぞれ args[0] と args[1] に格納されます。シグナル番号は args[2] に格納されます。signal-send の起動後は、受信側のプロセスとスレッド内の signal-handle または signal-clear が必ず起動します。 |
|
signal-handle |
スレッドがシグナルを処理する直前に起動するプローブ。signal-handle プローブは、シグナルを処理するスレッドのコンテキストで起動します。シグナル番号は args[0] に格納されます。シグナルの siginfo_t 構造体のポインタは、args[1] に格納されます。siginfo_t 構造体がない場合またはシグナルハンドラに SA_SIGINFO フラグが設定されていない場合は、args[1] の値は NULL です。プロセス内のシグナルハンドラのアドレスは、args[2] に格納されます。 |
|
signal-clear |
ターゲットスレッドが sigwait(2)、sigwaitinfo(3RT)、sigtimedwait(3RT) のいずれかでシグナルを待機しているために、保留状態のシグナルが消去されるとき、起動するプローブ。この条件に当てはまる場合、保留状態のシグナルが消去され、呼び出し側にシグナル番号が返されます。シグナル番号は args[0] に格納されます。signal-clear は、待機していたスレッドのコンテキストで起動します。 |
|
start |
新しく作成されたプロセスのコンテキストで起動するプローブ。start プローブは、プロセス内でユーザーレベルの命令が実行される前に起動します。 |
表 25–2 に、proc プローブの引数の型を示します。引数については、表 25–1 を参照してください。
表 25–2 proc プローブ引数|
プローブ |
args[0] |
args[1] |
args[2] |
|---|---|---|---|
|
create |
psinfo_t * |
— |
— |
|
exec |
char * |
— |
— |
|
exec-failure |
int |
— |
— |
|
exit |
int |
— |
— |
|
fault |
int |
siginfo_t * |
— |
|
lwp-create |
lwpsinfo_t * |
psinfo_t * |
— |
|
lwp-start |
— |
— |
— |
|
lwp-exit |
— |
— |
— |
|
signal-discard |
lwpsinfo_t * |
psinfo_t * |
int |
|
signal-discard |
lwpsinfo_t * |
psinfo_t * |
int |
|
signal-send |
lwpsinfo_t * |
psinfo_t * |
int |
|
signal-handle |
int |
siginfo_t * |
void (*)(void) |
|
signal-clear |
int |
— |
— |
|
start |
— |
— |
— |
一部の proc プローブは、lwpsinfo_t 型の引数をとります。構造体 lwpsinfo_t については、proc(4) に文書化されています。DTrace コンシューマで使用可能な構造体 lwpsinfo_t の定義は、次のとおりです。
typedef struct lwpsinfo {
int pr_flag; /* flags; see below */
id_t pr_lwpid; /* LWP id */
uintptr_t pr_addr; /* internal address of thread */
uintptr_t pr_wchan; /* wait addr for sleeping thread */
char pr_stype; /* synchronization event type */
char pr_state; /* numeric thread state */
char pr_sname; /* printable character for pr_state */
char pr_nice; /* nice for cpu usage */
short pr_syscall; /* system call number (if in syscall) */
int pr_pri; /* priority, high value = high priority */
char pr_clname[PRCLSZ]; /* scheduling class name */
processorid_t pr_onpro; /* processor which last ran this thread */
processorid_t pr_bindpro; /* processor to which thread is bound */
psetid_t pr_bindpset; /* processor set to which thread is bound */
} lwpsinfo_t;
pr_flag フィールドは、プロセスについて記述するフラグが格納されているビットマスクです。表 25–3 に、これらのフラグとその意味を示します。
表 25–3 pr_flag の値|
PR_ISSYS |
プロセスはシステムプロセスです。 |
|
PR_VFORKP |
プロセスは vfork(2) の子の親です。 |
|
PR_FORK |
プロセスがフォーク時継承モードを設定しました。 |
|
PR_RLC |
プロセスが最終終了時実行モードを設定しました。 |
|
PR_KLC |
プロセスが最終終了時終了モードを設定しました。 |
|
PR_ASYNC |
プロセスが非同期停止モードを設定しました。 |
|
PR_MSACCT |
プロセスが microstate アカウンティングを有効にしました。 |
|
PR_MSFORK |
プロセスの microstate アカウンティングがフォーク時に継承されました。 |
|
PR_BPTADJ |
プロセスがブレークポイント調整モードを設定しました。 |
|
PR_PTRACE |
プロセスが ptrace(3C) 互換モードを設定しました。 |
|
PR_STOPPED |
スレッドは停止した LWP です。 |
|
PR_ISTOP |
スレッドは重要なイベントで停止した LWP です。 |
|
PR_DSTOP |
スレッドは停止指令が有効になっている LWP です。 |
|
PR_STEP |
スレッドはシングルステップ指令が有効になっている LWP です。 |
|
PR_ASLEEP |
スレッドはシステムコール内で割り込み可能なスリープ状態になっている LWP です。 |
|
PR_DETACH |
スレッドは切り離された LWP です。pthread_create(3C) と pthread_join(3C) のマニュアルページを参照してください。 |
|
PR_DAEMON |
スレッドはデーモン LWP です。pthread_create(3C) のマニュアルページを参照してください。 |
|
PR_AGENT |
スレッドはプロセスのエージェント LWP です。 |
|
PR_IDLE |
スレッドは CPU のアイドルスレッドです。アイドルスレッドは、その CPU の実行キューが空のときにだけ実行されます。 |
pr_addr フィールドは、スレッドを表す非公開のカーネル内データ構造のアドレスです。データ構造体が非公開でも、pr_addr フィールドは、スレッドの有効期限が切れるまで、そのスレッド固有のトークンとして使用できます。
pr_wchan フィールドは、同期オブジェクト上でスレッドがスリープ状態になっているときに設定されます。pr_wchan フィールドの意味はカーネル実装以外に対しては公開されませんが、フィールド自体は、同期オブジェクトに固有のトークンとして使用できます。
pr_stype フィールドは、同期オブジェクト上でスレッドがスリープ状態になっているときに設定されます。表 25–4 に、pr_stype フィールドに入る値を一覧します。
表 25–4 pr_stype の値|
SOBJ_MUTEX |
カーネル相互排他同期オブジェクト。カーネル内の共有データ領域へのアクセスを直列化するために使用します。カーネル相互排他同期オブジェクトの詳細については、第 18 章lockstat プロバイダと mutex_init(9F) のマニュアルページを参照してください。 |
|
SOBJ_RWLOCK |
カーネル読み取り/書き込み同期オブジェクト。カーネル内の共有オブジェクトへのアクセスを同期化するために使用します。カーネル内の共有オブジェクトへのアクセスでは、同時に複数の読み取り、または単一の書き込みが許可されます。カーネル読み取り/書き込み同期オブジェクトの詳細については、第 18 章lockstat プロバイダと rwlock(9F) のマニュアルページを参照してください。 |
|
SOBJ_CV |
条件変数同期オブジェクト。条件変数は、一定の条件が揃うまで待機し続けるように設計されています。通常、条件変数は、共有データ領域へのアクセス以外の目的で同期化を行うために使用します。条件変数は、一般的にプロセスがプログラムに従って待機するときに使用されます。たとえば、poll(2)、pause(2)、wait(3C) などでブロックが発生した場合に使用されます。 |
|
SOBJ_SEMA |
セマフォ同期オブジェクト。条件変数オブジェクトと同じく、所有権の概念を追跡しない汎用同期オブジェクトです。所有権は、Solaris カーネル内で優先順位の継承を行うときに必要になります。このため、セマフォオブジェクト内に固有の所有権がない場合、これらを広く利用することができません。詳細については、semaphore(9F)を参照してください。 |
|
SOBJ_USER |
ユーザーレベル同期オブジェクト。ユーザーレベル同期オブジェクト上でのすべてのブロックは、SOBJ_USER 同期オブジェクトで処理されます。ユーザーレベル同期オブジェクトには、mutex_init(3C)、sema_init(3C)、rwlock_init(3C)、cond_init(3C) で作成されたものと、これらと同等の POSIX コマンドで作成されたものがあります。 |
|
SOBJ_USER_PI |
優先順位の継承を行うユーザーレベル同期オブジェクト。所有権を追跡する一部のユーザーレベル同期オブジェクトでは、優先順位の継承も行うことができます。たとえば、pthread_mutex_init(3C) で作成された相互排他オブジェクトは、pthread_mutexattr_setprotocol(3C) を使って優先順位を継承できます。 |
|
SOBJ_SHUTTLE |
往復同期オブジェクト。往復オブジェクトは、door の実装に使用します。詳細については、door_create(3DOOR) を参照してください。 |
pr_state フィールドには、表 25–5 に示すいずれかの値が設定されます。pr_sname フィールドには、同じ表の丸括弧内の文字が設定されます。
表 25–5 pr_state の値|
SSLEEP (S) |
スレッドはスリープ中です。sched:::sleep プローブは、スレッドが SSLEEP 状態に移行する直前に起動します。 |
|
SRUN (R) |
スレッドは実行可能ですが、現在実行されていません。sched:::enqueue プローブは、スレッドが SRUN 状態に移行する直前に起動します。 |
|
SZOMB (Z) |
スレッドはゾンビ LWP です。 |
|
SSTOP (T) |
スレッドは、明示的な proc(4) 指令またはその他の停止機構により停止しています。 |
|
SIDL (I) |
スレッドは、プロセス作成中の中間状態です。 |
|
SONPROC (O) |
CPU 上でスレッドが実行されています。sched:::on-cpu プローブは、スレッドが SONPROC 状態に移行した直後に、SONPROC スレッドのコンテキストで起動します。 |
一部の proc プローブは、psinfo_t 型の引数をとります。構造体 psinfo_t については、proc(4) に文書化されています。DTrace コンシューマで使用可能な構造体 psinfo_t の定義は、次のとおりです。
typedef struct psinfo {
int pr_nlwp; /* number of active lwps in the process */
pid_t pr_pid; /* unique process id */
pid_t pr_ppid; /* process id of parent */
pid_t pr_pgid; /* pid of process group leader */
pid_t pr_sid; /* session id */
uid_t pr_uid; /* real user id */
uid_t pr_euid; /* effective user id */
gid_t pr_gid; /* real group id */
gid_t pr_egid; /* effective group id */
uintptr_t pr_addr; /* address of process */
dev_t pr_ttydev; /* controlling tty device (or PRNODEV) */
timestruc_t pr_start; /* process start time, from the epoch */
char pr_fname[PRFNSZ]; /* name of execed file */
char pr_psargs[PRARGSZ]; /* initial characters of arg list */
int pr_argc; /* initial argument count */
uintptr_t pr_argv; /* address of initial argument vector */
uintptr_t pr_envp; /* address of initial environment vector */
char pr_dmodel; /* data model of the process */
taskid_t pr_taskid; /* task id */
projid_t pr_projid; /* project id */
poolid_t pr_poolid; /* pool id */
zoneid_t pr_zoneid; /* zone id */
} psinfo_t;
pr_dmodel フィールドには、32 ビットプロセスであることを示す PR_MODEL_ILP32 と 64 ビットプロセスであることを示す PR_MODEL_LP64 のいずれかが設定されます。
exec プローブを使用すると、どのプログラムがだれによって実行されているか、簡単に調べることができます。次の例を参照してください。
#pragma D option quiet
proc:::exec
{
self->parent = execname;
}
proc:::exec-success
/self->parent != NULL/
{
@[self->parent, execname] = count();
self->parent = NULL;
}
proc:::exec-failure
/self->parent != NULL/
{
self->parent = NULL;
}
END
{
printf("%-20s %-20s %s\n", "WHO", "WHAT", "COUNT");
printa("%-20s %-20s %@d\n", @);
}
ビルドマシン上でしばらくの間このスクリプトを実行すると、次のような出力が得られます。
# dtrace -s ./whoexec.d ^C WHO WHAT COUNT make.bin yacc 1 tcsh make 1 make.bin spec2map 1 sh grep 1 lint lint2 1 sh lint 1 sh ln 1 cc ld 1 make.bin cc 1 lint lint1 1 sh lex 1 make.bin mv 2 sh sh 3 sh make 3 sh sed 4 sh tr 4 make make.bin 4 sh install.bin 5 sh rm 6 cc ir2hf 33 cc ube 33 sh date 34 sh mcs 34 cc acomp 34 sh cc 34 sh basename 34 basename expr 34 make.bin sh 87 |
プログラムが作成されてから終了するまでの実行時間を調べたい場合は、次の例のように start プローブと exit プローブを有効にします。
proc:::start
{
self->start = timestamp;
}
proc:::exit
/self->start/
{
@[execname] = quantize(timestamp - self->start);
self->start = 0;
}
ビルドサーバー上で数秒間このスクリプトを実行すると、次のような出力が得られます。
# dtrace -s ./progtime.d
dtrace: script './progtime.d' matched 2 probes
^C
ir2hf
value ------------- Distribution ------------- count
4194304 | 0
8388608 |@ 1
16777216 |@@@@@@@@@@@@@@@@ 14
33554432 |@@@@@@@@@@ 9
67108864 |@@@ 3
134217728 |@ 1
268435456 |@@@@ 4
536870912 |@ 1
1073741824 | 0
ube
value ------------- Distribution ------------- count
16777216 | 0
33554432 |@@@@@@@ 6
67108864 |@@@ 3
134217728 |@@ 2
268435456 |@@@@ 4
536870912 |@@@@@@@@@@@@ 10
1073741824 |@@@@@@@ 6
2147483648 |@@ 2
4294967296 | 0
acomp
value ------------- Distribution ------------- count
8388608 | 0
16777216 |@@ 2
33554432 | 0
67108864 |@ 1
134217728 |@@@ 3
268435456 | 0
536870912 |@@@@@ 5
1073741824 |@@@@@@@@@@@@@@@@@@@@@@@@@ 22
2147483648 |@ 1
4294967296 | 0
cc
value ------------- Distribution ------------- count
33554432 | 0
67108864 |@@@ 3
134217728 |@ 1
268435456 | 0
536870912 |@@@@ 4
1073741824 |@@@@@@@@@@@@@@ 13
2147483648 |@@@@@@@@@@@@ 11
4294967296 |@@@ 3
8589934592 | 0
sh
value ------------- Distribution ------------- count
262144 | 0
524288 |@ 5
1048576 |@@@@@@@ 29
2097152 | 0
4194304 | 0
8388608 |@@@ 12
16777216 |@@ 9
33554432 |@@ 9
67108864 |@@ 8
134217728 |@ 7
268435456 |@@@@@ 20
536870912 |@@@@@@ 26
1073741824 |@@@ 14
2147483648 |@@ 11
4294967296 | 3
8589934592 | 1
17179869184 | 0
make.bin
value ------------- Distribution ------------- count
16777216 | 0
33554432 |@ 1
67108864 |@ 1
134217728 |@@ 2
268435456 | 0
536870912 |@@ 2
1073741824 |@@@@@@@@@ 9
2147483648 |@@@@@@@@@@@@@@@ 14
4294967296 |@@@@@@ 6
8589934592 |@@ 2
17179869184 | 0
|
特定のプロセスの実行にかかる時間ではなく、個々のスレッドの実行にかかる時間を調べることもできます。以下の例では、この目的で lwp-start プローブと lwp-exit プローブを使用する方法を紹介します。
proc:::lwp-start
/tid != 1/
{
self->start = timestamp;
}
proc:::lwp-exit
/self->start/
{
@[execname] = quantize(timestamp - self->start);
self->start = 0;
}
NFS /カレンダサーバー上でこのスクリプトを実行すると、次のような出力が得られます。
# dtrace -s ./lwptime.d
dtrace: script './lwptime.d' matched 3 probes
^C
nscd
value ------------- Distribution ------------- count
131072 | 0
262144 |@ 18
524288 |@@ 24
1048576 |@@@@@@@ 75
2097152 |@@@@@@@@@@@@@@@@@@@@@@@ 245
4194304 |@@ 22
8388608 |@@ 24
16777216 | 6
33554432 | 3
67108864 | 1
134217728 | 1
268435456 | 0
mountd
value ------------- Distribution ------------- count
524288 | 0
1048576 |@ 15
2097152 |@ 24
4194304 |@@@ 51
8388608 |@ 17
16777216 |@ 24
33554432 |@ 15
67108864 |@@@@ 57
134217728 |@ 28
268435456 |@ 26
536870912 |@@ 39
1073741824 |@@@ 45
2147483648 |@@@@@ 72
4294967296 |@@@@@ 77
8589934592 |@@@ 55
17179869184 | 14
34359738368 | 2
68719476736 | 0
automountd
value ------------- Distribution ------------- count
1048576 | 0
2097152 | 3
4194304 |@@@@ 146
8388608 | 6
16777216 | 6
33554432 | 9
67108864 |@@@@@ 203
134217728 |@@ 87
268435456 |@@@@@@@@@@@@@@@ 534
536870912 |@@@@@@ 223
1073741824 |@ 45
2147483648 | 20
4294967296 | 26
8589934592 | 20
17179869184 | 19
34359738368 | 7
68719476736 | 2
137438953472 | 0
iCald
value ------------- Distribution ------------- count
8388608 | 0
16777216 |@@@@@@@ 20
33554432 |@@@ 9
67108864 |@@ 8
134217728 |@@@@@ 16
268435456 |@@@@ 11
536870912 |@@@@ 11
1073741824 |@ 4
2147483648 | 2
4294967296 | 0
8589934592 |@@ 8
17179869184 |@ 5
34359738368 |@ 4
68719476736 |@@ 6
137438953472 |@ 4
274877906944 | 2
549755813888 | 0
|
シグナルの送受信のプロセスを特定するには、次の例のように signal-send プローブを使用します。
#pragma D option quiet
proc:::signal-send
{
@[execname, stringof(args[1]->pr_fname), args[2]] = count();
}
END
{
printf("%20s %20s %12s %s\n",
"SENDER", "RECIPIENT", "SIG", "COUNT");
printa("%20s %20s %12d %@d\n", @);
}
このスクリプトを実行すると、次のような出力が得られます。
# dtrace -s ./sig.d
^C
SENDER RECIPIENT SIG COUNT
xterm dtrace 2 1
xterm soffice.bin 2 1
tr init 18 1
sched test 18 1
sched fvwm2 18 1
bash bash 20 1
sed init 18 2
sched ksh 18 15
sched Xsun 22 471
|
以下の表に、proc プロバイダの安定性を DTrace の安定性機構に従って示します。安定性機構の詳細については、第 39 章安定性を参照してください。
|
要素 |
名前の安定性 |
データの安定性 |
依存クラス |
|---|---|---|---|
|
プロバイダ |
発展中 |
発展中 |
ISA |
|
モジュール |
非公開 |
非公開 |
不明 |
|
機能 |
非公開 |
非公開 |
不明 |
|
名前 |
発展中 |
発展中 |
ISA |
|
引数 |
発展中 |
発展中 |
ISA |