On this page:
3.1 Handler Functions
Handler
Trap  K
Interrupt  K
3.2 Messages, Topics and Roles
Message
Topic
wild
?
role
Role
Orientation
Interest  Type
3.3 Endpoint Events
Endpoint  Event
Presence  Event
Absence  Event
Message  Event
presence-event
absence-event
message-event
3.4 Actions
Action
Pre  Action
at-meta-level
At  Meta  Level
yield
Yield
3.4.1 Endpoints and Messages
add-endpoint
Add  Endpoint
delete-endpoint
Delete  Endpoint
send-message
Send  Message
3.4.2 Process Management
spawn
process-spec
Co  Transition
Spawn
Process  Spec
quit
Quit
PID
6.3.90.900

3 Low-level interface

 (require marketplace) package: marketplace

At its heart, the interface between each process and its containing VM is based on handler functions exchanging event and action structures with the VM. Both events and actions are simple Racket structures.

This low-level interface between a VM and a process is analogous to the system call interface of a Unix-like operating system. The High-level interface corresponds to the C library interface of a Unix-like operating system.

3.1 Handler Functions

Each handler function is always associated with a particular endpoint, registered with the VM via endpoint/add-endpoint. A handler function for a given process with state type State has type:

(EndpointEvent -> State -> (Transition State))

That is, given an EndpointEvent followed by the process’s current state, the handler should reply with a Transition containing a new process state and a collection of Actions.

type

Handler : (All (State) (TrapK State))

type

TrapK : (All (State) (EndpointEvent -> (InterruptK State)))

type

InterruptK : (All (State) (State -> (Transition State)))

Typed Racket types capturing various notions of handler function.

3.2 Messages, Topics and Roles

type

Message : Any

type

Topic : Any

As previously mentioned, messages are ordinary Racket values, and topics are ordinary Racket values which may have embedded wildcards.

procedure

(wild)  Topic

syntax

? : Topic

Each time ? (or (wild)) is used in an expression context, it produces a fresh topic wildcard, suitable for use in a topic pattern.

struct

(struct role (orientation topic interest-type)
    #:prefab)
  orientation : Orientation
  topic : Topic
  interest-type : InterestType

type

Role : role

Roles are almost always constructed by the endpoint/endpoint: macros or by the VM implementations themselves. User programs generally only need to destructure role instances.

A role describes the conversational role of a peer as seen by some process. For example, a subscriber to topic 'foo with interest-type 'participant might receive a presence notification carrying the role

(role 'publisher 'foo 'participant)

Notice that the orientation of the role is the opposite of the orientation of the endpoint.

type

Orientation : (U 'publisher 'subscriber)

Describes an endpoint’s orientation: will it be acting as a publisher of messages, or as a subscriber to messages? Publishers (orientation 'publisher) tend to use send-message and tend to respond to feedback from subscribers; subscribers ('subscriber) tend to use send-feedback and respond to messages from publishers.

type

InterestType : (U 'participant 'observer 'everything)

Using interest-type 'participant in an endpoint’s role indicates that the endpoint is intending to act as a genuine participant in whatever protocol is associated with the endpoint and its topic.

Using 'observer indicates that the endpoint is intended to monitor other ongoing (participant) conversations instead. Observer endpoints receive presence and absence notifications about participant endpoints, but participant endpoints only receive notifications about other participant endpoints, and not about observer endpoints.

The 'observer interest-type is intended to make it easier to monitor resource demand and supply. The monitoring endpoints/processes can react to changing demand by creating or destroying resources to match.

Finally, the 'everything interest-type receives notifications about presence and absence of all the types of endpoint, 'participant, 'observer, and 'everything. Endpoints with interest-type 'everything are rare: they are relevant for managing demand for observers, as well as in some cases of cross-layer presence/absence propagation. Most programs (and even most drivers) will not need to use the 'everything interest-type.

3.3 Endpoint Events

type

EndpointEvent : (U PresenceEvent AbsenceEvent MessageEvent)

type

PresenceEvent : presence-event

type

AbsenceEvent : absence-event

type

MessageEvent : message-event

Endpoint events are passed to handler functions by VMs, conveying some change in the world the process lives in. An endpoint event can signal the arrival or departure of a conversational peer, or can deliver a message that has been sent on a VM’s IPC facility.

struct

(struct presence-event (role)
    #:prefab)
  role : Role
Indicates the arrival of a new conversational partner: an endpoint with a topic that intersects our own, with Orientation opposite to our own.

The presence-event-role describes the arriving peer, or more precisely, describes the shared interest between ourselves and the new peer. In particular, the role-orientation of the presence-event-role is the orientation that the peer supplied in its add-endpoint structure.

struct

(struct absence-event (role reason)
    #:prefab)
  role : Role
  reason : Any
Indicates the departure of an existing conversational partner, through either an explicit delete-endpoint action or the implicit deleting of all of a process’s endpoints when a process exits.

The absence-event-role describes the departing peer, analogously to presence-event-role.

struct

(struct message-event (role message)
    #:prefab)
  role : Role
  message : Message
Indicates the arrival of a message matching the topic pattern in the handler’s endpoint.

3.4 Actions

type

Action : 
(All (State) (U (PreAction State)
                (yield State)
                (at-meta-level State)))

type

PreAction : 
(All (State) (U (add-endpoint State)
                delete-endpoint
                send-message
                (spawn State)
                quit))
Actions are requests from a process to its containing VM. If wrapped in an at-meta-level structure, the action is to apply to the VM’s own containing VM; otherwise, the action applies to the process’s containing VM.

struct

(struct at-meta-level (preaction)
    #:prefab)
  preaction : (PreAction State)

type

AtMetaLevel : (All (State) (at-meta-level State))

An at-meta-level structure wraps a plain action, and makes it apply to the outer VM instead of the inner VM (the default).

struct

(struct yield (k)
    #:prefab)
  k : (InterruptK State)

type

Yield : (All (State) (yield State))

Because current VM implementations are cooperatively scheduled, it can sometimes be necessary to explicitly yield the CPU to other processes using a yield action. When control returns to the yielding process, the yield-k is invoked.

3.4.1 Endpoints and Messages

struct

(struct add-endpoint (pre-eid role handler)
    #:prefab)
  pre-eid : Any
  role : Role
  handler : (Handler State)

type

AddEndpoint : (All (State) (add-endpoint State))

Creates a new endpoint subscribing to the given Role. When events pertaining to the given role occur, the Handler is invoked.If invoked at-meta-level, subscribes to events in the containing VM’s container.

The name of the new endpoint will be the pre-eid; it must be unique within the current process, but otherwise can be any value at all. If the endpoint’s name matches an existing endpoint, and the new role is the same as the existing endpoint’s role, the handler function is replaced in the existing endpoint.

To delete an endpoint, perform a delete-endpoint action built with the name of the endpoint to delete.

struct

(struct delete-endpoint (pre-eid reason)
    #:prefab)
  pre-eid : Any
  reason : Any

type

DeleteEndpoint : delete-endpoint

Deletes an existing endpoint named pre-eid. The given reason is passed along to peer endpoints as part of an absence-event.

If no specific reason is needed, it is conventional to supply #f as the delete-endpoint-reason. See also the convenience delete-endpoint function from marketplace/sugar.

struct

(struct send-message (body orientation)
    #:prefab)
  body : Message
  orientation : Orientation

type

SendMessage : send-message

Sends a message to peers.Or, if at-meta-level, peers of the containing VM. The given Orientation should describe the role the sender is playing when sending this message: usually, it will be 'publisher, but when the message is feedback for some publisher, it will be 'subscriber. See also the send-message and send-feedback convenience functions from marketplace/sugar.

3.4.2 Process Management

struct

(struct spawn (spec k debug-name)
    #:prefab)
  spec : process-spec
  k : (Option (PID -> (InterruptK State)))
  debug-name : Any

struct

(struct process-spec (boot)
    #:prefab)
  boot : (PID -> CoTransition)

type

CoTransition : 
(All (Result)
     (All (State) (Transition State) -> Result)
     -> Result)

type

Spawn : (All (State) (spawn State))

type

ProcessSpec : process-spec

A spawn requests the creation of a sibling processIf wrapped in an at-meta-level, the new process will instead be a sibling of the creating process’s VM.. The spawn-k runs in the context of the creating process, communicating to it the PID of the new process.

The spawn-spec describes the new process to be created. Its process-spec-boot field is a function taking the PID of the new process and returning a "cotransition". Cotransitions use a second-order encoding of existential types to guarantee that the VM remains oblivious to the specific process state type of the new process. The downside of this approach is its syntactic and type complexity: see spawn: for an easier-to-use, higher-level approach.

struct

(struct quit (pid reason)
    #:prefab)
  pid : (Option PID)
  reason : Any

type

Quit : quit

Kills a sibling process.Or, if at-meta-level, a sibling process of the containing VM. If quit-pid is #f, kills the current process; otherwise, kills the process with the given PID. The quit-reason is passed on to peers of currently-active endpoints in the process to be killed, as part of a absence-event, just as if each active endpoint were deleted manually before the process exited.

If no specific reason is needed, it is conventional to supply #f as the quit-reason.

type

PID : Number

In the current VM implementations, process IDs are simply numbers. PIDs are scoped to and allocated by each individual VM instance.