Example code that sets stdin to be non-blocking, then makes a read system call.
section .text
global _start
_start:
mov eax, 55 ; __NR_fcntl
mov ebx, 0
mov ecx, 4 ; F_SETFL
mov edx, 2048 ; O_RDONLY|O_NONBLOCK
int 0x80
mov eax, 3 ; __NR_read
mov ebx, 0
mov ecx, buf
mov edx, 1024
int 0x80
mov [br], eax
mov eax, 4 ; __NR_write
mov ebx, 1
mov ecx, buf
mov edx, [br]
int 0x80
mov eax, 1 ; __NR_exit
mov ebx, 0
int 0x80
section .bss
buf resb 1024
br resd 1
Expected behavior: program exits without printing anything because I expect read
to return 0
in EAX when there's nothing to read (on the terminal).
Current behavior: program prints 4 random bytes as read
returns -11
when nothing was passed to stdin.
$ strace ./nonblocking
execve("./nonblocking", ["./nonblocking"], 0x7fff196fcb40 /* 53 vars */) = 0
strace: [ Process PID=4112759 runs in 32 bit mode. ]
fcntl(0, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
read(0, 0x804a000, 1024) = -1 EAGAIN (Resource temporarily unavailable)
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4294967285����) = 4096
exit(0) = ?
(Editor's note: \0
prints as zero-width on terminals, but the 4 non-zero bytes the question is talking about are the -11
dword in br
, starting 1024 bytes into the output.)
Linux system calls return -errno
values on error. read
is returning -EAGAIN
as documented for non-blocking I/O on a device that has no bytes "ready", thus EAX = -11
which has 4 non-zero bytes in its bit-pattern.
You're not actually printing 4 bytes, you're passing a huge value to write
. It writes until the end of the page. Instead of returning -EFAULT
, it returns a count of how many bytes it actually copied from the buffer to the file descriptor, even though it stopped because it hit an unmapped page.
Writing output to the terminal makes that less visible, unless you look at the strace output. ASCII NUL (\0
, a zero byte) prints as zero-width on a standard VT100-style terminal, but in other contexts that's very much not the same as not writing anything. Run
./nonblocking | hexdump -C --no-squeezing
to see the 4kB of zero bytes you write to stdout.
BTW, there's no point in storing EAX to memory just to reload it again. Just mov edx, eax
.
You only get EOF on a TTY when the user types control-D. (Assuming "cooked" mode and default stty
settings).
Non-blocking doesn't turn no-data-ready into EOF; that would make it impossible to distinguish actual end of file! (Non-blocking I/O on a regular file will give you EOF at the end of the file, or -EAGAIN
if the file hasn't been fetched from disk yet so you'd have to block on I/O.)
The situations where read
returns 0
(meaning EOF) are the same for blocking and non-blocking read
.
If blocking read
would sit there waiting for the user to type something (and "submit" it in line-buffered cooked mode with return or control-D), non-blocking read
will return -EAGAIN
.
From the Linux read(2)
man page:
EAGAIN
The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. See open(2) for further details on the O_NONBLOCK flag.