Module Ev


module Ev: sig .. end
Ev is a module for binding libev, which is a high-performance event loop. You may wish to browse libev's documentation from time to time, but this documentation attempts to be as self-containing API documentation as possible, with links to relevant libev's documentation where appropriate.

type loop_flag = [ `FORKCHECK | `NOENV ] 
loop_flag is used when constructing a new loop with loop_new or default_loop
See also

type run_loop_flag =
| OneShot
| NonBlock
type backend = [ `DEVPOLL | `EPOLL | `KQUEUE | `POLL | `PORT | `SELECT ] 
supported backends
See also Functions controlling the event loop (ev_default_loop)
type loop_arg = [ `DEVPOLL | `EPOLL | `FORKCHECK | `KQUEUE | `NOENV | `POLL | `PORT | `SELECT ] 
loop_new and default_loop construction argument
See also

type unloop_how =
| UnloopOne (*unloop the innermost loop*)
| UnloopAll (*unloop all loops*)
how to stop a loop
See also loop

type revent =
| READ (*ev_io detected read will not block*)
| WRITE (*ev_io detected write will not block*)
| IOFDSET (*internal use only*)
| TIMEOUT (*timer timed out*)
| PERIODIC (*periodic timer timed out*)
| SIGNAL (*signal was received*)
| CHILD (*child/pid had status change*)
| STAT (*stat data changed*)
| IDLE (*event loop is idling*)
| PREPARE (*event loop about to poll*)
| CHECK (*event loop finished poll*)
| EMBED (*embedded event loop needs sweep*)
| FORK (*event loop resumed in child*)
| ERROR (*sent when an error occurs*)
event types that are recognized
See also Anatomy of a watcher
exception NoLoop
no loop started for an event when one required
exception LoopInitFailed
failed to create a loop object
exception VersionMismatch
there is too great version difference to use system libev
exception StaleObject
an attempt to access a destroyed object was made
type revents = revent list 
list of events received
type loop 
abstract data type for event loops
type 'a ev 
abstract data type for events
type 'a cb = 'a ev -> revents -> unit 
callback function; called when an event occurs
type exn_handler = loop -> exn -> unit 
an exception handler; if this function throws, it will end the event loop which will forward the exception
val string_of_loop_arg : [< loop_arg ] -> string
convert a loop argument into a human-readable string
val string_of_revent : revent -> string
convert an revent into a human-readable string

Backend information


val embeddable_backends : unit -> backend list
list of backends that may be embedded; embedding not yet supported
See also libev global functions (ev_embeddable_backends)
val supported_backends : unit -> backend list
list of supported backends
See also libev global functions (ev_supported_backends)
val recommended_backends : unit -> backend list
list of recommended backends for this host
See also libev global functions (ev_recommended_backends)

Event loop management


val default_loop : loop_arg list -> loop
access the default loop. the next call will ignore the flags and return the same loop. note: do NOT destroy this loop if you wish to use it again, calling default_loop again won't bring it back. (libev bug?)
Raises
val loop_new : loop_arg list -> loop
create a new event loop
Raises See also Functions controlling the event loop (ev_default_loop)
val loop_destroy : loop -> unit
destroy an event loop. Future access to the object will raise StaleObject. note: do NOT destroy the default loop if you wish to use it again, calling default_loop again won't bring it back. (libev bug?)
val loop_now : loop -> float
time of day according to the event loop
See also Functions controlling the event loop (ev_loop_new)
val is_default_loop : loop -> bool
is this the default loop?
val loop_count : loop -> int
a monotonic (wrapping) counter that roughly indicates the number of times the event loop has iterated
See also Functions controlling the event loop (ev_loop_count)
val loop : loop -> run_loop_flag list -> unit
loop l flags - run an event loop
val unloop : loop -> unloop_how -> unit
unloop l how - run an event loop. Running loop will reset the unloop state of the event loop object.
val set_exn_handler : loop -> exn_handler -> unit
set_exn_handler loop handler - set the exception handler of an event loop
val default_exn_handler : loop -> exn -> unit
default exception handler; it output diagnostics to stderr and swallows the exception
val forked : loop -> unit
forked loop - inform an event loop that we have forked (and we'd like to keep using the libev services)
val set_io_collect_interval : loop -> float -> unit
set_io_collect_interval loop interval - collect io events in lumps. may help throughput in high load situations by avoiding work, but will increase latency.
val set_timeout_collect_interval : loop -> float -> unit
set_timeout_collect_interval loop interval - collect timeout events in lumps. may help throughput in high load situations by avoiding work, but will increase latency.

Event object management


val set_cb : 'a ev -> 'a cb -> unit
set_cb ev f - sets the callback of an event
val get_cb : 'a ev -> 'a cb
get_cb ev - retrieves the callback of an event
Returns the callback function
val no_cb : 'a cb
no_cb ev - a callback that does nothing; could be useful as the callback parameter to _init functions.
Returns the callback function
val is_active : 'a ev -> bool
is_active ev - is this event active? an event is active when it has been issued *_start an inactive after a *_stop.
Returns the status
val is_pending : 'a ev -> bool
is_pending ev - does this even have outstanding events?
Returns the status
val get_priority : 'a ev -> int
get_priority ev - retrieve the priority of an event. values range from -2 to 2.
Returns the status
val set_priority : 'a ev -> int -> unit
set_priority ev priority - set the priority of an event. Priority should range from -2 to 2 and it may of may not be clamped by libev. (??)
val set_keepalive : 'a ev -> bool -> unit
keepalive ev state - set the the significance of this event watcher from its loop, when considering whether to exit or not. If the state is set to true and this is the last event stopping the event loop from exiting, it will exit.
val get_loop : 'a ev -> loop
raises NoLoop the event is not active
Raises NoLoop if the event is not active
See also is_active
val invoke : 'a ev -> revents -> unit
invoke an event as if it had just been fired. the event must be registered to a loop, or NoLoop is thrown.
Raises NoLoop if the event is not active
val clear_pending : 'a ev -> revents
clear pending events from an event watcher: return the list if events that were pending
val start : loop -> 'a ev -> unit
start loop ev - attach an event watcher to an event loop (that is, activate it). If the event watcher is already active (with the same loop), do nothing.
Raises Invalid_argument the event loop is started to another loop
val stop : 'a ev -> unit
stop ev - detach an event watcher from an event loop (thus deactivating it). If the event watcher is already inactive, do nothing.

Event-specific functions



Io events

A file descriptor will not block when read from or written to.

Libev documentation: Libev ev_io

type io 
abstract data type containing the event watcher
val io_init : Unix.file_descr -> revents -> io cb -> io ev
io_init f fd revents

Timer events

Fired after a certain time period; optionally recurringly.

Libev documention: Libev ev_timer

type timer 
abstract data type containing the event watcher
val timer_init : float -> float -> timer cb -> timer ev
timer_init f offset repeat - call a callback after offset seconds; if repeat > 0.0, retrigger the timer to run periodically.
val timer_again : timer ev -> unit
timer_again ev - retrigger the timer to run again after the interval.
Raises NoLoop if this event is not active
See also

Periodic events

Fired with a certain periodic schedule.

Libev documention: Libev ev_periodic

type periodic 
abstract data type containing the event watcher
type reschedule_cb = periodic ev -> float -> float 
callback for rescheduling next event, for periodic events
See also

type periodic_time =
| Absolute of float (*absolute unix time*)
| Repeating of float * float (*offset * interval - repeat every interval seconds, with unix time offset offset*)
| Manual of reschedule_cb (*use a custom rescheduling function*)
describes the desired times when a periodic event should fire
See also
val periodic_init : periodic_time -> periodic cb -> periodic ev
periodic_init f periodic_time - call a callback with a certain schedule.
Returns the periodic event object, still detached from event loop
See also ev_periodic
val periodic_set : periodic ev -> periodic_time -> unit
periodic_set ev periodic_time - set the periodic parameters again
See also periodic_init
val periodic_get_at : periodic ev -> float
periodic_get_at ev - retrieve the epoch time when the event will be fired the next time

Unix signals

Fired when a unix signal is received.

Libev documention: Libev ev_signal

type signal 
abstract data type containing the event watcher
val signal_init : int -> signal cb -> signal ev
signal_init f signal - call a callback when a certain signal is raised.
Returns the signal event object, still detached from event loop

Child process events

Fired when the status of a child process changes.

Libev documention: Libev ev_child

type child 
abstract data type containing the event watcher
val child_init : int -> bool -> child cb -> child ev
child_init f child trace - call a callback when the status of a child process changes.
Returns the child event object, still detached from event loop
val child_set : child ev -> int -> bool -> unit
child_set ev child trace - set the child event parameters again
See also child_init
val child_get_pid : child ev -> int
child_get_pid ev - retrieve the pid that is being watched
Returns the monitored process pid
val child_get_rpid : child ev -> int
child_get_rpid ev - retrieve the pid that issued a status change
Returns the child process pid
val child_get_rstatus : child ev -> int
child_get_status ev - retrieve the status of the child process
Returns the child process status

Stat events

Fired when the state of a file changes.

Libev documentation: Libev ev_stat

type stat 
abstract data type containing the event watcher
val stat_init : string -> float -> stat cb -> stat ev
stat_init f filename interval - call a callback when the state of a file (as seen by stat) changes
val stat_set : stat ev -> string -> float -> unit
stat_set filename interval - sets the parameters of the event watcher.
val stat_get_attr : stat ev -> Unix.stats
stat_get_attr ev - retrieve the stats of the monitored file
val stat_get_prev : stat ev -> Unix.stats
stat_get_attr ev - retrieve the old stats of the monitored file (befoe the callback)

Idle events

Fired when the event loop has nothing else to do.

Libev documentation: Libev ev_idle

type idle 
abstract data type containing the event watcher
val idle_init : idle cb -> idle ev
idle_init f - call a callback when the event loop has nothing else to do

Fork events

Fired after a fork has been done (and the event loop notices it/is notified about it).

Libev documentation: Libev ev_fork

type fork 
abstract data type containing the event watcher
val fork_init : fork cb -> fork ev
fork_init f - call a callback after a fork (and the event loop notices it/is notified about it).

Prepare/check events

Fired before and after waiting for events.

Libev documention: Libev ev_prepare/check

type prepare 
abstract data type containing the event watcher
type check 
abstract data type containing the event watcher
val prepare_init : prepare cb -> prepare ev
prepare_init f - call a callback when the event loop is about to start waiting for events
val check_init : check cb -> check ev
check_init f - call a callback when the event loop is about to start calling the callbacks after receiving the events

Examples

Complete example: receive lines with timeout

A complete example of semi-efficiently receiving data from stdin and timing out when there has not been input for a short interval (5 seconds).

For some reason this example can misbehave when copy-pasted to a toplevel. #use works fine, though. The problem is that the timeout is fired either instantaneously or otherwise too fast (in about 3 seconds).

(* function for feeding strings to buffer and retrieving whole lines *)
let add_buf_str buf str length =
  let rec add_buf_at buf ofs = 
    let rec find_eol at =
      if at < length then
        if str.[at] = '\n' then
          Some at
        else
          find_eol (at + 1)
       else
         None
    in
      match find_eol ofs with
       | None -> 
         if length <> ofs then
           Buffer.add_substring buf str ofs (length - ofs);
         []
       | Some at ->
         Buffer.add_substring buf str ofs (at - ofs);
         let str = Buffer.contents buf in
           Buffer.clear buf;
           str::add_buf_at buf (at + 1)
  in
    add_buf_at buf 0

let main () = 
  (* the default event loop *)
  let loop = Ev.default_loop [] in

  (* intermediate storage for incoming bytes *)
  let buf = Buffer.create 1024 in

  let exit_io io =
    Printf.printf "Bye!\n%!"; 
    Ev.stop io
  in

  (* a receiving buffer for a single message *)
  let str_buf = String.create 1024 in
  (* start io immediately after creating it *)
  let io_wait = Ev.io_init Unix.stdin [Ev.READ] Ev.no_cb in
  let timeout_wait = Ev.timer_init 5.0 5.0 Ev.no_cb in
    Ev.set_cb io_wait (
      (* use io parameter for an easy mechanism to stop itself *)
      (* revents parameter is ignored *)
      fun io _ ->
        (* receive data from the peer.. (stdin in this case) *)
        try
          let n = Unix.read Unix.stdin str_buf 0 (String.length str_buf) in
            (* bail out when there is an EOF or an error (doesn't handle EAGAIN) *)
            if n <= 0 then exit_io io
            else
              ((* reset timer *)
                Ev.timer_again timeout_wait;
                (* output received messages *)
                List.iter
                  (fun str -> 
                     Printf.printf "Received: %s\n%!" str;
                     if str = "bye" then
		       begin
			 Ev.stop io;
			 Ev.stop timeout_wait;
		       end
                  )
                  (add_buf_str buf str_buf n)
              )
        with 
          | Unix.Unix_error ((Unix.EAGAIN | Unix.EINTR), _, _) -> ()
          | Unix.Unix_error _ -> exit_io io
    );
    Ev.set_cb timeout_wait (
      fun io revents ->
        Printf.printf "Timeout! %s\n%!" (String.concat " " (List.map Ev.string_of_revent revents));
	Ev.unloop (Ev.get_loop io) Ev.UnloopOne;
    );

    Ev.start loop io_wait;
    Ev.start loop timeout_wait;

    (* set the descriptor to a non-blocking mode just in case (certain platforms may produce
       spurious events) *)
    Unix.set_nonblock Unix.stdin;
    (* start it! *)
    Ev.loop loop [];
    Unix.clear_nonblock Unix.stdin

let () = main ()