Lock on some special file reading within XML-RPC

Hi,
I was having a timeout in a client/server program using xml-rpc under
Linux. Trying to find why, here is the small test case I achieved :

[pterjan@cmoi tmp]$ ruby -r 'xmlrpc/server' -e 's =
XMLRPC::Server.new(23269, "127.0.0.1", 4, nil); s.add_handler("f", File);
s.serve' &
[1] 12756
[pterjan@cmoi tmp]$ ruby -r 'xmlrpc/client' -e 'p
XMLRPC::Client.new("127.0.0.1",nil,23269).call("f.readlines",
"/proc/cpuinfo")'
["processor\t: 0\n", "vendor_id\t: GenuineIntel\n", "cpu
family\t: 6\n", "model\t\t: 13\n", "model name\t: Intel(R) Pentium(R) M
processor 1.60GHz\n", "stepping\t: 6\n", "cpu MHz\t\t: 1595.471\n", "cache
size\t: 2048 KB\n", "fdiv_bug\t: no\n", "hlt_bug\t\t: no\n", "f00f_bug\t:
no\n", "coma_bug\t: no\n", "fpu\t\t: yes\n", "fpu_exception\t: yes\n",
"cpuid level\t: 2\n", "wp\t\t: yes\n", "flags\t\t: fpu vme de pse tsc msr
mce cx8 sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss tm
pbe est tm2\n", "bogomips\t: 3162.11\n", "\n"]
[pterjan@cmoi tmp]$ ruby -r 'xmlrpc/client' -e 'p
XMLRPC::Client.new("127.0.0.1",nil,23269).call("f.readlines",
"/proc/cmdline")'
/usr/lib/ruby/1.8/timeout.rb:42:in `rbuf_fill': execution expired (Timeout::Error)
        from /usr/lib/ruby/1.8/net/protocol.rb:196:in `timeout'
        from /usr/lib/ruby/1.8/timeout.rb:55:in `timeout'
        from /usr/lib/ruby/1.8/net/protocol.rb:196:in `rbuf_fill'
        from /usr/lib/ruby/1.8/net/protocol.rb:160:in `readuntil'
        from /usr/lib/ruby/1.8/net/protocol.rb:171:in `readline'
        from /usr/lib/ruby/1.8/net/http.rb:1554:in `read_status_line'
        from /usr/lib/ruby/1.8/net/http.rb:1538:in `read_new'
        from /usr/lib/ruby/1.8/net/http.rb:833:in `request'
        from /usr/lib/ruby/1.8/net/http.rb:823:in `request'
        from /usr/lib/ruby/1.8/net/http.rb:821:in `start'
        from /usr/lib/ruby/1.8/net/http.rb:821:in `request'
        from /usr/lib/ruby/1.8/net/http.rb:778:in `post2'
        from /usr/lib/ruby/1.8/xmlrpc/client.rb:524:in `do_rpc'
        from /usr/lib/ruby/1.8/xmlrpc/client.rb:409:in `call2'
        from /usr/lib/ruby/1.8/xmlrpc/client.rb:399:in `call'
        from -e:1
[pterjan@cmoi tmp]$ strace -p 12756
Process 12756 attached - interrupt to quit
select(6, [3 5], [], [], NULL

If I'm not wrong, 3 is the socket and 5 the file I'm trying to read.
The problem also occurs on some other files in /proc, replacing the read
(any sort of it will fail) by `cat /proc/cmdline` is OK. I guess these
files do not like select...

The read works fine outside xmlrpc :

[pterjan@cmoi tmp]$ ruby -e 'puts File.readlines("/proc/cmdline")'
auto BOOT_IMAGE=linux ro root=301 acpi=on resume=/dev/hda6 splash=silent

Thanks for reading until there :slight_smile:
Any idea is welcome.

Excerpts from Pascal Terjan's mail of 20 Feb 2005 (EST):

I was having a timeout in a client/server program using xml-rpc under
Linux.

[snip]

[pterjan@cmoi tmp]$ strace -p 12756
Process 12756 attached - interrupt to quit
select(6, [3 5], , , NULL

If I'm not wrong, 3 is the socket and 5 the file I'm trying to read.
The problem also occurs on some other files in /proc, replacing the read
(any sort of it will fail) by `cat /proc/cmdline` is OK. I guess these
files do not like select...

The read works fine outside xmlrpc :

[pterjan@cmoi tmp]$ ruby -e 'puts File.readlines("/proc/cmdline")'
auto BOOT_IMAGE=linux ro root=301 acpi=on resume=/dev/hda6 splash=silent

This is a known problem with no solution, only workarounds.

xmlrpc uses threads. In threading mode, Ruby uses the select system call
rather than read. But in kernel 2.6, many /proc files do not respond to
select. For example, the following slight modification of the above hangs
indefinitely:

  ruby -e 'Thread.new { sleep 0 }; puts File.readlines("/proc/cmdline")'

To the best of my knowledge, your only option is to say:

  IO.popen("cat /proc/cmdline")

Gory details here: Bola88 : Agen Judi Bola Qris Bca Nomor 1 di Dunia

···

--
William <wmorgan-ruby-talk@masanjin.net>

Thanks for the explanation and URL

···

Le Mon, 21 Feb 2005 04:06:22 +0900, William Morgan a écrit :

To the best of my knowledge, your only option is to say:

  IO.popen("cat /proc/cmdline")

Gory details here: http://www.all-thing.net/Ruby/select_and_procfs.html