Reputation: 7719
I can't figure out why IO methods won't work on STDIN, when properly set to non-blocking mode:
require 'fcntl'
stdin_flags = STDIN.fcntl(Fcntl::F_GETFL)
p stdin_flags #32770
p STDIN.fcntl(Fcntl::F_SETFL, stdin_flags | Fcntl::O_NONBLOCK) # 0
p STDIN.fcntl(Fcntl::F_GETFL) # 34818
#at_exit { STDIN.fcntl(Fcntl::F_SETFL, stdin_flags & ~Fcntl::O_NONBLOCK) }
STDIN.readline # this call blocks, IO::EAGAINWaitReadable expected
exit
IO.fcntl
successfully sets non-blocking mode but all IO functions like read
, readline
, gets
, readchar
ignore the mode and hang at reading when no input has been received.
Setting sync mode to true has no effect.
If I replace STDIN.readline
with the shell call system('read line')
it does work correctly. It won't wait or would wait for input depending if non-blocking mode was set.
I'm aware of IO.read_nonblock
but looking for an efficient way how to read newline terminated strings. Calling read_nonblock
for each single character is painfully slow.
Can anybody explain this (mis)behavior?
Upvotes: 6
Views: 1868
Reputation: 7719
It's a bit unfortunate but standard functions from IO
module seem to not respect status flags associated with a file descriptor.
One of the working solutions is use of IO.select
class method for input polling, then read the data with regular methods as they become available.
Be aware when line processing methods are used, code may hang until terminating newline character gets consumed. It's advisable to enclose polling code in Timeout
block when things are going out of control.
In cases when amount of characters/bytes is known beforehand, stock IO.read_nonblock
would simply serve well.
Upvotes: 3