Creating Nonblocking I/O Handles You can make a Perl filehandle nonblocking when you first open it, or change its nonblocking status at any time thereafter. As implied by the name , a filehandle that is nonblocking never blocks on read or write operations, but instead generates an error message. Nonblocking filehandles can be safely operated only on using the sysread () and syswrite() functions. Because of the buffering issues, combining nonblocking handles with the stdio routines used by the higher-level functions is guaranteed to lead to tears of frustration. A nonblocking handle always returns immediately from sysread() or syswrite() . If the call can be satisfied without blocking, it returns the number of bytes read or written. If the call would block, it returns undef and sets $! to the error code EWOULDBLOCK (also known as EAGAIN ). The string form of EWOULDBLOCK appears variously as "operation in progress" or "resource temporarily unavailable." sysread() and syswrite() can, as always, encounter other I/O errors as well. The EWOULDBLOCK constant may be imported from the Errno module. The other distinctive feature of a nonblocking handle is that it enables partial writes . With an ordinary blocking handle, syswrite() does not return until the entire request has been satisfied. With nonblocking handles, however, this behavior is changed such that if some but not all of a write request can be satisfied immediately, syswrite() writes as much of the data as it can and then returns the number of bytes sent. Recall that partial reads from sysread() are always possible, regardless of the blocking status of the handle. Creating Nonblocking Handles: Function Interface Perl provides both low-level and object-oriented interfaces for creating and working with nonblocking handles. We will look at the low-level interface first, and then show how the API is cleaned up in the object-oriented versions. $result = sysopen (FILEHANDLE,$filename,$mode [,$perms]) The sysopen() call, introduced in Chapter 2, allows you to mark a filehandle as nonblocking when it is opened. The idiom is to add the O_NONBLOCK flag to the flags passed in the $mode argument. For example, to open device /dev/tape0 for nonblocking writes, you might call: use Fcntl; sysopen (TAPE,'/dev/tape0',O_WRONLYO_NONBLOCK); | sysopen() works only with local files and cannot be used to open pipes or sockets. Therefore, unless you are dealing with slow local devices such as tape drives , you'll probably never create a nonblocking filehandle in this way. More typically, you'll take a handle that has been opened with socket() or open() and mark it as nonblocking after the fact. This is what the fcntl() function can do. $result = fcntl($handle, $command, $operand) To put a previously opened filehandle or socket into nonblocking mode, use fcntl() . The fcntl() function is actually a catchall utility for many low-level handle operations. In addition to altering a handle's flags, you can lock and unlock it, duplicate it, and perform more esoteric options. We will see some of these applications in Chapter 14. | The call takes three arguments. The first two arguments are a previously opened handle and a numeric constant specifying a command to perform on the handle. The third argument is a numeric parameter to pass to the command. Some commands don't need additional data, in which case passing a third argument of 0 will do. If successful, fcntl() returns a true value. Otherwise , it sets $! and returns undef . | The Fcntl module provides constants for all the fcntl() commands. The two commands relevant to nonblocking handles are F_GETFL and F_SETFL , which are used to retrieve and modify a handle's flags after creation. When you call fcntl() with a command of F_GETFL , it returns a bitmask containing the handle's current flags. Call fcntl() with the F_SETFL command to change the handle's flags to the value set in $operand . You will want $operand to include the O_NONBLOCK flag. The result code will indicate success or failure in changing the flags. There is a subtlety to using fcntl() to set the nonblocking status of a filehandle. Because nonblocking behavior is just one of several options that can be set in the flag bitmap, you should call F_GETFL first to find out what options are already set, set the O_NONBLOCK bit using a bitwise OR, and then call F_SETFL to apply the modified flags to the handle. Here's a small subroutine named blocking() that illustrates this. The routine's first argument is a handle, and its optional second argument is a Boolean value that can be used to turn blocking behavior on or off. If called without a second argument, the subroutine returns true if the handle is blocking; otherwise, it returns false: use Fcntl; sub blocking { my ($handle,$blocking) = @_; die "Can't fcntl(F_GETFL)" unless my $flags = fcntl($handle,F_GETFL,0); my $current = ($flags & O_NONBLOCK) == 0; if (defined $blocking) { $flags &= ~O_NONBLOCK if $nonblocking; $flags = O_NONBLOCK unless $blocking; die "Can't fcntl(F_SETFL)" unless fcntl($handle,F_SETFL,$flags); } return $current; } Notice that sockets start blocking by default. To make them nonblocking, you need to call blocking() with a argument. warn "making socket nonblocking"; blocking($sock,0); The Perl perlfunc POD pages contain more information on the fcntl() function. Creating Nonblocking Handles: Object-Oriented Interfacye If you are using the object-oriented IO::Socket or IO::File modules, then setting nonblocking mode is as easy as calling its blocking() method. $blocking_status = $handle->blocking([$boolean]) Called without an argument, blocking() returns the current status of blocking I/O for the handle. A true value indicates that the handle is in normal blocking mode; a false value indicates that nonblocking I/O is active. You can change the blocking status of a handle by providing a Boolean value to blocking() . A false value makes the socket nonblocking; a true argument restores the normal blocking behavior. | Remember that socket objects start blocking by default. To make a socket nonblocking, you must call blocking() with a false argument: $socket->blocking(0); |