7.20. Doing Non-Blocking I/O
7.20.1. Problem
You want to read from or write to a
filehandle without the system blocking your process until the
program, file, socket, or device at the other end is ready. This is
desired less often of regular files than of special files.
7.20.2. Solution
Open the file with
sysopen, specifying the
O_NONBLOCK option:
use Fcntl;
sysopen(MODEM, "/dev/cua0", O_NONBLOCK|O_RDWR)
or die "Can't open modem: $!\n";
If you already have an open filehandle, invoke the
blocking method from IO::Handle with an argument
of 0:
use IO::Handle;
MODEM->blocking(0); # assume MODEM already opened
Or use the low-level fcntl function:
use Fcntl;
$flags = ";
fcntl(HANDLE, F_GETFL, $flags)
or die "Couldn't get flags for HANDLE : $!\n";
$flags |= O_NONBLOCK;
fcntl(HANDLE, F_SETFL, $flags)
or die "Couldn't set flags for HANDLE: $!\n";
7.20.3. Discussion
On a disk file, when no more data can be read because you're at the
end of the file, the input operation returns immediately. But suppose
the filehandle in question were the user's keyboard or a network
connection. In those cases, simply because there's no data there
right now doesn't mean there never will be, so the input function
normally doesn't return until it gets data. Sometimes, though, you
don't want to wait; you want to grab whatever's there and carry on
with whatever you were doing.Once a filehandle has been set for non-blocking I/O, the
sysread or syswrite calls that
would otherwise block will instead return undef
and set $! to
EAGAIN:
use Errno;
$rv = syswrite(HANDLE, $buffer, length $buffer);
if (!defined($rv) && $!{EAGAIN}) {
# would block
} elsif ($rv != length $buffer) {
# incomplete write
} else {
# successfully wrote
}
$rv = sysread(HANDLE, $buffer, $BUFSIZ);
if (!defined($rv) && $!{EAGAIN}) {
# would block
} else {
# successfully read $rv bytes from HANDLE
}
The O_NONBLOCK constant is part of the POSIX
standard, so most machines should support it. We use the Errno module
to test for the error EAGAIN. Testing
$!{EAGAIN} is the same as testing whether
$! = = EAGAIN.
7.20.4. See Also
The sysopen and fcntl functions
in perlfunc(1) and in Chapter 29 of
Programming Perl; the documentation for the
standard Errno and IO::Handle modules (also in Chapter 32 of
Programming Perl); your system's
open(2) and fcntl(2)
manpages; Recipe 7.22; Recipe 7.21