Rubyで遊んだ日々の記録。あくまで著者視点の私的な記録なので、正確さを求めないように。
Rubyと関係ない話題にはその旨注記しているはず。なので、一見関係無いように見える話題もどこかで関係あるのかもしれません。または、注記の書き忘れかもしれません...
_ 達人出版会さんから刊行されている話題の書『なるほどUnixプロセス ― Rubyで学ぶUnixの基礎』を紐解きながら、Windows版RubyがどーやってUnix版Rubyとスクリプトレベルの互換性を維持していたりいなかったりするのか、ということを解説してみようと思い立ってしまったのでありました。
puts Process.pid
とすればpidが確認できる(ところでなんでputsなの?)。
Windowsにはpsコマンドはないがtasklistコマンドがあって、それで現在実行中のプロセスのpidが確認できるので、比べてみるとよい。
_ Unixではgetpid(2)でpidを取っているわけだが、WindowsではAPIのGetCurrentProcessId()を利用している。
なお、Rubyソースコード上での煩雑な#ifとかを避けるため、実際にはwin32/win32.c内でrb_w32_getpid()という関数を定義し、これをinclude/ruby/win32.h内でgetpidという名前に#defineした上でRubyソースコードから利用している。
puts Process.ppid
とすればppidが確認できる。
tasklistコマンドの出力と比較すればわかるとおり、ちゃんと親のプロセス(普通の人ならcmd.exeになるはず)を指しているはずだ。
_ ところが、tasklistコマンドでは、あるプロセスのppidを表示させる方法が提供されていない。
それどころか、タスクマネージャーなどを使ってもppidを表示する方法はないはずだ。
_ 実は、Windowsでは「表向きは」プロセスに親子関係などは存在しないのだ。
Windowsではプロセスは生まれた瞬間から孤児なのである。不憫な...。
_ しかし、何事にも裏はあるわけで、やっぱりOSはプロセスの親子関係をしっかり覚えてはいるのである。
SysinternalsからProcess Walkerというツールを入手して確認してみてほしい。
膨大なプロセス群が、きっちりと親子関係順に並べて表示されるはずだ。
(Process Walkerは非常に便利なツールなので、Windowsプログラマならぜひとも入手しておいて使いこなしたいものである。)
_ さて、では、この表向きは存在しない親子関係、というかppidを、Windows版Rubyはどうやって掘り出しているのだろうか?
答えはwin32/win32.cのrb_w32_getppid()関数にある。
なんかいきなり複雑だが、要するにNtQueryInformationProcess()というAPIを呼び出してpbiなる構造体(ちなみに、PROCESS_BASIC_INFORMATIONという本名がある)を取得しており、その中のParentProcessIdメンバの値を返しているだけである。
Unixでgetppid(2)を呼ぶだけなのと比べればやや複雑だが、わかっちゃえばAPIを1個呼んでるだけだし大したことはない... と、思ったでしょ?
ところがどっこい、NtQueryInformationProcess()の説明をMSDN Libraryで見てみると、なんと、PROCESS_BASIC_INFORMATIONにはParentProcessIdなどというメンバは存在せず、該当する位置にはReserved3というメンバが冷たく置かれているだけなのだ。
_ というわけで、Windowsは表向きにはプロセスの親子関係を認めていない。
ただ、公式には認めないで、戸籍上の予備欄にこっそりと留めているだけなのである。
Windows版Rubyはそんな秘密の関係をあっさり暴き出す容赦のない処理系である。
_ こんな感じで、思い出したら時々なんか書きます。
なんかもう飽きてきたので続きそうな気がしないけど。
被捕捉アンテナ類
[Ant]
[Antenna-Julia]
[Rabbit's Antenna]
[Ruby hotlinks]