Programming directly with Unixqueues can be quite ineffective. One needs a lot of code to perform even simple problems. The question arises whether there is a way to construct event-driven code from larger units that do more complicated tasks than just looking at the possible I/O operations of file descriptors. Ideally, there would be a construction principle that scales with the problems the programmer wants to solve.
An engine is an object bound to an event system that performs a task in an autonomous way. After the engine has started, the user of the engine can leave it alone, and let it do what it has been designed for, and simply wait until the engine has completed its task. The user can start several engines at once, and all run in parallel. It is also possible to construct larger engines from more primitive ones: One can run engines in sequence (the output of the first engine is the input of the next), one can run synchronize engines (when two engines are done the results of both engines are combined into a single result), and map the results of engines to different values.
The formalization of engines assumes that there are four major states (see the module Uq_engines):
type 't engine_state =
[ `Working of int
| `Done of 't
| `Error of exn
| `Aborted
]
A `Working engine is actively performing its
task. The number argument counts the events that are processed while
progressing. The state `Done indicates that the
task is completed. The argument of `Done is the
result value of the engine. The state `Error means
that the engine ran into a problem, and cannot continue. Usually an
exception was raised, and in order to be able to pass the exception to
the outside world, it becomes the argument of
`Error. Finally, an engine can be explictly
`Aborted by calling the abort
method. This forces that the engine stops and releases the resources
it has allocated.The last three states are called final states because they indicate that the engine has stopped. Once it is in a final state, the engine will never go back to `Working, and will also not transition into another final state.
There is no state for the situation that the engine has not yet begun operation. It is assumed that an engine starts performing its task right when it has been created, so the initial state is usually `Working 0.
Engines are objects that implement this class type:
class type [ 't ] engine = object
method state : 't engine_state
method abort : unit -> unit
method request_notification : (unit -> bool) -> unit
method event_system : Unixqueue.event_system
end
The method state reports the state the engine
currently has. By calling abort the engine is
aborted. The method request_notification will
be explained later. Finally, event_system reports
the Unixqueue event system the engine is attached to.