Chrome の Linux版と Chrome OS版では、D-Bus というIPC(プロセス間通信)システムを使って、Chrome以外のプログラムとの通信を行なっている(Chrome内でのIPCはまた別)。
D-Busの特徴のひとつは dbus-send というコマンドラインツールを使ってIPCのテストができることだ。Chrome OSのオープンソース版の Chromium OSでは Ctrl-Alt-F2 を叩くとテキストコンソールに行けるので、ここから、dbus-send を使うことができる。
つい先日、ちょっとした確認のために、テキストコンソールから dbus-send を叩いて Chromium (Chromeのオープンソース版)に IPCのリクエストを投げてみた。
いつもならすぐに結果が返ってくるのだが、今回は反応がない。タイムアウトして不吉なエラーメッセージが表示された。これはまずい。dbus-send を何度叩いても結果は変わらず、毎回、25秒でタイムアウトだ。これは非常にまずい。。
原因究明のため、とりあえずログを仕込んだバイナリを作って試してみたが、すぐにはわからない。IPCのリクエストを受け取っていることは確かなのだが、結果を返す前のどこかで止まってしまうのだ。一体どこで?もっとログを仕込んでみるかな。。
とかなんとかやっているうちに、予想外のことが起きた。気づくと、先ほどまで確実にタイムアウトしていた dbus-send コマンドが正常に終了して結果を表示していたのだ。なぜそんなことが?レースコンディションでたまたま動いてしまったのだろうか?だとすると、ますます厄介なバグなのかもしれないぞ。。
いや、待て待て。何か今、自分は変な操作をしなかったのだろうか?コマンドを実行した後に。。そうだ、タイムアウトを待っている間、無意識的に Ctrl-Alt-F1 と Ctrl-Alt-F2 を交互に叩いて、 GUIが表示されているメインのスクリーンとテキストコンソールを切り替えていたような気がする。でもそんなことでIPCが影響を受けるだろうか?
そんなわけはない!と思ってふたたび同じことをやってみた。テキストコンソールから dbus-send コマンドを実行する。Ctrl-Alt-F1でメインのスクリーンへ切り替える。Ctrl-Alt-F2で再びテキストコンソールへ戻る。dbus-send は正常に終了している。何度やっても結果は同じだ。おかしい。そもそも、こんな変な操作をしなくたって今までは動いてたはずなのだが。。
この不思議な現象について、さっそく同僚に話しに行ったところ、「ああ、最近、メインスレッドのメッセージループの実装が切り替わったからその影響じゃない?」とのこと。で、その新しいメッセージループでは、画面がテキストコンソールに切り替わっている間は、どういうわけかループが止まってしまうのだ。これはメインスレッドが止まるに等しい。
IPCのリクエストの処理の一部はメインスレッドで実行されるので、メインスレッドが止まっていると、そこで止まってしまう。一方、IPCの通信部分は別スレッドで動いているのでリクエストを受け取るところまでは動く。受け取ったリクエストを処理できないからタイムアウトが発生する。
と、まあ、原因がわかってしまうとどうってことなかったのだが、画面の切り替えでIPCの流れを制御できるという挙動はなかなか画期的で、同僚に見せたら結構、受けていた。時間を食ってしまったけど、受けたからまあいいかなと。。