NAME

IO::Async - a collection of modules that implement asynchronous filehandle IO

SYNOPSIS

use IO::Socket::INET;
use IO::Async::Buffer;
use IO::Async::Set::IO_Poll;

my $socket = IO::Socket::INET->new(
   PeerHost => "some.other.host",
   PeerPort => 12345,
   Blocking => 0,
);

my $buffer = IO::Async::Buffer->new(
   handle => $socket,

   on_read => sub {
      return 0 unless( $$_[0] =~ s/^(.*\n)// );

      print "Received a line $1";

      return 1;
   }
);

$buffer->write( "An initial line here\n" );

my $set = IO::Async::Set::IO_Poll->new();

$set->add( $buffer );

$set->loop_forever();

DESCRIPTION

This collection of modules allows programs to be written that perform asynchronous filehandle IO operations. A typical program using them would consist of a single subclass of IO::Async::Set to act as a container for a number of IO::Async::Notifier objects (or subclasses thereof). The set itself is responsible for checking read- or write-readiness, and informing the notifiers of these conditions. The notifiers then perform whatever work is required on these conditions, by using subclass methods or callback functions.

Notifiers

A IO::Async::Notifier object represents a single IO stream that is being managed. While in most cases it will represent a single filehandle, such as a socket (for example, an IO::Socket::INET connection), it is possible to have separate reading and writing handles (most likely for a program's STDIN and STDOUT streams). Subclass methods or callback functions are then used by the containing IO::Async::Set object, to inform the notifier when the handles are read- or write-ready.

The IO::Async::Buffer class is a subclass of IO::Async::Notifier which maintains internal incoming and outgoing data buffers. In this way, it implements bidirectional buffering of a byte stream, such as a TCP socket. The class automatically handles reading of incoming data into the incoming buffer whenever it is notified as being read-ready, and writing of the outgoing buffer when it is notified as write-ready. Methods or callbacks are used to inform when new incoming data is available, or when the outgoing buffer is empty.

The IO::Async::SignalProxy object allow for safe signal handling to be performed alongside other asynchronous IO tasks, within the (explicit or implicit) loop provided by the subclass of IO::Async::Set that is used.

Sets

The IO::Async::Set object class represents an abstract collection of IO::Async::Notifier objects. It performs all of the low-level set management tasks, and leaves the actual determination of read- or write- readiness of filehandles to a particular subclass for the purpose.

IO::Async::Set::IO_Poll uses an IO::Poll object for this test.

IO::Async::Set::Select provides methods to prepare and test three bitvectors for a select() syscall.

IO::Async::Set::GMainLoop acts as a proxy for the Glib::MainLoop of a Glib-based program.

Detached Code

The IO::Async framework generally provides mechanisms for multiplexing IO tasks between different handles, so there aren't many occasions when such detached code is necessary. Two cases where this does become useful are when a large amount of computationally-intensive work needs to be performed, or when an OS or library-level function needs to be called, that will block, and no asynchronous version is supplied. For these cases, an instance of IO::Async::DetachedCode can be used around a code block, to execute it in a detached child process.

Timers

Each of the IO::Async::Set subclasses supports a pair of methods for installing and cancelling timers. These are callbacks invoked at some fixed future time. Once installed, a timer will be called at or after its expiry time, which may be absolute, or relative to the time it was installed. An installed timer which has not yet expired may be cancelled.

Merge Points

The IO::Async::MergePoint object class allows for a program to wait on the completion of multiple seperate subtasks. It allows for each subtask to return some data, which will be collected and given to the callback provided to the merge point, which is called when every subtask has completed.

MOTIVATION

The purpose of this distribution is two-fold.

The first reason is to allow programs to be written that perform multiplexed asynchronous IO from within one thread. This is a useful programming model because it avoids a lot of the problems created by multi-threading or other techniques, such as the potential for race conditions or deadlocks. The downside to this approach is the extra complexity in dealing with events asynchronously, handling incoming data as it arrives, even if it is as-yet incomplete. This distribution aims to provide abstractions that minimise the effort required here, through such objects as IO::Async::Buffer.

The second reason is to act as a base-layer API, that can be extended while still remaining generic. The split between notifiers and sets allows new subclasses of notifer to be derived from the IO::Async::Notifier or IO::Async::Buffer classes without regard for how they will interact with the actual looping constructs emplyed by the containing program. Similarly, new subclasses of IO::Async::Set can be developed to interact with existing programs written for other styles of asynchronous IO loop, without requiring detailed knowledge of the way the notifiers work.

TODO

This collection of modules is still very much in development. As a result, some of the potentially-useful parts or features currently missing are:

  • A way to perform asynchronous name lookups. This will likely be performed by fork()ing a subprocess, and calling the getaddrinfo() or getnameinfo() functions from Socket6 in this subprocess, using an internal socket or pair of pipes to perform communications with the main program.

  • A IO::Async::Set subclass to perform integration with Event.

  • A consideration of whether it is useful and possible to provide integration with POE.

SEE ALSO

  • Event - Event loop processing

  • POE - portable multitasking and networking framework for Perl

AUTHOR

Paul Evans <leonerd@leonerd.org.uk>