A Maisie program is a collection of C functions and entity definitions.
An entity definition (or an entity type) describes a class of objects.
Instances of an entity type may be created to model
object(s) in the physical system. For instance, an entity type
server may be defined to model server objects;
specific instances of the server entity type
are created to model server objects in the physical system.
Henceforth we will use the term entity to mean an entity instance.
The definition of an entity type is similar to the definition of a C function. The syntax is as follows:
entity-def ::= entity ident { [parameters] } [declarations] body
parameters ::= a C parameter list
declarations ::= [type ident [,ident]...;]...
body ::= a C compound statement possibly including Maisie constructs
type ::= ename (see section 2.2)
| message ident (see section 3)
| clocktype (see section 4.2)
| any C type declaration
The entity heading is similar to a function heading; it specifies a name for the entity type and gives a list of typed parameters. The entity body is a compound statement that essentially describes the actions executed by an entity type. The first example below gives the heading for an entity type manager with one integer parameter munits . The second example shows an entity type sort that declares two formal parameters: an array parameter a and an integer n, which represents the size of the array a.
Examples:Remarks: variable declarations and initializationsentity manager {max_printers} int max_printers; { int units; ... }
entity sort {n, a} int n, a[20]; { ... }
Maisie supports dynamic and recursive entity creation. A Maisie entity is created by using the new statement, which has the following syntax:
new-st ::= [ename-expr =] new ident {[arg]...} [at node-no]
ename-expr ::= an expression of type ename
arg ::= array-param | C argument expression
array-param ::= pointer[::size]
pointer ::= a C pointer expression
size ::= a positive integer-valued expression
node-no ::= a positive integer-valued expression
The following example creates a new instance of the manager entity type (defined in the previous section) and saves the unique identifier assigned to the entity in variable s1. An entity may refer to its own identifier by using keyword self.
Example:{ ename s1; ... s1 = new manager{10}; ... }
By default, the new entity executes on the same processor as its creator entity. The new statement may optionally include an at clause to specify a different processor (node) for execution of the new entity. The node-no in the new statement may be an arbitrary positive integer; it is mapped to a specific node on the parallel architecture as follows: the actual number of nodes, say N, used in an execution of the program is specified as a command line argument (see Appendix A). The node-no in a new statement is interpreted as node-no modulo N to determine the target processor. The at clause is ignored for sequential implementations of the program.
Execution of a new statement returns a unique identifier of type ename. This is a new type introduced by Maisie; variables of this type are used only to refer to entities. Very few operations are defined on variables of type ename: they may be passed as entity or message parameter and may be assigned a value by a new statement. In addition, a function ename_cmp (e1,e2) is defined by the runtime library, where e1 and e2 are of type ename. The function returns a non-zero value if and only if the two variables are identical.
As mentioned before, an entity may include array parameters. However, unlike C functions, the array parameters are passed by value. An actual array parameter is specified by a pointer expression and an optional integer value. The pointer contains the address of the first element and the integer indicates the subsequent number of bytes to be passed; if the size is omitted, all elements beginning from the specified address will be passed. In the following example, the driver entity demonstrates several different ways to instantiate entity sort (defined in the previous section).
Example:Remarks:entity driver {} { ename s1; int x[20]; s1 = new sort{20, x}; /* Send the entire array x */ new sort{10, x::10*sizeof(int)}; /* Send 10 elements in x[0] .. x[9] */ new sort{10, &x[10]::10*sizeof(int)}; /* Send 10 elements in x[10] .. x[19] */ ... }
A Maisie entity may terminate itself in one of two ways: by executing a C return statement (if the return statement includes an expression, it is ignored) or by `falling off the end' of the entity-body.
Local data of an entity is inaccessible by any function that is called by the entity. It is, however, possible to allow a function to access local variables of the calling entity, without explicitly passing the variable as a parameter to the function, simply by including a declaration for the function in the entity body. In its definition, the function name must be prefixed with the entity-name, and the function definition must follow the entity definition in the same file. The following example illustrates the use of friend functions.
Example:entity sort { n, a } int n, a[20]; { void sorting(); ... sorting(); } void sort::sorting() { int i, t; /* ** the function can access the local variable a ** defined in the corresponding entity */ for(t = a[0], i=1; i < n; i++) { if(a[i] < t) ... } }