/proc
もう夏はすっかり終わって、幽霊シーズンも沈静化しちゃったけど、ゾンビを作り出してみる。 ゾンビは、子が死んでも、親が看取るのを放棄すると出来る。
int fork(void);
int sleep(int);
int main(){
if (fork() == 0){
return 0;
}
return sleep(500);
}
今回は、脳内cppを適用して、いいかげんに関数の型を定義しておいた。(正確なやつは、man fork等として調べてね)あれ? returnの型はどうなるんだろう? 書かなくてもコンパイラーが文句を言ってこなかったぞ。K&R本を見たら、returnは、return 式; と言う文になってた。(文と言う事は、returnはキーワードです)
このmainを見てたら、書き換え可能って事に気が付いたよ。
int main(){ return (fork() ? sleep(500) : 0); }
面白い。そして、更に面白いのがこれ
遊んじゃったな。話を戻そう。
子が死んでも、親は忙しいって言って、子をほったらかしにした図。酒喰らって寝てるんだか、 パチンコに勤しんでいるんだか、秋の競馬に出かけているんだか(指紋認証のカードで、馬券が買えて、馬券データはカードの中。馬券の紛失を防げるし、払い戻しもカードにチャージされるとか、どこまで搾取する積りや >JRA)、そういう時にゾンビだぞが現れる。
debian:z$ ./a.out & [1] 4335 debian:z$ ps 4335 4336 4335 pts/2 S 0:00 ./a.out 4336 pts/2 Z 0:00 [a.out] <defunct>
ステータスがZってなってる、defunctってのは、辞書を引いたら、今は亡きって出てたぞ。
ob6$ ps l UID PID PPID CPU PRI NI VSZ RSS WCHAN STAT TT TIME COMMAND 1000 10506 73617 0 -22 0 0 0 - Z p0 0:00.00 (a.out) 1000 73617 84840 0 10 0 228 772 nanosle I p0 0:00.00 ./a.out 1000 84840 44929 0 18 0 796 828 pause Ssp p0 0:00.12 -ksh (ksh
こちらはOpenBSDでの結果。ゾンビはカッコ付きになるのね。終了しちゃってるのでメモリーは既に取り上げられてる事が分かる。親の名前(じゃなくて、国民総番号)だけは、覚えてる。親の親は、kshって事も分かるな。
こんな薄情な親でも、生きている間は、仏様のinitは手を出さない。(ひょっとして親の気が変わってwaitするかも知れないからね。)しかし、親が死ぬと、哀れに思ったinitは、養子として受け入れ、成仏させてくれる。仏教思想がいきづいていますなあ。
あれ? unixって発祥地はキリストの国だよな。かの国にもそういう思想は有るのかな? そういう事は、あの人に聞けばいいのかな?
ある人が言ってた、『盆はご先祖様とのオフ会』と。連綿と続く命の営みの末に、自分が居る事を忘れちゃいけないぞ。
ps
例によって、psが何をやってるか見る。ps.cが主戦場。
270│ if (nlistf == NULL && memf == NULL && swapf == NULL) {
271├───────────────> kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
272│ kvm_sysctl_only = 1;
:
326│ /*
327│ * select procs
328│ */
329├───────> kp = kvm_getprocs(kd, what, flag, sizeof(*kp), &nentries);
主要部分は以上。
(gdb) p *kp
$2 = {
p_forw = 0,
p_back = 0,
:
p_pid = 83638,
p_ppid = 82407,
p_sid = 83638,
p__pgid = 83638,
p_tpgid = 83638,
p_uid = 1000,
:
p_comm = "a.out", '\000' <repeats 18 times>,
p_wmesg = "\000\000\000\000\000\000\000",
p_wchan = 0,
p_login = "sakae", '\000' <repeats 26 times>,
p_vm_rssize = 301,
:
p_emul = "native\000",
p_rlim_rss_cur = 2055917568,
p_cpuid = 1,
なんか、見慣れたデータが含まれていますなあ。この巨大な構造体から、指定されたデータだけを抜き出して、整形して、並べ替えて、表示って塩梅だな。
kvm_getprocsの2番目の引数whatは、下記が選べるとな。
KERN_PROC_KTHREAD all processes (user-level plus kernel
threads)
KERN_PROC_ALL all user-level processes
KERN_PROC_PID processes with process ID arg
KERN_PROC_PGRP processes with process group arg
KERN_PROC_SESSION processes with session arg
KERN_PROC_TTY processes with tty(4) arg
KERN_PROC_UID processes with effective user ID arg
KERN_PROC_RUID processes with real user ID arg
psのために用意されたようなものだな。
/proc
リナについては、psを見る代わりに有名な、/procを見るか。
何でもファイルの思想によって、際限なく見せているね。こんなに開陳していいのか?
/proc in *BSD
そう思って、BSD陣営も見ておく。
OpenBSDには、そんなの無い。NetBSDは最初から見える。FreeBSDは、
mount -t procfs proc /proc
すると、見えるようになる。主張が違うんだなあ。で、FreeBSDのやつ。procfs(5) で、興味あるのは、
status The process status. This file is read-only and returns a single
line containing multiple space-separated fields as follows:
o command name
o process id
o parent process id
o process group id
o session id
o device name of the controlling terminal, or a minus sign
("-") if there is no controlling terminal.
o a list of process flags: ctty if there is a controlling
terminal, sldr if the process is a session leader, noflags if
neither of the other two flags are set.
o the process start time in seconds and microseconds, comma
separated.
o the user time in seconds and microseconds, comma separated.
o the system time in seconds and microseconds, comma separated.
o the wait channel message
o the process credentials consisting of the effective user id
and the list of groups (whose first member is the effective
group id) all comma separated.
o the hostname of the jail in which the process runs, or `-' to
indicate that the process is not running within a jail.
ぐらいかな。
sakae@fb:~ % sleep 1000 & [2] 763 sakae@fb:~ % cat /proc/763/status sleep 763 695 763 695 pts/1 ctty 1535867324,723778 0,0 0,1244 nanslp 1001 1001 1001,1001,0,5 -
セキュリティーに五月蝿いOpenBSDでも、世間の風には抵抗出来ないだろう。man -k proc とかやってみる。
ob6$ procmap procmap: /dev/mem: Permission denied ob6$ doas procmap procmap: /dev/mem: Operation not permitted
それらしい雰囲気のコマンドが見つかったので、実行してみたけどエラー。諦めてman。
NAME
procmap - display process memory map
procmap requires the ability to open /dev/kmem which may be restricted
based upon the value of the kern.allowkmem sysctl(8).
ob6# sysctl kern.allowkmem=1 sysctl: kern.allowkmem: Operation not permitted
オンラインでも書き換えを許していない。/etc/sysctl.confに設定を書いてからrebootして やっと、有効になる。
ob6$ sleep 1000 & [1] 28072 ob6$ procmap 28072 procmap: /dev/mem: Permission denied
でも、一般ユーザーには、解放されていない。rootさんの権限を得て、やっと見られるぞ。
ob6$ doas procmap 28072 0000000000001000 0K [ anon ] 0000009F63B00000 84K read/exec /bin/sleep 0000009F63C14000 24K read /bin/sleep 0000009F63D00000 0K [ anon ] 0000009F63D19000 4K read /bin/sleep 0000009F63D1A000 4K read/write /bin/sleep 0000009F63D1B000 4K read/write [ anon ] 0000009F63D1C000 20K read/write [ anon ] 000000A163D00000 0K [ anon ] 000000A1BA903000 4K read/exec [ uvm_aobj ] 000000A21B317000 4K read/write [ anon ] 000000A223D85000 4K read [ anon ] 00007F7FFDEF0000 29696K [ stack ] 00007F7FFFBF0000 4032K read/write [ anon ] 00007F7FFFFE0000 60K read/write [ anon ] 00007F7FFFFEF000 4K [ anon ] total 4244K
気持ち、融通を利かせてくれている。リナは巨大な利権だからなあ。そっぽを向くわけにはいかないのね。
-l Dumps information in a format like the contents of the maps
pseudo-file under the /proc file system which was, in turn,
modeled after the similarly named entry in the Linux /proc
file system. When combined with the -v option, identifiers
for all entries are printed.
OpenBSD3.5の時に、NetBSDで知られてるpmapをお手本に導入したって説明されてた。大人になれよと諭されたんだな。
procじゃないけど、たまたま見つけた面白いデータ。
ob6$ sysctl -a | grep men kern.malloc.buckets=16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288 kern.malloc.bucket.16=(calls = 999 total_allocated = 512 total_free = 231 elements = 256 high watermark = 1280 could_free = 0) kern.malloc.bucket.32=(calls = 1961 total_allocated = 768 total_free = 98 elements = 128 high watermark = 640 could_free = 0) : kern.malloc.bucket.262144=(calls = 0 total_allocated = 0 total_free = 0 elements = 1 high watermark = 5 could_free = 0) kern.malloc.bucket.524288=(calls = 1 total_allocated = 1 total_free = 0 elements = 1 high watermark = 5 could_free = 0)
カーネル内でメモリーが必要になった時、まさかGC(ガベコレ)やる訳にいかない。どう逃げるかと言うと、メモリーを要求する時、要求サイズに応じて、エリアを分割してるんだな。そうする事によって、メモリーの無駄を無くすとな。それから、メモリーの割り当て、返却処理も高速化されるんかな。
kern.mallocと名の付くものを見ていくと、他にも有った。
kern.malloc.kmemnames=free,,devbuf,,pcb,rtable,,,,ifaddr...... kern.malloc.kmemstat.ifaddr=(inuse = 27, calls = 28, memuse = 8K, limblocks = 0, mapblocks = 0, maxused = 8K, limit = 78644K, spare = 0, sizes = (32,64,128,256,4096)) kern.malloc.kmemstat.mount=(inuse = 2, calls = 2, memuse = 2K, limblocks = 0, mapblocks = 0, maxused = 2K, limit = 78644K, spare = 0, sizes = (1024))
とか、メモリーの使い方とかも、リアルタイムに取れるっぽい。こういうのも広義のprocですかね。
sysctl(2)に、他の面白そうなものが載ってる。と思ったら、コマンドを使えとか言われた。
ob6$ sysctl kern.mbstat sysctl: use netstat to view kern.mbstat ob6$ sysctl kern.proc sysctl: use ps to view kern.proc information
めげずに、こんなのを見る。
ob6$ sysctl kern.timecounter.choice kern.timecounter.choice=i8254(0) acpihpet0(1000) tsc(2000) acpitimer0(1000) dummy(-1000000) ob6$ sysctl kern.timecounter.hardware kern.timecounter.hardware=tsc
時計と言うか計時するカウンターが色々あるよ。数字の大きいやつが優秀ですと。それで、今kernelがどれを使ってるか、教えてもらう。
カーネルの属性だけじゃなく、ハードウェアの状況も、
ob6$ sysctl hw hw.machine=amd64 hw.model=Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz hw.ncpu=2 hw.byteorder=1234 hw.pagesize=4096 hw.disknames=cd0:,wd0:42ea0f64e77db907 hw.diskcount=2 hw.sensors.acpiac0.indicator0=On (power supply) :
この他にネット関係の情報がいやになる程、取れる。色々チューニングが出来るって事だな。 よって、/procなんて無くてもへっちゃらだい。
voluntary context switch
以前、\timeを調べていた時に忘れていた事があった。自発的なコンテキストスイッチの件。 調べてみると、sched_bsd.c の yield が呼び出されているようなので、BPを貼ってみた。
#0 yield () at /usr/src/sys/kern/sched_bsd.c:297 #1 0xd0700e3e in uvm_pagezero_thread (arg=0xd17722cc) at /usr/src/sys/uvm/uvm_pmemrange.c:2014 #2 0xd089aec9 in proc_trampoline ()
290│ /*
291│ * General yield call. Puts the current process back on its run queue and
292│ * performs a voluntary context switch.
293│ */
294│ void
295│ yield(void)
296│ {
297│ struct proc *p = curproc;
298│ int s;
299│
300│ NET_ASSERT_UNLOCKED();
301│
302│ SCHED_LOCK(s);
303│ p->p_priority = p->p_usrpri;
304│ p->p_stat = SRUN;
305│ setrunqueue(p);
306├───────> p->p_ru.ru_nvcsw++;
307│ mi_switch();
308│ SCHED_UNLOCK(s);
309│ }
確かに、カウンターの値がインクリメントされてる。
軽くkernの中を調べてみたら、そこそこ呼んでいる所が見つかった。システムコールの一員なのね。
NAME
sched_yield - yield the processor
DESCRIPTION
The sched_yield() function makes the current thread yield the processor
and be put at the end of its run queue without altering its priority.
やる事ないから、CPUの権利を譲るわって、まるで日本人みたいな(最近は、米流に毒されて、がめつい奴らがのさばってきたけど)謙虚なシステムコールだ。
もう、これぐらいにしておくか。最後にまとめ
まとめ
パイプ屋さんが、残ってた。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char** argv)
{
pid_t pid;
int status;
int fd;
pid = fork();
if (pid == 0) {
// ファイルオープン
fd = open("./output", O_CREAT | O_WRONLY, 0666);
/*
* オープンしたファイルのディスクリプタを
* 標準出力に複製する
*/
dup2(fd, stdout);
close(fd); // 作成したディスクリプタはクローズ
execl("/bin/ls", "ls", (char *)NULL);
}
waitpid(pid, &status, 0);
printf ("child process (PID = %d) finished\n", pid);
return 0;
}
Same as ls >output