package tezt

  1. Overview
  2. Docs

Send and receive messages to and from workers.

Messages are composed of:

  • a tag, that uniquely identifies the type of the message;
  • a dynamic value.

Values are said to be "dynamic" because, while they carry information about their type at runtime, their type is lost at compilation time. To recover static type information, one must decode the value by matching with one or more expected tags.

Ideally, we would have used an extensible GADT type to define tags. This would have been both more efficient (no need to encode values into the dynamic value type) and more convenient (no need to define encoding and decoding functions), while still allowing new types of messages to be defined by the user. Unfortunately, values of extensible types (GADT or not) interact badly with Marshal.

type value =
  1. | Unit
  2. | Bool of bool
  3. | Char of char
  4. | Int of int
  5. | Int32 of int32
  6. | Int64 of int64
  7. | Float of float
  8. | String of string
  9. | Block of value array
  10. | Closure of unit -> unit

Untyped values.

Values are serialized and deserialized using Marshal. Be careful with variables that are captured in Closures. For instance, extensible types like exceptions can be serialized, but they cannot be matched on after they are deserialized.

val show_value : value -> string

Convert an untyped value to a human-readable string, for debugging.

type 'mv typ

Type descriptions for message values of type 'mv.

exception Failed_to_decode of value * string

A value could not be decoded.

The first argument is the value that could not be decoded. The second argument is the name of the type that the value was expected to have, such as "bool" or "string".

val typ : encode:('mv -> value) -> decode:(value -> 'mv) -> 'mv typ

Make a type description from an encoding and a decoding function.

It is recommended to raise Failed_to_decode in decode if the value cannot be decoded for the expected type.

val encode : 'mv typ -> 'mv -> value

Get the encoding function of a type description.

val decode : 'mv typ -> value -> 'mv

Get the decoding function of a type description.

val unit : unit typ

The unit type description.

val bool : bool typ

The bool type description.

val char : char typ

The char type description.

val int : int typ

The int type description.

val int32 : int32 typ

The int32 type description.

val int64 : int64 typ

The int64 type description.

val float : float typ

The float type description.

val string : string typ

The string type description.

val closure : (unit -> unit) typ

The type description for unit -> unit closures.

type 'mv tag

Message tags.

The type parameter 'mv is the type of message values before they are encoded and after they are decoded.

val register : 'mv typ -> string -> 'mv tag

Register a new message tag.

Usage: register typ name

This returns a new tag with a unique internal identifier. This guarantees that messages with different tags are not mistaken for each other. Unless you register so many tags that you reach an integer overflow.

The name of the tag is used by show. Note that if you register a tag in the scheduler, workers that are already running will not know about it. They will still be able to handle those messages, but show will print an integer instead of name. Declaring tags in a worker is kind of pointless because messages with this tag will not be readable in the scheduler.

type t

Messages.

val make : 'mv tag -> 'mv -> t

Make a message from a tag and a (typed) value.

val show : t -> string

Convert a message to a human-readable string, for debugging.

val match_with : t -> 'mv tag -> ('mv -> 'result) -> default:(unit -> 'result) -> 'result

Match a message with a tag.

Usage: match_with message tag handler ~default

If message has tag tag, the decoded message value is passed to handler. Else, default is called.

type 'a case

Cases for match_with_list.

val case : 'mv tag -> ('mv -> 'result) -> 'result case

Make a case for match_with_list

Cases are composed of a tag and a handler. The handler is called if the message that is being matched has this tag.

val match_with_list : t -> 'result case list -> default:(unit -> 'result) -> 'result

Same as match_with, but for a list of tags.

Example:

match_with_list message
  [
    (case a @@ fun x -> ...);
    (case b @@ fun x -> ...);
  ]
  ~default: (fun x -> ...)
val send_to_worker : scheduler_context -> 'mv tag -> 'mv -> unit

Send a message from the scheduler to a worker.

This is meant to be called from the scheduler. This is non-blocking.

There is no receive_from_worker function. Instead, use an on_message event handler to receive messages from workers.

val send_to_scheduler : worker_context -> 'mv tag -> 'mv -> unit

Send a message from a worker to the scheduler.

This is meant to be called from a worker. This is blocking, although it should usually return very quickly.

val receive_from_scheduler : worker_context -> t option

Receive a message from the scheduler.

This is meant to be called from a worker. This blocks until a message is available or end of file is received, in which case it returns None.

val receive_from_scheduler_with_timeout : worker_context -> float -> t option

Same as receive_from_scheduler but with a timeout, in seconds.

Returns None if the timeout is reached, or end of file is received, before receiving a complete message.

OCaml

Innovation. Community. Security.