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 endThe 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.