[ruby-list:50837] Re: Rubyとファイルディスクリプタの継承について

From: Kazuhiro NISHIYAMA <zn@...>
Date: 2019-10-22 06:21:14 UTC
List: ruby-list #50837
西山和広です。

On Thu, 12 Sep 2019 22:29:45 +0900,
MASAKI Haruka wrote:
> 
> 正木です。
> 
> Rubyにおいて状況によって子プロセスにファイルディスクリプタが引き継がれていなかったり、
> EOFに達した状態で引き渡されたりしている、
> ということなのですが、perl及びpythonでも同様の状況を確認しているため、Ruby固有ではないかもしれません。
> しかし、調べてみてもどうにも自己解決に至らなかったのでご助力お願いします。
> 
> 次の例では子プロセスのcatにファイルディスクリプタが引き渡され、catから一行読めています。
> 
> % ruby -e 'IO.popen(["cat"], "r") {|io| puts "#{io.gets} GET" }' -e 'p STDIN.eof?' -e 'puts STDIN.read' < 5LINES 
> AAA
>  GET
> true
> 
> しかし、事前にIO#eof?すると、catにはファイルディスクリプタが引き継がれていません。
> 
> % ruby -e 'p STDIN.eof?' -e 'IO.popen(["cat"], "r") {|io| puts "#{io.gets} GET" }' -e 'p STDIN.eof?' -e 'puts STDIN.read' < 5LINES
> false
>  GET
> false
> AAA
> BBB
> CCC
> DDD
> EEE
> FFF
> 
> 次の例ではrubyは一行読んでいるだけですが、EOFまで進んでしまいます。
> 
> % print -l A B C D E | ( ruby -e 'gets' && cat )
> 
> これはファイルから読んでも同じです。
> 
> % ( ruby -e 'gets' && cat ) < file

ファイルディスクリプタが引き継がれていないというのはどうやって確認していますか?
たぶん親プロセスがバッファの長さまで読み込んで (ファイルが短いので EOF まで)、
その状態のファイルディスクリプタが継承されているだけではないでしょうか。

sysread のようにシステムコールで直接読み込めば読み込み過ぎないのを確認できます。

% (ruby -e 'gets' -e 'exec(*%w"head -n 1")' ) < /etc/hosts
% (ruby -e 'STDIN.sysread(3)' -e 'exec(*%w"head -n 1")' ) < /etc/hosts
.0.0.1  localhost
% (ruby -e 'gets' -e 'exec("readlink", "/proc/self/fd/0")' ) < /etc/hosts
/etc/hosts

> ところが、IO#posするとcatには2行目以降が渡るようになります。
> 
> % ( ruby -e 'gets' -e 'STDIN.pos' && cat ) < file
> B
> C
> D
> E
> 
> execした場合も同様で普通はからっぽですが
> 
> % ( ruby -e 'gets' -e 'exec("cat")' ) < file
> 
> IO#posするとcatに渡ります。
> 
> % ( ruby -e 'gets' -e 'STDIN.pos' -e 'exec("cat")' ) < file
> B
> C
> D
> E
> 
> これはどういったことが起きているのでしょうか?

pos の中で lseek しているので、ファイルディスクリプタの方も
読み込み位置が戻っているようです。


-- 
|ZnZ(ゼット エヌ ゼット)
|西山和広(Kazuhiro NISHIYAMA)

In This Thread