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:
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
type
3.2 Messages, Topics and Roles
struct
(struct role (orientation topic interest-type) #:prefab) orientation : Orientation topic : Topic interest-type : InterestType
type
Role : role
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)
type
InterestType : (U 'participant 'observer 'everything)
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
struct
(struct presence-event (role) #:prefab) role : Role
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
The absence-event-role describes the departing peer, analogously to presence-event-role.
struct
(struct message-event (role message) #:prefab) role : Role message : Message
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))
struct
(struct at-meta-level (preaction) #:prefab) preaction : (PreAction State)
type
AtMetaLevel : (All (State) (at-meta-level State))
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))
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
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
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
type
ProcessSpec : process-spec
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.
If no specific reason is needed, it is conventional to supply #f as the quit-reason.
type
PID : Number