先日の続き。
file:open/2 に raw オプションを指定した場合の IoDevice の実体はポート+αだった。ということは、ポートに対するBIFを使えば、プロセス終了時の挙動も確かめられるはずである。
次のようなコードで確認してみた(rpc/2 の定義は省略)。
-module(raw_test). -compile(export_all). start() -> Pid = spawn(fun test/0), io:format("The process which opened the file is ~p.~n", [Pid]), Port = rpc(Pid, get), io:format("The opened port is ~p.~n~n", [Port]), io:format("is_process_alive: ~p~n", [erlang:is_process_alive(Pid)]), io:format("port_info: ~p~n~n", [erlang:port_info(Port)]), rpc(Pid, close), io:format("is_process_alive: ~p~n", [erlang:is_process_alive(Pid)]), io:format("port_info: ~p~n", [erlang:port_info(Port)]). test() -> %% IoDeviceのUndocumentedな内部構造に依存 {ok, {_,_,{Port,_}}} = file:open("raw_test.erl", [read, raw]), test(Port). test(Port) -> receive {From, get} -> From ! {self(), Port}, test(Port); {From, close} -> From ! {self(), close} end.
実行結果は次のようになった。
The process which opened the file is <0.60.0>.
The opened port is #Port<0.1695>.
is_process_alive: true
port_info: [{name,"efile"},
{links,[<0.60.0>]},
{id,1695},
{connected,<0.60.0>},
{input,9},
{output,18}]
is_process_alive: false
port_info: undefined
ファイルを開いたプロセスが生きているときにはきちんとポートの情報が取れる。links や connected に pid が入っていることも確認できる。プロセスが終了するとポート情報は undefined となり、ポートが閉じられたことが分かる。
IoDevice の内部実装についてはともかく、「ファイルを開いたプロセスが終了したとき、自動的にファイルが閉じられる」という挙動については信用しても良さそうだ。例えば『プログラミングErlang』14章のSHOUTcastサーバではクライアントがTCP接続を閉じたときにコントローラプロセスがクラッシュするという仕様になっているが、このときにもきちんとファイルは close される、ということになる。