Recipe 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