https://bugs.ruby-lang.org/
https://bugs.ruby-lang.org/favicon.ico?1711330511
2010-08-10T16:21:13Z
Ruby Issue Tracking System
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12734
2010-08-10T16:21:13Z
akr (Akira Tanaka)
akr@fsij.org
<ul></ul><p>=begin<br>
2010年8月10日10:53 Yui NARUSE <a href="mailto:redmine@ruby-lang.org" class="email">redmine@ruby-lang.org</a>:</p>
<blockquote>
<p>以下のプログラムが FreeBSD で終了しません。<br>
(test/ruby/test_rubyoptions.rb の test_script_from_stdin より)<br>
Ubuntu 8.04 や Mac OS X 10.6 では終わることを確認しています。</p>
</blockquote>
<p>単純化してみました。<br>
パイプは関係ありません。</p>
<p>freebsd8(16:07:56)% cat z.rb<br>
require 'pty'<br>
PTY.getpty('sleep 1') do |r, w, pid|<br>
p pid<br>
w.print("a")<br>
Process.wait pid<br>
end<br>
puts :fin</p>
<p>freebsd8(16:07:58)% ./ruby -v z.rb<br>
ruby 1.9.3dev (2010-08-07 trunk 28906) [i386-freebsd8.1]<br>
32576<br>
(ここでハング)</p>
<p>他の端末から ps してみると、以下のようになります。</p>
<p>freebsd8(16:07:25)% ps u32576<br>
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND<br>
akr 32576 0.0 0.1 1536 504 7- SEs+ 4:07PM 0:00.00 sleep 1</p>
<p>STAT の意味は</p>
<pre><code>S Marks a process that is sleeping for less than about 20
seconds.
E The process is trying to exit.
s The process is a session leader.
+ The process is in the foreground process group of its
control terminal.
</code></pre>
<p>ということで、E のままで終わらないのがわかりません。</p>
<p>また、sleep 1 を ktrace sleep 1 にして kdump すると、</p>
<p>freebsd8(16:18:10)% kdump -E<br>
...<br>
33428 sleep 0.001572 RET sigprocmask 0<br>
33428 sleep 0.001611 CALL nanosleep(0xbfbfeaac,0)<br>
33428 sleep 1.001607 RET nanosleep 0<br>
33428 sleep 1.001672 CALL sigprocmask(SIG_BLOCK,0x2807acc0,0xbfbfea10)<br>
33428 sleep 1.001681 RET sigprocmask 0<br>
33428 sleep 1.001688 CALL sigprocmask(SIG_SETMASK,0x2807acd0,0)<br>
33428 sleep 1.001693 RET sigprocmask 0<br>
33428 sleep 1.001712 CALL sigprocmask(SIG_BLOCK,0x2807acc0,0xbfbfe9d0)<br>
33428 sleep 1.001718 RET sigprocmask 0<br>
33428 sleep 1.001723 CALL sigprocmask(SIG_SETMASK,0x2807acd0,0)<br>
33428 sleep 1.001742 RET sigprocmask 0<br>
33428 sleep 1.001757 CALL exit(0)</p>
<h2>というように nanosleep で 1秒待った後、exit(0) を呼んでいるようなのが<br>
観察されます。</h2>
<p>[田中 哲][たなか あきら][Tanaka Akira]</p>
<p>=end</p>
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12747
2010-08-10T23:32:37Z
akr (Akira Tanaka)
akr@fsij.org
<ul></ul><p>=begin<br>
2010年8月10日16:21 Tanaka Akira <a href="mailto:akr@fsij.org" class="email">akr@fsij.org</a>:</p>
<blockquote>
<p>freebsd8(16:07:56)% cat z.rb<br>
require 'pty'<br>
PTY.getpty('sleep 1') do |r, w, pid|<br>
p pid<br>
w.print("a")<br>
Process.wait pid<br>
end<br>
puts :fin</p>
</blockquote>
<p>C にしてさらに単純化するとこうですかね。</p>
<p>freebsd8(23:26:18)% cat t.c<br>
#include <stdlib.h><br>
#include <stdio.h><br>
#include <fcntl.h><br>
#include <sys/types.h><br>
#include <unistd.h><br>
#include <sys/wait.h></p>
<p>int main(int argc, char *argv[])<br>
{<br>
int m, s;<br>
char *slavedev;<br>
pid_t pid;<br>
int status;</p>
<p>if ((m = posix_openpt(O_RDWR|O_NOCTTY)) == -1) {<br>
perror("posix_openpt"); exit(1); }<br>
if (grantpt(m) == -1) { perror("grantpt"); exit(1); }<br>
if (unlockpt(m) == -1) { perror("unlockpt"); exit(1); }<br>
if ((slavedev = ptsname(m)) == NULL) { perror("ptsname"); exit(1); }<br>
if ((s = open(slavedev, O_RDWR|O_NOCTTY, 0)) == -1) {<br>
perror("open(slavedev)"); exit(1); }</p>
<p>pid = fork();<br>
if (pid == -1) { perror("fork"); exit(1); }<br>
if (pid == 0) {<br>
sleep(1);<br>
exit(0);<br>
}<br>
if (close(s) == -1) { perror("close"); exit(1); }</p>
<p>if (write(m, "a", 1) == -1) { perror("write"); exit(1); }</p>
<p>fprintf(stderr, "pid=%d\n", (int)pid);<br>
if (waitpid(pid, &status, 0) == -1) { perror("waitpid"); exit(1); }</p>
<p>return 0;<br>
}<br>
freebsd8(23:26:22)% gcc -Wall t.c<br>
freebsd8(23:28:02)% time ./a.out<br>
pid=68602<br>
^C<br>
./a.out 0.00s user 0.00s system 0% cpu 19.719 total</p>
<p>^C する前に ps した結果:<br>
freebsd8(23:28:08)% ps u68602<br>
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND<br>
akr 68602 0.0 0.1 1536 664 3 SE+ 11:28PM 0:00.00 ./a.out</p>
<p>やっぱ E ですが、E って具体的にはどういう状況なのかなぁ。</p>
<p>しかし、setsid しなくても再現するなら</p>
<p>% ./ruby -rpty -e '<br>
m, s = PTY.open<br>
pid = spawn("sleep 1")<br>
s.close<br>
m.write "a"<br>
Process.wait pid<br>
'</p>
<a name="で発症してもおかしくないと思うんですが再現しない"></a>
<h2 >で発症してもおかしくないと思うんですが再現しない...<a href="#で発症してもおかしくないと思うんですが再現しない" class="wiki-anchor">¶</a></h2>
<p>[田中 哲][たなか あきら][Tanaka Akira]</p>
<p>=end</p>
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12756
2010-08-11T08:06:05Z
naruse (Yui NARUSE)
naruse@airemix.jp
<ul></ul><p>=begin<br>
成瀬です。</p>
<p>(2010/08/10 23:32), Tanaka Akira wrote:</p>
<blockquote>
<p>C にしてさらに単純化するとこうですかね。</p>
</blockquote>
<p>どうもです。</p>
<blockquote>
<p>^C する前に ps した結果:<br>
freebsd8(23:28:08)% ps u68602<br>
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND<br>
akr 68602 0.0 0.1 1536 664 3 SE+ 11:28PM 0:00.00 ./a.out</p>
<p>やっぱ E ですが、E って具体的にはどういう状況なのかなぁ。</p>
</blockquote>
<p>とりあえず ps(3) のソースをみると、exit しているがゾンビではない、と。<br>
if (flag & P_WEXIT && k->ki_p->ki_stat != SZOMB)<br>
*cp++ = 'E';<br>
<a href="http://svn.freebsd.org/viewvc/base/head/bin/ps/print.c?revision=205271&view=markup" class="external">http://svn.freebsd.org/viewvc/base/head/bin/ps/print.c?revision=205271&view=markup</a></p>
<p>あと、ps で wchan を見てみると、以下のようになりますね<br>
% pgrep a.out|xargs procstat<br>
PID PPID PGID SID TSID THR LOGIN WCHAN EMUL COMM<br>
35305 35304 35304 47112 47112 1 naruse ttyout FreeBSD ELF64 a.out<br>
35304 47112 35304 47112 47112 1 naruse wait FreeBSD ELF64 a.out</p>
<p>--<br>
NARUSE, Yui <a href="mailto:naruse@airemix.jp" class="email">naruse@airemix.jp</a></p>
<p>=end</p>
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12759
2010-08-11T11:17:57Z
akr (Akira Tanaka)
akr@fsij.org
<ul></ul><p>=begin<br>
2010年8月11日8:05 NARUSE, Yui <a href="mailto:naruse@airemix.jp" class="email">naruse@airemix.jp</a>:</p>
<blockquote>
<p>あと、ps で wchan を見てみると、以下のようになりますね<br>
% pgrep a.out|xargs procstat<br>
PID PPID PGID SID TSID THR LOGIN WCHAN EMUL COMM<br>
35305 35304 35304 47112 47112 1 naruse ttyout FreeBSD ELF64 a.out<br>
35304 47112 35304 47112 47112 1 naruse wait FreeBSD ELF64 a.out</p>
</blockquote>
<p>これは良い情報です。<br>
ttyout ってことはなにか出力を待っているんですね。</p>
<p>子プロセスも取り除けました。</p>
<p>freebsd8% cat tst.c<br>
#include <stdlib.h><br>
#include <stdio.h><br>
#include <fcntl.h><br>
#include <sys/types.h><br>
#include <unistd.h></p>
<p>int main(int argc, char *argv[])<br>
{<br>
int m, s;<br>
char *slavedev;</p>
<p>if ((m = posix_openpt(O_RDWR|O_NOCTTY)) == -1) {<br>
perror("posix_openpt"); exit(1); }<br>
if (grantpt(m) == -1) { perror("grantpt"); exit(1); }<br>
if (unlockpt(m) == -1) { perror("unlockpt"); exit(1); }<br>
if ((slavedev = ptsname(m)) == NULL) { perror("ptsname"); exit(1); }<br>
if ((s = open(slavedev, O_RDWR|O_NOCTTY, 0)) == -1) {<br>
perror("open"); exit(1); }</p>
<p>if (write(m, "a", 1) == -1) { perror("write"); exit(1); }</p>
<p>fprintf(stderr, "before close(s)\n");<br>
if (close(s) == -1) { perror("close"); exit(1); }<br>
fprintf(stderr, "after close(s)\n");</p>
<p>return 0;<br>
}<br>
freebsd8% gcc -Wall tst.c<br>
freebsd8% ./a.out<br>
before close(s)<br>
(ここでハング)</p>
<p>どうやら、close がブロックしているようですね。<br>
exit も内部的には close 相当のことをするでしょうから、<br>
そこでブロックしているのでしょう。</p>
<p>以下のようにしてもハングします。</p>
<p>% ./ruby -rpty -e '<br>
m, s = PTY.open<br>
m.write "a"<br>
s.close<br>
'</p>
<p>なんで出力があるかというと、おそらく tty のエコーだろうということで、<br>
エコーを抑制するとハングしません。</p>
<p>#include <stdlib.h><br>
#include <stdio.h><br>
#include <fcntl.h><br>
#include <sys/types.h><br>
#include <unistd.h><br>
#include <sys/wait.h><br>
#include <termios.h></p>
<p>int main(int argc, char *argv[])<br>
{<br>
int m, s;<br>
char *slavedev;<br>
struct termios t;</p>
<p>if ((m = posix_openpt(O_RDWR|O_NOCTTY)) == -1) {<br>
perror("posix_openpt"); exit(1); }<br>
if (grantpt(m) == -1) { perror("grantpt"); exit(1); }<br>
if (unlockpt(m) == -1) { perror("unlockpt"); exit(1); }<br>
if ((slavedev = ptsname(m)) == NULL) { perror("ptsname"); exit(1); }<br>
if ((s = open(slavedev, O_RDWR|O_NOCTTY, 0)) == -1) {<br>
perror("open(slavedev)"); exit(1); }</p>
<p>if (tcgetattr(s, &t) == -1) { perror("tcgetattr"); }<br>
t.c_lflag &= ~(tcflag_t)(ECHO|ECHOE|ECHOK|ECHONL);<br>
if (tcsetattr(s, TCSANOW, &t) == -1) { perror("tcsetattr"); }</p>
<p>if (write(m, "a", 1) == -1) { perror("write"); exit(1); }</p>
<p>if (close(s) == -1) { perror("close"); exit(1); }</p>
<p>return 0;<br>
}</p>
<p>ruby ならこうです。</p>
<p>% ./ruby -rio/console -rpty -e '<br>
m, s = PTY.open<br>
s.echo = false<br>
m.write "a"<br>
s.close<br>
'</p>
<p>では、test_script_from_stdin でも、というと、そこが微妙です。<br>
PTY.spawn は slave tty を教えてくれないので、<br>
slave tty に tcsetattr ができません。<br>
FreeBSD だと以下のように master 側に tcsetattr を発行しても動くんですが、<br>
これはポータブルではありません。[ruby-list:28382]</p>
<h1>% svn diff --diff-cmd diff -x -u test/ruby/test_rubyoptions.rb<br>
Index: test/ruby/test_rubyoptions.rb</h1>
<p>--- test/ruby/test_rubyoptions.rb (revision 28906)<br>
+++ test/ruby/test_rubyoptions.rb (working copy)<br>
@@ -436,6 +436,7 @@<br>
result = nil<br>
s, w = IO.pipe<br>
PTY.spawn(EnvUtil.rubybin, out: w) do |r, m|</p>
<ul>
<li>
<pre><code> m.echo = false
w.close
m.print("\C-d")
assert_nothing_raised('<a href="/issues/1029">[ruby-dev:37798]</a>') do
</code></pre>
</li>
</ul>
<p>@@ -446,6 +447,7 @@<br>
assert_equal("", result, '<a href="/issues/1029">[ruby-dev:37798]</a>')<br>
s, w = IO.pipe<br>
PTY.spawn(EnvUtil.rubybin, out: w) do |r, m|</p>
<ul>
<li>
<pre><code> m.echo = false
w.close
m.print("$stdin.read; p $stdin.gets\n\C-d")
m.print("abc\n\C-d")
</code></pre>
</li>
</ul>
<h2>このテストでは制御端末を変える必要はないと思うので、<br>
PTY.open を使って書き直すのがいいかなぁ。</h2>
<p>[田中 哲][たなか あきら][Tanaka Akira]</p>
<p>=end</p>
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12771
2010-08-12T00:27:05Z
akr (Akira Tanaka)
akr@fsij.org
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>=begin<br>
This issue was solved with changeset r28965.<br>
Yui, thank you for reporting this issue.<br>
Your contribution to Ruby is greatly appreciated.<br>
May Ruby be with you.</p>
<p>=end</p>
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12819
2010-08-14T19:55:45Z
naruse (Yui NARUSE)
naruse@airemix.jp
<ul></ul><p>=begin<br>
まずはテストの修正ありがとうございます。</p>
<p>確かに以下の通り close(2) の前にエコーによって出力された文字列を読んであげるとちゃんと閉じられますね。<br>
うーん、前の Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: FreeBSD wrongly raises ECONNRESET on close(2) (Closed)" href="https://bugs.ruby-lang.org/issues/3515">#3515</a> と関係あるのかなぁ。</p>
<p>#include <stdlib.h><br>
#include <stdio.h><br>
#include <fcntl.h><br>
#include <sys/types.h><br>
#include <unistd.h><br>
#include <sys/wait.h><br>
#include <termios.h></p>
<p>int main(int argc, char *argv[])<br>
{<br>
int m, s;<br>
char *slavedev;<br>
struct termios t;</p>
<pre><code> if ((m = posix_openpt(O_RDWR|O_NOCTTY)) == -1) {
perror("posix_openpt"); exit(1); }
if (grantpt(m) == -1) { perror("grantpt"); exit(1); }
if (unlockpt(m) == -1) { perror("unlockpt"); exit(1); }
if ((slavedev = ptsname(m)) == NULL) { perror("ptsname"); exit(1); }
if ((s = open(slavedev, O_RDWR|O_NOCTTY, 0)) == -1) {
perror("open(slavedev)"); exit(1); }
if (tcgetattr(s, &t) == -1) { perror("tcgetattr"); }
t.c_lflag &= ~(tcflag_t)(ECHO|ECHOE|ECHOK|ECHONL);
//if (tcsetattr(s, TCSANOW, &t) == -1) { perror("tcsetattr"); }
if (write(m, "a", 1) == -1) { perror("write"); exit(1); }
{
char buf[100];
if (read(m, buf, 1) == -1) { perror("write"); exit(1); }
printf("echo: %c\n", buf[0]);
}
if (close(s) == -1) { perror("close"); exit(1); }
return 0;
</code></pre>
<p>}</p>
<p>=end</p>
Ruby master - Bug #3673: PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://bugs.ruby-lang.org/issues/3673?journal_id=12820
2010-08-14T22:56:23Z
akr (Akira Tanaka)
akr@fsij.org
<ul></ul><p>=begin<br>
2010年8月14日19:55 Yui NARUSE <a href="mailto:redmine@ruby-lang.org" class="email">redmine@ruby-lang.org</a>:</p>
<blockquote>
<p>うーん、前の Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: FreeBSD wrongly raises ECONNRESET on close(2) (Closed)" href="https://bugs.ruby-lang.org/issues/3515">#3515</a> と関係あるのかなぁ。</p>
</blockquote>
<a name="NetBSD-や-OpenBSD-でも再現するので関係ないと思います"></a>
<h2 >NetBSD や OpenBSD でも再現するので関係ないと思います。<a href="#NetBSD-や-OpenBSD-でも再現するので関係ないと思います" class="wiki-anchor">¶</a></h2>
<p>[田中 哲][たなか あきら][Tanaka Akira]</p>
<p>=end</p>