User and Application Programmer's Manual

User and Application Programmer's Manual
SchemeStation documentation

1 Running SCHEMESTATION

The actual SCHEMESTATION simulator consists of two programs. These programs are the domain simulator ss and the network simulator ssnetsim. Both programs utilize also a third program, namely the SCHEMESTATION console ssconsole, but it does not need to be started manually and can be seen as a part of the other programs.

Domains can be run without the network simulator. However, in such a case different domains cannot communicate between anothers. Usually the network simulator is used.

The network simulator is used to simulate a virtual network where the SCHEMESTATION domains connect to. It is implement on the top of TCP/IP communications. The network simulator opens a port that it listens to, and the domain simulators connect to it in order to connect to the virtual network. All data between different domains is then actually transferred via the network simulator. This gives the possibility to gather statistical data about inter-domain communications and to observe the workings of the distributed system easily.

Both the network simulator and the domain simulator are UNIX processes. The overall picture resulting is shown in Fig. 1.


Fig. 1. Domain and network simulators

1.1 Running the network simulator

The network simulator is started from the UNIX command line with the command ssnetsim. The simulator accepts certain command-line options. In the absence of all options, the simulator sets as its own domain address to be Network----AAAAAAAAAAA in the SCHEMESTATION base 64 encoding, and begins to listen the TCP/IP port number 7000. (In principle, the network simulator is also a SCHEMESTATION domain. Thus, in principle, it can be extended to communicate with casual SCHEMESTATION agents. However, this is sort of meta simulation and is perhaps not interesting.) It also opens a console window where it shows information about connected domains and transferred packets. The statistics are updated every two seconds.

A summary of the few command line options can be got, as usual, by ssnetsim --help. The network simulator does not need the standard input/output streams after it has been started, so it can be easily started on background. The simulator can be terminated by clicking the appropriate command button in the console display, or by sending an interrupt signal.

Here is an actual snapshot of the network simulator console display:

The first line shows the domain address of the simulator itself and also features the exit button. Lines below correspond to connected domains, one line for one domain. The first number at the left is the ordinal number of the connection. Most recently connected domains are shown first. Next comes the connected domain's domain address, then the corresponding domain simulator's IP address and the port where it has connected. Then come statistics about packets sent, received and redirected as well as byte counts.

1.2 Starting a SCHEMESTATION domain instance

A SCHEMESTATION domain simulator is started from the UNIX command line with the command ss. The domain simulator supports certain command line options. A summary of them can be got, as usual, by ss --help. They are also described below.

There are two kinds of boot-ups for a SCHEMESTATION domain. First, the initial boot-up, and second, a system wake-up. During the initial boot-up, a domain that has not existed before is created. System wake-ups occur when a domain that has been temporarily freezed starts working again and the persistent agents stored continue execution from the point where they were left when the system went down. In the simulation the freezing essentially means saving the entire state of the simulator to disk: agents and their heaps, addressing system and all such. [Network connections need not to be saved as they are automatically opened upon request.]

When you start a domain simulator, you must do, thus, either an initial boot-up or a wake-up. Initial boot-up is specified by giving the "--new=true" switch (can be abbreviated to "-N", and that is set by default if you do not specify a core file name). Wake-up requires a core file that contain the image of the state to be recovered. The name of the core file is specified by the option "--core=FILENAME" (can be abbreviated to "-c"). If you give a core file name, it is also used as the name for a core file name created during shutdown.

If you start a virgin domain (i.e. do an initial boot-up), you need to configure the newly created domain by giving certain command line options, such as specifying the domain address of the domain. You do not need to give the options again when you wake the domain up after a shutdown, as they are saved as a part of the domain's state.

The easiest way to start a fully functional domain instance that does not need the virtual network simulator is, assuming that you have correctly built the distribution,

ss -T -i -b -O

Here, -T denotes that you want a terminal, -i that you do not want to connecto the network, -b that you want a status bar display, and -O that you want to run an object server. See the discussion below for a comprehensive listing of all the command line options provided.

1.2.1 Command line options

--bar=Bool (-b)
Include the status bar display device. The default value is false (not to include). The status bar display device is a small terminal window that displays graphically the proportional amounts of time spent in running byte code, system activities, in being idle.

--core=String (-c)
Set the core file name. The core file name is used for two purposes. (1) If the core file name is given, the core file of a domain is written to a file with the given name. (2) When a station is revived after having been shut down previously, the core file to use is specified by this option. The default is empty, i.e. no specified core file name. If the core file has not been specified, wake-up cannot be performed. Upon shutdown, the core file name will be then invented by the simulator software.

--debug=String (-D)
Set debug flags. -D '' disables all debugging information. If the distribution has been built without debugging support this flag does nothing. The default is "S", i.e. output generic station debugging information but nothing else.

--dm=Bool
Inhibit actual messaging and just dump all messages sent by all agents to the output. Actually you can run then only one agent, and the messages sent must be simple strings. This is a low-level debugging option and not useful to you. The default is false, i.e. really send messages; this is what you wish.

--dns-name=String (-d)
Set the abstract domain name of the current domain. The abstract domain name is stored in the system's object server and associated with the binary domain address. There is no other mandated use of the abstract name. The default is "rose".

--externals=Bool (-E)
Enable the external agent interface. The default is to enable (true).

--externals-port=Integer (-e)
Set the number of the TCP/IP port the station should listen and where the external agents should connect. The default is 8001. This option does nothing if --externals=false is specified.

--have-mother=True (-M)
Use the mother domain's object server. The default is not to use, i.e. false. The purpose of using another domain's object server is to enable a set of multiple domains to easily share a common object server and thus use it for storing also common data.

--have-os=True (-O)
Spawn an own object server. The default is not to spawn, i.e. false. If an own object server is spawned, it is also used. The common thing to do is to run one domain with the -O option and the others with -M.

--have-terminal=True (-T)
Include the terminal device. The default is not to include (false). The terminal is required for interacting conveniently with the system. However, not every station instance needs a terminal. Commonly, you start only few stations with terminal and a lot of them without.

--kernel=String (-k)
Set the UNIX file name of the kernel byte code file, i.e. the agent object that is executed first and works as the DKI. The default is kernel.ssbc in the default objects directory (which is schemestation/station/objects/).

--mother-domain=String (-m)
Set the address of the current domain's mother domain. This has no effect if -M is not specified. The domain is specified in the SCHEMESTATION base 64 encoding. The default is Big-Mother-AAAAAAAAAAA.

--mping=True
Start the message ping-pong test. This is a low-level debugging option and you are not probably interested in it. The default is not to start.

--network-IP=String (-I)
Set the IP address of the virtual network simulator. This is not used if you do not want to connect to the network at all. The default is localhost.

--network-domain=String (-n)
Set the domain address of the network simulator. Whatever you set it to be, it must match the domain address of the network simulator itself, i.e. the value given to ssnetsim via the -a flag. There is probably no point in changing the value of the address. The default is Network----AAAAAAAAAAA, which is also the default for ssnetsim.

--network-port=Integer (-P)
Set the TCP/IP port number where the virtual network simulator is found. This option is a counterpart of --network-IP. The default is 7000, which is also the default for ssnetsim.

--new=True (-N)
Start a new SCHEMESTATION domain instead of restarting old from a core file. If a core file has not been specified, this flag assumes implicitly the value of true (start a new domain). The default is however false (not to start), thus if you specify a core file name but not -N the core file is loaded and an old domain restarted. The only situation where you need to specify both -N and -c is to start a new domain with an explicitly given name for outputting a core file later.

--nogc=Bool
Completely disable agent memory garbage collection, causing the size of the simulator grow quickly. This is a low-level debugging switch, meant mainly for performance measurements and heap implementation troubleshooting, that you do not probably want to set. The default is false, i.e. to perform GC.

--nonet=Bool (-i)
Do not connect to the virtual network. The default is to connect. This is useful if you want to run only one station, and do that quickly. Note, however, that you do not need to be connected to a network in order to run the virtual network simulator and multiple domains, as long as your machine has a TCP/IP implementation that works locally.

--objects-dir=String (-o)
Set the "objects directory" where objects are injected to an object server that is spawned via the -O flag. The default is schemestation/station/objects. All regular files in the objects directory are assumed to be linearized SCHEMESTATION objects that can be inserted to the object server. The most common source for getting linearized objects is the .ssbc files produced by the SCHEMESTATION assembler.

--os=String
Set the byte code file name of the object server code. The default is object-server.ssbc in the default objects directory, which is schemestation/station/objects.

--own-domain=String (-a)
Set the domain address of the current domain. If you are running multiple domains, connected via the virtual network, you need to take care that all the domains have distinct domain addresses. Otherwise problems will arise. The domain address must be specified in the SchemeStation base 64 encoding. The default is Domain-One-AAAAAAAAAAA.

--ping=True
Start the message network ping-pong test. This is a low-level debugging option and you are not probably interested in it. If you really want to run the ping-pong test, you need to start the network simulator in the "pong" mode (ssnetsim --pong=true). The default is not to start.

--quiet=Bool (-q)
Suppress printing of system log entries to the standard output. The default is not to suppress (false), i.e. to have a visible system log. If you set -q, the domain simulator will print nothing to the standard output, and only certain fatal error messages to the standard error stream.

1.3 Shutting down a SCHEMESTATION

System shutdown is initiated by an agent with sufficient priviledges. In the SCHEMESTATION simulator the user has always an access to such an agent. The agent program shutdown.ssbc shuts down the domain where it is run. The shutdown that takes place is a "persistent" shutdown, i.e. a core file is created. If the current domain was once recovered from a core file, the same core file name is used. Otherwise the core file name is derived from user name and the current date, except if another name has been explicitly specified via the -c switch.

SchemeStation simulator can be also stopped by sending one of the SIGINT, SIGHUP and SIGTERM signal to it, but the no core file created.

2 Basic Usage of SCHEMESTATION

SCHEMESTATION is an operating system, and thus it is a little dubious to talk about "using" SCHEMESTATION in any particular way, as you can e.g. tweak the kernel code to do whatever you wish. Starting new agents, communicating with them and observing their workings can be seen, however, as the principal usage of the SCHEMESTATION simulator. This section describes these things in the default setting.

2.1 Start

First, you start up the domain. You type in the shell ss -T -i -b -o, and soon a terminal window appears. It should look like this:

Here we see a login window, and a piece of fine poetry. The login window is actually a non-op. Write whatever you wish there. After pressing return twice, the login window disappears and you get a shell. After that, the top of the terminal should look like this:

From the shell, you can start new agents. For example, if you wish to run the program blop.ssbc (comes in the distribution), you type the name to the shell and press return. After a while, the program starts to run, opening a window and beginning to increment a number in it. Then the top of the terminal should look like this:

You can see three "buttons" in the right ends of the title bars. The first button, [+], increases the size of the window. The next, [_] hides the window. If you hide a window, the title of the window appears in the "task bar" in the bottom of the terminal. You can then get the window back by clicking on the title there. The last button, [X] destroys the window. Usually the application using the window exits then also, but it is of course completely in the discretion of the individual program.

You can also see that the title bars come in two different colors. The window with a blue title bar is the current "focus window". When you type text, the focus window receives the text you write. You can change the focus window by clicking on the title bars.

3 General Concepts of SCHEMESTATION Programming

In order to program agents for the SCHEMESTATION [simulator], it is important to understand the general internal structure of a SCHEMESTATION domain, as well as the main features of the operating environment.

3.1 Kernel Structure

The SCHEMESTATION kernel is responsible for one domain. The kernel itself is a set of agents, although special ones; it is possible to communicate with the kernel by the same way of message passing as with other agents. The main kernel agent is called the core domain kernel agent (CDK). Other kernel agents exist also, for example the terminal device driver.

Usually a kernel agent has as its counter-part a kernel-implementing agent. Kernel-implementing agents are standard agents, running on the top of the virtual machine. They communicate with their corresponding kernel agent parts. Kernel-implementing agents are used to provide more convenient interfaces and to implement functionality that does not necessarily be implemented as a code in the (C-)kernel. For example, the kernel-implementing agent corresponding to CDK is the domain kernel interface agent (DKI).

3.2 Agents

Agents are asynchronous processes that communicate with other agents via message passing. Usually agents execute on the top of the SCHEMESTATION virtual machine. The exceptions to this rule are (1) kernel agents and (2) external agents. For kernel agents, see above. External agents are described later. They are external programs that get an agent interface inside a SCHEMESTATION domain.

3.3 Object Servers

Object servers are an integral part of the SCHEMESTATION operating environment. They act much as files servers, but have more general functionality. They are capable of storing and retrieving arbitrary objects. In this way, object servers can act as conventional file servers (by storing strings), as domain name servers (by storing domain addresses), as agent address servers (by storing agent addresses), etc.

Normally an object server is started during boot time via the -O command line switch. The object server that is started is just a normal agent, but the kernel knows that it works as an object server and thus gives it treatment according to that. Agents communicate with the object server agents just normally via message passing. There are functions in the SCHEMESTATION Scheme standard library that make accessing object servers easy (see below).

One way to access the system's obejct server is to run a program from the shell, because the "program" is an object that is fetched from the object server. This happens behind the scenes in this case, though, so you do not necessarily "see" it happen.

4 Running Agents

Agents are run by asking the kernel to start a new agent. The agent is specified either by directly sending the byte code object to the kernel, or by specifying an ID corresponding to an object in the object server used by the domain kernel. As a simulator user you have full access to the domain kernel and can thus spawn arbitrary agents as you wish. One way to ask the kernel to start a new agent is to use the shell. The SCHEMESTATION Scheme standard library includes a function that you can use very conveniently to start an agent, see blow.

4.1 Agent Anatomy

The casual SCHEMESTATION agents are byte code programs that run on the top of the SCHEMESTATION virtual machine. This section describes the structure of agents and of the virtual machine, to the extent that is required in order to understand how new agents can be designed.

4.1.1 Heap the Memory

An agent has a theoretically infinite amount of memory that is a garbage-collected list-structured heap. The byte code program of the agent accesses and modifies this heap when run: new objects can be created and older accessed, modified, and deleted by losing the last references to them. The objects in the heap are dynamically typed, i.e. the type information of an object is saved automatically in the heap also. The heap can contain objects of the following types:

Booleans
A boolean object is either the True or the False.
64-bit signed integers
64-bit (double-precision) floating point numbers
Arbitrary bit strings
There are two types of bit strings that can be stored in the heap: shared and private. The contents of shared bit strings can be modified. Private bit strings are constant in the sense that if they are modified a copy is made and the original, unmodified version is also preserved. This dynamic property is of course not a property of the heap alone, but also of the virtual machine utilizing the heap.
Pairs of objects
Pairs glue two objects together, creating a new object that contains both of them.
Vectors of objects
Vectors are like pairs, but can contain an arbitrary number of objects. For example, a 4-vector contains four objects.
Procedures
It is possible to create procedures (closures) on the fly and pass them around just as any other values, e.g. integers. Thus procedures need also to be able to be stored in the heap. Note, that all procedures are considered just as procedures and there are not different types for procedures taking e.g. a different number of arguments.
Tagged pairs, vectors and bit strings
There are "tagged" versions of the compound objects (pairs and vectors) and the bit strings. A tagged object is associated with an extra type tag that can be used to define and identify new (oblique) types. For example, agent addresses are shared bit strings that are associated with the tag one (1).
Certain special objects
There is a special object that is used to terminate list structures. It is commonly called the nil (or null) object.

4.1.2 Message Passing

The agents are able --- in addition to fiddling with their own heap --- to send and receive messages. Messages are arbitrary heap objects that are passed around between (different) running agents. However, procedures may not be included in messages due to well-understandable reasons (the heaps of different agents are not shared between).

Sending messages is easy. There is a virtual machine instruction that can be used to send an arbitrary message to an arbitrary address. This instruction is mapped to a procecure send-message that is available in the cross-compiler (see below).

Messages are received as exceptions. When an agent is being delivered a message and its exceptions are enabled, the agent's exception handler is started. The handler gets the message as its argument, and then the agent may do whatever it wishes to the message in the handler. When the exception handler returns exceptions are enabled again and a new exception can take place.

However, normally messages are not actually processed in the exception handler. Instead, the default exception handler (produced by the compiler) puts all messages it receives to a message queue that is maintained in the agent's heap, and then just returns. The items in this queue can be read and removed one by one in a way that if the queue is empty, the agent stops execution and moves to a blocking state. In a blocking state the only thing that can make agent proceed further is getting and exception. The exception can then cause the message queue to get a message and then the agent can continue to run.

This procedure is not enforced by the virtual machine but is implemented in the compiler. Of course, other exception handling mechanisms can be implemented by the user.

4.2 Creating New Agents

New agents are created by compiling Scheme source code into byte code objects. The byte code objects are then incorprated via object servers into the operating system and made available. The byte code objects can be "executed", i.e. the programs contained in the objects can be started as agents.

5 SCHEMESTATION Cross-Compiler

The byte code objects are created by compiling Scheme source code. This compilation happens currently outside the SCHEMESTATION simulation, i.e. in the underlying UNIX environment using the supplied SCHEMESTATION cross-compiler ssc.

5.1 Running the Compiler

ssc is invoked using the syntax

ssc [file | option] ...

where are the source code files to be compiled and options are options that control the behaviour of the compiler. The following options are recognized:

--asmopts STRING
Pass STRING to the assmbler when invoked as a sub-process of the compiler. Default is the empty string.
--assemble, --noassemble
Choose whether or not to run assembler. Default is to run.
--assembler NAME
Set the assembler executable name as given to a sub-shell starting the assembler (default is "ssasm").
--help
Output a help message and exit.
--includedir DIR
Add the directory DIR as the first to the list of directories to be searched for included files.
--optimize LEVEL
Set the optimization level, zero for no optimization at all and larger integers for more optimization.
--verbose
Make the compiler to print information about its progress. Can be given multiple times to get more verbosity.
--trace ITEM
Choose to trace a specific part of the compiler identifier by ITEM. This is for debugging only.
--std, --nostd
Choose to include or to not include the standard include files that define e.g. the derived forms of the Scheme language. The default is to include.

The source code files must have the suffix ".ssscm" in their names. This suffix is replaced with ".ssbc" to get a name for the byte code object file resulting. For example,

ssc foo.ssscm

compiles the file foo.ssscm in the current directory and, if the compilation succeeds, output the resulting byte code object file to foo.ssbc.

5.1.1 Dialect Understood

ssc understands roughly the Scheme programming language as specified in the Revised4 Report on the Algorithmic Programming Language Scheme. Certain differences exist due to needs that are SCHEMESTATION-specific. These differences are summarized here; more elaborate description of the dialect and different features follow later.

5.1.1.1 Core Syntactic Forms

The core syntactic forms provided by the compiler in any setting are the following:


Syntactic form: (lambda args-list ...)
This is just as lambda in R4RS Scheme.


Syntactic form: (if test consequence [alternative])
As in R4RS Scheme.


Syntactic form: (set! variable value)
As in R4RS Scheme.


Syntactic form: (begin body ...)
As in R4RS Scheme.


Syntactic form: (quote literal)
As in R4RS Scheme.


Syntactic form: (_define variable value)
Define the global value variable to exist and assign the value value to it. Only global _defines are allowed. _define does not support the abbreviated syntax for defining procedures. define is implemented as a standard syntactic form on the top of _define and does this. Don't use _define, use define instead.


Syntactic form: (asm-closure instruction-or-label ...)
asm-closure is used to denote closures that are written directly in inlined assembler.


Syntactic form: (include filename)
This form is replaced by the expression that is read from the file filename. Beware of cyclic includes!


Syntactic form: (let-syntax ((macro-name literals patterns) ...))
Define a new syntactic forms. Also available are letrec-syntax for creating recursively defined syntactic forms and define-syntax for defining new global syntactic forms. These core forms are part of the macro system and are described later.

5.1.2 Standard Syntactic Forms

On the top of the core syntactic forms, a set of standard syntactic forms is defined by using the macro system. The definitions of these forms are included in compilation by default; there is a compiler flag that can be used to disable the inclusion.


Syntactic form: (define variable value)
Syntactic form: (define (variable arg ...) body ...)
Syntactic form: (define (variable arg ... . arg) body ...)
As in R4RS Scheme.


Syntactic form: (let ((variable value) ...) body ...)
As in R4RS Scheme.


Syntactic form: (letrec ((variable value) ...) body ...)
As in R4RS Scheme.


Syntactic form: (let* ((variable value) ...) body ...)
As in R4RS Scheme.


Syntactic form: (and value ...)
As in R4RS Scheme.


Syntactic form: (or value ...)
As in R4RS Scheme.


Syntactic form: (cond (test body ...) ... [(else body ...)})
As in R4RS Scheme. The => construction is supported.


Syntactic form: (when test body ...)
Evaluate test and execute body ... if the evaluation resulted in a true value; then return the value of the last body executed. Otherwise return an undefined value. Equivalent to (if test (begin body ...)).


Syntactic form: (unless test body ...)
Evaluate test and execute body ... if the evaluation resulted in False; then return the value of the last body executed. Otherwise return an undefined value. Equivalent to (if (not test) (begin body ...)).

5.1.2.1 Macro System

The macro system of the SCHEMESTATION cross-compiler is very much like the macro system described in the appendix of R4RS. It is a hygienic macro system, meaning that identifier names introduced in different contexts cannot clash even if the read the same. The implication of this is that whatever names can be used as local variables introduced in macros; they will not clash with the same names injected into the macro expansion from the outside via a macro parameter.

Macros can be defined using let-syntax, letrec-syntax and define-syntax. let-syntax defines a set of local macros that are in effect inside the body of let-syntax. letrec-syntax does the same but the macros defined can be mutually recursive. define-syntax is used to define a global macro that is in effect after the definition. In order to avoid certain surprises that could result when referring to a global macro before its definition, it is recommended that all global macros be defined at the beginning of a program. This is not enforced, though.

In all the macro-defining forms the actual macro definition(s) are done according to the same syntax:

macro definition = (name (literal ...) ((pattern template)...))

name is the name of the macro. Following is a possibly empty list of literals, which are special keywords that the macro wants to recognize. For example, for the derived syntactic form cond these keywords are "else" and "=>", as they have a special meaning inside the cond macro.

After the literals list, there is a set of pattern-template pairs. When the macro is being expanded, the patterns are matched against the actual invokation of the macro. If a matching pattern is found, the macro invokation is replaced with the corresponding template. If multiple patterns are found the first one in the macro definition is used. If no patterns matchin the invokation are found there is an error and the compilation is aborted.

The patterns are about as in R4RS and the templates as well. Consult the report for details.

5.1.2.2 Core Procedures

The core procedures described here are implemented more or less directly on the top of the virtual machine and are always available.

Pairs


Core procedure: (car pair)
Return the first item of a given pair.


Core procedure: (cdr pair)
Return the second item of a given pair.


Core procedure: (cons value value)
Create a new pair.


Core procedure: (set-car! pair value)
Set the first item of a given pair.


Core procedure: (set-cdr! pair value)
Set the second item of a given pair.


Core procedure: (make-tagged-pair tag)
Create a new tagged pair with the given tag.

Vectors


Core procedure: (make-vector length)
Create a new vector of the given length.


Core procedure: (make-tagged-vector length tag)
Create a new tagged vector with the given tag and of the given length.


Core procedure: (vector-set! vector index value)
Set the indexth value of vector to value.


Core procedure: (vector-get vector index)
Return the indexth value of the given vector.


Core procedure: (vector-ref vector index)
A synonym to vector-get.

Bit strings


Core procedure: (make-shared-bit-string length)
Core procedure: (make-private-bit-string length)
Core procedure: (make-shared-bit-string length tag)
Core procedure: (make-private-bit-string length tag)
Create a new bit string whose length is LENGTH bits (not bytes).


Core procedure: (bit-string-length string)
Return the length of string in bits (not bytes).


Core procedure: (bit-string-shr string amount)
Core procedure: (bit-string-shl string amount)
Core procedure: (bit-string-rol string amount)
Core procedure: (bit-string-ror string amount)
Shift (shr/shl) or rotate (rol/ror) bit strings left or right; return newly allocated bit strings.


Core procedure: (bit-string-and string1 string2)
Core procedure: (bit-string-or string1 string2)
Core procedure: (bit-string-xor string1 string2)
Core procedure: (bit-string-neg string1)
Bit-wise bit string operations; return newly allocated bit strings.


Core procedure: (set-bit-substring! string1 string2 offset)
Copy the contents of string2 over string1, starting at the position offset.


Core procedure: (get-bit-substring string1 start length)
Return a newly allocated bit string that contains the region of string1 that starts at the startth bit and spans length bits.

Messages


Core procedure: (send-message address message)
Send a given message to a given address.

Miscallenous


Core procedure: (not value)
Return #f if value is not #f, otherwise #t.


Core procedure: (eq? value value)
Return #t if two values are exactly the same object, otherwise #f.


Core procedure: (halt)
Terminate; commit a suicide; exit; quit; halt for ever.


Core procedure: (exit)
A synonym to halt.


Core procedure: (quit)
A synonym to halt.

Arithmetics


Core procedure: (int+ integer integer)
Core procedure: (int/ integer integer)
Core procedure: (int- integer integer)
Core procedure: (int* integer integer)
Core procedure: (int= integer integer)
Core procedure: (int>= float float)
Integer arithmetics and comparison.


Core procedure: (float+ float float)
Core procedure: (float/ float float)
Core procedure: (float- float float)
Core procedure: (float* float float)
Core procedure: (float= integer integer)
Core procedure: (float>= float float)
Floating-point arithmetics.


Core procedure: (modulo integer integer)
Core procedure: (divide integer integer)
Core procedure: (remainder integer integer)
Number-theoretical division and remainders for integers.

Type predicates


Core procedure: (boolean? value)
Return #t if value is a boolean object, otherwise #f.


Core procedure: (integer? value)
Return #t if value is an integer object, otherwise #f.


Core procedure: (float? value)
Return #t if value is a floating-point number object, otherwise #f.


Core procedure: (pair? value)
Return #t if value is a pair, otherwise #f.


Core procedure: (vector? value)
Return #t if value is a vector of any length, otherwise #f.


Core procedure: (shared-bit-string? value)
Return #t if value is a shared bit string, otherwise #f.


Core procedure: (private-bit-string? value)
Return #t if value is a private bit string, otherwise #f.


Core procedure: (tagged-pair? value tag)
Return #t if value is a tagged pair and has the tag tag, otherwise #f.


Core procedure: (tagged-vector? value tag)
Return #t if value is a tagged vector of any length and has the tag tag, otherwise #f.


Core procedure: (tagged-shared-bit-string? value tag)
Return #t if value is a tagged shared bit string and has the tag tag, otherwise #f.


Core procedure: (tagged-private-bit-string? value tag)
Return #t if value is a tagged private bit string and has the tag tag, otherwise #f.


Core procedure: (procedure? value)
Return #t if value is a procedure object, otherwise #f.

5.1.3 Error messages

The cross-compiler can produce several error and warning messages. Usually the messages are self-explanatory. However, a message about "internal compiler error" means that there is a bug in the compiler and that the bug was detected by an internal consistency check. If you encounter internal compiler errors, please report them to our help desk (see above).

5.1.4 SCHEMESTATION Standard Library

The SCHEMESTATION standard library consists of miscallenous and more or less useful procedures that are distributed along with the compiler. Technically the library consists currently of procedure definitions that can be included in a program, for example by using the include syntactic form. The standard library needs to be recompiled every time it is used in a program because the simulator does not support, at least yet, linking of pre-compiled program pieces together. The library consists of multiple files. They can be included separately, or the file stdlib.ssscm can be included in order to include a certain subset of the files; see below.

File: carcdr.ssscm; part of the SCHEMESTATION compiler standard library


Procedure: (caar value)
Procedure: (cadr value)
Procedure: (caaar value)
Procedure: (caadr value)
Procedure: (cadar value)
Procedure: (caddr value)
Procedure: ...
Procedure: (cddaar value)
Procedure: (cddadr value)
Procedure: (cdddar value)
Procedure: (cddddr value)
As in R4RS.

File: asynchronous.ssscm; part of the SchemeStation compiler standard library


Syntax: push-continuation
(push-continuation var id cont)
Assume that the variable VAR contains an association list, and add the association (ID . CONT) to the beginning of the list.


Syntax: process-continuation
(process-continuation var id arg1 ...)
Assume that the variable VAR contains an association list. Find the first association with the key ID. The associated value must be a procedure. The associated procedure is then called with the arguments ARG1 ... and the first association, where the procedure was found from, is removed from the list named by VAR.

File: control.ssscm; part of the SchemeStation compiler standard library


Procedure: (apply procedure arguments)
Call the procedure PROCEDURE with the arguments list ARGUMENTS. For example, (apply cons '(1 2)) returns the pair (1 . 2).


Procedure: (call-with-current-continuation thunk)
Call THUNK, which must be a procedure accepting one parameter, with a procedure that captures the current continuation of the program execution. This continuation procedure (exit-procedure) gets one argument that will be, if the procedure is called, passed to the continuation that was in force when call-with-current-continuation was called. Then the program execution continues from that continuation. This can be mind-boggling at first. call/cc is provided as a convenient abbreviation of the long name.


Procedure: (map func . lists)
Create a list that is obtained by applying the function FUNC to the elements of LISTS one by one. The function FUNC should accept as many parameters as there are lists in the procedure invocation. For example, (map + '(1 2 3) '(3 0 -100)) returns '(4 2 -97).


Procedure: (for-each proc . lists)
As map, but do not create any list but evaluate the procedure PROC as in map for side-effects only. It is guaranteed that PROC is called for the elements in the lists in the order they appear in the lists.


Special form: (delay expr)
Do not evaluate EXPR but create a promise instead. A promise is an object that can be later "forced" to yield the value of EXPR then. See also force.


Procedure: (force promise)
Force a promise; see delay.

File: display.ssscm; part of the SchemeStation compiler standard library


Procedure: (integer->string integer)
Convert the integer INTEGER to a string that contains a representation of the integer in decimal base.


Procedure: (object->string object)
Convert an arbitrary object to a (pseudo) written representation of the object. This is currently a pseudo representation, because strings are surrounded with quotes but quotes inside are NOT prefixed with backslashes.

File: exceptions.ssscm; part of the SchemeStation compiler standard library


Procedure: (standard-message-loop handler)
HANDLER is a procedure that accepts one argument, namely a message. Initialize the exception handler to catch all incoming messages and then run the agent so that when messages are received they are passed to the HANDLER in the FIFO order.


Syntax: define-handler
(define-handler type min-args args body1 body2 ...)
Define a new message handler, to be called from inside dispatching-message-loop. TYPE is an object that must match the first element of a received message. Typically it is a string. MIN-ARGS is the minimum number of arguments (i.e. list elements) that must be present in the message, not including the type identifier. ARGS is an arguments list, similar to that in lambda expressions. When a message with the type identifier TYPE is received and that contains at least MIN-ARGS other elements, the sequence BODY1 BODY2 ... is evaluated in a new environment where the elements from the message are bound to the variables named in ARGS.


Procedure: (dispatching-message-loop additional-handler)
ADDITIONAL-HANDLER is a procedure that accepts on argument, name a message. This procedure is similar to standard-message-loop, but upon receiving a message, it is first checked if there is a handler defined via define-handler (see that) that can accept the received message. If so, invoke the defined handler. Otherwise call (ADDITIONAL-HANDLER MESSAGE). ADDITIONAL-HANDLER is typically used to handle erroneous message. A common idiom is (dispatching-message-loop (lambda () #f)) to ignore all erroneous messages.

File: lists.ssscm; part of the SchemeStation compiler standard library


Procedure: (memq a b)
Search for an occurrence of the object A in the list B, in the sense of eq? If an occurrence is found return the longest postfix of B such that A is the first element of it; otherwise #f.


Procedure: (member a b)
Search for an occurrence of the object A in the list B, in the sense of equal? If an occurrence is found return the longest postfix of B such that A is the first element of it; otherwise #f.


Procedure: (assq a b)
Search for a pair in the list B that is of the form (A . X) --- the car of the pair found must be equal with A in the sense of eq? If an occurrence is found then return the first pair found. Otherwise return #f. B must be an association list, i.e. a list of pairs; otherwise the procedure may not work.


Procedure: (assoc a b)
Search for a pair in the list B that is of the form (A . X) --- the car of the pair found must be equal with A in the sense of equal? If an occurrence is found then return the first pair found. Otherwise return #f. B must be an association list, i.e. a list of pairs; otherwise the procedure may not work.


Procedure: (append . lists)
append gets a variable number of arguments. All the arguments must be lists. The return value is a new list that has all the elements of the argument lists in the order of their appearance in the arguments list. The new list may share structure with the last item of the arguments list.


Procedure: (reverse l)
L must be a list. Return a new list that contains the elements in L but in exactly reverse order.


Procedure: (list-tail l k)
L must be a list and K an integer. Return a postfix of L that contains all but the K first items of L.


Procedure: (list-head l k)
Return the first K elements of the list L; a counterpart of list-tail.


Procedure: (list-ref l k)
Return the Kth element of the list L.


Procedure: (deleteq i l)
Return a new list that is as L but with elements that are equal (in the sense of eq?) to I.


Procedure: (delete i l)
Return a new list that is as L but with elements that are equal (in the sense of equal?) to I.

File: misc.ssscm; part of the SchemeStation compiler standard library


Procedure: (min . args)
Return the minimum of all the arguments ARGS, which must be numbers.


Procedure: (max . args)
Return the maximum of all the arguments ARGS, which must be numbers.


Procedure: (null? x)
Return #t if X is the empty list, otherwise #f.


Procedure: (list . a)
Return a newly-allocated list that consists of all the arguments provided to the procedure.


Procedure: (list? a)
Return #t if A is a proper list, i.e. either the empty list '() or a pair whose cdr is a proper list, otherwise #f. If the structure A is cyclic, however, it is possible that the procedure never returns (this is in conformance with R4RS).


Procedure: (length a)
A must be a list. Return its length, counting the pairs the list consists of.


Procedure: (= A B)
Compare two numbers (integers or floating-point numbers) for equality.


Procedure: (>= A B)
Compare two numbers (integers or floating-point numbers).


Procedure: (< a b)
Compare two numbers.


Procedure: (> a b)
Compare two numbers.


Procedure: (<= a b)
Compare two numbers.


Procedure: (!= a b)
Compare two numbers; equivalent to (not (= A B)).


Procedure: (equal? a b)
Return #t if the two objects A and B are structurally equivalent, otherwise #f. In essence this is "=" for two numbers, string=? for two strings and compound objects are examined inductively.


Procedure: (vector->list v)
V must be a vector. Return a list that consists of the elements in V in their original order.


Procedure: (list->vector l)
L must be a proper list. Return a vector that consists of the elements in L in their original order and has the length of the list.


Procedure: (vector . args)
Create a new vector that contains the (evaluated!) items ARGS. Equal to (list->vector args).

File: read.ssscm; part of the SchemeStation compiler standard library


Procedure: (string->integer str)
Convert the string STR to an integer; return the value of conversion. STR is not modified. The return value is always an integer, but can be invalid in the case of a conversion error. In particular, if STR cannot be interpreted as a number at all, zero is returned.

File: standard-agent.ssscm; part of the SchemeStation compiler standard library


Variable: (sa:own-address)
The address of the current agent itself, after it has been received from the kernel.


Variable: (sa:my-kernel)
The "current" kernel of the agent. This is set upon receiving the message DKIdkia (Domain Kernel Interface: domain kernel interface agent address).


Variable: (sa:object-server)
The "current" object server of the agent.


Procedure: (sa:exec-with-continuation template cont)
Start a new agent. The byte code object found from the current object server corresponding to the template TEMPLATE is executed as an agent. This requires, of course, interaction with the kernel but this is implemented in the standard agent library. When the new agent is actually running, call (CONT ADDRESS), where ADDRESS is the address of the freshly created agent. If the template is invalid, CONT is never called.


Procedure: (sa:fetch-with-continuation template cont)
Fetch an object from the object server. Fetch an object that matches TEMPLATE. Call (CONT OBJECT) when the object has been received. If object server cannot be contacted, cont is never called (object server returns #f as OBJECT if no objects whose identifiers match TEMPLATE cannot be found).


Procedure: (sa:timeout-with-continuation msecs cont)
Register a timeout. This requires interaction with the kernel, but it is done "behind the scenes". Register timeout MSECS milliseconds from now, and call (CONT) when the corresponding timeout message has been received from the kernel (it can take more than MSECS milliseconds to that if the system is heavily loaded).

File: strings.ssscm; part of the SchemeStation compiler standard library


Procedure: (string-length string)
Return the length of the bit string STRING divided by eight; in essence, consider STRING to be a casual eight-bit-byte text string and return its length.


Procedure: (make-string length)
Create a new byte-string that has LENGTH bytes.


Procedure: (set-substring! string start what)
Set the substring of the text string STRING, starting at the STARTth (zero-based) character, to WHAT (which must be a text string also.)


Procedure: (substring string start end)
Return the substring of the text string STRING that starts at the STARTth (zero-based) character and includes all characters upto, but excluding, the ENDth character.


Procedure: (string-append . strings)
Append all the strings given as argument to a one, new string and return the string.


Procedure: (string? string)
Return #t if STRING is either a shared or a private bit string, otherwise false.


Procedure: (string-ref string k)
Return the Kth character of the string STRING as an integer.


Procedure: (string-set! string k char)
Set the Kth character of the text string STRING to be CHAR, which must be an integer.


Procedure: (string=? a b)
Compare two (text) strings; return #t if they contain exactly the same characters in the same order; otherwise #f. Case is, of course, significant.


Procedure: (string>=? a b)
Lexical comparison of two strings; the lexical order of characters is the natural ordering of the corresponding integers as returned by string-ref.


Procedure: (string
Lexical comparison.


Procedure: (string>? a b)
Lexical comparison.


Procedure: (string<=? a b)
Lexical comparison.


Procedure: (string!=? a b)
Lexical comparison.


Procedure: (string->list str)
Convert the string STR to a list of characters; as in R4RS (however, in SchemeStation characters are integers are the same type). STR is not modified. Return the list.


Procedure: (list->string s)
Convert the list of characters (i.e. integers, see string->list) S to a newly allocated string. Return the result of the conversion. S is not modified.


Procedure: (char->string char)
Convert the single character CHAR to a string of length one. E.g. (char->string 65) => "A", or (char->string #\A) => "A".


Procedure: (string-ref string K)
Pick the Kth character from string STRING and return the character. The string must be long enough.

File: text.ssscm; part of the SchemeStation compiler standard library


Procedure: (substring-index s string)
Return the smallest index such that S is the substring of STRING that starts at the index; #f, if no such is found.


Procedure: (split-string s separators)
Split the string S into a list of strings, treatening the characters in the list SEPARATORS as separators. E.g. (split-string " Hello world" '(#\ )) => ("Hello" "world").

6 Examples

6.1 A detailed example

The following example agent writes a new number on its window every 400 ms. This agent is also found from the distribution; the source file is in schemestation/station/scheme-src/blop.ssscm.


 ;;; Blop 

(include "stdlib.ssscm") ; SchemeStation standard library (include "display.ssscm") ; Display related functions (include "standard-agent.ssscm") ; standard functions

; The standard-agent.sscm includes all sorts of convenience ; functions; message handlers and such.

; Initialize the global variables (define TCA-address #f) (define window-handler #f) (define blop 0)

; We use here a readily defined timeout continuation, ; timeout, that generates a timed alarm. When the ; timer wakes up the agents, the new value of the blob ; is updated onto the window. This takes place after every ; 400 ms.

(define (make-blop) (sa:timeout-with-continuation 400 (lambda () (set! blop (+ blop 1)) (send-message window-handler (list "TWw" (object->string blop) 0 0)) (make-blop))))

; Here we acquire a handle to a newly created window ; * TCAwc = Terminal Controlling Agent window created (define-handler "TCAwc" 2 (id controller) (set! window-handler controller) (make-blop))

; The system sends us the address from which we can access ; the terminal. We send a open window request to the terminal. ; * TCAad = Terminal Controlling Agent address ; * TCAwc = Terminal Controlling Agent window create

(define-handler "TCAad" 1 (address) (set! TCA-address address) (send-message TCA-address (list "TCAcw" "Blop" 2 sa:own-address 0)))

; Define a handler for the close window event. ; As soon as the window of the agent is closed, the ; agent it self halts its execution. ; * TWwk = Terminal Window window kill

(define-handler "TWwk" 1 (id) (halt))

; In order to have the agent remain running, it has ; to have a message dispatcher, that handles the messages ; sent to the agent.

(dispatching-message-loop (lambda (erroneous-message) #f))

The agent works as follows. When it starts running, someone (e.g. the shell) sends it the address of a terminal controlling agent in a TCAad message. This message is captured in the message handler whose definition begins (define-handler "TCAad"... The agent stores the address of the TCA to the variable TCA-address, and then requests the TCA to create a window that has the title Blop and is two rows high (see the used messages list below).

When a window has been created, a TCAwc message is sent back to the agent. From this message the agent gets the address of an agent that is created to control the particular window that was opened for the Blop agent. Having the window, the agent starts its cycle where it prints a new number to the window every 400 ms. This cycle is implemented in the make-blop procedure, which calls itself indirectly recursively via the timeout mechanism provided by the standard library (see above).

The messages sent between Blop and the rest of the system are sketched in Fig. 2.


Fig 2. The flow of messages in the example agent

6.2 Descriptions of the Programs Distributed

This sections describes shortly all Scheme agents that are a part of the distribution.

WTCA.ssscm
The name of this agent is an abbreviation of the words Windowing Terminal Controlling Agent. This agent implements that part of the terminal driver that can be written in Scheme. It is automatically started by the default DKI agent if the domain where the DKI runs on has a terminal device.

WTCAwin.ssscm
This agent works closely with WTCA. One instance of WTCAwin is started for every window that is opened on the terminal. The WTCAwin agent begins to control the window it was started for and communicates with the application drawing something on the window and receiving events that take place "in the window".

blop.ssscm
This agent is extensively studied above. It is demonstration program that just increments a number with regular intervals in a dedicated window.

eai.ssscm
Eai stands for External Agent Interface. One instance of this agent is spawned for every connection that comes to the external agent interface of a SCHEMESTATION domain.

kernel.ssscm
This is the default DKI agent. It is started when a new domain starts up as the first agent ever. It works as an interface between the CDK and the rest of the world, and spawns certain agents during boot-up, for example the TCA and a login agent.

login.ssscm
This is a mainly non-op "login" agent. It prompts for a user name and password and then starts a shell.

migrate.ssscm
This agent can be used to send any agent (except the DKI) to a remote domain. The proper way to use it is to start if from the shell, giving it two arguments. The first argument denotes a scheduling identifier (a number) and the second an abstract domain name. The program tries to make the agent that has the given scheduling identifier to be moved to the domain specified. For example, you could type in the SchemeStation shell

$ migrate.ssbc 5 daisy

meaning that you would like to see the agent that has the scheduling indentifier 5 to be moved to the domain that has the abstract domain name "daisy". You can inspect the current processes in a domain (and their scheduling identifiers) via another program, top (see below).

object-server.ssscm
This agent implements the object server as specified in Operating system specification. See the used messages list below for more information.

promo.ssscm
This agent displayes a short poem in a dedicated window and then halts. It is the simplest of all the demonstration programs. The login agent starts this to decorate the login phase.

shell.ssscm
This agent implements a rudimentary shell. It can be used to start other agents simply by typing the corresponding filename. Note, however, that no UNIX file system is used, but the filename is used just as a key by which agent code can be found from the object server. For example, typing in the shell

$ blop.ssbc

($ is the prompt) would start running the Blop agent (see above). You can also type exit to exit from the shell (if you do not want to do that by deleting the shell window, which causes the shell to exit also). For your convenience, you can also migrate the shell to another domain by simply typing e.g.

$ > daisy

($ is the prompt again), where daisy is now the abstract domain name of the domain where you want your shell jump to. The shell detects the change of the domain and starts to communicate with the new, local DKI.

shutdown.ssscm
This small agent just sends the shutdown message to the kernel, causing the current domain to shutdown.

taxman.ssscm
Taxman is a great (?) game that you can play. Initially there is a list of integers from 1 to 50. You start choosing integers from the list one after one. Every time you choose an integer, you get as many points as the integer is. The integer is then removed from the list. At the same time, the "taxman" removes all such integers from the list that are dividers of the integer you chose, and gets in his score an increase equivalent to their sum. You cannot choose an integer, that has no factors remaining in the list. In essence, you cannot get an integer that you cannot be taxed for. You can finish the game by clicking the topmost line in the window. When you do this, the "taxman" gets all the remaining numbers. The objective of the game is to get more points than the "taxman" gets "tax".

top.ssscm
This agent is named after a well-known UNIX utility, although it does not sort processes according to their CPU-intensity. It simply displays information about processes running in the current domain with regular intervals.

7 List of Used Messages

This chapter documents the messages that are used in the example programs distributed.

Message: ("CA" arguments)
Name shortcut for: Command-line Arguments

Description: This message is sent to an agent when it has been started from a shell-like program; ARGUMENTS is a list of strings that the user has supplied as command-line arguments.

Message: ("CDKacr" domain address new-domain new-address)
Name shortcut for: Core Domain Kernel Address Control Remap
Description: As DKIacr, but passed from a DKI to a CDK.

Message: ("CDKeir" address)
Name shortcut for: Core Domain Kernel External agent Interface Running
Description: This message is sent by a DKI to a CDK to inform that a previously requested external agent interface agent is now running and has the address ADDRESS.

Message: ("CDKpir" address)
Name shortcut for: Core Domain Kernel Process Information Request
Description: As DKIpir, but passed from a DKI to a CDK.

Message: ("CDKrkq" domain)
Name shortcut for: Core Domain Kernel Remote Kernel Query
Description: This message is sent to a CDK by the corresponding DKI in order to query for the address of the DKI of the remote domain that has the domain address DOMAIN. The CDK answers with DKIrka.

Message: ("CDKru" id address)
Name shortcut for: Core Domain Kernel RUnning
Description: This message is sent by the CDK to the DKI to denote that the agent that was requested to start executing, associated with the identifier ID, is now really running and has the address ADDRESS.

Message: ("CDKsd")
Name shortcut for: Core Domain Kernel ShutDown.
Description: This is as DKsd, but passed from a DKI to a CDK.

Message: ("CDKsl" message)
Name shortcut for: Core Domain Kernel System Log message
Description: As DKIsl, but passed to a CDK by a DKI.

Message: ("CDKto" id)
Name shortcut for: Core Domain Kernel TimeOut
Description: This message is sent by a CDK to an address that has requested the deliver of a timeout message some time ago. ID is the same integer that was supplied in the DKItr (or CDKtr) message.

Message: ("CDKtr" address time id)
Name shortcut for: Core Domain Kernel Timeout Request
Description: This is actually the same message as DKItr, but understood by the CDK instead of the DKI.

Message: ("DKIacr" domain address new-domain new-address)
Name shortcut for: Domain Kernel Interface Address Control Remap
Description: This message is sent to a DKI in order to note that the remote address DOMAIN:ADDRESS points actually to NEW-DOMAIN:NEW-ADDRESS. It is sent to a domain when a domain is sending messages to DOMAIN:ADDRESS instead of sending them directly to NEW-DOMAIN:NEW-ADDRESS; the intention is to let the receiving domain change its address table and thus optimize messaging cost by dropping one level of indirection.

Message: ("DKIdkc" address)
Name shortcut for: Domain Kernel Interface Domain Kernel Changed
Description: This message is sent to an agent after it has been migrated to a new domain. ADDRESS contains the address of the DKI in the new domain. It is up to the receiving application to decide what to do with this information.

Message: ("DKIosa" address)
Name shortcut for: Domain Kernel Interface Object Server Address
Description: This message is sent by a DKI as a response to a previously received DKIosar message. ADDRESS is the address of the locally used object server, or #f if no object server is in use (which is a very rare occasion).

Message: ("DKIosar" address)
Name shortcut for: Domain Kernel Interface Object Server Address Request
Description: This message is sent to a DKI to query for the address of the object server used in the corresponding domain. The response is sent with the message DKIosa to ADDRESS.

Message: ("DKIpir" address)
Name shortcut for: Domain Kernel Interface Process Information Request
Description: Sent to a DKI in order to request information about the processes (agents) running currently in the domain of the DKI. Process information is returned by sending a DKpi message to ADDRESS.

Message: ("DKIrka" domain address)
Name shortcut for: Domain Kernel Interface Remote Kernel Address
Description: This message is sent to a DKI by a CDK in order to deliver the address of the DKI of a remote domain. (The CDK is able to construct such an address due to the fact that DKI's have local addresses zero by convention.) DOMAIN is a domain address and ADDRESS the address of the DKI in the domain.

Message: ("DKIsl" message)
Name shortcut for: Domain Kernel Interface System Log message
Description: This message is sent to the DKI by any agent. It requests outputting the message MESSAGE in the system log.

Message: ("DKItr" address time id)
Name shortcut for: Domain Kernel Interface Timeout Request
Description: This message is sent to a DKI in order to request the delivery of a timeout message to ADDRESS after TIME milliseconds. The message ("CDKto" id) is sent to ADDRESS after TIME ms. ID must be an integer.

Message: ("DKIx" template address)
Name shortcut for: Domain Kernel Interface eXecute
Description: This message is sent to a DKI to request the execution of an agent whose code is found from a local object server with an identifier matching TEMPLATE. When the agent has started, a DKIru message is sent to ADDRESS.

Message: ("DKcd" type address)
Name shortcut for: Domain Kernel Control Device
Description: This message is sent to the DKI by the CDK in order to request the DKI to get control over a device whose low-level device driver is found from the address ADDRESS. TYPE is the type of the device. (Currently, only the type "terminal" is understood.)

Message: ("DKgei")
Name shortcut for: Domain Kernel Get External agent Interface agent
Description: This message is sent by the CDK to the DKI in order to request the spawning of a new generic external agent interface agent.

Message: ("DKin" key value)
Name shortcut for: Domain Kernel INformation
Description: This message is sent by the CDK to the DKI to pass information about the current status of the system. KEY is a string that describes what kind of information is provided in VALUE. The following keys are used:

kernel-address
VALUE denotes the address of the CDK.
domain-address
VALUE denotes the local domain address.
abstract-name
VALUE denotes the abstract name of the domain, as specified by the user (during startup).
object-server
VALUE denotes the address of the locally started object server.
mother-domain-DKI
VALUE denotes the address of the DKI of the domain that is chosen to work as the mother domain.

Message: ("DKpi" id name status frac id name status frac ...)
Name shortcut for: Domain Kernel Process Information
Description: This is sent by the core domain kernel as a response to a DKIpir/CDKpir message. The contents of the message describe the currently existing processes. ID is the scheduler identifier of particular process. NAME is the name of a process as supplied originally by the compiler (actually it is the first entry in the constants table of the running agent's heap). STATUS is the status of the process and can be one of the following: 1 = no agent (should not be sent), 2 = running, 3 = running with exceptions disabled, 4 = blocking (i.e. waiting for a message), 5 = dead (should not be sent). There are as many (ID NAME STATUS FRAC) quadruples as there are processes running in the local domain.

Message: ("DKsd")
Name shortcut for: Domain Kernel ShutDown
Description: This message is sent to a DKI in order to request domain shutdown.

Message: ("DKwe" address)
Name shortcut for: Domain Kernel WElcome
Description: This message is sent to every ordinary agent as the first message a new agent ever receives. It contains the address of the agent itself.

Message: ("MIdo" address domain agent-object)
Name shortcut for: MIgration DO
Description: This message is sent by a DKI to another DKI in order to transport an agent object during migration. ADDRESS is the local address the agent had in the sending domain as a bit string in order to prevent address remapping. DOMAIN is the domain address of the sending domain. AGENT-OBJECT is the agent object to transport.

Message: ("MIin" address domain agent-object)
Name shortcut for: MIgration INitialize
Description: This message is sent to a DKI by the corresponding CDK in order to transport an agent object to another domain. AGENT-OBJECT is a packed agent that had the local address ADDRESS and should be transported to the remote domain having the domain address DOMAIN.

Message: ("MIok" original-address new-address new-domain)
Name shortcut for: MIgration OK
Description: This message is sent by a DKI that has received a new agent, by migration, to the DKI of the domain that sent the agent. ORIGINAL-ADDRESS is the local address the agent had before migration in the old domain, NEW-ADDRESS is the new local address in the new, current domain and NEW-DOMAIN is the domain address of the new domain.

Message: ("MIre" address domain agent-object)
Name shortcut for: MIgration REceive
Description: As MIdo, but passed from the receiving DKI to the corresponding CDK.

Message: ("MIss" original-address new-address original-domain new-domain new-address-*)
Name shortcut for: MIgration SuccesS
Description: This message is sent by a CDK to the corresponding DKI after an agent has been succesfully received. ORIGINAL-ADDRESS is the address the agent had before being transported to the current domain. NEW-ADDRESS is its new address in the local domain. Similarly, ORIGINAL-DOMAIN is the domain where the agent came from and NEW-DOMAIN is the current domain address. NEW-ADDRESS-* is as NEW-ADDRESS but is of the actual address type, whereas NEW-ADDRESS is a bit string without address tag in order to prevent it from being remapped later.

Message: ("MIst" address domain)
Name shortcut for: MIgration STart
Description: This message is sent to a DKI in order to start migrating the agent that has the local address ADDRESS to the domain having the domain address DOMAIN.

Message: ("MIsti" id domain)
Name shortcut for: MIgration STart with Identifier
Description: This message is sent to a DKI in order to start migrating the agent that is running with the scheduler identifier ID in the current domain to the domain having the domain address DOMAIN.

Message: ("OSad" identifier object)
Name shortcut for: Object Server ADd
Description: This message is sent to an object server to request the adding of the object OBJECT, indexed by the identifier IDENTIFIER, to the store.

Message: ("OSfe" address template)
Name shortcut for: Object Server FEtch
Description: This message is sent to an object server to fetch an object whose identifier matches TEMPLATE. The object server returns an object by sending the message OSfr back to ADDRESS.

Message: ("OSfr" template object)
Name shortcut for: Object Server Fetch Result
Description: This message is sent by an object server as a response to a previous OSfe message. TEMPLATE is the template that was given and OBJECT is an object that was found from the object server's store, associated with an identifier that matches TEMPLATE. If there was no object with a matching identifier, this message is still sent; object is then the boolean false #f.

Message: ("OSin" filename object)
Name shortcut for: Object Server INject
Description: This message is sent to an object server to request the insertion of the object OBJECT that was read from a UNIX file named FILENAME. It is equivalent to ("OSin" (("filename" filename)) object).

Message: ("OSqr" template matching-identifiers)
Name shortcut for: Object Server Query Result
Description: This message is sent by an object server as a response to a previous OSqu message. TEMPLATE is the template that was given and MATCHING-IDENTIFIERS is a set of identifiers that match TEMPLATE and that are found from the object server's store.

Message: ("OSqu" address template)
Name shortcut for: Object Server QUery
Description: This message is sent to an object server to query for a set of identifiers that match the template TEMPLATE. The object server returns the list of matching identifiers (either all of them or a subset at its own discretion) by sending the message OSqr back to ADDRESS.

Message: ("OSre" template)
Name shortcut for: Object Server REmove
Description: This message is sent to an object server to request the removal of all objects whose identifiers match TEMPLATE.

Message: ("TCAad" address)
Name shortcut for: Terminal Controlling Agent ADdress
Description: This message is sent to an agent to pass the address of a TCA forward. (It is required if the agent needs to e.g. open a window.)

Message: ("TCAcd" address)
Name shortcut for: Terminal Controlling Agent Control Device
Description: This message is sent to a TCA to inform that the TCA should take over the control of a terminal device driver whose address is ADDRESS.

Message: ("TCAcw" title height address id)
Name shortcut for: Terminal Controlling Agent Create Window
Description: This message is sent to a TCA in order to request the creation of a new window, whose title is TITLE, height originally HEIGHT lines and that has the identifier ID.

Message: ("TCAkp" key)
Name shortcut for: Terminal Controlling Agent Key Press
Description: As TDDkp, but sent by a TCA.

Message: ("TCAmc" x y button)
Name shortcut for: Terminal Controlling Mouse Click
Description: As TDDmc, but sent by a TCA.

Message: ("TCAwc" user-id address)
Name shortcut for: Terminal Controlling Agent Window Created
Description: This message is sent after a TCA has created a new window. The message is sent to the address that was given in the corresponding TCAcw message. USER-ID is the identifier the using application supplied in the TCAcw message, and ADDRESS is the address of the agent controlling the newly created window.

Message: ("TCAwin" TCA-address id user-id address)
Name shortcut for: Terminal Controlling Agent Window INitialize
Description: This message is sent to a window controlling agent, which is an agent taking care of one window displayed on a terminal controlled by a TCA. The purpose of the message is to initialize the agent. TCA-ADDRESS is the address of the TCA, ID is an id invented by the TCA, USER-ID is a window identifier invented by an application requesting the window creation, and ADDRESS is the address where information about the window should be sent, in particular, a TCAwc message.

Message: ("TCAwiw" id x y string fg bg)
Name shortcut for: Terminal Controlling Agent Write In Window
Description: This message is sent to a TCA in order to request the agent to draw the string in the window with the identifier ID at position (X, Y) with the foreground color FG and background color FG. This message is mainly used by the window controlling agent and should not be used for other purposes, otherwise the terminal can get messy.

Message: ("TCAwk" id)
Name shortcut for: Terminal Controlling Agent Window Kill
Description: Sent to a TCA, request the deletion of the window that has the identifier ID.

Message: ("TCAwrs" new-height)
Name shortcut for: Terminal Controlling Agent Window ReSize
Description: Sent to a window controlling agent by the TCA, inform the agent that the size of the window as displayed on the terminal has changed to NEW-HEIGHT and the window should be redrawn.

Message: ("TDDcf" width height)
Name shortcut for: Terminal Device Driver ConFiguration
Description: Report the configuration of the hardware device driver, i.e. the size of the terminal. This message is sent to a TCA by the terminal device driver special agent.

Message: ("TDDkp" char)
Name shortcut for: Terminal Device Driver Key Press
Description: This message is sent to a TCA from a terminal device driver. It is used to announce that the user has pressed the key CHAR.

Message: ("TDDmc" x y button)
Name shortcut for: Terminal Device Driver Mouse Click
Description: This message is sent to a TCA from a terminal device driver. It is used to announce that the user has clicked the BUTTONth button of a pointer device at position (X, Y).

Message: ("TDDqc")
Name shortcut for: Terminal Device Driver Query Configuration
Description: Sent to a terminal device driver, request the driver to send a TDDcf message to the corresponding TCA.

Message: ("TDDsc" address)
Name shortcut for: Terminal Device Driver Set Controller
Description: Sent to a terminal device driver, tell the driver that it is from now on controlled by the TCA in address ADDRESS. From receiving this message on, the driver sends e.g. all mouse-click and key-press events to the given ADDRESS.

Message: ("TDDws" x y string fg bg)
Name shortcut for: Terminal Device Driver Write String
Description: Request the string STRING to be displayed on the terminal at position (X, Y), drawn with foreground color FG and background color BG.

Message: ("TWcl")
Name shortcut for: Terminal Window CLear
Description: Sent to a window controlling agent, request the contents of the window to be emptied.

Message: ("TWsc" amount)
Name shortcut for: Terminal Window SCroll
Description: Sent to a window controlling agent, request the contents of the window to be scrolled AMOUNT lines upwards.

Message: ("TWw" string x y)
Name shortcut for: Terminal Window Write
Description: Sent to a window controlling agent, request the string STRING to be display at the position (X, Y), relative to the upperleft corner of the window. The change in the window contents is cached, as opposed to the (not very useful) TWws.

Message: ("TWwl" line)
Name shortcut for: Terminal Window Write Line
Description: Sent to a window controlling agent, request the line LINE to be displayed at the bottom of the window after the old contents have been scrolled up once.

Message: ("TWws" string x y fg bg)
Name shortcut for: Terminal Window Write String
Description: Sent to a window controlling agent, request the string STRING to be display at the position (X, Y), relative to the upper-left corner of the window, with foreground color FG and background color BG. This message bypasses the contents caching normally applied by the window controlling agent and is no longer very useful.

8 External Agent Interface

The kernel provides an interface for external agents to directly connect to the system. The external agent can show as members of that domain in the SCHEMESTATION system. The communication between the external agent and the domain will be done through a unix socket. The networking module will provide the way for the external agents to connect and register themselves.

The scheme used is quite simple: the external agent programmer requests the ssextagent-library to open a connection to the specified SCHEMESTATION domain. After that he can both send and receive byte-string messages using the descriptor of that connection. The read facility is non-blocking, while writing is done in possibly-blocking manner.

The external agant interface is rahter simple and provides no support for the SCHEMESTATION data structures such as heaps. The users of the external agent interface are urged to write some kind of interface agents in scheme, through which the external agents should communicate with the rest of the world.


Fig. 3.The external agent interface scheme

To use the external agent interface in a C program, the user has to include the ssextegent.h file included in the distribution, and link the libssextagent.a to the executable.

There is a more detailed description of the external agent interface in [External Agent Interface Specification and External Agent Interface Implementation].

8.1 External file server agent

In order to use the underlying unix system's file system from the SCHEMESTATION domain, one can use the external file server agent that comes with the distribution.

The SCHEMESTATION system includes an object server (Operating system specification). Since the Operating System specification requires the system to be persistent, there has to be some backup mechanism for the objects.

Also, since the compiler has not yet been ported to be a native part of he system, there has to be a way to import bytecode files to the system.

The files system acts as an gateway from the SCHEMESTATION system to the underlying unix file system. The user may access the files inside the domain communicating through the interface agent of the external agents'.

The file server external agent executable can be started using the following command line swithces:

The exact protocol between the client agent and the file server is specified in [External agents].

More detailed description on the file server is in [External agents].

8.2 External TCP server agent

The TCP server gives the SCHEMESTATION the ability to do any kind of TCP communication. Once the server is started, it begins waiting for a command for the interface agent. The interface agent may instruct the server to begin listening for a local TCP port, or to directly connect to a remote port. The result of a listen request is either a success acknowledgement, or an error message.

If a connection occurs to a listened port, or when an explicitly requested remote connection is succesfully opened, the server acknowledges the interface agent with a open-acknowledgement, which includes the port to which the connection was established (either the local port that was listened for, or the remote port, where the connection was requested to), possibly the remote host (if the ack corresponds to a remote open request) and the connection number, with which the interface id is supposed to later address the connection.

The interface agent may thereafter send packets to the open connection giving the connection number, the length of the data and the data itself.

The interface agent receives similar messages when data arrives to the port.

The TCP external agent executable can be started using the following command line swithces:

8.3 Using the external agent from inside a scheme agent

The external agent interface to the native scheme agent is best illustrated through an example. For this reason, we have included an http server in the distribution. It can be inspected in [Code browser: httpd.ssscm].

More detailed description on the TCP server is in [External agents].

8.4 Troubleshooting

ProblemTentative solutions
I try to start a domain, but I "can't connect to the virtual network." (1) You do not have the network simulator running. You need to start it first, if you are going to use the network. Start ssnetsim.

(2) You actually do not want to have a network simulator, and try to run the station without, but have not given the -i switch. Set -i, and the station does not try to connect to the network.

(3) You have set incorrectly the TCP/IP address and/or the port of the simulator. See the domain simulator command line options.

I try to start a domain, but it seems that "the terminal cannot be spawned." The most probable reason is that the ssconsole program is not in your path. Set your path to include schemestation/bin.
I still do not get a terminal. You need an X server to use the terminal. Make sure your DISPLAY environment variable points to the right X server.
I tried to write my first Scheme program, but the compiler would not compile it. (1) You have misbalanced parenthesis in your program. Add yet one more ')'!

(2) Check the error messages provided by the compiler.

(3) Try to run your Scheme program in another Scheme interpreter, e.g. VSCM, if that would describe the problem better.

To me, the external agent interface seems fairly cumbersome. (1) Tough.

(2) Oh yeah? Write your own one!