raw モードで開いたファイルの後始末

先日の続き。

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 される、ということになる。

Leave a Reply