diff --git a/Concepts.html b/Concepts.html index 2990f2b..3b377fc 100644 --- a/Concepts.html +++ b/Concepts.html @@ -1,10 +1,10 @@ -1 Concepts
On this page:
1.1 What is a process, what are event handlers?
1.2 What is a VM?
1.3 Endpoints:   Subscription and Advertisement
1.4 Messages and Topics
1.5 Presence
1.6 Nesting, relaying, and levels of discourse
5.3.4.10

1 Concepts

Marketplace integrates ideas from both distributed systems and +1 Concepts

5.3.4.11

1 Concepts

Marketplace integrates ideas from both distributed systems and virtualized operating system designs to obtain an architecture of nested virtual machines (VMs). Each nested layer is equipped with its own publish/subscribe network that also propagates presence information about the (dis)appearance of services.

Throughout this manual, diagrams such as the following will illustrate -various process structures:

image

Rectangular boxes represent VMs. The processes running within each VM +various process structures:

image

Rectangular boxes represent VMs. The processes running within each VM are placed atop its box. The narrow rectangular strip at the top of each VM’s box represents the network connecting all the VM’s processes to each other; it will frequently contain a short description of the @@ -24,7 +24,7 @@ handlers is called with the process’s current state and a description of the event. The handler is expected to return an updated state value and a collection of actions for the containing VM to perform. An event handler, then, has the following approximate type:

State × EventState × (Listof Action)

Event handlers are registered with the VM by creating endpoints -using the endpoint macro (described in Creating endpoints) or +using the endpoint macro (described in Creating endpoints) or the low-level add-endpoint structure (described in Endpoints and Messages).

Events, passed to event handlers, describe the results of actions from the outside world, neighbouring processes in the VM, or @@ -97,7 +97,7 @@ may be quite different in syntax and meaning from those sent across the same VM’s external network: consider the case of the TCP chat server, which employs a nested VM to separate out TCP-related messages from higher-level, application-specific chat -messages:

image

Each VM’s network corresponds to a distinct level of discourse. +messages:

image

Each VM’s network corresponds to a distinct level of discourse. The nesting of VMs is then roughly analogous to the layering of network protocol stacks. For example (and purely hypothetically!) the -TCP-IP/HTTP/Webapp stack could perhaps be represented as

image

 
\ No newline at end of file +TCP-IP/HTTP/Webapp stack could perhaps be represented as

image

 
\ No newline at end of file diff --git a/Drivers.html b/Drivers.html index d0bbd64..5b102c4 100644 --- a/Drivers.html +++ b/Drivers.html @@ -1,9 +1,9 @@ -4 Drivers
On this page:
4.1 event-relay
event-relay
4.2 tcp-bare
tcp-driver
tcp
4.2.1 TCP channels
tcp-channel
Tcp  Sub  Packet
4.2.2 TCP addresses
Tcp  Address
tcp-address
tcp-handle
tcp-listener
4.2.3 Opening an outbound connection
4.2.4 Accepting inbound connections
4.2.5 Receiving data
4.2.6 Sending data
4.3 timer (typed and untyped)
4.4 udp (typed and untyped)
5.3.4.10

4 Drivers

4.1 event-relay

procedure

(event-relay self-id)  Spawn

  self-id : Symbol
Lets processes in some nested-vm interact with the outside +4 Drivers
5.3.4.11

4 Drivers

4.1 event-relay

procedure

(event-relay self-id)  Spawn

  self-id : Symbol
Lets processes in some nested VM interact with the outside world using ground-vm-level event-based subscriptions.

Returns a spawn which starts an event-relay process with debug-name `(event-relay ,self-id).
The relay process observes subscriptions matching the topic-pattern (cons (? evt?) _), and when one appears, constructs an -analogous one using at-meta-level to connect to the next VM +analogous one using at-meta-level to connect to the next VM down the stack. Messages from the meta-level will be relayed up to the current level. When the subscription disappears, the relay withdraws the subscription at the meta-level as well.

4.2 tcp-bare

This module is only available for use by untyped Racket processes. It @@ -27,18 +27,18 @@ sure not to accidentally clash in handle ID selection. They are also used in TcpChannel to mean a specific instance of a TCP connection, so if you are likely to want to reconnect individual flows, use different values for id.

struct

(struct tcp-listener (port)
  #:prefab)
  port : (integer-in 0 65535)
Describes a local half-connection with a user-assigned port number. -Use this to describe server sockets.

4.2.3 Opening an outbound connection

Choose a tcp-handle, and then create endpoints as follows:

(let ((local (tcp-handle 'some-unique-value))
      (remote (tcp-address "the.remote.host.example.com" 5999)))
  (transition/no-state
   (endpoint #:publisher (tcp-channel local remote ?))
   (endpoint #:subscriber (tcp-channel remote local ?)
             [(tcp-channel _ _ (? eof-object?))
              ; Handle a received end-of-file object
              (transition ...)]
             [(tcp-channel _ _ (? bytes? data))
              ; Handle received data
              (transition ...)])))

The TCP driver will automatically create an outbound connection in +Use this to describe server sockets.

4.2.3 Opening an outbound connection

Choose a tcp-handle, and then create endpoints as follows:

(let ((local (tcp-handle 'some-unique-value))
      (remote (tcp-address "the.remote.host.example.com" 5999)))
  (transition/no-state
   (publisher (tcp-channel local remote ?))
   (subscriber (tcp-channel remote local ?)
     (on-message
      [(tcp-channel _ _ (? eof-object?))
       ; Handle a received end-of-file object
       (transition ...)]
      [(tcp-channel _ _ (? bytes? data))
       ; Handle received data
       (transition ...)]))))

The TCP driver will automatically create an outbound connection in response to the presence of the endpoints. When the endpoints are deleted (or the process exits), the TCP driver will notice the absence and will close the underlying TCP socket.

For a complete example, see TCP chat client.

4.2.4 Accepting inbound connections

Choose a port number, and then create an observer endpoint as -follows:

(endpoint #:subscriber (tcp-channel ? (tcp-listener 5999) ?) #:observer
          #:conversation (tcp-channel them us _)
          #:on-presence (spawn #:child (chat-session them us)))

The use of #:observer here indicates that this endpoint isn’t +follows:

(observe-publishers (tcp-channel ? (tcp-listener 5999) ?)
  (match-conversation (tcp-channel them us _)
    (on-presence (spawn (chat-session them us)))))

The use of observe-publishers here indicates that this endpoint isn’t actually interested in exchanging any TCP data; instead, it is -monitoring demand for such exchanges. The TCP driver uses a rare -#:everything endpoint to monitor the presence of -#:observers, and creates listening TCP server sockets in +monitoring demand for such exchanges. The TCP driver uses the unusual +'everything InterestType to monitor the presence of +'observers, and creates listening TCP server sockets in response. When a connection comes in, the TCP driver spawns a manager -process which offers regular #:participant endpoints for -communicating on the newly-arrived socket.

To illustrate the code for handling a newly-arrived connection,

(define (chat-session them us)
  (transition/no-state
   (endpoint #:subscriber (tcp-channel them us ?)
             #:on-absence (quit)
             [(tcp-channel _ _ (? bytes? data))
              ; Handle incoming data
              (transition ...)])))
4.2.5 Receiving data

TCP-related messages will be of the form

(tcp-channel remote-address local-address subpacket)

where the subpacket is either eof or a +process which offers regular 'participant endpoints for +communicating on the newly-arrived socket.

To illustrate the code for handling a newly-arrived connection,

(define (chat-session them us)
  (transition/no-state
   (subscriber (tcp-channel them us ?)
     (on-absence (quit))
     (on-message [(tcp-channel _ _ (? bytes? data))
                  ; Handle incoming data
                  (transition ...)]))))
4.2.5 Receiving data

TCP-related messages will be of the form

(tcp-channel remote-address local-address subpacket)

where the subpacket is either eof or a bytes?.

4.2.6 Sending data

Send data with

(send-message (tcp-channel local-address remote-address subpacket))

where, as for receiving data, the subpacket is either eof or a bytes?.

4.3 timer (typed and untyped)

For examples of the use of the timer driver, see uses of set-timer and timer-expired in diff --git a/Examples.html b/Examples.html index dc2bb0a..0a43dbf 100644 --- a/Examples.html +++ b/Examples.html @@ -1,19 +1,17 @@ -6 Examples

5.3.4.10

6 Examples

6.1 TCP echo server

Here is a complete Marketplace program:

"examples/echo-paper.rkt"

#lang marketplace
 
(endpoint #:subscriber (tcp-channel ? (tcp-listener 5999) ?)
          #:conversation (tcp-channel from to _)
          #:on-presence (spawn #:child (echoer from to)))
 
(define (echoer from to)
(transition stateless
(endpoint #:subscriber (tcp-channel from to ?)
          #:on-absence (quit)
          [(tcp-channel _ _ data)
           (send-message (tcp-channel to from data))])))

The top-level endpoint action subscribes to TCP connections -arriving on port 5999, and spawns a fresh process in response to -each (#:on-presence). The topic of -conversation (#:conversation) associated with the newly-present -subscription is analyzed to give the remote +6 Examples

5.3.4.11

6 Examples

6.1 TCP echo server

Here is a complete Marketplace program:

"examples/echo-paper.rkt"

#lang marketplace
 
(observe-publishers (tcp-channel ? (tcp-listener 5999) ?)
(match-conversation (tcp-channel from to _)
(on-presence (spawn (echoer from to)))))
 
(define (echoer from to)
(transition stateless
(publisher (tcp-channel to from ?))
(subscriber (tcp-channel from to ?)
(on-absence (quit))
(on-message
 [(tcp-channel _ _ data)
  (send-message (tcp-channel to from data))]))))

The top-level observe-publishers monitors TCP connections +arriving on port 5999 and spawns a fresh process in response +to each with the help of the auxiliary echoer function. The +topic of conversation associated with the each new connection is +parsed (with match-conversation) to name the remote (from) and local (to) TCP addresses, which are -passed to the echoer function to give the initial actions for -the corresponding process. Here, the process is stateless, using the -special constant stateless as its state.

Each connection’s process creates an endpoint subscribing to data -arriving on its particular connection, using from and to -passed in from the top-level endpoint. When data arrives, it is -echoed back to the remote peer using send-message. Presence -manages disconnection; when the remote peer closes the TCP connection, -the #:on-absence handler in echoer issues a quit -action, terminating the connection’s process. The heart of our system -is the interface between a process and its containing VM. Our -implementation instantiates this interface as a collection of Typed -Racket programs.

6.2 TCP chat server

"examples/chat-paper.rkt"

#lang marketplace
 
(nested-vm
 (at-meta-level
  (endpoint #:subscriber (tcp-channel ? (tcp-listener 5999) ?) #:observer
            #:conversation (tcp-channel them us _)
            #:on-presence (spawn #:child (chat-session them us)))))
 
(define (chat-session them us)
(define user (gensym 'user))
(transition stateless
            (listen-to-user user them us)
            (speak-to-user user them us)))
 
(define (listen-to-user user them us)
(list
 (endpoint #:publisher `(,user says ,?))
 (at-meta-level
  (endpoint #:subscriber (tcp-channel them us ?)
            #:on-absence (quit)
            [(tcp-channel _ _ (? bytes? text))
             (send-message `(,user says ,text))]))))
 
(define (speak-to-user user them us)
(define (say fmt . args)
(at-meta-level (send-message (tcp-channel us them (apply format fmt args)))))
(define (announce who did-what)
(unless (equal? who user) (say "~s ~s.~n" who did-what)))
(list
 (say "You are ~s.~n" user)
 (at-meta-level
  (endpoint #:publisher (tcp-channel us them ?)))
(endpoint #:subscriber `(,? says ,?)
          #:conversation `(,who says ,_)
          #:on-presence (announce who 'arrived)
          #:on-absence  (announce who 'departed)
          [`(,who says ,what) (say "~a: ~a" who what)])))

6.3 TCP chat client

"examples/chat-client.rkt"

#lang marketplace
(require racket/port)
 
(spawn #:debug-name 'console-output-driver
       #:child
       (transition/no-state
        (endpoint #:subscriber (list 'console-output ?)
                  [(list 'console-output item)
                   (begin (printf "~a" item)
                          (void))])))
 
(spawn #:debug-name 'console-input-driver
       #:child
       (transition/no-state
        (endpoint #:publisher (list 'console-input ?)
                  #:name 'input-relay
                  #:on-absence
                  (list (send-message (list 'console-output "Connection terminated.\n"))
                        (quit)))
(endpoint #:subscriber (cons (read-line-evt (current-input-port) 'any) ?)
          [(cons _ (? eof-object?))
           (list (send-message (list 'console-output "Terminating on local EOF.\n"))
                 (delete-endpoint 'input-relay))]
[(cons _ (? string? line))
 (send-message (list 'console-input line))])))
 
(spawn #:debug-name 'outbound-connection
       #:child
       (let ((local (tcp-handle 'outbound))
             (remote (tcp-address "localhost" 5999)))
(transition/no-state
 (endpoint #:subscriber (list 'console-input ?)
           #:on-absence (quit)
           [(list 'console-input line)
            (list (send-message (list 'console-output (format "> ~a \n" line)))
                  (send-message (tcp-channel local remote (string-append line "\n"))))])
(endpoint #:publisher (tcp-channel local remote ?))
(endpoint #:subscriber (tcp-channel remote local ?)
          #:on-absence (quit)
          [(tcp-channel _ _ (? eof-object?))
           (quit)]
[(tcp-channel _ _ data)
 (list (send-message (list 'console-output (format "< ~a" data)))
       (void))]))))
 
\ No newline at end of file +passed to echoer to create the initial state and actions for +the corresponding process. In this case, the process is stateless, +indicated by the special constant stateless.

Each connection’s process watches for incoming data, using +from and to to configure a subscriber. It +also declares its intent to produce outbound TCP data, using +publisher. When data arrives, it is echoed back to the remote +peer using the send-message operation. Absence notifications +signal disconnection; when the remote peer closes the TCP connection, +the on-absence handler issues a quit action, which +terminates the connection’s process.

6.2 TCP chat server

"examples/chat-paper.rkt"

#lang marketplace
 
(spawn-vm
 (at-meta-level
  (observe-publishers (tcp-channel ? (tcp-listener 5999) ?)
(match-conversation (tcp-channel them us _)
(on-presence (spawn (chat-session them us)))))))
 
(define (chat-session them us)
(define user (gensym 'user))
(transition stateless
(listen-to-user user them us)
(speak-to-user user them us)))
 
(define (listen-to-user user them us)
(list
 (at-meta-level
  (subscriber (tcp-channel them us ?)
(on-absence (quit))
(on-message
 [(tcp-channel _ _ (? bytes? text))
  (send-message `(,user says ,text))])))
(publisher `(,user says ,?))))
 
(define (speak-to-user user them us)
(define (say fmt . args)
(at-meta-level
 (send-message
  (tcp-channel us them (apply format fmt args)))))
(define (announce who did-what)
(unless (equal? who user)
(say "~s ~s.~n" who did-what)))
(list
 (say "You are ~s.~n" user)
 (at-meta-level
  (publisher (tcp-channel us them ?)))
(subscriber `(,? says ,?)
(match-conversation `(,who says ,_)
(on-presence (announce who 'arrived))
(on-absence  (announce who 'departed))
(on-message [`(,who says ,what)
             (say "~a: ~a" who what)])))))

6.3 TCP chat client

"examples/chat-client.rkt"

#lang marketplace
(require racket/port)
 
; Usually it's OK to just use display and friends directly.
; Here we have a console output driver just to show how it's done.
(name-process 'console-output-driver
(spawn (transition/no-state
(subscriber (list 'console-output ?)
(on-message [(list 'console-output item)
             (printf "~a" item)
             (void)])))))
 
(name-process 'console-input-driver
(spawn (transition/no-state
(name-endpoint 'input-relay
(publisher (list 'console-input ?)
(on-absence
 (send-message (list 'console-output "Connection terminated.\n"))
 (quit))))
(subscriber (cons (read-line-evt (current-input-port) 'any) ?)
(on-message
 [(cons _ (? eof-object?))
  (send-message (list 'console-output "Terminating on local EOF.\n"))
  (delete-endpoint 'input-relay)]
[(cons _ (? string? line))
 (send-message (list 'console-input line))])))))
 
(name-process 'outbound-connection
(spawn (let ((local (tcp-handle 'outbound))
             (remote (tcp-address "localhost" 5999)))
(transition/no-state
(subscriber (list 'console-input ?)
(on-absence (quit))
(on-message
 [(list 'console-input line)
  (send-message (list 'console-output (format "> ~a \n" line)))
  (send-message (tcp-channel local remote (string-append line "\n")))]))
(publisher (tcp-channel local remote ?))
(subscriber (tcp-channel remote local ?)
(on-absence (quit))
(on-message
 [(tcp-channel _ _ (? eof-object?))
  (quit)]
[(tcp-channel _ _ data)
 (send-message (list 'console-output (format "< ~a" data)))]))))))
 
\ No newline at end of file diff --git a/Management_and_Monitoring.html b/Management_and_Monitoring.html index 1dad487..d8cc938 100644 --- a/Management_and_Monitoring.html +++ b/Management_and_Monitoring.html @@ -1,6 +1,6 @@ -5 Management and Monitoring
5.3.4.10

5 Management and Monitoring

5.1 generic-spy

procedure

(generic-spy label)  Spawn

  label : Any
Returns a spawn action that, when executed, creates a process -with a #:subscriber endpoint listening for every +5 Management and Monitoring
5.3.4.11

5 Management and Monitoring

5.1 generic-spy

procedure

(generic-spy label)  Spawn

  label : Any
Returns a spawn action that, when executed, creates a process +with a #:subscriber endpoint listening for every message. Each EndpointEvent received by the endpoint is printed to the current output port. Using this process gives a crude trace of activity within a VM: presence-events and diff --git a/high-level-interface.html b/high-level-interface.html index 83bb07c..0d70f22 100644 --- a/high-level-interface.html +++ b/high-level-interface.html @@ -1,5 +1,5 @@ -2 High-level interface
5.3.4.10

2 High-level interface

This high-level interface between a VM and a process is analogous to +2 High-level interface

5.3.4.11

2 High-level interface

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

2.1 Using #lang marketplace and friends

 #lang marketplace

Programs written for Marketplace differ from normal Racket modules @@ -19,7 +19,7 @@ directly.

Such programs need to use "examples/echo-plain.rkt" uses ground-vm along with -tcp and an initial endpoint action:

(ground-vm
  tcp
  (endpoint #:subscriber (tcp-channel ? (tcp-listener 5999) ?)
            #:conversation (tcp-channel from to _)
            #:on-presence (spawn #:child (echoer from to))))

syntax

(ground-vm maybe-boot-pid-binding maybe-initial-state initial-action ...)

syntax

(ground-vm: maybe-boot-pid-binding maybe-typed-initial-state initial-action ...)

 
maybe-boot-pid-binding = 
  | #:boot-pid id
     
maybe-initial-state = 
  | #:initial-state expr
     
maybe-typed-initial-state = 
  | #:initial-state expr : type
     
initial-action = expr
Starts the ground VM, in untyped and typed programs, respectively. If +tcp and an initial endpoint action:

(ground-vm tcp
           (subscriber (tcp-channel ? (tcp-listener 5999) ?)
             (match-conversation (tcp-channel from to _)
               (on-presence (spawn (echoer from to))))))

syntax

(ground-vm maybe-boot-pid-binding maybe-initial-state initial-action ...)

syntax

(ground-vm: maybe-boot-pid-binding maybe-typed-initial-state initial-action ...)

 
maybe-boot-pid-binding = 
  | #:boot-pid id
     
maybe-initial-state = 
  | #:initial-state expr
     
maybe-typed-initial-state = 
  | #:initial-state expr : type
     
initial-action = expr
Starts the ground VM, in untyped and typed programs, respectively. If #:boot-pid is specified, the given identifier is bound within the form to the PID of the primordial process that performs the initial actions. If #:initial-state is specified (with a @@ -53,73 +53,91 @@ actions; if it is a procedure, it is called with the
(sequence-actions (transition 'x
                    (send-message (list 'message 0)))
                  (send-message (list 'message 1))
                  (send-message (list 'message 2))
                  (lambda (old-state)
                    (transition (cons 'y old-state)
                      (send-message (list 'message 3))))
                  (send-message (list 'message 4)))

produces the equivalent of

(transition (cons 'y 'x)
  (send-message (list 'message 0))
  (send-message (list 'message 1))
  (send-message (list 'message 2))
  (send-message (list 'message 3))
  (send-message (list 'message 4)))

2.4 Creating endpoints

The primitive action that creates new endpoints is add-endpoint, but because endpoints are the most flexible and -complex point of interaction between a process and its VM, a DSL, -endpoint, streamlines endpoint setup.

syntax

(endpoint orientation topic maybe-interest-type
          maybe-let-name
          maybe-name
          maybe-state-pattern
          maybe-on-presence
          maybe-on-absence
          maybe-role-patterns
          maybe-reason-pattern
          maybe-message-handlers)

syntax

(endpoint: maybe-typed-state-pattern : State
           orientation topic maybe-interest-type
           maybe-let-name
           maybe-name
           maybe-on-presence
           maybe-on-absence
           maybe-role-patterns
           maybe-reason-pattern
           maybe-message-handlers)
 
maybe-typed-state-pattern = 
  | pattern
     
orientation = #:subscriber
  | #:publisher
     
topic = expr
     
maybe-interest-type = 
  | #:participant
  | #:observer
  | #:everything
     
maybe-let-name = 
  | #:let-name identifier
     
maybe-name = 
  | #:name expr
     
maybe-state-pattern = 
  | #:state pattern
     
maybe-on-presence = 
  | #:on-presence handler-expr
     
maybe-on-absence = 
  | #:on-absence handler-expr
     
maybe-role-patterns = 
  | #:role pattern
  | 
#:peer-orientation pattern
#:conversation pattern
#:peer-interest-type pattern
     
maybe-reason-pattern = 
  | #:reason pattern
     
maybe-message-handlers = 
  | message-handler ...
     
message-handler = [pattern handler-expr]
     
handler-expr = expr
Almost everything is optional in an endpoint. The only -mandatory parts are the orientation and the topic. For -endpoint:, the expected type of the process state must also -be supplied.

For example, a minimal endpoint subscribing to all messages would be:

(endpoint #:subscriber ?)

or in Typed Racket, for a process with Integer as its process -state type,

(endpoint: : Integer #:subscriber ?)

A minimal publishing endpoint would be:

(endpoint #:publisher ?)
(endpoint: : Integer #:publisher ?)

While topic patterns are ordinary Racket data with embedded ? +complex point of interaction between a process and its VM, a +collection of macros helps streamline endpoint setup.

syntax

(publisher topic handler ...)

syntax

(publisher: State topic handler ...)

syntax

(subscriber topic handler ...)

syntax

(subscriber: State topic handler ...)

syntax

(observe-subscribers topic handler ...)

syntax

(observe-subscribers: State topic handler ...)

syntax

(observe-publishers topic handler ...)

syntax

(observe-publishers: State topic handler ...)

syntax

(observe-subscribers/everything topic handler ...)

syntax

(observe-subscribers/everything: State topic handler ...)

syntax

(observe-publishers/everything topic handler ...)

syntax

(observe-publishers/everything: State topic handler ...)

syntax

(build-endpoint pre-eid role handler ...)

syntax

(build-endpoint: State pre-eid role handler ...)

The many variations on the core +build-endpoint/build-endpoint: form exist to give +good control over InterestType in the endpoint under +construction; +see Participating in a conversation vs. observing conversations.

Almost everything is optional in an endpoint definition. The only +mandatory part is the topic, unless you’re using Typed Racket, in +which case the process state type must also be specified.

For example, a minimal endpoint subscribing to all messages would be:

(subscriber ?)

or in Typed Racket, for a process with Integer as its process +state type,

(subscriber: Integer ?)

A minimal publishing endpoint would be:

(publisher ?)
(publisher: Integer ?)

While topic patterns are ordinary Racket data with embedded ? wildcards (see Messages and Topics), all the other patterns -in an endpoint are match-patterns. In particular +in an endpoint definition are match-patterns. In particular note that ? is a wildcard in a topic pattern, while -_ is a wildcard in a match-pattern.

2.4.1 Receiving messages

Supply one or more message-handler clauses to handle incoming -message events (as distinct from presence- or absence-events).

The following endpoint subscribes to all messages, but only -handles some of them:

(endpoint #:subscriber ?
          ['ping (send-message 'pong)]
          ['hello (list (send-message 'goodbye)
                        (quit))])
2.4.2 Action-only vs. State updates

If #:state occurs in an endpoint, or the -maybe-typed-state-pattern occurs in an endpoint:, -then all the handler-exprs in that endpoint are expected to -return transition structures.

If not, however, the event handler expressions are expected to return -plain ActionTrees.

This way, simple endpoints that do not need to examine the process +_ is a wildcard in a match-pattern.

2.4.1 Receiving messages

syntax

(on-message [pattern expr ...] ...)

Supply an on-message handler clause to an endpoint definition +to handle incoming message events (as distinct from presence- or +absence-events).

The following endpoint subscribes to all messages, but only +handles some of them:

(subscriber ?
  (on-message
   ['ping (send-message 'pong)]
   ['hello (list (send-message 'goodbye)
                 (quit))]))
2.4.2 Action-only vs. State updates

syntax

(match-state pattern handler ...)

If a group of handlers is wrapped in match-state, then all +the wrapped handlers are expected to return +transition structures.

If not, however, the handler expressions are expected to return plain +ActionTrees.

This way, simple handlers that do not need to examine the process state, and simply act in response to whichever event triggered them, can be written without the clutter of threading the process state -value through the code.

For example, a simple endpoint could be written either as

(endpoint #:subscriber 'ping
          ['ping (send-message 'pong)])

or, explicitly accessing the endpoint’s process’s state,

(endpoint #:subscriber 'ping
          #:state old-state
          ['ping (transition old-state
                   (send-message 'pong))])
2.4.3 Naming endpoints

Endpoint names can be used to update -or delete endpoints.

If #:name is supplied, the given value is used as the name of -the endpoint. If not, a fresh name is created. (At present, -gensym is used.)

If #:let-name is supplied, the given identifier is bound in -the handler-exprs to the name of the endpoint. If not, the -name of the endpoint is inaccessible to the handler-exprs.

2.4.4 Handling presence and absence events

Other endpoints (in this or other processes) may have matching topics +value through the code.

For example, a simple endpoint could be written either as

(subscriber 'ping
  (on-message ['ping (send-message 'pong)]))

or, explicitly accessing the endpoint’s process’s state,

(subscriber 'ping
  (match-state old-state
    (on-message ['ping (transition old-state
                         (send-message 'pong))])))
2.4.3 Handling presence and absence events

syntax

(on-presence expr ...)

syntax

(on-absence expr ...)

Other endpoints (in this or other processes) may have matching topics and complementary orientations to the current endpoint. When such endpoints come and go, presence and absence events are generated in -the current endpoint.

By default, no actions are taken on such events, but -#:on-presence and #:on-absence override this -behaviour.

For example, say process A establishes the following endpoint:

(endpoint #:subscriber 'ping
          #:on-presence (send-message 'pinger-arrived)
          #:on-absence  (send-message 'pinger-departed)
          ['ping (send-message 'pong)])

Some time later, process B takes the following endpoint-establishing -action:

(endpoint #:publisher 'ping
          #:let-name ping-endpoint-name
          #:on-presence
          (list (endpoint #:subscriber 'pong
                          #:let-name pong-waiter-name
                          ['pong (list (delete-endpoint ping-endpoint-name)
                                       (delete-endpoint pong-waiter-name))])
                (send-message 'ping)))

The sequence of events will be:

  1. Process A’s #:on-presence handler will run, and the +the current endpoint.

By default, no actions are taken on such events, but +on-presence and on-absence handlers override this +behaviour.

For example, say process A establishes the following endpoint:

(subscriber 'ping
  (on-presence (send-message 'pinger-arrived))
  (on-absence  (send-message 'pinger-departed))
  (on-message ['ping (send-message 'pong)]))

Some time later, process B takes the following endpoint-establishing +action:

(let-fresh (ping-endpoint-name pong-waiter-name)
  (name-endpoint ping-endpoint-name
    (publisher 'ping
      (on-presence
       (list (name-endpoint pong-waiter-name
               (subscriber 'pong
                 (on-message
                  ['pong (list (delete-endpoint ping-endpoint-name)
                               (delete-endpoint pong-waiter-name))])))
             (send-message 'ping))))))

The sequence of events will be:

  1. Process A’s on-presence handler will run, and the 'pinger-arrived message will be sent. At the same time,In the current implementation, one happens before the other, but it is nondeterministic which is run first. process B’s -#:on-presence handler runs, installing a second endpoint +on-presence handler runs, installing a second endpoint and sending the 'ping message.

  2. Process A’s endpoint receives the 'ping message, and sends the 'pong message.

  3. Process B’s second endpoint receives the 'pong -message, and deletes both of process B’s endpoints.

  4. The #:on-absence handler in process A runs, sending +message, and deletes both of process B’s endpoints.

  5. The on-absence handler in process A runs, sending the 'pinger-departed message.

One possible trace of messages in the VM containing processes A and B is

'pinger-arrived
'ping
'pong
'pinger-departed

By sending the 'ping message only once the -#:on-presence handler has fired, process B ensures that +on-presence handler has fired, process B ensures that someone is listening for pings.

This way, if process B starts before process A, then B will automatically wait until A is ready to receive ping requests before -issuing any.

2.4.5 Exit reasons

If a #:reason pattern is supplied, then the exit reason -supplied to the delete-endpoint or quit action that -led to the absence-event is available to the endpoint’s -#:on-absence handler expression.

2.4.6 Updating endpoints

If, when an endpoint is created, an existing endpoint with an +issuing any.

2.4.4 Exit reasons

syntax

(match-reason pattern handler ...)

If a handler is wrapped in a match-reason form, then the exit +reason supplied to the delete-endpoint or quit +action that led to the absence-event is available to the +endpoint’s on-absence handler expression.

2.4.5 Updating endpoints

If, when an endpoint is created, an existing endpoint with an equal? name is already present, then if the existing and to-be-added endpoints have exactly equal roles (meaning equal orientations, interest-types, and topic patterns), the handlers for the endpoint are updated without emitting presence or absence notifications.

This dubious feature can be used to avoid "glitching" of presence signals. A future release of this library will include better -automatic support for avoiding such transients.

2.4.7 Who am I talking to?

If either #:role or any of #:peer-orientation, -#:conversation, or #:peer-interest-type are -supplied, the handler-exprs are given access to the role -carried in the EndpointEvent that triggered them.

This role describes the intersection of interests between the -current endpoint and the peer endpoint, and so can proxy for the -identity of the other party. It is in a sense a description of the -scope of the current conversation.

Using #:role allows a handler complete access to the -role structure in the triggering event. It is more common -however to simply use #:conversation to extract the -role-topic alone, since it is seldom necessary to examine +automatic support for avoiding such transients.

2.4.6 Who am I talking to?

syntax

(match-orientation pattern handler ...)

syntax

(match-conversation pattern handler ...)

syntax

(match-interest-type pattern handler ...)

Wrapping a handler in match-orientation, +match-conversation, and/or match-interest-type gives +a handler access to the contents of the role structure +carried in the triggering EndpointEvent.

The carried role describes the intersection of interests +between the current endpoint and the peer endpoint, and so can proxy +for the identity of the other party. It is in a sense a description of +the scope of the current conversation.

It is most common to simply use match-conversation to extract +the role-topic alone, since it is seldom necessary to examine role-orientation (since it’s guaranteed to be complementary to the orientation of the current endpoint) or -role-interest-type. If access to those parts is required, use -#:peer-orientation and #:peer-interest-type.

2.5 Deleting endpoints

procedure

(delete-endpoint id [reason])  Action

  id : Any
  reason : Any = #f
Use this action to delete a previously-added endpoint by name. The +role-interest-type.

See Examples for examples of the use of +match-conversation and friends.

2.4.7 Participating in a conversation vs. observing conversations

The core build-endpoint form takes an expression evaluating +to a role, rather than a simple topic. This gives full +control over the new endpoint’s Orientation and +InterestType.

The other forms exist for convenience, since usually the orientation +and interest-type is known statically, and only the topic varies +dynamically:

The publisher, observe-subscribers and +observe-subscribers/everything forms create +publisher-oriented endpoints, and subscriber, +observe-publishers and observe-publishers/everything +create subscriber-oriented endpoints. The rationale for this is +that as a participant, the code should declare the role being played; +but as an observer, the code should declare the roles being observed.

2.4.8 Naming endpoints

Endpoint names can be used to update +or delete endpoints.

procedure

(name-endpoint id add-endpoint-action)  AddEndpoint

  id : Any
  add-endpoint-action : AddEndpoint
Returns a copy of the passed-in add-endpoint action +structure, with the id field set to the passed-in identifying +value.

syntax

(let-fresh (identifier ...) expr ...)

Binds the identifiers to freshly-gensymmed symbols so that +they are available to the exprs. let-fresh is useful +for inventing a guaranteed-unused name for a temporary endpoint:

(let-fresh (my-name)
  (name-endpoint my-name
    (subscriber ?
      (on-message [_ (list (delete-endpoint my-name)
                           ...)]))))

2.5 Deleting endpoints

procedure

(delete-endpoint id [reason])  Action

  id : Any
  reason : Any = #f
Use this action to delete a previously-added endpoint by name. The id given must be equal? to the corresponding -add-endpoint-pre-eid; when endpoint was used to +add-endpoint-pre-eid; when endpoint was used to construct the endpoint to be deleted, the relevant name is that bound by #:let-name or supplied to #:name. See Naming endpoints.

If reason is supplied, it is included in the corresponding @@ -127,45 +145,48 @@ action, and made available in any resulting 'publisher; it means that the sender of the message is acting in the "publisher" role. Use 'subscriber instead when acting in the "subscriber" -role, i.e. sending feedback.

procedure

(send-feedback body)  Action

  body : Any
Equivalent to (send-message body 'subscriber).

2.7 Creating processes

syntax

(spawn maybe-pid-binding maybe-debug-name maybe-parent-continuation
       #:child boot-expr)

syntax

(spawn: maybe-pid-binding maybe-debug-name typed-parent-continuation
        #:child : ChildStateType boot-expr)
 
maybe-pid-binding = 
  | #:pid identifier
     
maybe-debug-name = 
  | #:debug-name expr
     
maybe-parent-continuation = 
  | #:parent k-expr
  | #:parent parent-state-pattern k-expr
     
typed-parent-continuation = #:parent : ParentStateType
  | #:parent : ParentStateType k-expr
  | #:parent parent-state-pattern : ParentStateType k-expr
     
k-expr = expr
     
boot-expr = expr
Action describing a new process to create. The boot-expr +role, i.e. sending feedback.

procedure

(send-feedback body)  Action

  body : Any
Equivalent to (send-message body 'subscriber).

2.7 Creating processes

syntax

(spawn maybe-pid-binding boot-expr)

syntax

(spawn/continue maybe-pid-binding
                #:parent parent-state-pattern k-expr
                #:child boot-expr)

syntax

(spawn: maybe-pid-binding
        #:parent : ParentStateType
        #:child : ChildStateType boot-expr)

syntax

(spawn/continue: maybe-pid-binding
                 #:parent parent-state-pattern : ParentStateType k-expr
                 #:child : ChildStateType boot-expr)
 
maybe-pid-binding = 
  | #:pid identifier
     
k-expr = expr
     
boot-expr = expr
Action describing a new process to create. The boot-expr should be an expression yielding a transition that contains the child process’s initial state and initial actions.

If #:pid is supplied, the associated identifier is bound to the child process’s PID in both boot-expr and the parent’s -k-expr.

Any supplied #:debug-name will be used in VM debug output. -See also logging (MARKETPLACE_LOG).

If #:parent is supplied, the associated k-expr will -run in the parent process after the child process has been created. If -the parent-state-pattern is also supplied, then -k-expr must return a Transition; otherwise, it must -return an ActionTree. Note that in Typed Racket, for type -system reasons, spawn: requires ParentStateType to -be supplied.

2.8 Exiting and killing processes

procedure

(quit [who reason])  Action

  who : (Option PID) = #f
  reason : Any = #f
Action causing the termination of a process. If who is +k-expr.

The spawn/continue and spawn/continue: variations +include a k-expr, which will run in the parent process after +the child process has been created. Note that k-expr must +return a Transition, since parent-state-pattern is +always supplied for these variations.

In Typed Racket, for type system reasons, spawn: and +spawn/continue: require ParentStateType to be +supplied as well as ChildStateType.

procedure

(name-process id spawn-action)  Spawn

  id : Any
  spawn-action : Spawn
Returns a copy of the passed-in spawn action structure, with +the debug-name field set to the passed-in identifying value. +The debug name of a process is used in VM debug output. See also +logging (MARKETPLACE_LOG).

2.8 Exiting and killing processes

procedure

(quit [who reason])  Action

  who : (Option PID) = #f
  reason : Any = #f
Action causing the termination of a process. If who is omitted or #f, terminates the acting process; otherwise, terminates the peer process having who as its PID.

If reason is supplied, it is included in the corresponding action, and made available in any resulting absence-events.

Terminating the current process is as simple as:

(quit)

When a process raises an exception that it does not catch, its containing VM catches the exception and turns it into an implicit quit action. In that case, the reason will be the raised exception -itself.

2.9 Cooperative scheduling

syntax

(yield maybe-state-pattern k-expr)

syntax

(yield: typed-state-pattern k-expr)

 
maybe-state-pattern = 
  | #:state pattern
     
typed-state-pattern = : State
  | pattern : State
     
k-expr = expr
Lets other processes in the system run for a step, returning to +itself.

2.9 Cooperative scheduling

syntax

(yield state-pattern k-expr)

syntax

(yield: state-pattern : State k-expr)

Lets other processes in the system run for a step, returning to evaluate k-expr only after doing a complete round of the -scheduler.

If pattern is supplied, k-expr should evaluate to a -Transition; otherwise it should produce an ActionTree.

2.10 Creating nested VMs

syntax

(nested-vm maybe-vm-pid-binding maybe-boot-pid-binding
           maybe-initial-state
           maybe-debug-name
           boot-action-expr ...)

syntax

(nested-vm: : ParentStateType
            maybe-vm-pid-binding maybe-boot-pid-binding
            maybe-typed-initial-state
            maybe-debug-name
            boot-action-expr ...)
 
maybe-vm-pid-binding = 
  | #:vm-pid identifier
     
maybe-boot-pid-binding = 
  | #:boot-pid identifier
     
maybe-initial-state = 
  | #:initial-state expr
     
maybe-typed-initial-state = 
  | #:initial-state expr : StateType
     
maybe-debug-name = 
  | #:debug-name expr
     
boot-action-expr = expr
Results in a spawn action that starts a nested VM. The +scheduler.

The state of the yielding process will be matched against +state-pattern when the process is resumed, and +k-expr must evaluate to a Transition.

2.10 Creating nested VMs

syntax

(spawn-vm maybe-vm-pid-binding maybe-boot-pid-binding
          maybe-initial-state
          maybe-debug-name
          boot-action-expr ...)

syntax

(spawn-vm: : ParentStateType
           maybe-vm-pid-binding maybe-boot-pid-binding
           maybe-typed-initial-state
           maybe-debug-name
           boot-action-expr ...)
 
maybe-vm-pid-binding = 
  | #:vm-pid identifier
     
maybe-boot-pid-binding = 
  | #:boot-pid identifier
     
maybe-initial-state = 
  | #:initial-state expr
     
maybe-typed-initial-state = 
  | #:initial-state expr : StateType
     
maybe-debug-name = 
  | #:debug-name expr
     
boot-action-expr = expr
Results in a spawn action that starts a nested VM. The primordial process in the new VM executes the boot-actions with the given initial state. (If no initial state is supplied, (void) is used.)

If #:vm-pid is present, the corresponding identifier is bound in the boot-action expressions to the container-relative PID of the new VM itself. If #:boot-pid is present, however, the corresponding identifier is bound to the new-VM-relative PID of the -primordial process in the new VM.

2.11 Relaying across layers

syntax

(at-meta-level: : StateType preaction ...)

procedure

(at-meta-level preaction ...)  (Action StateType)

  preaction : (PreAction State)
Each VM gives its processes access to two distinct IPC facilities: the +primordial process in the new VM.

2.11 Relaying across layers

syntax

(at-meta-level: StateType preaction ...)

procedure

(at-meta-level preaction ...)  (Action StateType)

  preaction : (PreAction State)
Each VM gives its processes access to two distinct IPC facilities: the internal one, provided for the VM’s processes to talk amongst themselves, and the external one, the network that the VM itself is a process within.

Marketplace’s actions can apply to either of those two networks. By default, actions apply to the VM of the acting process directly, but -using at-meta-level (or at-meta-level: in typed +using at-meta-level (or at-meta-level: in typed code) to wrap an action level-shifts the action to make it -apply at the level of the acting process’s VM’s container instead.

For example, wrapping an endpoint in at-meta-level +apply at the level of the acting process’s VM’s container instead.

For example, wrapping an endpoint in at-meta-level adds a subscription to the VM’s container’s network. Instead of listening to sibling processes of the acting process, the new endpoint will listen to sibling processes of the acting process’s VM. In this -example, the primordial process in the nested-vm creates an -endpoint in the VM’s own network, the ground VM:

(nested-vm
 (at-meta-level
  (endpoint #:subscriber (tcp-channel ? (tcp-listener 5999) ?) ...)))

In this example, a new process is spawned as a sibling of the -nested-vm rather than as a sibling of its primordial process:

(nested-vm
 (at-meta-level
  (spawn #:child (transition/no-state (send-message 'hello-world)))))

Compare to this example, which spawns a sibling of the -nested-vm’s primordial process:

(nested-vm
 (spawn #:child (transition/no-state (send-message 'hello-world))))
 
\ No newline at end of file +example, the primordial process in the nested VM creates an +endpoint in the VM’s own network, the ground VM:

(spawn-vm
 (at-meta-level
  (subscriber (tcp-channel ? (tcp-listener 5999) ?) ...)))

In this example, a new process is spawned as a sibling of the +nested VM rather than as a sibling of its primordial process:

(spawn-vm
 (at-meta-level
  (spawn (transition/no-state (send-message 'hello-world)))))

Compare to this example, which spawns a sibling of the +nested VM’s primordial process:

(spawn-vm
 (spawn (transition/no-state (send-message 'hello-world))))
 
\ No newline at end of file diff --git a/index.html b/index.html index a4ca6ed..0d2efba 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ -Marketplace: Network-Aware Programming
5.3.4.10

Marketplace: Network-Aware Programming

Tony Garnock-Jones <tonyg@ccs.neu.edu>

Every program is a network. +Marketplace: Network-Aware Programming

5.3.4.11

Marketplace: Network-Aware Programming

Tony Garnock-Jones <tonyg@ccs.neu.edu>

Every program is a network. This is the insight behind the π-calculus. Encoding a program as a π-calculus term shows it as a network of communicating processes. It is also one of the original inspirations for Smalltalk, where every @@ -34,4 +34,4 @@ location of mutable state, failure detection and recovery, access control, I/O and user interface, debugging and profiling.

Marketplace addresses these concerns with a small set of primitives chosen to make network programming in-the-small as flexible, scalable, manageable and securable as network programming in-the-large—and -vice versa.

    1 Concepts

      1.1 What is a process, what are event handlers?

      1.2 What is a VM?

      1.3 Endpoints: Subscription and Advertisement

      1.4 Messages and Topics

      1.5 Presence

      1.6 Nesting, relaying, and levels of discourse

    2 High-level interface

      2.1 Using #lang marketplace and friends

      2.2 Using Marketplace as a library

      2.3 Constructing transitions

      2.4 Creating endpoints

        2.4.1 Receiving messages

        2.4.2 Action-only vs. State updates

        2.4.3 Naming endpoints

        2.4.4 Handling presence and absence events

        2.4.5 Exit reasons

        2.4.6 Updating endpoints

        2.4.7 Who am I talking to?

      2.5 Deleting endpoints

      2.6 Sending messages and feedback

      2.7 Creating processes

      2.8 Exiting and killing processes

      2.9 Cooperative scheduling

      2.10 Creating nested VMs

      2.11 Relaying across layers

    3 Low-level interface

      3.1 Handler Functions

      3.2 Messages, Topics and Roles

      3.3 Endpoint Events

      3.4 Actions

        3.4.1 Endpoints and Messages

        3.4.2 Process Management

    4 Drivers

      4.1 event-relay

      4.2 tcp-bare

        4.2.1 TCP channels

        4.2.2 TCP addresses

        4.2.3 Opening an outbound connection

        4.2.4 Accepting inbound connections

        4.2.5 Receiving data

        4.2.6 Sending data

      4.3 timer (typed and untyped)

      4.4 udp (typed and untyped)

    5 Management and Monitoring

      5.1 generic-spy

      5.2 logging (MARKETPLACE_LOG)

      5.3 debugger (experimental)

    6 Examples

      6.1 TCP echo server

      6.2 TCP chat server

      6.3 TCP chat client

 
\ No newline at end of file +vice versa.

    1 Concepts

      1.1 What is a process, what are event handlers?

      1.2 What is a VM?

      1.3 Endpoints: Subscription and Advertisement

      1.4 Messages and Topics

      1.5 Presence

      1.6 Nesting, relaying, and levels of discourse

    2 High-level interface

      2.1 Using #lang marketplace and friends

      2.2 Using Marketplace as a library

      2.3 Constructing transitions

      2.4 Creating endpoints

        2.4.1 Receiving messages

        2.4.2 Action-only vs. State updates

        2.4.3 Handling presence and absence events

        2.4.4 Exit reasons

        2.4.5 Updating endpoints

        2.4.6 Who am I talking to?

        2.4.7 Participating in a conversation vs. observing conversations

        2.4.8 Naming endpoints

      2.5 Deleting endpoints

      2.6 Sending messages and feedback

      2.7 Creating processes

      2.8 Exiting and killing processes

      2.9 Cooperative scheduling

      2.10 Creating nested VMs

      2.11 Relaying across layers

    3 Low-level interface

      3.1 Handler Functions

      3.2 Messages, Topics and Roles

      3.3 Endpoint Events

      3.4 Actions

        3.4.1 Endpoints and Messages

        3.4.2 Process Management

    4 Drivers

      4.1 event-relay

      4.2 tcp-bare

        4.2.1 TCP channels

        4.2.2 TCP addresses

        4.2.3 Opening an outbound connection

        4.2.4 Accepting inbound connections

        4.2.5 Receiving data

        4.2.6 Sending data

      4.3 timer (typed and untyped)

      4.4 udp (typed and untyped)

    5 Management and Monitoring

      5.1 generic-spy

      5.2 logging (MARKETPLACE_LOG)

      5.3 debugger (experimental)

    6 Examples

      6.1 TCP echo server

      6.2 TCP chat server

      6.3 TCP chat client

 
\ No newline at end of file diff --git a/low-level-interface.html b/low-level-interface.html index bc33918..4582226 100644 --- a/low-level-interface.html +++ b/low-level-interface.html @@ -1,5 +1,5 @@ -3 Low-level interface
5.3.4.10

3 Low-level interface

 (require marketplace)

At its heart, the interface between each process and its +3 Low-level interface

5.3.4.11

3 Low-level interface

 (require 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 @@ -7,15 +7,15 @@ the system call interface of a Unix-like 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/endpoint:/add-endpoint. A handler +endpoint/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, +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 +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 @@ -57,16 +57,16 @@ supplied in its 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 +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 +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 +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 @@ -77,7 +77,7 @@ with the name of the endpoint to delete.

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

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 +function from marketplace/sugar-values.

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 @@ -85,7 +85,7 @@ some publisher, it will be 'sub See also the send-message and send-feedback convenience functions from marketplace/sugar-values.

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 +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 @@ -95,7 +95,7 @@ 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 +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 diff --git a/pict.png b/pict.png index a0a84d7..a87c41e 100644 Binary files a/pict.png and b/pict.png differ diff --git a/pict_2.png b/pict_2.png index f8e93ce..3ccb1c2 100644 Binary files a/pict_2.png and b/pict_2.png differ diff --git a/pict_3.png b/pict_3.png index 1bf20d0..170ae9f 100644 Binary files a/pict_3.png and b/pict_3.png differ