User and Application Programmer's Manual
Document formatted by vherva at Fri Apr 24 11:23:55 1998 on the host schemestation. This document is produced by the SchemeStation project during the Tik-76.115 course.
| |||||||||||||
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.
| |||||||||||||
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 | |||||||||||||
| |||||||||||||
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:
| |||||||||||||
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:
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 a b) 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.
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.
| |||||||||||||
6.2 Descriptions of the Programs Distributed | |||||||||||||
This sections describes shortly all Scheme agents that are a part of the distribution.
| |||||||||||||
7 List of Used Messages | |||||||||||||
This chapter documents the messages that are used in the example programs distributed.
Message: ("CA" arguments)
Message: ("CDKacr" domain address new-domain new-address)
Message: ("CDKeir" address)
Message: ("CDKpir" address)
Message: ("CDKrkq" domain)
Message: ("CDKru" id address)
Message: ("CDKsd")
Message: ("CDKsl" message)
Message: ("CDKto" id)
Message: ("CDKtr" address time id)
Message: ("DKIacr" domain address new-domain new-address)
Message: ("DKIdkc" address)
Message: ("DKIosa" address)
Message: ("DKIosar" address)
Message: ("DKIpir" address)
Message: ("DKIrka" domain address)
Message: ("DKIsl" message)
Message: ("DKItr" address time id)
Message: ("DKIx" template address)
Message: ("DKcd" type address)
Message: ("DKgei")
Message: ("DKin" key value)
Message: ("DKpi" id name status frac id name status frac ...)
Message: ("DKsd")
Message: ("DKwe" address)
Message: ("MIdo" address domain agent-object)
Message: ("MIin" address domain agent-object)
Message: ("MIok" original-address new-address new-domain)
Message: ("MIre" address domain agent-object)
Message: ("MIss" original-address new-address original-domain new-domain
new-address-*)
Message: ("MIst" address domain)
Message: ("MIsti" id domain)
Message: ("OSad" identifier object)
Message: ("OSfe" address template)
Message: ("OSfr" template object)
Message: ("OSin" filename object)
Message: ("OSqr" template matching-identifiers)
Message: ("OSqu" address template)
Message: ("OSre" template)
Message: ("TCAad" address)
Message: ("TCAcd" address)
Message: ("TCAcw" title height address id)
Message: ("TCAkp" key)
Message: ("TCAmc" x y button)
Message: ("TCAwc" user-id address)
Message: ("TCAwin" TCA-address id user-id address)
Message: ("TCAwiw" id x y string fg bg)
Message: ("TCAwk" id)
Message: ("TCAwrs" new-height)
Message: ("TDDcf" width height)
Message: ("TDDkp" char)
Message: ("TDDmc" x y button)
Message: ("TDDqc")
Message: ("TDDsc" address)
Message: ("TDDws" x y string fg bg)
Message: ("TWcl")
Message: ("TWsc" amount)
Message: ("TWw" string x y)
Message: ("TWwl" line)
Message: ("TWws" string x y fg bg)
| |||||||||||||
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.
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 | |||||||||||||
|
© SchemeStation project 1997-1998 | [Back to the document index] |