From: Tanaka Akira Date: 2007-09-26T05:38:48+09:00 Subject: [ruby-dev:31865] Re: 拡張ライブラリ内での SIGVTALRM In article <20070926002126.06db083c.tommy@tmtm.org>, とみたまさひろ writes: > Solaris では、かなり前([ruby-dev:17878])にも同じような問題が起きたこと > があるので、常に --enable-pthread しといた方が無難なのかもしれません。 --enable-pthread だと % ./ruby -ve 'Thread.new {} r, w = IO.pipe r.sysread(10)' ruby 1.8.6 (2007-09-26 patchlevel 5000) [i686-linux] -e:3:in `sysread': Interrupted system call (Errno::EINTR) from -e:3 とか、 % ./ruby -rnet/http -e ' Thread.new {} h = Net::HTTP.new("www.ruby-lang.org") h.read_timeout = nil h.get("/")' /home/akr/ruby/18pth/lib/ruby/1.8/net/protocol.rb:135:in `sysread': Interrupted system call (Errno::EINTR) ... とか、 % ./ruby -e 'Thread.new {} r, w = IO.pipe p w.syswrite("a" * 1024 * 1024) p w.syswrite("a" * 1024 * 1024)' 65536 -e:4:in `syswrite': Interrupted system call (Errno::EINTR) from -e:4 とか、 nute(5:32:01)% ./ruby -e ' Thread.new { } n = 5000 w = STDOUT loop { w.write("a" * n) w.write("b" * n) w.flush } '|./ruby -e ' n = 5000 r = STDIN loop { sleep 0.1 s = r.read(n); p [s.length, s.squeeze] sleep 0.1 s = r.read(n); p [s.length, s.squeeze] } ' [5000, "a"] [5000, "b"] [5000, "a"] [5000, "b"] [5000, "a"] [5000, "b"] [5000, "a"] [5000, "b"] [5000, "a"] [5000, "b"] [5000, "a"] [5000, "b"] [5000, "a"] [5000, "ba"] [5000, "ab"] [5000, "ba"] [5000, "aba"] [5000, "ab"] ... % ./ruby -v ruby 1.8.6 (2007-09-26 patchlevel 5000) [i686-linux] とか起きるしなぁ。それはそれでなかなか。 なお、ここで使っている ./ruby は --enable-pthread です。 > # setitimer(ITIMER_VIRTUAL) はユーザー空間での CPU 時間がカウントされる > # ものだと思っていたので、システムコール中に SIGVTALRM が発生するのが不 > # 思議。そういうものではないのかな…。 この件がそうであるかどうかはわかりませんが、 setitimer(ITIMER_VIRTUAL) がシステムコール中に SIGVTALRM を 引き起こす例をひとつ知っています。 拡張ライブラリが内部的にネイティブスレッドを使っていて、その ネイティブスレッドが SIGVTARLM をマスクしている場合には、 SIGVTARLM がシステムコール中に発生することがあります。そのネ イティブスレッドがユーザー空間での CPU 時間を消費してタイマ が発火した時そのネイティブスレッドがシグナルを受け付けない場 合、他の、システムコールでブロックしているスレッドにシグナル が到着する、というストーリーみたいです。 % cat extconf.rb require 'mkmf' have_library('pthread') create_makefile('pth') % cat pth.c #include #include #include #include static void * loop(void *arg) { sigset_t sigset; int ret; if (sigfillset(&sigset) == -1) { perror("sigfillset"); exit(1); } ret = pthread_sigmask(SIG_BLOCK, &sigset, NULL); if (ret != 0) { perror("pthread_sigmask"); exit(1); } while (1); } void Init_pth() { pthread_t pth; int ret; ret = pthread_create(&pth, NULL, loop, NULL); if (ret != 0) { errno = ret; perror("pthread_create"); exit(1); } } % ruby-1.8 extconf.rb checking for main() in -lpthread... yes creating Makefile % make gcc -I. -I. -I/home/akr/ruby/18/lib/ruby/1.8/i686-linux -I. -fPIC -g -O2 -c pth.c gcc -shared -o pth.so pth.o -L. -L/home/akr/ruby/18/lib -Wl,-R/home/akr/ruby/18/lib -L. -rdynamic -Wl,-export-dynamic -lpthread -ldl -lcrypt -lm -lc % ruby-1.8 -rpth -e ' Thread.new {} r, w = IO.pipe r.sysread(10)' -e:4:in `sysread': Interrupted system call (Errno::EINTR) from -e:4 zsh: exit 1 ruby-1.8 -rpth -e ' Thread.new {} r, w = IO.pipe r.sysread(10)' % strace ruby-1.8 -rpth -e ' Thread.new {} r, w = IO.pipe r.sysread(10)' ... read(3, 0x8135308, 10) = ? ERESTARTSYS (To be restarted) --- SIGVTALRM (Virtual timer expired) @ 0 (0) --- sigreturn() = ? (mask now []) ... % ruby-1.8 -v ruby 1.8.6 (2007-09-26 patchlevel 5000) [i686-linux] なお、この ruby-1.8 は --enable-pthread ではありません。 -- [田中 哲][たなか あきら][Tanaka Akira]