2009年4月12日日曜日

Limbo でパイプを扱う

どう書く.org
http://ja.doukaku.org/127/
指定コマンドを別プロセスで起動

を考えてみました。
以前の投稿
http://inferno-hell.blogspot.com/2009/03/blog-post.html
をベースにしてみました。

パイプでのやり取りが難しく、結局C言語(posix)っぽくなりました。
明示的にパイプをクローズするのが簡単にはできないようではまりました。

以下コードです。
インデントがうまくいかなく、みづらいので、
気になる方はどう書く.orgの方の参照お願いします。
http://ja.doukaku.org/comment/8800/


implement d127;

include "sys.m";
sys: Sys;
include "draw.m";
include "sh.m";
sh: Sh;

d127: module{
init: fn(ctx: ref Draw->Context, argv: list of string);
};

init (ctx: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
sh = load Sh Sh->PATH;
buf := array[64] of byte;
fds := array[2] of ref Sys->FD;

argv = tl argv;
if(argv == nil){
return;
}
cmd := hd argv;

sys->pipe(fds); # open pipes
spawn child(ctx, fds[0], cmd);

# Read results of child process
n: int;
fds[0] = nil;
fdd := sys->open("/dev/cons", sys->OWRITE);
for(;;){
n = sys->read(fds[1], buf, len buf);
if(n == 0){
break;
}

# print result
sys->fprint(fdd, "%s", string buf[0:n]);
}
}

child (ctx: ref Draw->Context, fd: ref Sys->FD, cmd: string)
{
# duplicate stdout to the pipe
sys->dup(fd.fd, 1);

sh->system(ctx, cmd);

# pipe close
fdn := sys->open("/dev/null", sys->OWRITE);
sys->dup(fdn.fd, 1);
fd = nil;
}


ポイントはパイプをオープンして片方を子プロセスに渡すということと、
処理終了後になんとかパイプをクローズしているところです。

ファイルやパイプをクローズするにはcloseというシステムコールはなく、
どこからも参照しなくならないようにしなければなりません。
なので、三カ所で無理矢理パイプの参照を切っています。

1. 親プロセスの中、子プロセス呼び出し後、ファイルデスクリプタにnil代入
2. 子プロセスで、stdoutをパイプではなく、/dev/nullに
3. 子プロセスで、ファイルデスクリプタにnil代入

0 件のコメント:

コメントを投稿