Chapter 3. The Unixqueue module

Table of Contents
3.1. Description
3.2. Example: Copying several files in parallel

3.1. Description

The interface of the Unixqueue module.

open Unix
open Sys

type group                          (* Groups of events *)
type wait_id                        (* Wait ticket *)

type operation =
    Wait_in  of file_descr          (* wait for input data *)
  | Wait_out of file_descr          (* wait until output can be written *)
  | Wait_oob of file_descr          (* wait for out-of-band data *)
  | Wait of wait_id                 (* wait only for timeout *)

type event =
    Input_arrived of (group * file_descr)
  | Output_readiness of (group * file_descr)
  | Out_of_band of (group * file_descr)
  | Timeout of (group * operation)
  | Signal
  | Extra of exn

type event_system

exception Abort of (group * exn);;

val create_unix_event_system : unit -> event_system
val new_group : event_system -> group
val new_wait_id : event_system -> wait_id
val exists_resource : event_system -> operation  -> bool
val add_resource : event_system -> group -> (operation * float) -> unit
val add_close_action : 
          event_system -> group -> (file_descr * (file_descr -> unit)) 
            -> unit
val add_abort_action : 
          event_system -> group -> (group -> exn -> unit)
            -> unit
val remove_resource : event_system -> group -> operation -> unit
val add_handler : 
          event_system -> group -> 
          (event_system -> event Equeue.t -> event -> unit) 
             -> unit
val add_event : event_system -> event -> unit
val clear : event_system -> group -> unit
val run : event_system -> unit
val once : event_system -> group -> float -> (unit -> unit)
               -> unit

Theme of this module are four types of operations: Waiting for input data, waiting for output readiness, waiting for out-of-band data, and waiting for a period of time. You can associate resources which simply means that it is waited until one of the operations becomes possible or is timed out. Resources are the combination of an operation and a time-out value.

This module already implements an event source which checks whether the operations are possible or timed-out, and which generates events describing what has happended. As with Equeue you can add events yourself, and you can add handlers which perform actions on certain events. As Unixqueue is based on Equeue, the queue model is simply the same.

Resources, handlers and events are grouped, i.e. you can reference to a bundle of resources/events by specifying the group they belong to. Group are created by Unixqueue.new_group, and every resource must belong to a group. The events caused by a resource belong to the same group as the resource. Handlers have a group, too, and the handlers only get events of the same group (this has been changed between Equeue 1.1 and 1.2). Furthermore, the groups simplify clean-up actions.

You can associate a close action with a resource. The close action is automatically called if the resource is removed from the queue. The close action should then close the underlying file descriptor.

You can remove all handlers and resouces belonging to a group with only one function call (clear).

There is special support for aborting groups. Aborting means that an exception is to be raised, but there needs to be some cleanup before the event queue is in a sane state. Because of this, it is possible to asscociate an abort action with a group. The abort action is automatically performed if the special Abort exception is raised within a handler.

Details:

Object-oriented interface. In addition to the functional interface, there is also an object-oriented interface. Instead of calling one of the above functions f, one can also invoke the method with the same name. For example, the call

add_resource ues g (op,t)
can also be written as
ues # add_resource g (op,t)
Both styles can be used in the same program, and there is absolutely no difference (actually, the object-oriented interface is even the fundamental interface, and the functions are just wrappers for the method calls).

Instead of creating the event system with

let ues = create_unix_event_system()
one can also use
let ues = new unix_event_system()
Again, both calls do exactly the same.

The object-oriented interface has been introduced to support other implementations of file descriptor polling than [Unix.select]. The integration into the Tcl and Glib event systems has been implemented by defining additional classes that are compatible with Unixqueue.unix_event_system, but internally base on different polling mechanisms.