Project

General

Profile

Backport #5539

Readline.readline() blocks all threads

Added by cjameshuff (Christopher Huff) almost 9 years ago. Updated over 8 years ago.

Status:
Closed
Priority:
Normal
Assignee:
-
[ruby-core:40641]

Description

The standard library Readline.readline() function blocks the thread it's called from without unlocking the VM, thus blocking all threads. This code demonstrates the problem:

require 'pp'
t = Thread.new {10.times {|x| puts x; sleep 1}}
while(buf = Readline.readline)
p buf
if(buf == 'q')
break
end
end

Thread t will be blocked by the readline call, numbers being printed occasionally when lines are entered and readline() returns, rather than once per second. Reproduced on ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0] and ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin10.8.0].

The RubyInline gem allows a workaround:

require 'inline'
class BetterReadline
inline :C do |builder|
builder.include ''
builder.include ''
src = <<END
VALUE readline_intern(void * data) {
char ** rstr = (char **)data;
*rstr = readline(NULL);
return Qnil;
}
END
builder.prefix(src)
src = <<END
VALUE rb_readline(void) {
char * str = NULL;
rb_thread_blocking_region(readline_intern, &str, NULL, NULL);
return rb_str_new2(str);
}
END
builder.c_singleton(src, method_name: 'readline')
end
end # class BetterReadline

This then illustrates the desired behavior, with the thread running in the background while readline() waits for input:

require 'pp'
t = Thread.new {10.times {|x| puts x; sleep 1}}
while(buf = BetterReadline.readline)
p buf
if(buf == 'q')
break
end
end


Files

readline.patch (1009 Bytes) readline.patch nagachika (Tomoyuki Chikanaga), 11/04/2011 11:46 PM
readline_comment.patch (1.18 KB) readline_comment.patch nagachika (Tomoyuki Chikanaga), 11/08/2011 12:24 AM

Also available in: Atom PDF