The UniCon
Language Reference Manual

Gregory Zelesnik

School of Computer Science
Carnegie Mellon University
Pittsburgh, Pennsylvania 15213-3890

Abstract

This work represents the language reference manual for the UniCon architecture description language (ADL).

This research was supported by the Carnegie Mellon University School of Computer Science and Software Engineering Institute (which is sponsored by the U.S. Department of Defense), by a grant from Siemens Corporate Research, and by the Wright Laboratory, Aeronautical Systems Center, Air Force Materiel Command, USAF, and the Advanced Research Projects Agency (ARPA) under grant F33615-93-1-1330. The U.S. Government is authorized to reproduce and distribute reprints for Government purposes, notwithstanding any copyright notation herein. Views and conclusions contained in this document are those of the author and should not be interpreted as representing the official policies, either expressed or implied, of Wright Laboratory, the Department of Defense, the United States Government, Siemens Corporation, or Carnegie Mellon University.

This page intentionally left blank.

The UniCon Architecture Description Language

UniCon is an architecture description language (ADL) organized around two symmetrical constructs: components and connectors. Components represent loci of computation and data in a software system. They are used to organize the computation and data into parts that have well-defined semantics and behaviors. Connectors represent classes of interactions among the components. They are used to mediate component interactions.

Both components and connectors have a specification part and an implementation part.

Components are specified by an interface. The interface defines the computational commitments the component can make and the constraints on the way the component can be used. It also provides the guarantees that will hold of the performance and behavior of the component. The interface contains three types of information:

The component type expresses the designer's intentions about the general class of functionality to be provided by the component. It restricts the numbers, types, and specifications of the players that can be defined. Properties are attribute-value pairs that specify additional information about a component as a whole, such as assertions or constraints. Players are the visible semantic units, or hooks, in a component through which the component can interact with other components.

Connectors are specified by a protocol. The protocol defines the allowable interactions among a collection of components and provides guarantees about those interactions. It contains three types of information:

The connector type expresses the designer's intentions about the general class of component interactions to be mediated by the connector. It restricts the numbers, types, and specifications of the roles that can be defined. Properties are attribute-value pairs that specify additional information about a connector as a whole, such as assertions or constraints (e.g., rules about timing or ordering). They represent commitments about the interaction that the protocol supports. Roles are the visible semantic units through which the connector mediates the interactions among components. They get associated with players when forming connections in a system. Roles define the requirements and the responsibilities for the players in a connection.

Component implementations have two different forms: primitive and composite. A primitive implementation consists of a pointer to a source document external to the UniCon language that contains the implementation. The source document may be source code in your favorite programming language (at present, the UniCon toolset only supports C language source code), object code, a Unix archive file containing object code, a binary executable, a shell sdript, a sequential data file, or a C language include file. The UniCon toolset knows how to construct systems using this variety of source documents.

A composite implementation is a description of a configuration of other UniCon-defined components and connectors. It contains three types of information:

The pieces are the specific component and connector instances used to construct the configuration description. The configuration information is a description of how the components and connectors are hooked together (i.e., connected). The abstraction information is a mapping, or description, of how the players in the component interface are implemented by players in the component instances of the composite implementation.

Connector implementations are built into the language; they have specific implementations which are provided by the UniCon toolset. No mechanism exists in UniCon to allow for the definition of user-defined connector implementations.

Component

Description

In UniCon software systems are described in terms of two kinds of distinct, identifiable elements: components and connectors.

A component is an abstraction that represents a locus of computation and state in a system. It roughly corresponds to a compilation unit in a conventional programming language, a process in an operating system environment, or a user-level object such as a file in a filesystem. Components behave in identifiable, distinct ways, and they also interact with other components in similarly distinct and identifiable ways. These distinctions separate components into categories, or types. A component type captures the semantics of a component's behavior, the kind of functionality it implements, its performance characteristics, and its expectations of the style of interaction with other components.

A component has a specification, called an interface, and an implementation. The interface defines the computational commitments the component can make, and constraints on the way the component is to be used. It provides the guarantees that will hold of the behavior and performance of the component. It should be possible to use the component by reference to the interface alone.

The interface defines:

The component type expresses the designer's intention about the general class of functionality to be provided by the component; it restricts the numbers, types, and specifications of properties and players.

Properties can be thought of as attributes of a definition which are used to further describe (i.e., specify) it. They are global assertions and constraints that apply to the definition as a whole. There are many places in UniCon where lists of properties are used to further specify a definition. In component interfaces, properties are used to specify information such as the name of the processor that a process will run on, or the priority that a process will have in the run-time environment.

The interface defines the units of association used in system composition. These are named entities called players, and they are what get connected during system composition by connectors. They are the visible points through which a component interacts, requests or provides services, or is influenced by external state or events. Players are further specified by their own property lists.

The implementation of a component describes how it is constructed. Components have either primitive implementations, or composite implementations. A primitive implementation describes a component that is implemented by some source code or data that is external to UniCon (e.g., source code of a programming language, scripts of commands of an operating system shell, or data in a file in the file system).

A composite implementation describes a configuration of components and connectors. This mechanism in UniCon allows system designers to progressively build larger subsystems from collections of smaller components or subsystems, or more abstract components from less abstract ones.

Syntax

The following is the syntax for a component definition in UniCon:

  <component> :==  
COMPONENT <identifier>
<interface>
<component_implementation>
END <identifier> <interface> :==
INTERFACE IS
TYPE <component_type>
<property_list>
<player_list>
END INTERFACE <component_type> :==
Module
| Computation
| SharedData
| SeqFile
| Filter
| Process
| SchedProcess
| General
The properties in a <property_list> are separated by whitespace (i.e., spaces, tabs, and carriage returns). A <property_list> can be empty (in many cases), or it may contain one or more properties. A <property> is a name-value pair that specifies an attribute, an assertion, or a constraint pertaining to a definition. It is used to further specify that definition. The syntax of a property is as follows:

  <property> :== <name> <value>
  <name> :== <identifier>
  <value> :== 
EMPTY
| (<value_part>)
The <name> in a property has significance in UniCon (i.e., it conveys meaningful information about a definition); the <value> associates specific information with the property name in the given context. Here, the term context refers to the given language element of the given type (e.g., player, of type GlobalDataDef). The <value> may be NULL, or it may contain a <value_part> enclosed in parentheses. The <value_part> has a syntax that is specific to the property, in a given context. There are eleven common syntaxes for the values of UniCon properties.

The set of properties that can be legally specified in a property list depends on which definition the property list further specifies. For example, the set of properties legal for an interface property list is different from the set that is legal for an implementation's property list.

The players in a <player_list>, the variants in a <variant_list>, and the statements in a <composite_statement_list> are all separated by whitespace.

  <component_implementation> :==
<primitive_implementation>
| <composite_implementation> <primitive_implementation> :==
IMPLEMENTATION IS
<property_list>
<variant_list>
END IMPLEMENTATION <composite_implementation> :==
IMPLEMENTATION IS
<property_list>
<composite_statement_list>
END IMPLEMENTATION

Component Type

Description

Components behave in identifiable, distinct ways, and they also interact with other components in similarly distinct and identifiable ways. These distinctions separate components into categories, or types. A component type captures the semantics of a component's behavior, the kind of functionality it implements, its performance characteristics, and its expectations of the style of interaction with other components.

Every component definition has a type. In UniCon, there are eight pre-defined component types. The specification of the type comes as the first UniCon statement inside a component interface.

Syntax

The following is the syntax for specifying a component type:

  <component_type> :== 
Module
| Computation
| SharedData
| SeqFile
| Filter
| Process
| SchedProcess
| General

Module

Semantics

The component type Module corresponds to a compilation unit in a typical programming language. Such compilation units define and export function definitions and global data definitions, and they also make function calls and access global data that are defined in other compilation units. In addition, compilation units perform input and output to files. In typical programming languages, the input and output operations are performed by special function or procedure calls.

Player types

Players of the following types can be legally exposed in the interface of a component of type Module:

an exported procedure or function definition
a call to an exported procedure or function definition in another compilation unit
an exported global data definition
a reference to an exported global data definition in another compilation unit
a read operation from a file
a write operation to a file
a collection of programming language players, players of types
RoutineDef, RoutineCall, GlobalDataDef, and GlobalDataUse

Properties

The following properties can be legally included in the property list of a component of type Module. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type
Module is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type Module is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type Module is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The syntax for an EntryPoint property in a component of type Module is a single <identifier> or "string" surrounded by parentheses:
ENTRYPOINT (an_entrypoint_name)
ENTRYPOINT ("an entrypoint name")
The Library property has no associated value. The syntax, therefore, is simply:
LIBRARY

Semantic Checks

No special semantic checks are made for components of type Module.

Implementation Considerations

The source code implementation of a Module component is simply a collection of externally defined C functions and data definitions. The functions may make calls to externally defined functions in other compilation units, and both the functions and global data may reference other externally defined data during processing and initialization.

Computation

Semantics

The component type Computation is a specialization of the Module component type. The difference between the two is that a component of type Computation does not define and export global data or contain input and output operations to and from files. This type is intended to capture the semantics of purely computational units that are collections of procedure definitions and calls. Components of type Computation define and export procedures and functions, and they make calls to functions and access global data defined in other compilation units.

Player types

Players of the following types can be legally exposed in the interface of a component of type Computation:

an exported procedure or function definition
a call to an exported procedure or function definition in another compilation unit
a reference to an exported global data definition in another compilation unit
a collection of programming language players, players of types
RoutineDef, RoutineCall, and GlobalDataUse

Properties

The following properties can be legally included in the property list of a component of type Computation. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type
Computation is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type
Computation is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type
Computation is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The syntax for an EntryPoint property in a component of type
Computation is a single <identifier> or "string" surrounded by parentheses:
ENTRYPOINT (an_entrypoint_name)
ENTRYPOINT ("an entrypoint name")
The Library property has no associated value. The syntax, therefore, is simply:
LIBRARY

Semantic Checks

No special semantic checks are made for components of type Computation.

Implementation Consideration

The source code implementation of a Computation component is simply a collection of externally defined C functions. The functions may make calls to externally defined functions in other compilation units and may reference externally defined data as well.

SharedData

Semantics

The component type SharedData is a specialization of the Module component type. This type is intended to capture the semantics of compilation units that export only global data to be shared among collections of functions and procedures defined in other compilation units. Components of type SharedData define and export global data and reference global data defined in other compilation units.

Player types

Players of the following types can be legally exposed in the interface of a component of type SharedData:

an exported global data definition
a reference to an exported global data definition in another compilation unit
a collection of programming language players, players of types
GlobalDataDef and GlobalDataUse

Properties

The following properties can be legally included in the property list of a component of type SharedData. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type SharedData is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type
SharedData is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type
SharedData is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The Library property has no associated value. The syntax, therefore, is simply:
LIBRARY

Semantic Checks

No special semantic checks are made for components of type SharedData.

Implementation Considerations

The source code implementation of a SharedData component is simply a collection of external C data definitions that may reference other external data definitions for initialization purposes.

Filter

Semantics

The component type Filter is intended to capture the semantics of Unix filters. A Unix filter is a self-contained process in the Unix environment that reads input from the standard input port of the process, performs some type of computation, and writes output to the standard output port. A filter may start generating output before all of the input is consumed. It may also generate warning or error messages to the standard error port. A Unix filter does not interact with any other human, process, or file system entity in any other way.

The type Filter is a departure from the previous three types we've already seen: Module, Computation, and SharedData. Whereas these three types describe compilation units developed in some programming language, Filter describes a process in the Unix environment.

Player types

Players of the following types can be legally exposed in the interface of a component of type Filter:

data arriving as an input stream at a port in a Unix filter
data exiting as an output stream from a port in a Unix filter

Properties

The following properties can be legally included in the property list of a component of type Filter. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type Filter is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type Filter is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type Filter is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")

Semantic Checks

No special semantic checks are made for components of type Filter.

Implementation Considerations

A Filter component is implemented as a program, containing a "main" function, that performs input and output via the ports of the Unix process that is created for the program at run-time.

All ports that the filter will read from and write to are assumed to be already open at process creation time. This means that if, for example, the program assumes that there will be input on port 4, then port 4 will already have been opened for input by the time the first line of code in the program is executed.

SeqFile

Semantics

The component type SeqFile is intended to capture the abstraction of a sequential file in which lines, characters, or records (the format of the data is specified using the RecordFormat property) are read sequentially from the front and written sequentially at the end.

Player types

Players of the following types can be legally exposed in the interface of a component of type SeqFile:

the next data item to be read
the next data item to be written

Properties

The following properties can be legally included in the property list of a component of type SeqFile. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type
SeqFile is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type
SeqFile is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type
SeqFile is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The syntax for a RecordFormat property in a component of type
SeqFile is a comma-separated list of items, surrounded by parentheses, that are either <identifier>s or "strings":
RECORDFORMAT (a_type_name, "another type name")
If this property is omitted from the property list of the interface in a SeqFile component, the following default property is assumed:
RECORDFORMAT ("line")
The syntax for an OpenMode property in a component of type
SeqFile is a comma-separated list containing a subset of the words truncate, append, and create, surrounded by parentheses. These words can be specified as either <identifier>s or "strings":
OPENMODE (create, "append")
The Library property has no associated value. The syntax, therefore, is simply:
LIBRARY

Semantic Checks

If the SeqFile component has a primitive implementation, the implementation type of the source file (specified in the ImplType property in the variant's property list) must be of type Data.

Implementation Considerations

The implementation of a SeqFile component in the environment is simply a sequential file containing ASCII data.

Process

Semantics

The component type Process is intended to capture the semantics of an independently scheduled process in the operating system environment. The type of process that it describes is different from a Unix filter in that it communicates with other processes, and does so via remote procedure calls.

A Process component can behave in one of two ways. It can behave like a "server" process, providing services to other processes by exporting remote procedure definitions, or it can behave like a "client" process, requesting services from other processes via remote procedure calls. The distinction between client processes and server processes is important in UniCon because certain properties (e.g., the EntryPoint property) have different semantics based on the kind of Process being defined. To formalize the definitions, a client process is one that exports no remote procedure definitions, only calls. A server process is one that exports at least one remote procedure definition. A process that exports remote procedure definitions and calls is still considered to be a server (i.e., one that requires services from other processes in order to accomplish its work).

Player types

Players of the following types can be legally exposed in the interface of a Process component:

an exported remote procedure or function definition
a call to a remote procedure or function exported by another process

Properties

The following properties can be legally included in the property list of a Process component. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type
Process is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type
Process is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type
Process is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The syntax for the EntryPoint property in a Process component is a single <identifier> or "string" surrounded by parentheses:
ENTRYPOINT (an_entrypoint_name)
ENTRYPOINT ("an entrypoint name")
If this property is omitted from the property list of the interface in a client Process component, the following default property is assumed:
ENTRYPOINT ("main")
If this property is omitted from the property list of the interface in a server Process component, no default is assumed.
The syntax for the InitRoutine property in a Process component is a single <identifier> or "string" surrounded by parentheses:
INITROUTINE (a_routine_name)
INITROUTINE ("a routine name")
The syntax for an RPCTypeDef property in a Process component consists of a sequence of three fields, all separated by semicolons, with the entire sequence enclosed in parentheses. The first field is an <identifier> or "string". The second field is also an <identifier> or "string". The third field is optional, and consists of a <size item> (if the third field is omitted, the semicolon following the second field is also omitted). A <size item> consists of an optional <array item>, followed by an
<integer>. An <array item> consists of one or more consecutive <array index>s of the form `[` <integer> `]':
RPCTYPEDEF (a_type_name; "another one")
RPCTYPEDEF (a_type_name; another_one; 32)
RPCTYPEDEF ("a type name"; another_one; [25] [16] 32)
The syntax for an RPCTypesIn property in a Process component is a comma-separated list of items, surrounded by parentheses, that are either <identifier>s or "string"s:
RPCTYPESIN ("an_include_file.h", "another_one.h")

Semantic Checks

A Process component that has a composite implementation may not contain an instantiation of a Process or a SchedProcess component.

Implementation Considerations

In UniCon, the "glue code" required for accomplishing remote procedure calls in the implementation is generated automatically by the UniCon compiler. Therefore, remote procedure definitions and calls in the source code implementation of a Process are implemented exactly like local procedure or function definitions and calls. The software engineer will not create any "glue code."

In addition to the static, compile-time "glue code," remote procedure calls require run-time support. Each process must perform some initialization in the environment before starting to perform its tasks. This initialization takes the form of looking up (client) or registering (server) services with a common "name server" process that executes in the environment. This is how client processes are able to locate services provided by server processes in the run-time environment. The UniCon compiler generates this run-time initialization code automatically for each process. It generates a "main" program that performs the initialization and calls the initial entrypoint in the source code provided by the system designer. The designer specifies this entrypoint name using the EntryPoint property.

The source code implementation of a client process must be a function or a procedure.
UniCon currently only supports implementations in the C programming language, so for now it must be a C function. The function can be named "main," however it will be renamed in this case since UniCon produces a "main" function for each process. The "main" function that UniCon produces performs any initialization required to support remote procedure calls between this and other processes, and then it calls the function that implements the client process. The process terminates when this function returns, so some sort of infinite processing (i.e., loop) may be required to keep the process active.

The source code implementation of a server process is different. It must be a collection of C functions, called service functions, plus optionally one additional worker function. The worker function, if present, will run in parallel with a UniCon-generated "main" program. It performs application-specific processing. The service functions become the callable remote procedures at run-time. UniCon generates a "main" function that performs initialization required to support remote procedure calls between this and other processes and loops forever waiting for service requests from other processes. This main function will call the appropriate service function to perform a requested service, and then send the results back to the client process that made the request.

The worker function must be implemented as a simple C function. Under Mach, the worker function may or may not loop forever. In RPCGen-based servers, the worker thread must not loop forever, and will be called periodically (after performing each service request, and every 10 milliseconds if no requests are forthcoming). The presence or absence of a worker function is specified by the presence or absence of the EntryPoint property in the interface property list of a server Process component. The name of the worker function is supplied as the value of this property.

Each service function must be a simple C function that does not loop forever, but rather eventually returns.

One final note: remote procedure calls on Mach systems require that the functions pass results back to client processes via the arguments of the function (i.e., the return value is passed back to the caller by modifying the location pointed to by one of the input arguments), rather than as the return value of the function. This is not the case for RPCGen-based services.

SchedProcess

Semantics

The component type SchedProcess is a specialization of the Process component type. The semantics described for the Process component also apply to the SchedProcess component, except that a SchedProcess component does not represent an independently scheduled process in the operating system. It represents a process in a real-time operating system environment that is scheduled according to some real-time scheduling algorithm. This algorithm governs a set of such processes, all competing for the processor resource to meet real-time deadlines.

In addition to RPCCall and RPCDef players, a SchedProcess component exports players of type RTLoad. A player of this type represents a load that is to be placed on a particular processor (CPU) in the operating system environment. An RTLoad player is defined by a single trigger, and a set of segments, both of which are specified as properties in the player definition.

A trigger is an event that causes a process to become active and to perform its work. A segment is a well-defined block of that work. A trigger usually describes the expiration of a timer associated with a process in the operating system environment. The real-time scheduling algorithm interprets this as an event that requires the activation of the given process. Triggers are periodic; they happen over and over again at a given rate. For example, if a trigger has a period of one second, then the event occurs once per second. If the period is one half second, then the event occurs twice per second, and so on.

A SchedProcess component is broken down into a set of one or more work blocks called segments, each of which requires a specific amount of CPU time to execute. Collectively, the total execution time of the set of segments in an RTLoad player represents the load placed on the CPU by the SchedProcess component each time the event described by the trigger occurs.

In a real-time application described by a system of SchedProcess components, communication via remote procedure calls adds a level of complexity to the notion of an event. In such a system, a trigger activates only a client process. A server process becomes active whenever a request is made for a service it provides. When a process makes a remote procedure call, work blocks in a server process are executed in addition to the work blocks in the calling process. This means that, before work is completed in response to a given trigger, segments from a set of SchedProcess components will be executed if some of the processes are performing remote procedure calls. The specific sequence of segments that executes in response to a trigger is called the event trace. In systems of SchedProcess components performing RPCs, it is the load associated with an event trace that is considered during scheduling. To summarize, the RTLoad player in a SchedProcess component only describes the portion of a trace applicable to a single process. Since a trace can span multiple processes, the load placed on the CPU in response to an event comes from multiple RTLoad players.

In a SchedProcess component, triggers are defined and associated with periods by specifying a TriggerDef property in the property list of the component interface. Segments are defined and associated with execution times by specifying a SegmentDef property in the interface property list. Lastly, the specific trigger in an RTLoad player is specified by the Trigger property in the player's property list, and the set of segments is specified by the SegmentSet property in the same list. The trigger in the Trigger property must have been previously defined in a TriggerDef property, and the segments in the SegmentSet property must also have been previously defined in SegmentDef properties.

In real-time systems, not all of the work performed by SchedProcess components has the same priority. Some of the work is more urgent, and must always get priority over other work. To facilitate this pattern of execution, real-time operating systems make provisions for assigning priorities to processes. In UniCon, a priority is assigned to a SchedProcess component via the Priority property in the interface property list.

Player types

Players of the following types can be legally exposed in the interface of a SchedProcess component:

an exported remote procedure or function definition
a call to a remote procedure or function exported by another process
the execution-time and period information for the real-time process

Properties

The following properties can be legally included in the property list of a SchedProcess component. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type
SchedProcess is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type
SchedProcess is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type
SchedProcess is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The syntax for the EntryPoint property in a SchedProcess component is a single <identifier> or "string" surrounded by parentheses:
ENTRYPOINT (an_entrypoint_name)
ENTRYPOINT ("an entrypoint name")
If this property is omitted from the property list of the interface in a client SchedProcess component, the following default property is assumed:
ENTRYPOINT ("main")
If this property is omitted from the property list of the interface in a server SchedProcess component, no default is assumed.
The syntax for the InitRoutine property in a SchedProcess component is a single <identifier> or "string" surrounded by parentheses:
INITROUTINE (a_routine_name)
INITROUTINE ("a routine name")
The syntax for an RPCTypeDef property in a SchedProcess component consists of a sequence of three fields, all separated by semicolons, with the entire sequence enclosed in parentheses. The first field is an <identifier> or "string". The second field is also an <identifier> or "string". The third field is optional, and consists of a <size item> (if the third field is omitted, the semicolon following the second field is also omitted). A <size item> consists of an optional <array item>, followed by an <integer>. An <array item> consists of one or more consecutive <array index>s of the form `[` <integer> `]':
RPCTYPEDEF (a_type_name; "another one")
RPCTYPEDEF (a_type_name; another_one; 32)
RPCTYPEDEF ("a type name"; another_one; [25] [16] 32)
The syntax for an RPCTypesIn property in a SchedProcess component is a comma-separated list of items, surrounded by parentheses, that are either <identifier>s or "string"s:
RPCTYPESIN ("an_include_file.h", "another_one.h")
The syntax for a Priority property in a SchedProcess component is a single <integer>:
PRIORITY (12)
The syntax for a SegmentDef property in a SchedProcess component consists of two fields, separated by a semicolon, and enclosed in parentheses. The first field is a single <identifier> or "string". The second field is a single <floating point number>:
SEGMENTDEF (a_segment_name, 1.0E2)
SEGMENTDEF ("a segment name", 1.0E2)
The syntax for a TriggerDef property in a SchedProcess component consists of two fields, separated by a semicolon, and enclosed in parentheses. The first field is a single <identifier> or "string". The second field is a single <floating point number> or the word "asynchronous":
TRIGGERDEF (a_trigger_name, 1.0E2)
TRIGGERDEF ("a trigger name", asynchronous)

Semantic Checks

The following special semantic checks are made for SchedProcess components:

  1. A SchedProcess component that has a composite implementation may not contain an instantiation of a SchedProcess or a Process component.
  2. A SchedProcess component must expose at least one RTLoad player in the interface.
  3. A SchedProcess component describing a server process may not define any periodic triggers (i.e., triggers with non-zero periods).
  4. A SchedProcess component describing a client process may not define any aperiodic triggers (i.e., triggers with zero periods, or defined as "asynchronous").
  5. A SchedProcess component describing a client process must define at least one trigger and at least one segment.
  6. A segment defined in a SchedProcess component must be used in an RTLoad player exposed in the interface of that component.
  7. Each SchedProcess component in a system must be hooked to exactly one RTScheduler connector.

Implementation Considerations

The semantics of the underlying source code implementation of SchedProcess components are nearly identical to those of Process components except for the following:

Client processes must be implemented by C functions or procedures that do not loop forever. Since the real-time scheduling algorithm reschedules (i.e., reactivates) the code to execute over and over again, it must finish its work and return control to the operating system each time it is activated.

In addition to performing initialization to support remote procedure calls between processes, the "main" program for a process in a real-time environment must also initialize the process to run at a particular priority, and according to a particular rate (period). The priority information can be specified by the system designer in a SchedProcess component instantiation via the Priority property. The period information is specified via the floating point value in the TriggerDef property when defining a trigger in a SchedProcess component definition.

General

Semantics

The component type General is used to describe components that do not exhibit the behavior described by any of the other pre-defined UniCon component types. It is useful for describing systems and subsystems which do not, as a whole, exhibit the behavior described by a single component type. For example, it is useful for describing a system of Process or SchedProcess components. Since this type of system cannot be described with any of the other UniCon component types, the type General is used. The component type General does not describe a specific set of semantics, and therefore no special type-related semantic checks are performed.

The danger in using this type is that any component can be described using the type
General, and so it can be misused to bypass the checks that guarantee that a component behaves according to the semantics defined by one of the other pre-defined component types in UniCon.

A proper use of the General component type is to describe systems or subsystems that do not exhibit the behavior described by a single one of any of the other pre-defined component types in UniCon.

Player types

Players of any of the legal UniCon player types may be exposed in the interface of a component of type General:

an exported procedure or function definition
a call to an exported procedure or function definition in another compilation unit
an exported global data definition
a reference to an exported global data definition in another compilation unit
a collection of programming language players, players of types
RoutineDef, RoutineCall, GlobalDataDef, and GlobalDataUse
an exported remote procedure or function definition
a call to a remote procedure or function exported by another process
data arriving as an input stream at a port in a Unix filter
data exiting as an output stream from a port in a Unix filter
a read operation from a file
a write operation to a file
the next data item to be read
the next data item to be written
the execution-time and period information for the real-time process

Properties

Any of the component properties can be legally included in the property list of a General component. Properties legal in an <interface> property list have a C in parentheses after the property name; those legal in an <instantiation> property list have an I:

The syntax for an InstFormals property in a component of type
General is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Variant property in a component of type
General is a single <identifier> or "string" surrounded by parentheses:
VARIANT (a_variant_name)
VARIANT ("a variant name")
The syntax for a Processor property in a component of type
General is a single <identifier> or "string" surrounded by parentheses:
PROCESSOR (a_processor_name)
PROCESSOR ("a.processor.name")
The syntax for the EntryPoint property in a General component is a single <identifier> or "string" surrounded by parentheses:
ENTRYPOINT (an_entrypoint_name)
ENTRYPOINT ("an entrypoint name")
The syntax for the InitRoutine property in a General component is a single <identifier> or "string" surrounded by parentheses:
INITROUTINE (a_routine_name)
INITROUTINE ("a routine name")
The syntax for an RPCTypeDef property in a General component consists of a sequence of three fields, all separated by semicolons, with the entire sequence enclosed in parentheses. The first field is an <identifier> or "string". The second field is also an <identifier> or "string". The third field is optional, and consists of a <size item> (if the third field is omitted, the semicolon following the second field is also omitted). A <size item> consists of an optional <array item>, followed by an <integer>. An <array item> consists of one or more consecutive <array index>s of the form `[` <integer> `]':
RPCTYPEDEF (a_type_name; "another one")
RPCTYPEDEF (a_type_name; another_one; 32)
RPCTYPEDEF ("a type name"; another_one; [25] [16] 32)
The syntax for an RPCTypesIn property in a General component is a comma-separated list of items, surrounded by parentheses, that are either <identifier>s or "string"s:
RPCTYPESIN ("an_include_file.h", "another_one.h")
The syntax for a Priority property in a General component is a single <integer>:
PRIORITY (12)
The syntax for a SegmentDef property in a General component consists of two fields, separated by a semicolon, and enclosed in parentheses. The first field is a single <identifier> or "string". The second field is a single <floating point number>:
SEGMENTDEF (a_segment_name, 1.0E2)
SEGMENTDEF ("a segment name", 1.0E2)
The syntax for a TriggerDef property in a General component consists of two fields, separated by a semicolon, and enclosed in parentheses. The first field is a single <identifier> or "string". The second field is a single <floating point number> or the word "asynchronous" (either quoted, or unquoted):
TRIGGERDEF (a_trigger_name, 1.0E2)
TRIGGERDEF ("a trigger name", asynchronous)
The syntax for a RecordFormat property in a component of type
General is a comma-separated list of items, surrounded by parentheses, that are either <identifier>s or "strings":
RECORDFORMAT (a_type_name, "another type name")
The syntax for an OpenMode property in a component of type
General is a comma-separated list containing a subset of the words truncate, append, and create, surrounded by parentheses. These words can be specified as either <identifier>s or "strings":
OPENMODE (create, "append")
The Library property has no associated value. The syntax, therefore, is simply:
LIBRARY

Semantic Checks

No special semantic checks are made for components of type General.

Implementation Considerations

At this time, no implementation considerations are suggested, since no semantics are associated with this component type.

Player

Description

A player is a visible semantic unit in the interface of a component through which the component can interact with other components, request and provide services, or be influenced by external state and events. More concretely, a player is a named entity in the interface of a component that can be associated with a role (a named entity in the protocol of a connector) in a connection during system construction. It is through the connections of players that components interact with each other in a system.

A player definition contains:

Players behave in identifiable, distinct ways. Because of this, they play distinct roles in connections. For example, a procedure call connection requires two players that each play a different role. One plays the role of caller, and the other plays the role of definer. These distinct behaviors separate players into categories, or types. A player type captures the semantics of a player's behavior and specifies the kinds of roles a player can play in connections.

Players are further specified by properties in the property list of the player definition. Properties can be thought of as attributes of a definition which are used to further describe (i.e., specify) it. For players, they are attributes, requirements, and constraints that apply to the player as a whole. There are many places in UniCon where lists of properties are used to further specify a definition. In players, properties are used to specify information such as the signature of the arguments in a routine definition, the port in a Unix process through which a stream player will communicate, or the number of player/role associations that are allowed for a given player in a component.

Syntax

The following is the syntax for a player definition:

  <player> :==    
PLAYER <identifier> IS <player_type>
<optional_end_player_syntax> <player_type> :==
GlobalDataDef
| GlobalDataUse
| PLBundle
| ReadFile
| ReadNext
| RoutineCall
| RoutineDef
| RPCCall
| RPCDef
| RTLoad
| StreamIn
| StreamOut
| WriteFile
| WriteNext <optional_end_player_syntax> :==
EMPTY
| <property_list> END <identifier>
Players can be defined with and without properties. In the latter case, the player definition appears as follows:

  PLAYER my_read_player IS ReadNext
Notice that if no properties are specified in a player definition (i.e., the property list is empty), the END statement is omitted.

In the former case, the player definition appears as follows:

  PLAYER my_input_player IS StreamIn
SIGNATURE ("line")
PORTBINDING (stdin)
END my_input_player
The END statement is required in this case. The <identifier> in the END statement must be identical to the <identifier> following the keyword PLAYER.

Player Type

Description

Players behave in identifiable, distinct ways. Because of this, they play distinct roles in connections. For example, a procedure call connection requires two players that each play a different role. One plays the role of caller, and the other plays the role of definer. These distinct behaviors separate players into categories, or types. A player type captures the semantics of a player's behavior and specifies the kinds of roles a player can play in connections.

Every player definition has a type. In UniCon, there are fourteen pre-defined player types. The specification of the type appears immediately following the keyword IS in a UniCon player definition.

Syntax

The following is the syntax for specifying a player type:

  <player_type> :== 
GlobalDataDef
| GlobalDataUse
| PLBundle
| ReadFile
| ReadNext
| RoutineCall
| RoutineDef
| RPCCall
| RPCDef
| RTLoad
| StreamIn
| StreamOut
| WriteFile
| WriteNext

GlobalDataDef

Semantics

The player type GlobalDataDef corresponds to an exported data definition that is named and typed. Global data definitions are defined at the outer-most scope in a compilation unit and are made globally available for reference from anywhere within the process boundary in which it is defined.

A GlobalDataDef player does not correspond to a shared memory location in the operating system environment that can be accessed by code in different processes. It does represent data that can be accessed by any code within a process.

Component Types In

A player of type GlobalDataDef can legally be defined in components of the following types:

It cannot be defined in a component of type Computation because it breaks the abstraction of a purely computational unit that does not maintain state.

Role Type
Associations

A player of type GlobalDataDef can legally be associated with the following role types in connections of the specified type:

Properties

The following properties can be legally included in the property list of a GlobalDataDef player:

The syntax for the MaxAssocs property in a GlobalDataDef player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a GlobalDataDef player is a single <integer> surrounded by parentheses:
MINASSOCS (0)
The syntax for the Signature property in a GlobalDataDef player is a single <identifier> or "string" surrounded by parentheses:
SIGNATURE (int)
SIGNATURE ("char *")

Implementation Considerations

An example of a GlobalDataDef player in the implementation would be an external variable definition in a C source code file. The following are examples:

/* defined anywhere in a C source code such a definition is legal */
extern int my_global_variable; /* defined at the outer-most scope of a C source code file */
int another_global_variable;

GlobalDataUse

Semantics

The player type GlobalDataUse corresponds to an imported data object. An imported data object is actually a reference to a global data definition that is located in (i.e., exported by) another component. The data reference has a name and a type. The name refers to the name of the data object as it appears in the definition in the exporting component, and the type describes the expectations that the importing component has regarding the type of the data object (the GlobalDataDef player in the exporting component specifies the actual signature). GlobalDataUse players reference GlobalDataDef players within the boundary of a single process.

Component Types In

GlobalDataUse players can legally be defined in components of the following types:

Role Type
Associations

A player of type GlobalDataUse can legally be associated with the following role types in connections of the specified type:

Properties

The following properties can be legally included in the property list of a GlobalDataUse player:

The syntax for the MaxAssocs property in a GlobalDataUse player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a GlobalDataUse player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a GlobalDataUse player is a single <identifier> or "string" surrounded by parentheses:
SIGNATURE (int)
SIGNATURE ("char *")

Implementation Considerations

An example of a GlobalDataUse player in the implementation would be an external variable reference in a C source code file (in boldface type below):

/* defined, for example, in C include file my_application_globals.h */
extern int a_global_variable; /* defined, for example, in C source code file my_utility_file.c */
#include "my_application_globals.h"
static int a_local_variable = a_global_variable;

PLBundle

Semantics

Many compilation units export collections of players that have a coherent meaning as a group. For example, abstract data types (ADTs) usually consist of a collection of exported routine definitions, where use of the abstraction requires the use of all or most of the routines. In libraries of support functions there often exist groups of routine and global data definitions that together provide a single type of service, and therefore are used as a collection. For example, in the C standard library, there are many exported functions that provide
input/output services to the user, such as fgets, fprintf, etc., that are used as a group.

When designers think about the architecture of a system, they often think about the use of such collections of players, rather than about individual players. The PLBundle player type in UniCon allows the system designer to create a collection of players, to attach significance to a group of routines and data in an architectural description of a system. The name PLBundle denotes a programing language bundle; the bundle may only contain players of types that have corresponding programming language implementations: GlobalDataDef,
GlobalDataUse, RoutineCall, and RoutineDef players.

The individual players in a PLBundle are defined using the Member property. The value associated with this property has three fields, each of which corresponds to a portion of a UniCon player definition. The first field is the player name, the second is the player type, and the third is the player property list. PLBundle players must contain at least one member player definition, and there is no upper limit imposed for member players in a PLBundle.

Component Types In

A player of type PLBundle can legally be defined in components of the following types:

Role Type
Associations

A player of type PLBundle can legally be associated with the following role type in a PLBundler connection:

Properties

The following properties can be legally included in the property list of a PLBundle player:

The syntax for the MaxAssocs property in a PLBundle player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a PLBundle player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Member property in a PLBundle player is as follows: the value contains three fields, separated by semicolons, with the entire value surrounded by parentheses. The first and second fields consist of a single <identifier> or "string". The third field is a property list, containing properties that are separated by whitespace:
MEMBER (my_player; RoutineDef;
SIGNATURE ("int"; "int")
MINASSOCS (0))
MEMBER ("another_player"; StreamIn; SIGNATURE ("line"))

Implementation Considerations

Most player types in UniCon correspond directly to language constructs or system calls in a given programming language. For a PLBundle player, however, there is no corresponding bundle structure in the underlying implementation. In other words, in the source code implementation of a system, the members of a PLBundle player exist as separate definitions. The UniCon compiler also treats the members of a PLBundle as separate definitions. The PLBundle player type is an abstraction that only has significance in a UniCon architectural description.

Refer to the descriptions of the GlobalDataDef, GlobalDataUse, RoutineCall, and
RoutineDef player types for implementation guidance.

ReadFile

Semantics

The player type ReadFile corresponds to the capability of performing input from a file. It captures the semantics of a Module performing input from a file via a FileIO connection (as opposed to a Filter performing input from a file via a Pipe connection). In a UniCon architectural description, the ReadFile player is used to create an abstraction for an input operation in the underlying implementation of a system. The word operation here is not meant to refer to a specific function call or language construct, but refers to a group of language constructs or system calls that implement some capability (e.g., in C, a sequence of function calls to open, read, and close that perform some capability in the application).

Component Types In

A player of type ReadFile can legally be defined in components of the following types:

Role Type
Associations

A player of type ReadFile can legally be associated with the following role type in a FileIO connection:

Properties

The following properties can be legally included in the property list of a ReadFile player:

The syntax for the MaxAssocs property in a ReadFile player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a ReadFile player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a ReadFile player is a list of items that are either <identifier>s or "string"s, surrounded by parentheses:
SIGNATURE (int)
SIGNATURE (int, "char *", double)

Implementation Considerations

In the source code implementation of a system, a player of type ReadFile is implemented as a set of language constructs or system calls that implement some input capability in the application. For example, a player of type ReadFile might consist of a set of function calls to open, read, and close that reads the data from a file into a buffer in memory:

  #include <stdio.h>
#include <fcntl.h>

#define MAX_BUF_LEN 256
#define FOR_INPUT "r"

/* external data definitions required to support the code fragments below */

char input_buffer[MAX_BUF_LEN + 1];
int i, fd;

fd = open ("datafile", O_RDONLY);
for (i = 0;
i < MAX_BUF_LEN;
i++)
if (read (fd, &input_buffer[i], ONE_CHARACTER) == 0)
break;
close (fd);

ReadNext

Semantics

The ReadNext player type corresponds to data being read sequentially from the front of a sequential file. Since a sequential file is a passive object that simply contains data, there is no corresponding implementation of this player type in the underlying implementation of a system. It represents an abstraction in UniCon used to describe the action of data being read from a file.

Data can be read sequentially from a file in UniCon by a Filter component via a Pipe connection, and by a Module component via a FileIO connection. The ReadNext player type describes data being read from a file in either situation.

Component Types In

A player of type ReadNext can legally be defined in components of the following types:

Role Type
Associations

A player of type ReadNext can legally be associated with the following role types in connections of the specified type:

Properties

The following properties can be legally included in the property list of a ReadNext player:

The syntax for the MaxAssocs property in a ReadNext player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a ReadNext player is a single <integer> surrounded by parentheses:
MINASSOCS (1)

Implementation Considerations

There are no implementation considerations for this player type because there is no correspondence between a ReadNext player type and anything in the underlying implementation of a system.

RoutineCall

Semantics

The player type RoutineCall corresponds to an imported function or procedure (i.e., a routine). An imported routine is actually realized as a call to a function or procedure definition that is located in (i.e., exported by) another component. The routine call has a name and a signature. The name refers to the name of the function or procedure as it appears in the definition in the exporting component, and the signature describes the expectations that the importing component has regarding the types of the arguments and the type of the return value of the routine (the RoutineDef player in the exporting component specifies the actual signature). RoutineCall players make calls to RoutineDef players within the boundary of a single process.

A RoutineCall player does not describe a call to a function or service located in a remote process. It does describe a call to a function or procedure within a single process.

Component Types In

A player of type RoutineCall can legally be defined in components of the following types:

Role Type
Associations

A player of type RoutineCall can legally be associated with the following role types in connections of the specified type:

Properties

The following properties can be legally included in the property list of a RoutineCall player:

The syntax for the MaxAssocs property in a RoutineCall player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a RoutineCall player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a RoutineCall player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present:
SIGNATURE (int, "char *", double; "void")
SIGNATURE (int, "char *", double)
SIGNATURE (; "void")

Implementation Considerations

In the source code implementation, a RoutineCall player is implemented as a normal procedure or function call, in the syntax of the given programming language (in this case C). For example, the following are function calls in C (in boldface type) that implement
RoutineCall players:

/* assume the function returns an integer result, and the variable is of type integer */
an_integer = a_function_call (parameter1, parameter2); /* the result of the function call below is discarded, making it look like a procedure call */
a_C_procedure_call (parameter1, parameter2);

RoutineDef

Semantics

The player type RoutineDef corresponds to an exported procedure or function (i.e., routine) definition in a component. It has a name and a signature. The name is the identifier used in the implementation, and the signature describes the types of the arguments and the return type that the routine has in the implementation. The function and procedure definitions are defined at the outer-most scope in a compilation unit and are made globally available from anywhere within the process boundary in which they are defined.

A RoutineDef player does not describe a definition or service that can be accessed by a remote process. It does describe a routine that can be called locally with a single process.

Component Types In

A player of type RoutineDef can legally be defined in components of the following types:

Role Type
Associations

A player of type RoutineDef can legally be associated with the following role types in connections of the specified type:

Properties

The following properties can be legally included in the property list of a RoutineDef player:

The syntax for the MaxAssocs property in a RoutineDef player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a RoutineDef player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a RoutineDef player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a comma-separated list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present:
SIGNATURE (int, "char *", double; "void")
SIGNATURE (int, "char *", double)
SIGNATURE (; "void")

Implementation Considerations

In the source code implementation, a RoutineDef player is implemented as a normal procedure or function definition in the syntax of the given programming language (in this case C). The function or procedure definition must be at the outer-most scope of the enclosing compilation unit. The following are example function definitions in C that implement RoutineDef players:

  /* assume that "pointer" is a global integer variable
and that "stack" is a global character array */

int stack_is_empty (void) {
return (pointer == 0);
} void push (char *value) {
stack[pointer++] = value;
}

RPCCall

Semantics

The player type RPCCall corresponds to an imported remote procedure in a component. An imported remote procedure is actually realized as a call to a remote procedure definition that is located in (i.e., exported by) another component. The remote procedure call has a name and a signature. The name refers to the name of the remote procedure as it appears in the definition in the exporting component, and the signature describes the expectations that the importing component has regarding the types of the arguments and the type of the return value in the remote procedure definition (the RPCDef player in the exporting component specifies the actual signature).

An RPCCall player describes a call made in one process to a service located in a remote process. It does not describe a call to a function or procedure defined within the same process. Remote procedure calls are made between RPCCall and RPCDef players defined in Process or SchedProcess components.

Component Types In

A player of type RPCCall can legally be defined in components of the following types:

Role Type
Associations

A player of type RPCCall can legally be associated with the following role type in a RemoteProcCall connection:

Properties

The following properties can be legally included in the property list of an RPCCall player:

The syntax for the MaxAssocs property in an RPCCall player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in an RPCCall player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in an RPCCall player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present:
SIGNATURE (int, "char *", double; "void")
SIGNATURE (int, "char *", double)
SIGNATURE (; "void")

Implementation Considerations

In the source code implementation, an RPCCall player is implemented as a local procedure or function call, in the syntax of the given programming language (in this case C). The UniCon compiler generates the glue code to turn the local routine call into a remote procedure call, and the support for the remote procedure call gets built at system construction time. The following are examples of local function calls in C (in boldface type) that eventually get turned into remote procedure calls at system construction time:

/* assume the function returns an integer result, and the variable is of type integer */
an_integer = a_remote_function_call (parameter1, parameter2); /* the result of the remote function call below is discarded,
making it look like a remote procedure call */
a_remote_procedure_call (parameter1, parameter2);
NOTE: The UniCon compiler generates glue code that supports two forms of remote procedure calls: InterProcess Communication (IPC) calls on Mach platforms, and RPCGen-based remote procedure calls on SunOS platforms. The Mach IPC facility does not permit remote function calls, only remote procedure calls. Therefore, no remote procedure call in a Mach application may return a value (i.e., all remote procedure calls must look like example number two, above). If results must be returned in a Mach application, they must be returned via the arguments in the argument list.

RPCDef

Semantics

The player type RPCDef corresponds to an exported remote procedure definition in a component. It has a name and a signature. The name is the identifier used in the implementation of the remote procedure, and the signature describes the types of the arguments and the return type that the remote procedure has in the implementation. Remote procedure definitions are services defined within a Process or a SchedProcess component, and are made available (exported) to other processes or schedulable processes executing in the environment.

An RPCDef player describes a definition of a service that is accessed by a remote process. It does not describe a routine that can be called locally within a single process.

Component Types In

A player of type RPCDef can legally be defined in components of the following types:

Role Type
Associations

A player of type RPCDef can legally be associated with the following role type in a RemoteProcCall connection:

Properties

The following properties can be legally included in the property list of an RPCDef player:

The syntax for the MaxAssocs property in an RPCDef player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in an RPCDef player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in an RPCDef player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a comma-separated list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present:
SIGNATURE (int, "char *", double; "void")
SIGNATURE (int, "char *", double)
SIGNATURE (; "void")

Implementation Considerations

In the source code implementation, an RPCDef player is implemented as a normal procedure or function definition in the syntax of the given programming language (in this case C). The UniCon compiler generates the glue code to turn the routine into a remote procedure definition, and this remote procedure definition gets created at system construction time. The function or procedure definition must be at the outer-most scope of the enclosing compilation unit. It may also reference globally defined variables within the same compilation unit. The following are example function definitions in C that can be turned into remote procedure definitions:

  #include <stdio.h>
#include <time.h>

void timeget_Mach(int *get_time) {
time(get_time); /* get the system time */
}

void timeshow(void) {
int show_time;

time(&show_time); /* get the system time */

/* display the system time */
fprintf(stdout, "Server: %s\n", ctime(&show_time));
}

int timeget_RPCGen(void) {
int get_time;

time(&get_time); /* get the system time */
return get_time;
}
NOTE: The UniCon compiler generates glue code that supports two forms of remote procedure calls: InterProcess Communication (IPC) calls on Mach platforms, and RPCGen-based remote procedure calls on SunOS platforms. The Mach IPC facility does not permit remote function definitions, only remote procedure definitions. Therefore, no remote procedure definition in a Mach application may return a value (i.e., all remote procedure definitions must look like definitions one and two in the example above). If results must be returned in a Mach application, they must be returned via the arguments in the argument list (as in definition number one, above).

RTLoad

Semantics

A player of type RTLoad corresponds to the load placed on the central processing unit (CPU) of some host computer by the SchedProcess component in which the RTLoad player is defined. A load is defined to be the total execution time required to execute a well-defined piece of code in the schedulable process. The semantics of an RTLoad player are further described below, but the discussion requires some context first.

In a real-time environment, client schedulable processes are periodic. They do not run forever. When a client process is activated, it runs to completion and returns control to the environment. Server processes, however, do run forever, but control is given to a server process only via remote procedure calls from clients or other servers. During execution, the thread of control is given to a client schedulable process by the environment. The process performs some work, and it may return or it may make a remote procedure call to another process (a server process). If it makes a remote procedure call, the thread of control is transferred to the server process, which performs some work and returns (or makes another remote procedure call, and so on). Control is eventually returned back to the original client process, where work continues in a similar fashion until control is returned back to the environment. This entire thread of control is called an event in UniCon, and can be described by a trace. A trace is a specification of the event. It specifies the trigger, the mechanism by which control is first given to a client schedulable process from the environment, and the sequence of segments that execute as a result of the trigger in the order in which they are executed.

A trigger is an abstraction. As mentioned above, it describes the mechanism by which control is transferred from the environment to a schedulable process. Only client processes can define triggers, because they begin execution by receiving control from the environment. Server processes do not have triggers because they execute continuously and receive control only as a result of remote procedure calls. Since client processes execute to completion and return to the environment, they can be reactivated by the environment according to some rate (i.e., some number of times per second). Therefore, triggers have associated rates of initiation. Triggers are defined in the interface property list of SchedProcess components via the TriggerDef property. The value part of the property defines the name of the trigger and associates with it the rate (in seconds) at which the trigger is initiated.

A segment is also an abstraction. It describes a chunk of code in the implementation of the schedulable process. The chunk of code it describes may take any form that the designer chooses. For example, it may describe a function, a set of functions, a portion of a single function, or even a few statements within a given function. The designer typically defines segments based on structural and execution time properties of the code in order to facilitate certain types of analyses that can be done on sets of schedulable processes in a real-time environment (more on this later). Segments are defined in the interface property list of SchedProcess components via the SegmentDef property. The value part of the property defines the name of the segment and associates an execution time (in seconds) with it. Work done in a schedulable process is described by a sequence of one or more segments.

As described above an RTLoad player corresponds to the load that a schedulable process places on the CPU of a given processor. A load is the total amount of execution time that a single schedulable process requires for execution of the code that it contains that applies to a particular event. An RTLoad player consists of a trigger (possibly) and a sequence of segments. This is described further below, but the discussion requires an example for clarification.

Assume that some real-time application consists of two schedulable processes: a client and a server. Assume further that the application consists of a single event in which the client calls the server for a service that it exports. The event is characterized by a trigger transferring control to the client process from the environment followed by: some code executing in the client, a remote procedure call from the client to the server, some code executing in the server, return of control to the client, some code executing in the client, and finally a return of control to the environment.

In this example, the client process defines a trigger. It is defined in the client SchedProcess via the TriggerDef property in the interface property list.

Additionally, each schedulable process has one or more segments. For simplicity we choose to define the segments as the chunks of code in each process that execute from the time control is given to the process until control is yielded. According to this scheme, the client process has two segments: the chunk of code that executes from when control is given to it by the environment until control is relinquished via the remote procedure call to the server, and the chunk of code that executes from when control is returned by the server until the client finishes execution. The server has only one segment: the chunk of code that executes from when control is given to it by the client via the remote procedure call until the server returns control back to the client. These segments are defined in each SchedProcess component via the SegmentDef property in the interface property list.

Lastly, each schedulable process defines an RTLoad player. The RTLoad player is specified with the Trigger and SegmentSet properties in the player property list. In the client
SchedProcess, the RTLoad player specifies a Trigger property containing the name of the trigger as it was defined in the TriggerDef property in the interface property list. It also specifies the SegmentSet property containing the names of the two segments that were defined in the SegmentDef properties in the interface. The RTLoad player in the server process specifies only a SegmentSet property with a single segment name in it, the segment that was defined with the SegmentDef property in the interface property list of the server. RTLoad players in server schedulable processes will typically never contain Trigger properties because they execute continuously. UniCon allows the system designer to define and specify triggers in server processes, however the period for such a trigger must be defined to be asynchronous.

To summarize, a load is described as the total execution time that a single SchedProcess component places on the CPU while executing code associated with a particular event, an event which executes in response to a specific trigger (occurring repeatedly according to a specific rate) in the environment. A load is described in UniCon by an RTLoad player, and there will typically be one or more RTLoad players defined in a schedulable process for each distinct event. RTLoad players are further specified by Trigger and SegmentSet properties.

NOTE: As mentioned above, segments are defined by designers based on structural and execution time properties of the underlying source code in order to facilitate certain types of analyses on sets of schedulable processes. One such type of analysis is a rate monotonic analysis (RMA). An RMA determines whether or not a set of events, scheduled in the environment according to a rate monotonic scheduling algorithm, will meet their deadlines. This analysis requires the rate information from the trigger of the event and the execution time information from all of the segments.

Component Types In

A player of type RTLoad can legally be defined in components of the following types:

Role Type
Associations

A player of type RTLoad can legally be associated with the following role type in an RTScheduler connection:

Properties

The following properties can be legally included in the property list of an RTLoad player:

The syntax for the MaxAssocs property in an RTLoad player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in an RTLoad player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Trigger property in an RTLoad player is a single <identifier> or "string", surrounded by parentheses:
TRIGGER (a_trigger_name)
TRIGGER ("another trigger name")
The syntax for the SegmentSet property in an RTLoad player is a comma-separated list of items that are either <identifier>s or "string"s:
SEGMENTSET (a_segment_name)
SEGMENTSET ("another segment name")
SEGMENTSET (a_segment_name, "another", a_third)

Implementation Considerations

In the source code implementation, an RTLoad player has no corresponding implementation.

StreamIn

Semantics

A player of type StreamIn corresponds to input that arrives in the form of a stream at a port in a process that has Unix filter semantics. The input in the stream has a syntax, a structure that is imposed on elements in the stream. This structure is specified with the Signature property, whose value represents a single data type imposed on the data in the stream. The signature represents the expectations that the Filter component has for the syntax of the data. When performing Pipe connections during system construction, the signature of a StreamIn player is checked against the signature of the StreamOut player with which it is connected. The Signature property in a StreamOut player defines the actual syntax of the stream.

UniCon StreamIn and StreamOut players allow system designers to view streams of data as entities in a design, and to apply data typing semantics to these entities. System designers can, therefore, describe and reason about properties of streams in ways that are not possible by simply focusing on the source code implementations of the filters.

Component Types In

A player of type StreamIn can legally be defined in components of the following types:

Role Type
Associations

A player of type StreamIn can legally be associated with the following role type in a Pipe connection:

Properties

The following properties can be legally included in the property list of a StreamIn player:

The syntax for the MaxAssocs property in a StreamIn player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a StreamIn player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a StreamIn player is a single <identifier> or "string", surrounded by parentheses:
SIGNATURE (char)
SIGNATURE ("line")

Implementation Considerations

In the source code implementation, a StreamIn player is implemented as a set of system calls to routines that perform input in the form of a stream for a process. For example, in the C programming language, the read system call can be used to acquire input from a particular port (i.e., file descriptor) in the process. Alternatively, formatted I/O functions from the C standard library (wrappers that encapsulate the read and write system calls to make formatting of input and output more convenient for the user) can be used to acquire input from a particular port. In this case, however, the input port must first be wrapped in a data structure of the type expected by the formatted I/O functions; this is done with the fdopen function call.

NOTE: UniCon generates a program that performs the initialization of a pipe and filter system at run-time. This program creates all of the pipes, and hooks each end of each pipe to the appropriate port in one of the filters in the system. Therefore, a filter should never open or close a port; it should assume that the open is done automatically prior to execution of the first line of code in the filter, and that the close is done automatically after the last line of code in the filter is executed. Therefore, when using the read system call to implement the input stream, no calls to open and close are necessary. When any of the formatted I/O routines are used, such as fgets and fgetc, no calls to fopen and fclose are necessary - however in this case one call to fdopen is required to wrap the input port up as a file pointer, the data structure expected by the formatted I/O routines.

The following are examples of StreamIn players in the implementation of a filter:

  #include <stdio.h>

#define PORT_3 3
#define PORT_5 5
#define MAX_BUF_LEN 256
#define FOR_INPUT "r"

/* external data definitions required to support the code fragments below */

char input_buffer[MAX_BUF_LEN];
FILE *fp;

/* the following line of code performs stream input from port 3
using the read system call (inside the implementation of a filter) */

read (PORT_3, input_buffer, MAX_BUF_LEN);

/* the following lines of code performs stream input from port 5 using
the fgets formatted I/O routine (inside the implementation of a filter) */

fp = fdopen (PORT_5, FOR_INPUT); /* this call happens only once */
fgets (input_buffer, MAX_BUF_LEN, fp);

StreamOut

Semantics

A player of type StreamOut corresponds to output in the form of a stream that exits from a port in a process that has Unix filter semantics. The output in the stream has a syntax, a structure that is imposed on elements in the stream. This structure is specified with the
Signature property, whose value represents a single data type imposed on the data in the stream. The signature represents the exact syntax imposed on the stream by the Filter. When performing Pipe connections during system construction, the signature of a StreamIn player is checked against the signature of the StreamOut player with which it is connected.

UniCon StreamIn and StreamOut players allow system designers to view streams of data as entities in a design, and to apply data typing semantics to these entities. System designers can, therefore, describe and reason about properties of streams in ways that are not possible by simply focusing on the source code implementations of the filters.

Component Types In

A player of type StreamOut can legally be defined in components of the following types:

Role Type
Associations

A player of type StreamOut can legally be associated with the following role type in a Pipe connection:

Properties

The following properties can be legally included in the property list of a StreamOut player:

The syntax for the MaxAssocs property in a StreamOut player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a StreamOut player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a StreamOut player is a single <identifier> or "string", surrounded by parentheses:
SIGNATURE (char)
SIGNATURE ("line")

Implementation Considerations

In the source code implementation, a StreamOut player is implemented as a set of system calls to routines that perform output in the form of a stream for a process. For example, in the C programming language, the write system call can be used to write output to a particular port (i.e., file descriptor) in the process. Alternatively, formatted I/O functions from the C standard library (wrappers that encapsulate the read and write system calls to make formatting of input and output more convenient for the user) can be used to write output to a particular port. In this case, however, the output port must first be wrapped in a data structure of the type expected by the formatted I/O functions; this is done with the fdopen function call.

NOTE: UniCon generates a program that performs the initialization of a pipe and filter system at run-time. This program creates all of the pipes, and hooks each end of each pipe to the appropriate port in one of the filters in the system. Therefore, a filter should never open or close a port; it should assume that the open is done automatically prior to execution of the first line of code in the filter, and that the close is done automatically after the last line of code in the filter is executed. Therefore, when using the write system call to implement the output stream, no calls to open and close are necessary. When any of the formatted
I/O routines are used, such as fputc and fprintf, no calls to fopen and fclose are necessary - however in this case one call to fdopen is required to wrap the output port up as a file pointer, the data structure expected by the formatted I/O routines.

The following are examples of StreamOut players in the implementation of a filter:

  #include <stdio.h>

#define PORT_3 3
#define PORT_5 5
#define MAX_BUF_LEN 256
#define FOR_OUTPUT "w"
#define ONE_CHARACTER 1

/* external data definitions required to support the code fragments below */

char output_buffer[MAX_BUF_LEN + 1];
FILE *fp;
int i;

/* in each example below the code writes from output_buffer until
the end of the buffer is reached, or the value `\0' is encountered */

/* the following lines of code perform stream output to port 3, one character at
a time, using the write system call (inside the implementation of a filter) */

for (i = 0;
output_buffer[i] != `\0' && i < MAX_BUF_LEN;
i++)
write (PORT_3, &output_buffer[i], ONE_CHARACTER);

/* the following lines of code perform stream output to port 5 using
the fprintf formatted I/O routine (inside the implementation of a filter) */

fp = fdopen (PORT_5, FOR_OUTPUT); /* this call happens only once */
output_buffer[MAX_BUF_LEN] = `\0';
fprintf (fp, "%s", output_buffer);

WriteFile

Semantics

The player type WriteFile corresponds to the capability of performing output to a file. It captures the semantics of a Module performing output to a file via a FileIO connection (as opposed to a Filter performing output to a file via a Pipe connection). In a UniCon architectural description, the WriteFile player is used to create an abstraction for an output operation in the underlying implementation of a system. The word operation here is not meant to refer to a specific function call or language construct, but refers to a group of language constructs or system calls that implement some capability (e.g., in C, a sequence of function calls to open, write, and close that perform some capability in the application).

Component Types In

A player of type WriteFile can legally be defined in components of the following types:

Role Type
Associations

A player of type WriteFile can legally be associated with the following role type in a FileIO connection:

Properties

The following properties can be legally included in the property list of a WriteFile player:

The syntax for the MaxAssocs property in a WriteFile player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a WriteFile player is a single <integer> surrounded by parentheses:
MINASSOCS (1)
The syntax for the Signature property in a WriteFile player is a list of items that are either <identifier>s or "string"s, surrounded by parentheses:
SIGNATURE (int)
SIGNATURE (int, "char *", double)

Implementation Considerations

In the source code implementation of a system, a player of type WriteFile is implemented as a set of language constructs or system calls that implement some output capability in the application. For example, a player of type WriteFile might consist of a set of function calls to open, write, and close that writes the data to a file from a buffer in memory:

  #include <stdio.h>
#include <fcntl.h>

#define MAX_BUF_LEN 256
#define ONE_CHARACTER 1

/* external data definitions required to support the code fragments below */

char output_buffer[MAX_BUF_LEN + 1];
int i, fd;

fd = open ("datafile", O_WRONLY);
for (i = 0;
output_buffer[i] != `\0' && i < MAX_BUF_LEN;
i++)
write (fd, &output_buffer[i++], ONE_CHARACTER);
close (fd);

WriteNext

Semantics

The WriteNext player type corresponds to data being written sequentially to the end of a sequential file. Since a sequential file is a passive object that simply contains data, there is no corresponding implementation of this player type in the underlying implementation of a system. It represents an abstraction in UniCon used to describe the action of data being written to a file.

Data can be written sequentially to a file in UniCon by a Filter component via a Pipe connection, and by a Module component via a FileIO connection. The WriteNext player type describes data being written to a file in either situation.

Component Types In

A player of type WriteNext can legally be defined in components of the following types:

Role Type
Associations

A player of type WriteNext can legally be associated with the following role types in connections of the specified type:

Properties

The following properties can be legally included in the property list of a WriteNext player:

The syntax for the MaxAssocs property in a WriteNext player is a single <integer> surrounded by parentheses:
MAXASSOCS (1)
The syntax for the MinAssocs property in a WriteNext player is a single <integer> surrounded by parentheses:
MINASSOCS (1)

Implementation Considerations

There are no implementation considerations for this player type because there is no correspondence between a WriteNext player type and anything in the underlying implementation of a system.

Component Implementation

Description

The implementation of a component describes how it is constructed. Components have either primitive implementations, or composite implementations. A primitive implementation describes a component that is implemented by some source document that is external to UniCon (e.g., source code of a programming language, scripts of commands of an operating system shell, data in a file in the file system).

A composite implementation describes a configuration of components and connectors. This mechanism in UniCon allows system designers to progressively build larger subsystems from collections of smaller components or subsystems, or more abstract components from less abstract ones.

Syntax

The following is the syntax for a component implementation in UniCon:

  <component_implementation> :==
<primitive_implementation>
| <composite_implementation> <primitive_implementation> :==
IMPLEMENTATION IS
<property_list>
<variant_list>
END IMPLEMENTATION <variant> :== VARIANT <identifier> IN "<filespec>"
<property_list>
END <identifier> <composite_implementation> :==
IMPLEMENTATION IS
<property_list>
<composite_statement_list>
END IMPLEMENTATION <composite_statement> :==
<instantiation>
| <connection>
| <bind>
| <establish>

Primitive Implementation

Description

The implementation of a component describes how it is constructed. A primitive implementation describes a component that is implemented by some source document that is external to UniCon (e.g., source code of a programming language, scripts of commands for an operating system shell, or data in a file in the file system).

The implementation of a primitive component consists of a list of implementation variants. A variant is simply an alternative implementation. If a component has more than one variant defined in its primitive implementation, the specific variant to be used during system construction can be selected using the Variant property when the component is instantiated. A variant definition consists of a name, a pointer to a file in the operating system containing the source document that implements it, and (optionally) properties that further specify the variant. Below is an example of a primitive component implementation in UniCon. Assume that it is from the UniCon definition of a stack component. The source document referenced in the variant is a file containing C source code that implements a stack abstract data type:

  IMPLEMENTATION IS
VARIANT stack IN "stack.c"
IMPLTYPE (Source)
END stack
END IMPLEMENTATION
NOTE: It is important to note that the UniCon compiler does not check that the source document is consistent with the component definition. For example, if there exists a player of type RoutineDef named "push" in the interface of the component, the UniCon compiler does not open up the file "stack.c" to check that there is a function definition named push defined in the source code. Consistency between the source document implementing a component and the component's interface is the responsibility of the system designer.

Syntax

The following is the syntax for a primitive implementation in UniCon:

  <primitive_implementation> :==
IMPLEMENTATION IS
<property_list>
<variant_list>
END IMPLEMENTATION <variant> :==
VARIANT <identifier> IN "<filespec>"
<property_list>
END <identifier> <filespec> :==
a Unix filename, optionally prepended with a path
(e.g., /usr/gz/src/stack.c)

Properties

The only property that can be legally included in the <primitive_implementation> property list is the InitActuals property:

The syntax for an InitActuals property in a component implementation is a single <identifier> or "string" surrounded by parentheses:
INITACTUALS ("-f")
The following properties can be legally included in the <variant> property list:

The syntax for a BuildOption property in a variant is a list of items that are either <identifier>s or "string"s surrounded by parentheses:
BUILDOPTION ("+define=DEBUG_OPTION")
BUILDOPTION ("+define=ONE", "+gnu", "+cc=gcc")
The syntax for an ImplType property in a variant is a single
<identifier> or "string" surrounded by parentheses:
IMPLTYPE ("source")
IMPLTYPE (source)
If this property is omitted from the property list of a variant, the following default property is assumed:
IMPLTYPE (source)
The syntax for an InitActuals property in a variant is a single <identifier> or "string" surrounded by parentheses:
INITACTUALS ("-f")

Variant

Description

A variant is simply an alternative implementation in a primitive implementation of a component. It consists of a name, a pointer to a file in the operating system containing the source document that implements it, and (optionally) properties that further specify the variant. The name of a variant is significant if there are multiple variants in a primitive implementation. The specific variant to be used during system construction can be selected using the Variant property in an instantiation of the component. The <filespec> in a variant is the specification of the path to the file in the file system that contains the component's implementation. It contains the name of the file, and (optionally) the path specification. The path specification, if present, can be a relative path or an absolute path. The following are examples of legal <filespec>s for a file named stack.c:

  stack.c
/usr/gz/src/stack.c
../../../src/stack.c
Typically, the system designer will specify the ImplType property in the <variant> property list. By default, if this property is not specified, the UniCon compiler assumes that the implementation type of the file named in the <filespec> is Source.

Syntax

The following is the syntax for a variant in UniCon:

  <variant> :==  
VARIANT <identifier> IN "<filespec>"
<property_list>
END <identifier> <filespec> :==
a Unix filename, optionally prepended with a path

Properties

The following properties can be legally included in the <variant> property list:

The syntax for a BuildOption property in a variant is a list of items that are either <identifier>s or "string"s surrounded by parentheses:
BUILDOPTION ("+define=DEBUG_OPTION")
BUILDOPTION ("+define=ONE", "+gnu", "+cc=gcc")
The syntax for an ImplType property in a variant is a single
<identifier> or "string" surrounded by parentheses:
IMPLTYPE ("source")
IMPLTYPE (source)
If this property is omitted from the property list of a variant, the following default property is assumed:
IMPLTYPE (source)
The syntax for an InitActuals property in a variant is a single <identifier> or "string" surrounded by parentheses:
INITACTUALS ("-f")

Composite Implementation

Description

The implementation of a component describes how it is constructed. A composite implementation describes a configuration of components and connectors. This mechanism in UniCon allows system designers to progressively build larger subsystems from collections of smaller components or subsystems, or more abstract components from less abstract ones.

There are three types of information required in a composite implementation:

    1. the pieces
    2. the configuration information
    3. the abstraction information
The parts are the specific instances (i.e., instantiations) of components and connectors that are used to describe the implementation. The instantiation of a component and a connector in UniCon is accomplished with the USES statement. The instantiation of connectors can also be done implicitly via the ESTABLISH statement.

The configuration description is the set of instructions for hooking up the components and connectors. These instructions represent the connections in the implementation. Connections are accomplished with the CONNECT statement in UniCon, or with the role/player associations of an ESTABLISH (i.e., the AS statements).

The abstraction information is the specification of how the more abstract players in the interface of the component are implemented by the more concrete players in the composite implementation. These specifications are accomplished with the BIND statement. Every player in the interface of a component with a composite implementation must be mapped to one or more players in the implementation.

Syntax

  <composite_implementation> :==
IMPLEMENTATION IS
<property_list>
<composite_statement_list>
END IMPLEMENTATION <composite_statement> :==
<instantiation>
| <connection>
| <bind>
| <establish>

Properties

The only property that can be legally included in the <composite_implementation> property list is the InitActuals property:

The syntax for an InitActuals property in a component implementation is a single <identifier> or "string" surrounded by parentheses:
INITACTUALS ("a-z A-Z")

Instantiation

Description

The <instantiation> statement is used to create the instances of components and connectors that will be used in a configuration description in the composite implementation of a component.

More than one instance of the same element (i.e., a component or a connector) may be used in the implementation of a single component, so UniCon definitions are considered to be templates from which instances can be created. In other words, a new instance of a component or connector is created from a given definition each time that component or connector is instantiated in a composite implementation. Each instantiation makes a copy of the component or connector described by the definition. When a component is instantiated, its players are instantiated as well. Similarly, when a connector is instantiated, its roles are instantiated too.

The first <identifier> in an <instantiation> is the name of the instance. All instance names in a composite implementation must be unique. The second
<identifier> is the name of the component or connector as it appears in its UniCon definition.

When instantiating a component, the keyword INTERFACE is required after the first <identifier>. When instantiating a connector, the keyword PROTOCOL is required.

When instantiating a component, all of the properties in the <interface> property list that further specify the component definition apply to the instantiated component as well. However, the designer may further constrain the component instantiation by specifying properties in the <instantiation> property list. The properties in the instantiation and the properties in the definition are merged into a single list of properties, which is then used to specify the instantiation. Any duplicate specifications of the same property are resolved according to the merge rule for that property. In the case of a merge rule value of REPLACE, the value of the instantiation property overrides that of the definition property. In the case of the merge rule value of ERROR, the value of the instantiation property is ignored and a warning is issued by the UniCon compiler (i.e., the value of the definition property is used). In the case of a merge rule value of MERGE, the values of the definition property are merged with the values of the instantiation property, and the instantiation property is used.

The semantics for the property list for connector instantiations are the same as for component instantiations except that it is the <protocol> property list that is merged with the instantiation property list instead of the <interface> property list.

NOTE: Not all properties that are legal in an <interface> property list of a component definition are legal in the <instantiation> property list, and vice versa. The same is true about connectors. Refer to the individual component type descriptions for more information about the properties that are legal in either of these property lists.

Syntax

The following is the syntax for an <instantiation> statement:

<instantiation> :==
USES <identifier> <interface_or_protocol> <identifier>
<optional_end_instantiation_syntax>

<interface_or_protocol> :==
INTERFACE | PROTOCOL

<optional_end_instantiation_syntax> :==
EMPTY
|
<property_list>
END <identifier>
Syntactically, the END <identifier> statement is disallowed unless a property list has been specified in the <instantiation>.

Example

The following are four examples of instantiations. The first two are instantiations of
SchedProcess components. Notice that they contain property lists making the <optional_end_instantiation_syntax> required. The third is an instantiation of a component for which further specification with an <instantiation> property list is not necessary. The fourth is an instantiation of an RTScheduler connector. It requires further specification with a property list:

  USES RTClient INTERFACE Real_Time_Client
PRIORITY (10)
PROCESSOR ("TESTBED.XX.CMU.EDU")
ENTRYPOINT (client)
END RTClient USES RTServer INTERFACE Real_Time_Server
PRIORITY (11)
PROCESSOR ("TESTBED.XX.CMU.EDU")
RPCTYPEDEF (new_type; struct; 12)
RPCTYPESIN ("unicon.h")
END RTServer USES libmachrt INTERFACE Mach_Real_Time_Library USES RTM_RTScheduler PROTOCOL Real_Time_Scheduler
ALGORITHM (rate_monotonic)
PROCESSOR ("TESTBED.XX.CMU.EDU")
TRACE (RTClient.load.trigger,
RTClient.load.segment1,
RTServer.load.segment,
RTServer.load.segment2)
END RTM_RTScheduler

Connection

Description

The <connection> statement is used to describe how components and connectors are hooked together in a composite implementation of a component. Along with the
<establish> statement, it is used to specify the configuration information in a composite implementation. More concretely, it is used to associate a player in a component instantiation with a role in a connector instantiation. A "connection" in UniCon consists of all of the player/role associations in a composite implementation involving a given connector instantiation.

Each dot-separated pair of identifiers in a <connection> must name either a role or a player. There is no requirement regarding which one should come first. The
<connection> statement must name exactly one player and exactly one role; it may not name two players or two roles. If the pair of identifiers names a player, the first
<identifier> in the dot-separated pair must name a component instantiation, and the second must name a player in that component instantiation. If the pair of identifiers names a role, the first <identifier> must name a connector instantiation, and the second must name a role in that connector instantiation. In both cases, the component and connector named by the first <identifier> must have been instantiated in <instantiation> statements prior to the specification of the <connection> statement.

Syntax

The following is the syntax for a <connection> statement:

<connection> :== 
CONNECT <identifier>.<identifier> TO
<identifier>.<identifier>

Example

The following are two examples of <connection> statements that define a complete "connection" in UniCon. It connects players in the RTServer and RTClient components to the RTM_RTScheduler connector illustrated in the Example for the <instantiation> statement. Assume for the sake of this example that both the RTClient and RTServer components export RTLoad players named "rt_load." Also, assume that the RTScheduler connector exports a Load role named "load."

  CONNECT RTClient.rt_load TO RTM_RTScheduler.load
CONNECT RTServer.rt_load TO RTM_RTScheduler.load

Bind

Description

The interface of a component specifies the players that the component is providing to the external world. However, in a component with a composite implementation, these players are actually implemented by players in component instantiations in the implementation. This creates a relationship, or mapping, between the players in the interface and the players in the implementation. UniCon requires the designer to make this relationship explicit. This is done with the <bind> statement. All player definitions in the interface of a component with a composite implementation must be bound to players in the implementation.

There are two forms of the <bind> statement, the simple bind, and the abstraction bind. A <simple_bind> is an association of a player in the interface with a single player of the same type in the implementation. The bind, in this case, can almost be thought of as an aliasing operation, rather than as an abstraction, since the players are of the same type. In a simple bind, no special support is required at UniCon compile time to translate the implementation mechanism of the player in the implementation into anything else since the player in the interface is of the same type.

In a simple bind, the player in the implementation must not be bound to any other player.

An <abstraction_bind> is an association of a player in the interface with a collection of players in the implementation (not necessarily having the same type as the interface player), or a single player in the implementation having a different type than that of the interface player. Abstraction binds often are necessary when the type of the player in the interface is a UniCon (or operating system supported) abstraction that is not directly supported by the programming language in the underlying implementation (e.g., a Unix stream of data, represented by the UniCon player types StreamIn and StreamOut, often implemented in a programming language by a series of calls to routines in environment-specific software libraries). In other cases, abstraction binds are necessary when a mapping from one player to another involves a type change (e.g., binding an RPCDef player in an interface to a RoutineDef player in an implementation). This type of mapping requires UniCon compile-time support to wrap up the implementation mechanism of the player in the implementation so that it becomes the implementation mechanism dictated by the type of the interface player.

The <abstraction_bind> requires the use of the MapsTo property in its property list to specify the list of players in the implementation being collectively bound to the interface player. The players in the MapsTo list must be players in component instantiations in the containing composite implementation that have not been previously bound.

NOTE: In both simple binds and abstraction binds, the implementation players must not be involved in a connection anywhere in the composite implementation, except if the player is of one of the following types:

Players of these types may be connected as well as bound.

Syntax

The following is the syntax for a <bind> statement:

<bind> :== 
<simple_bind>
|
<abstraction_bind> <simple_bind> :==
BIND <identifier> TO <identifier>.<identifier>
<optional_end_simple_bind_syntax> <optional_end_simple_bind_syntax> :==
EMPTY
| <property_list>
END <identifier> <abstraction_bind> :==
BIND <identifier> TO ABSTRACTION
<property_list>
END <identifier>
A simple bind maps a player in the interface to only one player in the implementation. The player in the interface is specified by the single <identifier> following the keyword BIND. The player in the implementation is specified by a dot-separated pair of
<identifier>s following the word TO. The first <identifier> in this pair is the name of the component instantiation in which the player named by the second
<identifier> is defined. If there is a property list specified in a simple bind, then the END statement is required, and the <identifier> following the word END must be identical to the <identifier> following the word BIND, including the case of the letters. The only legal property for a simple bind is the Rename property, which is required if the interface player name and the name of the player in the implementation are not identical.

An abstraction bind maps a player in the interface to a collection of players in the implemenation, or a single player in the implementation having a different type. The player in the interface is specified by the <identifier> after the keyword BIND. The MapsTo property is used to specify the names of the implementation players. It is required to be in the property list; this means that the property list will never be empty for an abstraction bind and therefore the END <identifier> statement is always required. The
<identifier> in the END statement must be identical to the one after the word BIND, including the case of the letters.

In an abstraction bind, all of the players in the implementation that are being bound to the player in the interface must be specified in the MapsTo property, regardless of whether there is a single player or multiple players. Multiple specifications of the MapsTo property are allowed; UniCon interprets the collection as a single MapsTo property whose list of players is the union of the players in the lists of all of the MapsTo properties in the <bind> statement. The syntax of the value part of the MapsTo property is a semicolon-separated list of dot-separated pairs (or triples) of <identifier>s. The first
<identifier> in the pair or triple is the name of the component instantiation in which the player named by the second <identifier> is defined. If there exists a third
<identifier>, the second <identifier> must name a player of type PLBundle, and the third must name a Member player in that PLBundle.

Properties

The following property is legal in the property list of a <simple_bind>:

The Rename property has no associated value. The syntax, therefore, is simply:
RENAME
The following properties are legal in the property list of an <abstraction_bind>:

The syntax for a MapsTo property in an <abstraction_bind> consists of a semicolon-separated list of player names, enclosed in parentheses. A player name consists of a dot-separated pair (or triple) of <identifier>s. The first <identifier> names a component instantiation, the second names a player in the component instantiation named by the first, and the third (if present) names a Member in the PLBundle player named by the second.
MAPSTO (libc.dynamic_memory_allocation.malloc;
libc.exit,
libc.buffered_io.fgets)
The syntax for a Match property in an <abstraction_bind> is either the word "by_name", optionally enclosed in double-quotes, or a comma-separated list of relations, enclosed in parentheses. A relation is a comma-separated pair of player names, enclosed in parentheses. The player name of the left-hand player in a relation represents a Member player of a PLBundle player in the interface and consists of a dot-separated pair of <identifier>s. The first <identifier> names the PLBundle player, and the second names a Member player in the PLBundle. The player name of the right-hand player in a relation represents a player in the implementation and has two or three dot-separated <identifier>s. The first
<identifier> names a component instantiation, the second names a player in the component instantiation named by the first, and the third (if present) names a Member in the PLBundle player named by the second.
MATCH (by_name)
MATCH ("by_name")
MATCH ((my_stack_adt.pop_definition,
standard_library.stack_adt.pop_definition),
(my_stack_adt.push_definition,
standard_library.stack_adt.push_definition),
(my_stack_adt.stack_init_definition,
standard_library.stack_adt.stack_init_definition),
(my_stack_adt.stack_is_empty_def,
standard_library.stack_adt.stack_is_empty_def))

Example

The following are two examples of simple binds, one with a property list and one without. Assume for the sake of the example that the input and output stream players in the statements below are of types StreamIn and StreamOut, respectively:

  BIND my_input_stream TO sort_filter.input
RENAME
END my_input_stream BIND output_stream TO sort_filter.output_stream
The following are two examples of abstraction binds. Assume for the sake of the example that the players in the left-hand sides of the binds are of type StreamIn and StreamOut respectively, and that the players in the MapsTo property are of type RoutineCall:

  BIND input TO ABSTRACTION
MAPSTO (libc.buffered_io.fgets)
END input BIND output TO ABSTRACTION
MAPSTO (libc.buffered_io.fprintf,
libc.buffered_io.fputc)
END output

Establish

Description

The <establish> statement in UniCon is a form of syntax that, in a single statement, implicitly instantiates a connector and specificies all of the associations of players in an implementation to any of the connector's roles. It is equivalent to using an
<instantiation> statement to instantiate a connector, and then immediatly following it with <connection> statements that specify all of the player/role associations involving the roles in the previously instantiated connector.

The <establish> statement can simplify the task of instantiating a connector and associating players with its roles. In one statement, both tasks are accomplished. Whereas the syntax of the <connection> statement allows the associations between players and roles to appear in any order in a composite implementation, it is often helpful, however, to group together all the <connection> statements for one connector instantiation in one place. The syntax of the <establish> statement requires the designer to perform this grouping.

When grouping player/role associations in this manner, the connector instance name is purely local to the group. The <establish> statement eliminates this name by implicitly instantiating the connector. The connector is not given a name by which it can be referred to. Therefore, the roles of such a connector cannot be referred to outside the scope of the <establish> statement, forcing the designer to specify all player/role associations involving roles in the connector inside the given <establish> statement.

NOTE: The syntax of an <establish> is not symmetrical with respect to components; it cannot be used to instantiate components and associate roles with its players.

The property list of an <establish> statement has identical semantics to the property list of a connector <instantiation>. This means that properties that are legal and illegal in a property list of a connector <instantiation> of a given type are legal and illegal, respectively, in an <establish> of the same type of connector.

Syntax

The following is the syntax for an <establish> statement:

<establish> :== 
ESTABLISH <identifier> WITH
<establish_association_list>
<property_list>
END <identifier> <establish_association> :==
<identifier>.<identifier> AS <identifier>
The <identifier> following the word ESTABLISH must name a connector definition, not an instantiation. This is because the <establish> statement performs the connector instantiation.

The <establish_association_list> is a whitespace-separated list of <establish_association>s, and the list must contain at least one association. The <establish_association> looks remarkably similar to the association part of a <connection> statement, However, there are differences. Since there is no connector instantiation name, only one identifier is needed to identify the role in the association. Therefore, the dot-separated pair of <identifier>s before the word AS must name a player, and the single <identifier> following the AS must name a role in the connector named by the <identifier> following the word ESTABLISH. There is no pre-defined language limit to the number of <establish_association>s that can be present in the list.

Properties

As mentioned above, the properties that are legal and illegal in a property list of a connector <instantiation> of a given type are legal and illegal, respectively, in an
<establish> of the same type of connector.

Example

The following are two examples of the <establish> statement. The first one shows an <establish> of a ProcedureCall connector with no additional properties. The second one shows an <establish> of an RTScheduler connector with properties. The second example is equivalent to the combined syntax of the Example sections for the
<instantiation> statement and the <connection> statement:

  ESTABLISH C-proc-call WITH
my_main_program.malloc AS Caller
libc.malloc AS Definer
END C-proc-call
The above example assumes that the "libc" component contains a RoutineDef player named "malloc," and that the "my_main_program" component contains a RoutineCall player named "malloc." It also assumes that there exists a UniCon definition for a ProcedureCall connector named "C-proc-call."

  ESTABLISH Real_Time_Scheduler WITH
RTClient.load AS load
RTServer.load AS load
ALGORITHM (rate_monotonic)
PROCESSOR ("TESTBED.XX.CMU.EDU")
TRACE (RTClient.load.trigger,
RTClient.load.segment1,
RTServer.load.segment,
RTServer.load.segment2)
END Real_Time_Scheduler

Connector

Description

In UniCon software systems are described in terms of two kinds of distinct, identifiable elements: components and connectors.

A connector is an abstraction that represents the locus of definition for a relation among components. A connector mediates interactions among components; that is, it establishes the rules that govern component interactions and specifies any auxiliary implementation mechanisms required for realizing the interactions in the final system. A connector does not in general correspond individually to a compilation unit, but rather manifests itself in the final system as table entries, buffers, instructions to a linker, dynamic data structures, sequences of system calls embedded in source code, initialization parameters, etc.

Components interact with other components in a system in very distinct ways. These distinctions separate component interactions into classes, or types. A connector type captures the semantics of a particular class of interactions, assertions about that class, and the responsibilities and requirements that players in components must satisfy in an interaction from the class.

A connector has a specification, called a protocol, and an implementation. The protocol defines the allowable interactions among a collection of components and provides guarantees about those interactions.

The protocol defines:

A connector type expresses the designer's intention about the general class of connection to be provided by the connector; it restricts the numbers, types, and specifications of properties and roles. In particular some properties may or may not be required for a given connector type; additionally, some roles may require associations with players, some may not require them but constrain them if present, and some may be restricted to match players of certain types.

Properties can be thought of as attributes of a definition which are used to further describe (i.e., specify) it. They are global assertions and constraints that apply to the definition as a whole. There are many places in UniCon where lists of properties are used to further specify a definition. In connector protocols, properties are used to specify information such as rules about timing or ordering.

Roles are the visible semantic units through which the connector mediates the interactions among components. Their types are primitive typing units used to identify the players that must cooperate in a successful interaction. It is through associations of players to roles that interactions of components are mediated by connectors. Roles define the kinds of interactions a connector can establish - the kinds of components that can interact, and the player types that are involved. Roles form the bulk of the protocol.

The implementation of a connector can be primitive or composite, however only primitive implementations are supported at present - we do not fully understand composite implementations in a connector yet. We are currently engaged in research to understand the implementation implications of first-class connectors; we hope to someday use the results to specify and generate connectors and their implementations from specifications in semi-formal notations. This will give us insight into the problem of how to specify connectors with composite and user-defined implementations.

Syntax

The following is the syntax for a connector definition in UniCon:

  <connector> :==  
CONNECTOR <identifier>
<protocol>
<connector_implementation>
END <identifier> <protocol> :==
PROTOCOL IS
TYPE <connector_type>
<property_list>
<role_list>
END PROTOCOL <connector_type> :==
DataAccess
| FileIO
| Pipe
| PLBundler
| ProcedureCall
| RemoteProcCall
| RTScheduler <connector_implementation> :==
IMPLEMENTATION IS
BUILTIN
END IMPLEMENTATION
The properties in a <property_list> are separated by whitespace (i.e., spaces, tabs, and carriage returns). A <property_list> can be empty (in many cases), or it may contain one or more properties. A <property> is a name-value pair that specifies an attribute, an assertion, or a constraint pertaining to a definition. It is used to further specify that definition. The syntax of a property is as follows:

  <property> :== <name> <value>
  <name> :== <identifier>
  <value> :== 
EMPTY
| (<value_part>)
The <name> in a property has significance in UniCon (i.e., it conveys meaningful information about a definition); the <value> associates specific information with the property name in the given context. Here, the term context refers to the given language element of the given type (e.g., player, of type GlobalDataDef). The <value> may be NULL, or it may contain a <value_part> enclosed in parentheses. The <value_part> has a syntax that is specific to the property, in a given context. There are eleven common syntaxes for the values of UniCon properties.

The set of properties that can be legally specified in a property list depends on which definition the property list further specifies. For example, the set of properties legal for a protocol property list is different from the set that is legal for an interface property list.

The roles in a <role_list> are separated by whitespace.

Connector Type

Description

Components interact with other components in a system in very distinct ways. These distinctions separate component interactions (i.e., connections) into classes, or types. A connector type captures the semantics of a class of interactions, assertions about that class, and the responsibilities and requirements that players in components must satisfy in an interaction from the class.

A connector type expresses the designer's intention about the general class of connection to be provided by the connector; it restricts the numbers, types, and specifications of properties and roles. In particular some properties may or may not be required for a given connector type; additionally, some roles may require associations with players, some may not require them but constrain them if present, and some may be restricted to match players of certain types.

Every connector definition has a type. In UniCon, there are seven pre-defined connector types. The specification of the type comes as the first UniCon statement inside a connector protocol.

Syntax

The following is the syntax for specifying a connector type:

  <connector_type> :== 
DataAccess
| FileIO
| Pipe
| PLBundler
| ProcedureCall
| RemoteProcCall
| RTScheduler

DataAccess

Semantics

The connector type DataAccess provides an architectural abstraction for the global data defines/uses relation (inter-module connection) supported by programming languages. In addition to making this type of connection first-class (i.e., visible as an entity at the architecture description level), the DataAccess connector type supports type-checking of the players in the connection on the basis of signatures as well as the spelling of the names.

The system designer may specify the Rename property in the property list of an instantiation of a DataAccess connector to bypass the semantic check on the names of the players (meaning that they do not have to be the same). In such a case, the UniCon compiler detects and repairs the name mismatch in the underlying system implementation.

Role types

Roles of the following types can be legally defined in the protocol of a connector of type DataAccess:

a definer of global data
a user of the contents of a global data definition

Properties

The following properties can be legally included in the property list of a connector of type DataAccess. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type
DataAccess is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The Rename property has no associated value. The syntax, therefore, is simply:
RENAME

Semantic Checks

The following are the semantic checks made in connections of type DataAccess:

  1. The name of the player playing the User role must be identical (including case) to the name of the player playing the Definer role, unless the Rename property is specified in the connection.
  2. The data type in the signature of the player playing the User role must be identical (including case) to the data type in the signature of the player playing the Definer role. (Warning only)

Implementation Semantics

DataAccess connections are realized as linker directives that describe how global data references in the underlying system implementation are to be resolved with the addresses of the corresponding global data definitions within a single address space.

If a name mismatch is detected in a DataAccess connection and the Rename property was specified, the UniCon compiler renames both identifiers in the source code of the implementation to a third, UniCon-generated identifier to resolve the mismatch. The renaming occurs at compile-time via macro names supplied with the -D option to invocations of the C language compiler.

FileIO

Semantics

The connector type FileIO provides an architectural abstraction for reading and writing from and to a sequential file. In a read operation, records are read sequentially starting from the beginning of the file. In a write operation, records are written sequentially to the end of the file. In addition to making this type of connection first-class (i.e., visible as an entity at the architecture description level), the FileIO connector type supports type-checking of the players in the connection on the basis of signatures and record formats as well as the spelling of the names (the signatures of the players playing the Reader/Writer roles are checked against the RecordFormat of the sequential file in which the Readee/Writee players are defined).

The system designer may use the IOMode property in the protocol property list to constrain the behavior of the FileIO connector to readonly, readwrite, or writeonly operations.

Role types

Roles of the following types can be legally defined in the protocol of a connector of type FileIO:

records to be read from a sequential file
a reader of records from a sequential file
records to be written to a sequential file
a writer of records to a sequential file

Properties

The following properties can be legally included in the property list of a connector of type FileIO. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type FileIO is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for an IOMode property in a connector of type FileIO is one of the three keywords ReadOnly, ReadWrite, or WriteOnly, (optionally) enclosed in double-quotes, and surrounded by parentheses:
IOMODE (readonly)
IOMODE ("readwrite")
IOMODE ("writeonly")
If no IOMode property is specified in the protocol property list of a FileIO connector, the default value is "readwrite".

Semantic Checks

The following are the semantic checks made on connector definitions of type FileIO:

  1. If the IOMode of the FileIO connector is "readonly", then roles of types Readee and Reader must be defined in the protocol of the connector, and roles of types Writee and Writer must not be defined.
  2. If the IOMode of the FileIO connector is "readwrite", then roles of types Readee, Reader, Writee, and Writer must be defined in the protocol of the connector.
  3. If the IOMode of the FileIO connector is "writeonly", then roles of types Writee and Writer must be defined in the protocol of the connector, and roles of types Readee and Reader must not be defined.
The following are the semantic checks on connections made with FileIO connectors:

  1. The name of a player playing the Reader role must be identical (including case) to the name of the player playing the Readee role.
  2. The name of a player playing the Writer role must be identical (including case) to the name of the player playing the Writee role.
  3. The number of arguments and the data types of the arguments in the signature of the player playing the Reader role must be identical (including case of identifiers) to the number of elements and the data types of the elements in the
    RecordFormat property of the SeqFile component in which the player playing the Readee role is defined. (Warning only)
  4. The number of arguments and the data types of the arguments in the signature of the player playing the Writer role must be identical (including case of identifiers) to the number of elements and the data types of the elements in the
    RecordFormat property of the Seqfile component in which the player playing the Writee role is defined. (Warning only)

Implementation Semantics

FileIO connections are realized as linker directives that describe how (1) references to global data and (2) calls to input/output library routines and operating system services in the underlying system implementation are to be resolved with the addresses of the corresponding global data and routine definitions within a single address space. Recall that players associated with the Readee and Writee role types have no correspondence in the implementation of a system, and that those associated with the Reader and Writer role types are implemented as sequences of system calls to open, close, read, and write.

Pipe

Semantics

The connector type Pipe provides an architectural abstraction for a Unix pipe. It can establish interaction between two Filter components, or between a Filter component and a
SeqFile component. The Pipe connector establishes a data flow interaction. Data either flows from one filter to another, or it flows from a filter to a file (or vice versa). Depending on the type of interaction, the UniCon compiler chooses the correct implementation mechanism to realize the connection in the final system.

The system designer, however, may choose to constrain the implementation mechanism for data flowing between two filters by specifying the PipeType property in the protocol property list. The implementation mechanism that UniCon chooses in this case is a Unix mechanism called a pipe. A pipe is literally a buffer used to store data temporarily as it flows from one process to another. Pipes can be implemented in two ways in Unix: as relatively small, unnamed buffers internal to the Unix operating system, or as named files that exist in the file system. The advantage of using files over internal Unix buffers is that they are much larger in size. For all intents and purposes, they are virtually unconstrained, whereas the internal Unix buffers for unnamed pipes are small (4K to 8K bytes, depending on the system). Advantages to using the internal buffers over files is that they are less cumbersome to implement and more efficient at run-time. The system designer can use the PipeType property to specify the use of Named (files) or Unnamed (internal buffers) pipes.

Role types

Roles of the following types can be legally defined in the protocol of a connector of type Pipe:

a reader of the data in the pipe
a writer of data to the pipe

Properties

The following properties can be legally included in the property list of a connector of type Pipe. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type Pipe is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a PipeType property in a connector of type Pipe is one of the two keywords Named or Unnamed, (optionally) enclosed in double-quotes, and surrounded by parentheses:
PIPETYPE (named)
PIPETYPE ("unnamed")
If no PipeType property is specified in the protocol property list of a Pipe connector, the default value is "named".

Semantic Checks

The following are the semantic checks made in connections of type Pipe:

  1. Even if the MaxConns property associated with either the Source or the Sink role in a Pipe connector allows more than one connection to that role, UniCon enforces the restriction that a maximum of one connection to either of these roles is permitted.
  2. If the Pipe connection establishes interaction between two Filter components, then the data type in the signature of the player playing the Source role must be identical (including case) to the data type in the signature of the player playing the Sink role. (Warning only)
  3. If the Pipe connection establishes interaction between a Filter and a SeqFile, then the data type in the Signature of the StreamIn or StreamOut player must be identical (including case) to the data type in the RecordFormat of the SeqFile component in which the ReadNext or WriteNext player is defined. Additionally, the RecordFormat property may not contain more than one data type. (Warning only)
  4. A Pipe connection must contain at least one Filter component (i.e., it may not connect two SeqFile components).

Implementation Semantics

As described above, the Pipe connector may establish interaction between two Filters, or a Filter and a SeqFile. Depending upon the type of interaction, Pipe connections are realized by different mechanisms in the underlying implementation of the system. If establishing interaction between two Filters, Pipe connections in the implementation are realized as calls to the pipe, mkfifo, or mknod C library routines. The calls to pipe create unnamed pipes in the Unix environment that implement the Pipe connection, and the calls to mknod and mkfifo create named pipes.

Unnamed pipes are nameless buffers in the Unix operating system environment that have a fixed size (usually between 4K and 8K bytes, depending on your system). Unnamed pipes implement the following semantics:

The call to pipe returns two file descriptors, one opened for reading and the other for writing, which provide access to the buffer. The buffer is circular. Data is written sequentially and follows previously written bytes. When the buffer fills up, the process performing the write operations is suspended until data is read from the pipe and space becomes available in the buffer. When this happens, the writing process is resumed by the operating system and continues writing. Data is read from the buffer sequentially, in the order that the bytes were written. If all of the data in the buffer has been read and the reading process wishes to continue reading data, then the reading process is suspended until more data is written to the pipe. When this happens, the reading process is resumed and continues. If the writing process closes its end of the pipe, the reading process will receive an EOF after all data has been read from the buffer. If the reading process closes its end of the pipe, the writing process will receive a SIGPIPE signal from the operating system.

Named pipes are implemented as named files in the operating system. The advantage to using a named pipe instead of an unnamed pipe is that the size of the buffer is virtually unlimited, since the size of a file in the file system is unlimited (for all practical purposes). The semantics of the behavior of a named pipe are identical to the semantics of an unnamed pipe, except that each process must open the file after it is created by the call to mkfifo or mknod (one must open it for reading, and the other for writing), and the writing process is suspended after opening it until another process opens it for reading (and vice versa).

The implementation of named and unnamed pipes in the final system is transparent to the system designer. The only difference between named and unnamed pipes discernible to the system designer is the behavior of a pipe at run-time - the amount of data that can flow through a pipe during system execution.

If establishing interaction between a Filter and a SeqFile, a Pipe connection is realized by a call to the open C library routine in the process implementing the Filter. This call opens the file implementing the SeqFile for reading and/or writing, as specified in the UniCon description. Again, the implementation of this mechanism in the final system is transparent to the system designer.

When a system is constructed of many pipes, filters, and files, the UniCon compiler creates an initialization routine that, at run-time, creates all the pipes and starts up the filters with all the proper port bindings. It handles arbitrary topologies correctly.

PLBundler

Semantics

When designers think about the architecture of a system, they often think about the use of collections of players, rather than about individual players. The PLBundle player type in UniCon allows the system designer to create a collection of players to attach significance to a group of routines and data in an architectural description of a system. The name PLBundle denotes a programing language bundle; the bundle may only contain players of types that have corresponding programming language implementations: GlobalDataDef,
GlobalDataUse, RoutineCall, and RoutineDef players.

The PLBundler connector type supports the abstraction for connections of bundles of routine and data definitions, calls, and uses to other such bundles. Concretely, the PLBundler connector connects two or more PLBundle players. It abstracts from ProcedureCall and DataAccess connectors in the same way that the PLBundle player abstracts from the corresponding player definitions.

In the implementation of the abstraction, the UniCon compiler makes connections between individual Member players within the PLBundles. The compiler connects RoutineCall players in one PLBundle with their corresponding RoutineDef players in another PLBundle, and GlobalDataUse players in one PLBundle with their corresponding GlobalDataDef players in another.

The system designer can control how the UniCon compiler performs the connections by specifying the Match property in the property list of a PLBundler connector instantiation. The value of the Match property has two distinct forms. The first form consists simply of the word "by_name". This is the default value if the Match property is not specified in a PLBundler connection. If matching by name is specified, the compiler looks through every player in the PLBundler connection and attempts to find a match, based on player names, for every GlobalDataUse and RoutineCall player that it encounters. The second form of the Match property value is a comma-separated list of relations. A relation is a pair of player names, separated by a comma and enclosed in parentheses, that represent a connection to be made. The names in the relations must identify players or members of players in the PLBundler connection in which the Match property appears. With this form, the names of the players in the relations do not have to match. The name mismatches in this case will be resolved in the underlying system implementation.

If the value of the Match property is used to specify relations (i.e., it has the second form, as described above), then any RoutineCall or GlobalDataUse player in a PLBundler connection that is not connected explicitly in a relation will be automatically matched by name with a corresponding RoutineDef or GlobalDataDef player in the connection.

When performing matching by name, the UniCon compiler will report all instances of
GlobalDataUse and RoutineCall players that do not have corresponding matches in the connection.

Role types

A role of the following type can be legally defined in the protocol of a connector of type PLBundler:

a bundle of programming language entities: routine definitions and calls, and global data definitions and uses

Properties

The following properties can be legally included in the property list of a connector of type PLBundler. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type
PLBundler is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for a Match property in a connector of type PLBundler is either the word "by_name", optionally enclosed in double-quotes, or a comma-separated list of relations, enclosed in parentheses. A relation is a comma-separated pair of player names, enclosed in parentheses. A player name can either be two or three dot-separated <identifier>s. The first <identifier> names a component instantiation, the second names a player in the component instantiation named by the first, and the third (if present) names a Member in a PLBundle player named by the second.
MATCH (by_name)
MATCH ("by_name")
MATCH ((my_application.stack_adt.pop_call,
my_stack.stack_adt.pop_definition),
(my_application.stack_adt.push_call,
my_stack.stack_adt.push_definition),
(my_application.stack_adt.stack_init_call,
my_stack.stack_adt.stack_init_definition),
(my_application.stack_adt.stack_is_empty_call,
my_stack.stack_adt.stack_is_empty_definition))

Semantic Checks

No special semantic checks are made in connections of type PLBundler.

Implementation Semantics

PLBundler connections are implemented as a sequence of ProcedureCall and DataAccess connections corresponding to the matchings described by the Match property in the connector instantiation.

ProcedureCall

Semantics

The connector type ProcedureCall provides an architectural abstraction for the defines/calls relations (inter-module connections) of functions and procedures supported by programming languages. In addition to making this type of connection first-class (i.e., visible as an entity at the architecture description level), the ProcedureCall connector type supports type-checking of the players in the connection on the basis of signatures as well as the spelling of the names.

The system designer may specify the Rename property in the property list of an instantiation of a ProcedureCall connector to bypass the semantic check on the names of the players (meaning that they do not have to be the same). In such a case, the UniCon compiler detects and repairs such name mismatches in the underlying system implementation.

Role types

Roles of the following types can be legally defined in the protocol of a connector of type ProcedureCall:

a definer of a local function or procedure
a caller of a local function or procedure

Properties

The following properties can be legally included in the property list of a connector of type ProcedureCall. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type
ProcedureCall is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The Rename property has no associated value. The syntax, therefore, is simply:
RENAME

Semantic Checks

The following are the semantic checks made in connections of type ProcedureCall:

  1. The name of the player playing the Caller role must be identical (including case) to the name of the player playing the Definer role, unless the Rename property is specified in the connection.
  2. The number of arguments, the data types of the arguments, and the return type in the signature of the player playing the Caller role must be identical (including case of identifiers) to the number of arguments, the data types of the arguments, and the return type in the signature of the player playing the Definer role. (Warning only)

Implementation Semantics

ProcedureCall connections are realized as linker directives that describe how function and procedure calls in the underlying system implementation are to be resolved with the addresses of the corresponding function and procedure definitions within a single address space.

If a name mismatch is detected in a ProcedureCall connection and the Rename property is specified, the UniCon compiler renames both identifiers in the source code of the implementation to a third, UniCon-generated identifier to resolve the mismatch. The renaming occurs at compile-time via macro names supplied with the -D option to invocations of the C language compiler.

RemoteProcCall

Semantics

The connector type RemoteProcCall provides an architectural abstraction for the defines/calls relations of remote functions and procedures defined and called from within separate processes in the operating system. In other words, the abstraction corresponds to remote procedure calls (RPCs) supported by the operating system. In addition to making this type of connection first-class (i.e., visible as an entity at the architecture description level), the RemoteProcCall connector type supports type-checking of the players in the connection on the basis of signatures as well as the spelling of the names.

The system designer may specify the Rename property in the property list of an instantiation of a RemoteProcCall connector to bypass the semantic check on the names of the players (meaning that they do not have to be the same). In such a case, the UniCon compiler detects and repairs such name mismatches in the underlying system implementation.

Role types

Roles of the following types can be legally defined in the protocol of a connector of type RemoteProcCall:

a definer of a remote function or procedure (i.e, a function or procedure defined in a process so that it is callable from other processes)
a caller of a remote function or procedure

Properties

The following properties can be legally included in the property list of a connector of type RemoteProcCall. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type
RemoteProcCall is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for an IDLType property in a connector of type RemoteProcCall is one of the two keywords Mach or RPCL, (optionally) enclosed in double-quotes, and surrounded by parentheses:
IDLTYPE (Mach)
IDLTYPE ("rpcl")
If no IDLType property is specified in the protocol property list of a RemoteProcCall connector, the default value is "rpcl".
The Rename property has no associated value. The syntax, therefore, is simply:
RENAME

Semantic Checks

The following are the semantic checks made in connections of type RemoteProcCall:

  1. The name of the player playing the Caller role must be identical (including case) to the name of the player playing the Definer role, unless the Rename property is specified in the connection.
  2. The number of arguments, the data types of the arguments, and the return type in the signature of the player playing the Caller role must be identical (including case of identifiers) to the number of arguments, the data types of the arguments, and the return type in the signature of the player playing the Definer role. (Warning only)

Implementation Semantics

The UniCon compiler can generate the underlying mechanisms for RemoteProcCall connectors for two types of systems: applications which use the Mach interprocess communication (IPC) facility and applications which use the RPCGen facility. Both facilities make use of a message passing mechanism to facilitate remote procedure calls between processes. The selection of the type of facility is done through the specification of the IDLType property in the property list of a RemoteProcCall connector instantiation. If no IDLType property is specified, the value "rpcl" is assumed, which means that the underlying implementation mechanism will use the RPCGen facility.

The underlying mechanism that implements both the Mach and RPCGen message passing facilities is essentially the same. Both assume that applications implement remote procedure and function calls as local routine calls, and remote function and procedure definitions as local routine definitions. This model requires that processes making remote procedure calls contain source code that intercepts the local routine calls implementing the RPCs, builds a message containing the arguments of the call, and hands the message off to the operating system for delivery to the process containing the routine definition. It also requires that processes exporting remote routine definitions contain source code that extracts the arguments from service request messages from calling processes, makes the local routine call, builds a return message containing any results from the routine call, and hands the return message off to the operating system for delivery to the calling process. Generating this "glue code" in each process can be time consuming, intricate, and error prone. Therefore, both the Mach facility and the RPCGen facility provide a code generator for generating this code from their own brand of interface definition language (IDL). The Mach IDL is called the Mach Interface Generator (MIG) language. The RPCGen language is called Remote Procedure Call Language (RPCL).

UniCon automatically generates the IDL specification of the RPC interface between two Process or SchedProcess components directly from the UniCon definitions of the components. Then, at system construction time, the correct generation tool (i.e., MIG or RPCGen) produces the source for the "glue code" from the IDL specification, and the code is compiled and linked into the correct processes. The system designer is spared having to know the details of implementing the glue code directly.

In addition to the glue code required between processes making RPCs, each communication model requires processes making RPCs to communicate once during system initialization with a "name" server that is executing in the operating system environment. This name server is the mechanism by which server processes register their services (i.e., the remote procedure definitions) for general use, and by which client processes locate the services they will request. UniCon generates the initialization code in each process that is responsible for registering or locating services at run-time. This code runs as the "main" program in the environment; it registers/locates all of the services exported/imported by the Process or SchedProcess component implementing the process, and then calls the local routine definition that implements the main functionality of the component (recall that Process and SchedProcess components are implemented as function or procedure definitions).

The system designer need not know any details whatsoever regarding the implementation of the underlying mechanisms for RemoteProcCall connections. Indeed, remote procedure calls and definitions in the underlying implementation are identical to local routine calls and definitions. There literally is no difference. UniCon does all of the work in turning them into remote procedure calls and definitions. Similarly, at the UniCon architecture description level, RemoteProcCall connectors are nearly identical to ProcedureCall connectors in how they are specified, with the only exception being that RemoteProcCall connections require the specification of the IDLType property.

If a name mismatch is detected in a RemoteProcCall connection and the Rename property is specified, the UniCon compiler renames both identifiers in the source code of the implementation to a third, UniCon-generated identifier to resolve the mismatch. The renaming occurs at compile-time via macro names supplied with the -D option to invocations of the C language compiler.

RTScheduler

Semantics

The connector type RTScheduler mediates interaction between SchedProcess components in competition for a processor resource. Recall that a SchedProcess component is a process in a real-time operating system environment that is scheduled according to some real-time scheduling algorithm. This type of process performs some work, runs to completion, and then gets rescheduled in the operating system to run again. Because of this, the process runs periodically and requires a certain percentage of the processor resource over time. When there are multiple such processes in the system, the scheduling of each process becomes important; if scheduling is not done efficiently, the processes in contention for the resource may or may not be able to complete their work before they must run again. Similary, the processor resource may be idle for significant periods of time, while at the same time some processes are not completing their work.

The RTScheduler connector type corresponds to the mediation of this interaction between real-time processes in contention for the CPU resource. It requires an operating system with appropriate real-time capabilities; the UniCon compiler currently supports implementation mechanisms for the Real-Time Mach operating system. The processor resource in the Real-Time Mach kernel can be managed according to one of six different algorithms: the rate monotonic, deadline monotonic, earliest deadline first, fifo fixed priority, round robin fixed priority, or timesharing algorithm. The system designer can specify the particular algorithm with the Algorithm property in an RTScheduler connector instantiation. The system designer can also specify the particular processor to be managed with the Processor property in the connector instantiation.

If the system designer specifies the rate monotonic scheduling algorithm for the processor, UniCon will automatically prepare some input for a rate monotonic analysis (RMA) tool that will determine if the set of real-time processes in the RTScheduler connection will all meet their deadlines (i.e., complete execution before they must run again). To facilitate this, the system designer is required to specify one Trace property in the connector instantiation for each event that is being managed in the RTScheduler connection. The RMA is performed on events rather than processes; the schedulability of the events implies the schedulability of the processes.

An event in UniCon is a complete thread of execution in a real-time system that can span multiple processes because of the presence of RPC calls. An event describes execution of a thread from the time control is first given to a client process by the operating system via a trigger (the mechanism by which control is transferred; e.g., an timer interrupt), until control is returned to the operating system as a result of the client finishing its work. An event consists of a trigger, followed by a specific sequence of smaller chunks of code called segments. Segments are atomic blocks of work within a given process, atomic meaning that the thread of control within the block is continuous (i.e., not transferred to another process). The sequence of segments in an event are executed in an order that is defined by the thread of control in the application. For example, a client process gets activated by the operating system. The client does some work (a segment), and then, perhaps, makes an RPC call to a server process. The server process does some work (another segment) and either returns to the client, or makes an RPC call itself. This continues until control is eventually returned back to the client, which does more work (another segment). Work proceeds this way until control is returned back to the operating system.

There can be potentially many events in a single RTScheduler connection. There will be one for each trigger that transfers control to a client process in the set of application processes whose interaction is mitigated by the RTScheduler connector. The system designer must specify a Trace property for each one of these events. The value in the Trace property is a list of names. The first names a trigger, and the rest name the segments, in the proper sequence. Each name consists of three dot-separated <identifier>s. The third names the trigger or segment, the second names the RTLoad player in which the trigger/segment is defined, and the first names the component instantiation in which the RTLoad player is defined.

Role types

A role of the following type can be legally defined in the protocol of a connector of type RTScheduler:

the total execution time that a single SchedProcess component places on the CPU while executing code associated with a particular event

Properties

The following properties can be legally included in the property list of a connector of type RTScheduler. Properties legal in a <protocol> property list have a P in parentheses after the property name; those legal in an <instantiation> or <establish> property list have an I:

The syntax for an InstFormals property in a connector of type
RTScheduler is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an <identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character:
INSTFORMALS (first_parameter = "an initial value",
second_parameter = "a much" &
"longer initial value that " &
"will not fit on one line",
third_parameter = NODEFAULT)
The syntax for an Algorithm property in a connector of type RTScheduler is one of the six keywords rate_monotonic, deadline_monotonic, earliest_deadline_first, fifo_fixed_priority, round_robin_fixed_priority, or timesharing, (optionally) enclosed in double-quotes, and surrounded by parentheses:
ALGORITHM (rate_monotonic)
ALGORITHM ("fixed_priority")
If no Algorithm property is specified in the property list of an RTScheduler connector definition or instantiation, the default value is "rate_monotonic".
The syntax for the Processor property in a connector of type
RTScheduler is an <identifier> or "string", surrounded by parentheses:
PROCESSOR ("testbed.xx.cmu.edu")
PROCESSOR (my_hostname)
If no Processor property is specified in the property list of an RTScheduler connector definition or instantiation, the default value is the current processor name (i.e., the name of the processor that the UniCon compiler executes on while compiling/building the system). It is the name returned by the Unix "hostname" command executed compilation/building of the system.
The syntax for the Trace property in a connector of type
RTScheduler is a comma-separated list containing a trigger name followed by one or more segment names, surrounded by parentheses. Trigger and segment names contain three dot-separated
<identifier>s. The first <identifier> names a component instantiation, the second names an RTLoad player in the component instantiation named by the first, and the third names a trigger or segment in the RTLoad player named by the second:
TRACE (process_one.load.trigger,
process_one.load.segment_one,
process_two.load.segment,
process_one.load.segment_two)

Semantic Checks

The following are the semantic checks made in connections of type RTScheduler:

  1. If the Algorithm property in an RTScheduler connection specifies a rate_monotonic algorithm, then at least one Trace property must also be specified in the connection.
  2. Every RTScheduler connection must be intended for a different processor (i.e., specified with the Processor property).
  3. Every SchedProcess component involved in an RTScheduler connection must be designated to run on the same processor that the RTScheduler is intended for (Warning only).
  4. Every SchedProcess component involved in an RTScheduler connection must not be involved in any other RTScheduler connection (i.e., it must only be involved in one such connection).
  5. Every SchedProcess component instantiated in a system must be involved in an RTScheduler connection.
  6. If an RTScheduler connection specifies more than one Trace property such that more than one trigger from the same SchedProcess component is used, then the SchedProcess must not be a server process because the system designer is attempting to assign more than one period to a process (and server processes have no periods - they run continuously).

Implementation Semantics

An RTScheduler connector is realized in the final system by the interaction of processes competing for the processor resource via some scheduling algorithm implemented by the real-time operating system. Real-time scheduling requires each process to be initialized with certain properties, such as period and priority. The UniCon compiler generates C language initialization source code for each SchedProcess involved in an RTScheduler connection. This code is a C "main" program that creates and initializes the process in the real-time environment with the specified period and priority and performs initialization required to support remote procedure calls between it and other processes.

In addition to the process initialization code, the UniCon compiler generates a program executable that initializes the real-time scheduler in the operating system environment prior to the creation of the processes in the application.

Lastly, the UniCon compiler generates a Unix shell script that invokes the scheduler initialization program and starts the application processes at run-time, in the correct order (i.e., all processes providing services via remote procedure call are started before the processes that require these services).

All of this is done automatically. No additional support is required to be implemented by the system designer in order to realize an RTScheduler connector.

Analysis
Support

As mentioned above, when the algorithm of choice for an RTScheduler connection is the rate monotonic algorithm, UniCon automatically generates input for a tool that will perform a rate monotonic analysis (RMA) of the schedulability of the processes that will run on the particular processor. UniCon extracts the period, priority, and execution time data for each process from the appropriate property lists in the associated component definition, formats it, and writes it to a file with the name "RMA_<processor_name>". <processor_name> is the name of the processor as it appears in the Processor property in the RTScheduler connector instantiation. The RMA tool analyzes the data and returns a result indicating whether or not the schedule is achievable. It is achievable if each process can complete its work within its given period (i.e., before it must be activated to run again).

The RMA tool is an Excel spreadsheet program that runs on IBM PCs, so for now the invocation of the tool is carried out manually.

Role

Description

A role is a visible semantic unit in the protocol of a connector through which the connector can mediate the interaction between components. More concretely, a role is a named entity in the protocol of a connector that can be associated with a player, a named entity in the interface of a component, in a connection during system construction. Roles are used to identify the players that must cooperate in a successful interaction; roles identify the kinds of interactions that a connector can establish (i.e., the kinds of components it can work with and the player types it can handle).

A role definition contains:

A role defines the responsibilities and the requirements for a player involved in an interaction among components. Role types are primitive typing units used to (1) identify players that can play a given role in a connection and (2) define their responsibilities and requirements in such a connection. Each role type in UniCon has a pre-defined set of player types that it may be associated with in a connection, and each defines the semantics of the responsibilities of the players in the connection.

Roles are further specified by properties in the property list of the role definition. Properties can be thought of as attributes of a definition which are used to further describe (i.e., specify) it. For roles, they are attributes that apply to the role as a whole. There are many places in UniCon where lists of properties are used to further specify a definition. In roles, properties are used to specify information such as the legal component/player type combinations of players that can be associated with a given role in a connection, and the minimum and maximum number of player/role associations involving a given role in a connection.

Syntax

The following is the syntax for a role definition:

  <role> :== 
ROLE <identifier> IS <role_type>
<optional_end_role_syntax> <role_type> :==
Caller
| Definer
| Load
| Participant
| Readee
| Reader
| Sink
| Source
| User
| Writee
| Writer <optional_end_role_syntax> :==
EMPTY
| <property_list>
END <identifier>
Roles can be defined with and without properties. In the latter case, for example, the role definition appears as follows:

  ROLE Unix_Pipe_Input_End IS Source 
Notice that if no properties are specified in a role definition (i.e., the property list is empty), the END statement is omitted.

In the former case, the role definition appears as follows:

  ROLE Unix_Pipe_Input_End IS Source
MINCONNS (1)
MAXCONNS (1)
ACCEPT (Filter.StreamOut, General.StreamOut,
SeqFile.ReadNext, General.ReadNext)
END Unix_Pipe_Input_End
The END statement is required in this case. The <identifier> in the END statement must be identical to the <identifier> following the keyword ROLE, including the case of the letters.

Properties

There are only three properties in UniCon that are legal in the property list of a role definition: MinConns, MaxConns, and Accept. Every role type in UniCon has a pre-defined, default value for each of these properties; therefore, it is not required that these properties be specified in the property list in a role definition. The syntax of the value portion of each of these properties is the same across all role types:

The syntax for a MinConns property in a connector is an
<integer> surrounded by parentheses:
MINCONNS (1)
The syntax for a MaxConns property in a connector is an
<integer> surrounded by parentheses:
MAXCONNS (1)
The syntax for an Accept property in a connector is a comma-separated list of dot-separated pairs of <identifier>s, surrounded by parentheses:
ACCEPT (Filter.StreamOut, General.StreamOut,
SeqFile.ReadNext, General.ReadNext)

Role Type

Description

A role defines the responsibilities and the requirements for a player involved in an interaction among components. Role types are primitive typing units used to (1) identify players that can play a given role in a connection and (2) define their responsibilities and requirements in such a connection. Each role type in UniCon has a pre-defined set of player types that it may be associated with in a connection, and each defines the semantics of the responsibilities of the players in the connection.

Every role definition has a type. In UniCon, there are eleven pre-defined role types. The specification of the type appears immediately following the keyword IS in a UniCon role definition.

Syntax

The following is the syntax for specifying a role type:

  <role_type> :== 
Caller
| Definer
| Load
| Participant
| Readee
| Reader
| Sink
| Source
| User
| Writee
| Writer

Caller

Semantics

The role type Caller corresponds to the requirement that the associated player in a connection be a routine call: a local routine call in a ProcedureCall connection, and a remote routine call in a RemoteProcCall connection. The responsibility of the player is to act as a routine call in the connection.

In a ProcedureCall connection there must be at least one caller (i.e., one Caller role/player association), however there may be infinitely many. The same applies in the case of a RemoteProcCall connection.

Connector Types In

A role of type Caller can legally be defined in connectors of the following types:

Player Type
Associations

A role of type Caller can legally be associated with the following player types:

RoutineCall (of Computation, General, or Module components)
RPCCall (of General, Process, or SchedProcess components)

Property Defaults

The following are the default values of the properties for the Caller role:

MaxConns: infinite
MinConns: 1
Accept:
Computation.RoutineCall,
General.RoutineCall,
Module.RoutineCall
MaxConns: infinite
MinConns: 1
Accept:
General.RPCCall,
Process.RPCCall,
SchedProcess.RPCCall

Definer

Semantics

The role type Definer corresponds to the requirement that the associated player in a connection be a routine or data definition: a local routine definition in a ProcedureCall connection, a remote routine definition in a RemoteProcCall connection, or a global data definition in a DataAccess connection. The responsibility of the player is to act as a routine definition in the connection.

In ProcedureCall, DataAccess, and RemoteProcCall connections there must be at most one definition (i.e., one Definer role/player association).

Connector Types In

A role of type Definer can legally be defined in connectors of the following types:

Player Type
Associations

A role of type Definer can legally be associated with the following player types in a connection:

GlobalDataDef (of General, Module, or SharedData components)
RoutineDef (of Computation, General, or Module components)
RPCDef (of General, Process, or SchedProcess components)

Property Defaults

The following are the default values of the properties for the Definer role:

MaxConns: 1
MinConns: 1
Accept:
General.GlobalDataDef,
Module.GlobalDataDef,
SharedData.GlobalDataDef
MaxConns: 1
MinConns: 1
Accept:
Computation.RoutineDef,
General.RoutineDef,
Module.RoutineDef
MaxConns: 1
MinConns: 1
Accept:
General.RPCDef,
Process.RPCDef,
SchedProcess.RPCDef

Load

Semantics

The role type Load corresponds to the requirement that the associated player in an RTScheduler connection be a load on the central processing unit (CPU) in a real-time environment. A load is defined to be the amount of CPU time required to execute the segments of code in a particular SchedProcess component that are associated with a particular event. An event is defined to be a trigger that transfers control from the operating system to a segment of code in a client process in a real-time environment and all of the segments that get executed until control is returned back to the operating system. An RTLoad player in a SchedProcess component corresponds to a load. The responsibility of the player is to place this load on the CPU at run-time in the real-time environment.

Connector Types In

A role of type Load can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Load can legally be associated with the following player type in an
RTScheduler connection:

Property Defaults

The following are the default values of the properties for the Load role:

General.RTLoad,
SchedProcess.RTLoad

Participant

Semantics

The role type Participant corresponds to the requirement that the associated player in a PLBundler connection be any player of a UniCon type that represents a programming language entity: a GlobalDataDef, GlobalDataUse, RoutineCall, RoutineDef, or PLBundle player. The responsibility of the player is to behave as the programming language entity defined by its type.

There must always be at least two, but there may be potentially infinite, participants in a PLBundler connection.

Connector Types In

A role of type Participant can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Participant can legally be associated with the following player types in a PLBundler connection:

Property Defaults

The following are the default values of the properties for the Participant role:

General.GlobalDataDef,
Module.GlobalDataDef,
SharedData.GlobalDataDef,
Computation.GlobalDataUse,
General.GlobalDataUse,
Module.GlobalDataUse,
SharedData.GlobalDataUse,
Computation.RoutineCall,
General.RoutineCall,
Module.RoutineCall,
Computation.RoutineDef,
General.RoutineDef,
Module.RoutineDef,
Computation.PLBundle,
General.PLBundle,
Module.PLBundle,
SharedData.PLBundle

Readee

Semantics

The role type Readee corresponds to the requirement that the associated player in a FileIO connection be the next block of data to be read from the front of a sequential file. The format of this block is specified in the RecordFormat property associated with the SeqFile component. The player type ReadNext in UniCon captures the semantics of this data block. The responsibility of the ReadNext player is to act as the next data block to be read from a sequential file in a FileIO connection.

In a FileIO connection whose IOMode is either ReadOnly or ReadWrite, there must be exactly one data block to be read next from the sequential file (i.e., one Readee role/player association). This data block may be NULL.

Connector Types In

A role of type Readee can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Readee can legally be associated with the following player type in a FileIO connection:

Property Defaults

The following are the default values of the properties for the Readee role:

General.ReadNext,
SeqFile.ReadNext

Reader

Semantics

The role type Reader corresponds to the requirement that the associated player in a FileIO connection be a reader in a compilation unit of the next block of data to be read from the front of a sequential file. The player type ReadFile in UniCon captures the semantics of this read action. The responsibility of the ReadFile player is to act as the reader of the next data block in a FileIO connection.

In a FileIO connection whose IOMode is either ReadOnly or ReadWrite, there must be at least one reader (i.e., one Reader role/player association) of sequential file data blocks, however, there may be infinitely many.

Connector Types In

A role of type Reader can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Reader can legally be associated with the following player type in a FileIO connection:

Property Defaults

The following are the default values of the properties for the Reader role:

General.ReadFile,
Module.ReadFile

Sink

Semantics

The role type Sink corresponds to the requirement that the associated player in a Pipe connection be a stream of data that gets appended to the end of a sequential file or that gets used as input to a filter component. The player type WriteNext in UniCon captures the semantics of the stream being written to a sequential file. In this case, the stream is actually written as a series of data blocks whose format is specified in the RecordFormat property in the SeqFile component. The player type StreamIn in UniCon captures the semantics of the data stream being used as input by a Filter component. The responsibility of the WriteNext player is to act as a stream of data being written to the end of a sequential file in a Pipe connection. The responsibility of the StreamIn player is to act as a stream of data being extracted from a pipe in a Pipe connection.

In a Pipe connection there must be exactly one stream of data being extracted from the pipe or written to the file (i.e., one Sink role/player association).

Connector Types In

A role of type Sink can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Sink can legally be associated with the following player types in a Pipe connection:

Property Defaults

The following are the default values of the properties for the Sink role:

General.StreamIn,
Filter.StreamIn,
General.WriteNext,
SeqFile.WriteNext

Source

Semantics

The role type Source corresponds to the requirement that the associated player in a Pipe connection be a stream of data that is being read from the front of a sequential file or that is being generated as output from a filter component. The player type ReadNext in UniCon captures the semantics of the stream being read from a sequential file. In this case, the stream is actually read as a series of data blocks whose format is specified in the
RecordFormat property in the SeqFile component. The player type StreamOut in UniCon captures the semantics of the data stream being generated as output by a Filter component. The responsibility of the ReadNext player is to act as a stream of data being read from the front of a sequential file in a Pipe connection. The responsibility of the StreamOut player is to act as a stream of data being written to a pipe in a Pipe connection.

In a Pipe connection there must be exactly one stream of data being written to the pipe or being read from the file (i.e., one Source role/player association).

Connector Types In

A role of type Source can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Source can legally be associated with the following player types in a Pipe connection:

Property Defaults

The following are the default values of the properties for the Source role:

General.ReadNext,
SeqFile.ReadNext,
General.StreamOut,
Filter.StreamOut

User

Semantics

The role type User corresponds to the requirement that the associated player in a
DataAccess connection be a reference to a global data definition.

In a DataAccess connection there must be at least one reference to a data object (i.e., one User role/player association), however there may be infinitely many.

Connector Types In

A role of type User can legally be defined in a connector of the following type:

Player Type
Associations

A role of type User can legally be associated with the following player type in a
DataAccess connection:

Property Defaults

The following are the default values of the properties for the User role:

Computation.GlobalDataUse,
General.GlobalDataUse,
Module.GlobalDataUse
SharedData.GlobalDataUse

Writee

Semantics

The role type Writee corresponds to the requirement that the associated player in a FileIO connection be the next block of data that gets written to the end of a sequential file. The format of this block is specified in the RecordFormat property associated with the SeqFile component. The player type WriteNext in UniCon captures the semantics of this data block. The responsibility of the WriteNext player is to act as the next data block that gets written to a sequential file in a FileIO connection.

In a FileIO connection whose IOMode is either WriteOnly or ReadWrite, there must be exactly one data block that gets written next to the sequential file (i.e., one Writee
role/player association).

Connector Types In

A role of type Writee can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Writee can legally be associated with the following player type in a FileIO connection:

Property Defaults

The following are the default values of the properties for the Writee role:

General.WriteNext,
SeqFile.WriteNext

Writer

Semantics

The role type Writer corresponds to the requirement that the associated player in a FileIO connection be a writer in a compilation unit of a data block that gets appended to the end of a sequential file. The player type WriteFile in UniCon captures the semantics of this write action. The responsibility of the WriteFile player is to act as the writer of such a data block in a FileIO connection.

In a FileIO connection whose IOMode is either WriteOnly or ReadWrite, there must be at least one writer (i.e., one Writer role/player association) of sequential file data blocks, however, there may be infinitely many.

Connector Types In

A role of type Writer can legally be defined in a connector of the following type:

Player Type
Associations

A role of type Writer can legally be associated with the following player type in a FileIO connection:

Property Defaults

The following are the default values of the properties for the Reader role:

General.WriteFile,
Module.WriteFile

Connector Implementation

Description

At present only primitive implementations of connectors are supported. We do not yet know what the implementation implications of composite connector implementations might be as of the publication date of this reference manual. Additionally, connector implementations are all builtin in the language. This means that the UniCon compiler chooses the appropriate implementation mechanism to realize the connection in the resulting software system. Therefore, there are no user-defined connector implementations in the language either. Again, we do not yet know the implementation implications of user-defined connector implementations.

Refer to the UniCon Implementor's Guide for more details on the implementations of
UniCon connector abstractions.

Syntax

The following is the syntax for a connector implementation in UniCon:

  <connector_implementation> :==
IMPLEMENTATION IS
BUILTIN
END IMPLEMENTATION

Property

A property is a name-value pair that specifies an attribute, an assertion, or a constraint pertaining to a UniCon definition or language element (e.g., a component, connector, role, or player). It is used to further specify the definition or language element. Properties are specified in <property_list>s, and these lists are a part of the syntax of the following UniCon language elements:

  <interface>
  <component_implementation>
  <instantiation>
  <protocol>
  <establish>
  <role>
  <player>
  <variant>
  <abstraction_bind>
  <simple_bind>
All properties in all <property_list>s in UniCon are separated by whitespace (i.e., spaces, tabs, and carriage returns). A <property_list> can be empty (in many cases), or it may contain one or more properties.

The syntax of a property is as follows:

  <property> :== <name> <value>
  <name> :== <identifier>
  <value> :== 
EMPTY
| (<value_part>)
The <name> in a property has significance in UniCon (i.e., it conveys meaningful information about a definition). There are 35 pre-defined property names in the UniCon language, and the property list associated with each language element listed above accepts only a certain subset of the pre-defined properties. Additionally, a given pre-defined property may be accepted in the property lists of more than one distinct UniCon language element. All property lists accept user-defined properties.

The <value> in a property associates specific information with the given property name in the given context. Here, the term context refers to the given language element of the given type (e.g., player, of type GlobalDataDef). The <value> may be NULL, or it may contain a <value_part> enclosed in parentheses. The <value_part> has a syntax that is specific to the property, in a given context. There are eleven common syntaxes for the values of UniCon properties - the syntaxes for all 35 pre-defined UniCon properties in all contexts fall into these eleven categories.

Examples of properties with and without <value_part>s are shown below:

LIBRARY
SIGNATURE ("int")
Each pre-defined UniCon property has a required rule associated with it. The property is either always required to be specified in the property list for which it is designated, or it is optional. If it is required to be present in a property list and the system designer does not specify it, the UniCon compiler will generate an error message and prevent system construction. If a property is optional in its designated list, the UniCon compiler will provide a default value.

Each pre-defined UniCon property has a merge rule associated with it. The merge rule tells the UniCon compiler how to resolve duplicate property specifications in a single property lists. For example, what does the compiler do when it encounters two Accept property specifications in the same property list? Does it throw out the first set of values, or the second? Or does it use the union of both lists? It depends on the value of the merge rule; the rule can take on one of the following three values: ERROR, REPLACE, or MERGE.

A merge rule value of ERROR instructs the UniCon compiler to ignore each subsequent specification of the given property in the same list, and treat it as an error (Warning). A merge rule value of REPLACE instructs the UniCon compiler to accept the last specification of a given property in the same list, and treat each prior specification as an error (Warning). A merge rule value of MERGE instructs the UniCon compiler to take the union of the elements in the value portions of all specifications of a given property in the same list.

NOTE: When instantiating a component in UniCon, the value part of a given property in a component <instantiation> property list overrides the value part of the same property in the <interface> property list in the component definition if the merge rule is REPLACE. The one in the <interface> overrides the one in the <instantiation> if the merge rule is ERROR. The values in both lists are merged together into one specification if the merge rule is MERGE. The same semantics apply for connector definitions and instantiations as well.

Accept

Description

The Accept property is used to further specify a role definition in UniCon. It specifies which players can be associated with the given role in a connection. The players are specified as component-player type combinations. For example, assume the type combination Filter.StreamIn is in the value part of an Accept property. This means that the role may be associated with players of type StreamIn that are defined in components of type Filter.

Each role type in UniCon has a default accept list specifying a distinct set of type combinations. The Accept property can only be used in a role definition to restrict this default set; the default set cannot be extended in any way.

Property Lists

The Accept property can legally be specified in the property list in the following UniCon language element:

Value Syntax

The syntax of the value part of the Accept property is a comma-separated list of dot-separated pairs of <identifier>s, enclosed in parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default values depend upon the <role_type> in the <role> definition. Please refer to the descriptions of the UniCon role types in this manual for information on the default values for the Accept property in each case.

Merge Rule

MERGE

More than one specification of the Accept property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

The following are the semantic checks performed on values of the Accept property:

  1. The first "string" or <identifier> in each dot-separated pair must name a valid UniCon component type.
  2. The second "string" or <identifier> in each dot-separated pair must name a valid UniCon player type.
  3. Each component-player type combination must name a valid component-player type combination in the default accept list for the given role type.

Example

The following is an example of an Accept property. It is embedded in a definition of a role of type Source:

  ROLE Unix_Pipe_Input_End IS Source
ACCEPT (General.ReadNext, SeqFile.ReadNext,
General.StreamOut, Filter.StreamOut)
END Unix_Pipe_Input_End

Algorithm

Description

The Algorithm property is used to further specify an RTScheduler connector. It is typically used to specify an instantiation of such a connector, but it can also be used to specify a definition. However, when left out of the definition, the connector is more general and can be parameterized at instantiation time with this property.

An RTScheduler connector governs the interaction of SchedProcess components contending for a single processor resource in a real-time environment. This connector corresponds to a scheduler in the kernel of a real-time operating system. The scheduler's responsibility is to provide each schedulable process in a system of such processes with access to the processor resource. This is done according to some algorithm.

In the Real-Time Mach operating system (the target evironment for instantiations of RTScheduler connectors in UniCon systems) there are six distinct real-time scheduling algorithms:

Schedulable processes are given priorities based on their periods of execution. Processes with shorter periods are given higher priorities. Highest priority processes get access to the processor first.
Schedulable processes are given priorities based on the length of time between the start of the period and the deadline of the process. Processes with the shorter of these "deadline" periods are given higher priorities. Highest priority processes get access to the processor first.
The schedulable process with the closest deadline is given access to the processor first. A deadline is an absolute time, and the closest deadline is measured from the current time.
The schedulable processes of a given priority are given access to the processor in the order in which they get rescheduled to run. The processes, in this case, always run to completion.
The schedulable processes of a given priority are given access to the processor in the order in which they are created (the highest priority processes in a system still get access to the processor first). Each process is given a time slice in which to run. If the process completes or uses up the allotted time in the slice, it is moved to the back of its queue.
Each schedulable process is initially given the same priority in the system by the scheduler and placed in a multi-level feedback queue. Processes that are compute bound have their priorities bumped down over time, and processes that are I/O bound have their priorities bumped up over time. Highest priority processes get access to the processor first.
The system designer uses the Algorithm property to specify the scheduling algorithm for a system of schedulable processes contending for the processor resource at run-time. The UniCon compiler generates an initialization program for the processor associated with the RTScheduler connector that sets the scheduling algorithm in the kernel to the one selected by the system designer. The UniCon compiler also generates a Unix shell script that initializes a real-time application at run-time. This shell script executes the scheduling algorithm initialization program prior to starting up the executables in the application system.

If the Algorithm property in an RTScheduler connector instantiation specifies the rate_monotonic scheduling algorithm, the UniCon compiler can facilitate a Rate Monotonic Analysis (RMA) on the events described by the Trace properties in that connector instantiation (see the Description for the Trace property for more information on events). For a RMA, the UniCon compiler collects the segment names, their execution times, and the period information for each event associated with a given processor; it also collects the priority information for each schedulable process associated with that same processor. It then formats this information and prepares a file containing input to a RMA tool which performs the analysis. This tool is invoked manually and reports a simple answer to indicate whether or not all of the events will meet their respective deadlines. The file that UniCon prepares with the input to the RMA tool is named RMA_<processor_name>, where <processor_name> is taken from the Processor property associated with the RTScheduler connector instantiation in which the Trace properties are specified. An RMA input file is generated by the UniCon compiler for each RTScheduler connector instantiation whose Algorithm property specifies a rate_monotonic scheduler.

Property Lists

The Algorithm property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of an Algorithm property is one of the six keywords rate_monotonic, deadline_monotonic, earliest_deadline_first, fifo_fixed_priority, round_robin_fixed_priority, or timesharing, optionally enclosed in double-quotes, surrounded by parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the Algorithm property is rate_monotonic.

Merge Rule

REPLACE

Subsequent specifications of the Algorithm property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The value of the Algorithm property must be one of the following six values: rate_monotonic, deadline_monotonic, earliest_deadline_first, fifo_fixed_priority, round_robin_fixed_priority, or timesharing.

Example

The following is an example of an Algorithm property. It is embedded in an
<establish> of an RTScheduler connector:

  ESTABLISH RTM-RealTime-Sched WITH
client.load AS load
server.load AS load
PROCESSOR (TESTBED.XX.CMU.EDU)
ALGORITHM (rate_monotonic)
TRACE (client.load.trigger,
client.load.segment1,
server.load.segment,
client.load.segment2)
END RTM-RealTime-Sched

BuildOption

Description

The BuildOption property is used to further specify a variant definition in the primitive implementation of a UniCon component. It is used to pass Odin system construction instructions to the system build phase of the UniCon compilation process. The system construction instructions get applied to the construction of the external source file specified in the variant. For example, if the default Odin C language compiler is "cc" and the system designer desires "gcc" for compilation of a given source file, the BuildOption property can be used to pass the "+gnu" Odin option to the construction of that source file.

Property Lists

The BuildOption property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value part of the BuildOption property is a comma-separated list of items that are either "string"s or <identifier>s, enclosed in parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

There is no default value for the BuildOption property.

Merge Rule

MERGE

More than one specification of the BuildOption property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

No semantic checks are performed on the value of the BuildOption property.

Example

The following are two examples of specifications of BuildOption properties. Both examples are equivalent; they are examples of how you would pass two compiler options to Odin for a particular source file during the system build phase of compilation:

  VARIANT My_Stack IN "stack.c"
IMPLTYPE (Source)
BUILDOPTION ("+define=DEBUG_ENABLE")
BUILDOPTION ("+gnu") /* specifies "gcc" */
END My_Stack
An alternative, yet equivalent definition:

  VARIANT My_Stack IN "stack.c"
IMPLTYPE (Source)
BUILDOPTION ("+define=DEBUG_ENABLE", "+gnu")
END My_Stack

EntryPoint

Description

The EntryPoint property is used to further specify a Computation, Module, Process, or SchedProcess component. It is typically used to specify an instantiation of such a component, but it can also be used to specify a definition.

The value of the EntryPoint property is the name of the entrypoint in the implementation that is to receive control at run-time after initialization of the process containing the source code is completed. For example, in UniCon the system designer must implement a Process component as a function or a collection of functions in some programming language (e.g., the C language). UniCon generates the main program that initializes the Process component at run-time and then transfers control to the function specified in the EntryPoint property.

For Computation and Module components, UniCon ignores the EntryPoint property for now. This is because Unix processes generated from Module or Computation components need no additional run-time initialization, and therefore UniCon does not need to produce a main program for them. For these components, the entrypoint is assumed to be "main" for now, since UniCon only handles implementations in the C language to date.

For Process and SchedProcess components, the value of the EntryPoint property has a different set of semantics for client processes and server processes. In UniCon, a process is a client process if it makes remote routine calls and does not export remote routine definitions (services) to be called. A process is a server process if it exports remote routine definitions. Processes not involved in remote procedure calls have the same semantics as client processes.

For client processes, the value of the EntryPoint property must name the function that will get control once the main program generated by the UniCon compiler to initialize the Unix process at run-time finishes its initialization. The name supplied as the entrypoint can be "main," but the UniCon compiler will rename this to some generated name when building the code for the process. This is because the main program it generates to do the initialization must be named "main."

For server processes, the value of the EntryPoint property must name a "worker function" that performs application-specific work not directly related to the task of servicing requests from clients. For server processes, the UniCon compiler generates a "main" program for initialization, and it also generates a function that polls for messages from clients and calls the appropriate functions that provide requested services. This polling function gets control from the "main" program after initialization and does not return. The function named by the value of the EntryPoint property will be invoked to perform work in parallel with the polling function.

In the Mach and Real-Time Mach environments, the worker function is turned into a light-weight process that runs in parallel with the light-weight process that polls for service requests. In these environments, the function must be designed so that it never returns. If it does, then the light-weight process will never be rescheduled to run. In environments that support RPCGen such as SunOS, the function is called periodically from the heavyweight process that polls for the service requests. The worker function is called after each service request, and once every 10 milliseconds when no service requests are made. In this environment, the worker function must be designed to return. If it does not, then the polling function will never regain control and the server will appear to "hang."

Property Lists

The EntryPoint property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the EntryPoint property is a single "string" or
<identifier>, enclosed in parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the EntryPoint property for Process and SchedProcess client components is "main." Client also refers to a component that does not make RPCs.

There is no default value for the EntryPoint property for Process and SchedProcess server components.

There is no default value for the EntryPoint property for Module and Computation components.

Merge Rule

REPLACE

Subsequent specifications of the EntryPoint property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

All source files implementing the Process or SchedProcess component are scanned for a C language function definition of the name specified in the EntryPoint property. Case is significant in this check. If the name is not found, an error is reported to the system designer. In the case of a client Process or SchedProcess where no EntryPoint property is specified, the source is scanned for the name "main."

If an EntryPoint property is specified, but none of the files implementing the component are source files, then the check is abandoned. In this case, the UniCon compiler will attempt to build the executable for the process, but no guarantees are made about the viability of such an executable at run-time.

Example

The following is an example of a specification of an EntryPoint property. It is embedded in the instantiation of a client SchedProcess component in some real-time system:

  USES Client INTERFACE RT_Client
PRIORITY (10)
ENTRYPOINT (client)
END Client

IDLType

Description

The IDLType property is used to further specify a RemoteProcCall connector. It is typically used to specify an instantiation of such a connector, but it can also be used to specify a definition.When left out of the definition, the connector is more general and can be parameterized at instantiation time with this property.

A RemoteProcCall connector governs the interaction between SchedProcess or Process components performing remote procedure calls. The realization of this connector in the system at run-time is usually some message passing mechanism.

UniCon supports two different models of communication for RPC connections: the Mach InterProcess Communication (IPC) facility and the RPCGen remote procedure call facility. Both models use message passing as the underlying mechanism for transmitting data between processes.

Both of these models of communication are nearly identical. Both have a specification language in which the services exported by a server process are specified. Both have a compiler for the specification language that compiles the specifications of the services into "glue code." The glue code gets compiled and linked into both client and server processes; it facilitates the creation, passing, and decoding of messages using the arguments and return values of the routine calls. Lastly, both models make use of a "name server" in the run-time environment. The name server is an independent process running on the target machine that facilitates the message passing between clients and servers. Servers register their services with the name server, and clients use the name server to "look up" the services they need.

The system designer uses the IDLType property to specify the underlying model of communication for each RPC connection. For the Mach IPC facility, the system designer specifies "mach" as the value in the IDLType property. For the RPCGen facility, the designer specifies "rpcl":

Mach IPC facility
RPCGen RPC facility
The Mach IPC facility should only be chosen if the Process or SchedProcess components involved in the remote procedure call are targetted for a Mach or Real-Time Mach environment, respectively. The RPCGen facility can be used when the components are targetted for an operating system that supports RPCGen, such as SunOS.

Property Lists

The IDLType property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of an IDLType property is one of the two keywords rpcl or mach, optionally enclosed in double-quotes, surrounded by parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the IDLType property is rpcl.

Merge Rule

ERROR

Subsequent specifications of the IDLType property in a single property list are reported as errors. The UniCon compiler uses the first of the duplicate IDLType properties it encounters.

Semantic Checks

The value of the IDLType property must be one of the following two values: rpcl or mach.

Example

The following is an example of an IDLType property. It is embedded in an <establish> of a RemoteProcCall connector:

  ESTABLISH RTM-RemoteProc-Call WITH
client.timeget AS caller
server.timeget AS definer
IDLTYPE (mach)
END RTM-RemoteProc-Call

ImplType

Description

The ImplType property is used to further specify a variant definition in the primitive implementation of a UniCon component. It is used to describe the form of the contents of the external source file in a <variant> definition. The external source file is specified in double-quotes after the word IN in the <variant> definition. The UniCon compiler generates the appropriate Odin system construction instructions for the external source file based on its implementation type (i.e., ImplType).

For example, if the file is a Source file, the UniCon compiler assumes it contains source code in a conventional programming language and instructs Odin to compile it with the appropriate programming language compiler. If it is Object code, the UniCon compiler instructs Odin to simply link it with the other code into the executable that it is building. If the external source file is an executable, the UniCon compiler generates no construction instructions, since it has already been built.

The following forms of external source are recognized in UniCon:

source code in a conventional programming language - it gets compiled with the appropriate programming language compiler, and linked with other source into an executable
object code - it gets linked with other source into an executable
a Unix archive file containing object code - it gets linked with other source into an executable
a C language include file - no further construction is necessary
a binary executable - no further construction is necessary
a sequential file containing ASCII data - no further construction is necessary
a file containing a specification of remote routine definitions exported by a server process in the IDL-like language of a particular RPC facility - the appropriate RPC facility's IDL compiler is used to generate the glue code for client and server processes, and then this code gets compiled and linked with other source into the executables for these processes

Property Lists

The ImplType property can legally be specified in the property list in the following UniCon language element:

Value Syntax

The syntax of the value part of an ImplType property is one of the seven keywords source, object, objectlibrary, executable, include, data or mig, optionally enclosed in double-quotes, surrounded by parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the ImplType property is "source".

Merge Rule

REPLACE

Subsequent specifications of the ImplType property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the ImplType property:

  1. The value of the ImplType property must be one of the following seven keywords: source, object, objectlibrary, executable, include, data, or mig.
  2. If the value of the ImplType property is object, the file name in the IN clause of the variant must have a ".o" extension.
  3. If the file name in the IN clause of the variant has a ".o" extension, the value of the ImplType must be object.
  4. If the value of the ImplType property is objectlibrary, the file name in the IN clause of the variant must have a ".a" extension.
  5. If the file name in the IN clause of the variant has a ".a" extension, the value of the ImplType must be objectlibrary.
  6. If the value of the ImplType property is mig, the file name in the IN clause of the variant must have a ".defs" extension.
  7. If the file name in the IN clause of the variant has a ".defs" extension, the value of the ImplType must be mig.

Example

The following are three examples of specifications of an ImplType property. The examples show that the value of the ImplType property corresponds to the extension in the name of the file in the variant:

  VARIANT My_Stack IN "stack.c"
IMPLTYPE (Source)
END My_Stack VARIANT My_Stack IN "stack.o"
IMPLTYPE (Object)
END My_Stack VARIANT My_Stack IN "stack.a"
IMPLTYPE (ObjectLibrary)
END My_Stack

InitActuals

Description

The InitActuals property is used to further specify the implementation of a UniCon component. It is used to pass command line options to executable versions of programs when they are started at run-time. The typical usage of the property is to pass options to filters during pipe-and-filter system initialization at run-time.

Only one InitActuals property is accepted by the UniCon compiler for a given executable. Therefore, if an InitActuals property is specified in both the <component_implementation> and the <variant> property lists in the primitive implementation of a component, the UniCon compiler accepts only the one in the <component_implementation> property list.

The InitActuals property is typically specified in the <component_implementation> property list when the component has a composite implementation. It is otherwise generally found in the <variant> property list.

Property Lists

The InitActuals property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the InitActuals property is a single "string" or
<identifier>, enclosed in parentheses. The case of the letters is significant. The command line options are passed unchanged to the associated executable program in the run-time environment.

Required Rule

Optional

There is no default value for the InitActuals property.

Merge Rule

REPLACE

Subsequent specifications of the InitActuals property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

No semantic checks are performed on the value of the InitActuals property.

Example

The following are two examples of specifications of InitActuals properties. The first example is embedded in the property list of a <variant> definition:

  VARIANT My_Sort_Filter IN "sort"
IMPLTYPE (Executable)
INITACTUALS ("-f")
END My_Sort_Filter
The second example is embedded in the <component_implementation> property list of a composite implementation:

  IMPLEMENTATION IS
INITACTUALS ("-f")

USES main INTERFACE Sort_Main
USES sort INTERFACE Sort
USES libc INTERFACE Libc

BIND input TO ABSTRACTION
MAPSTO (main.libc.fgets)
END input
BIND output TO ABSTRACTION
MAPSTO (main.libc.fprintf)
END output

ESTABLISH C-PLBundler WITH
main.sort_routines AS participant
sort.sort_routines AS participant
END C-PLBundler

ESTABLISH C-PLBundler WITH
main.libc AS participant
libc.libc AS participant
END C-PLBundler
END IMPLEMENTATION

InitRoutine

Description

The InitRoutine property is used to further specify a Process or SchedProcess component. It is typically used to specify an instantiation of such a component, but it can also be used to specify a definition.

The InitRoutine property is used to specify the entrypoint (i.e., name) of a parameterless function, supplied in the code of the implementation, that will perform application-specific initialization in a process or schedulable process before control is handed from the "main" program to the function(s) implementing the process itself. The UniCon compiler will generate the code to call this routine at the appropriate time before control is handed to the function(s) implementing the process.

If this property is present, a parameterless function call will be generated in the implementation. If no corresponding function definition is supplied, the system construction will fail.

Property Lists

The InitRoutine property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the InitRoutine property is a single <identifier> or "string", enclosed in parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

There is no default value for the InitRoutine property.

Merge Rule

REPLACE

Subsequent specifications of the InitRoutine property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

All source files implementing the Process or SchedProcess component are scanned for a C language function definition of the name specified in the InitRoutine property. Case is significant in this check. If the name is not found, an error is reported to the system designer.

If an InitRoutine property is specified, but none of the files implementing the component are source files, then the check is abandoned. In this case, the UniCon compiler will attempt to build the executable for the process, but no guarantees are made about the viability of such an executable at run-time.

Example

The following is an example of a specification of an InitRoutine property. It is embedded in the instantiation of a client SchedProcess component in some real-time system:

  USES Client INTERFACE RT_Client
PRIORITY (10)
ENTRYPOINT (client)
INITROUTINE (initialize_client)
END Client

InstFormals

Description

The InstFormals property is used to further specify a component or a connector definition in UniCon. This property is used to define UniCon string variables whose scope is the entire component or connector definition. The names of the variables must be unique among all specifications of InstFormals properties in a single property list.

The string variables that are defined with the InstFormals property have no use in a UniCon definition to date. In the future, UniCon may provide a means for obtaining the string values and semantics for using them.

Property Lists

The InstFormals property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the InstFormals property is a comma-separated list of <parameter>s enclosed in parentheses. A <parameter> consists of an
<identifier>, followed by a `=', followed by a <complex string> or the language keyword NODEFAULT. A <complex string> is a simple "string" or a sequence of "string"s concatenated by the `&' character.

Required Rule

Optional

There is no default value for the InstFormals property.

Merge Rule

MERGE

More than one specification of the InstFormals property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

Each variable name (i.e., <identifier>) in the value of the InstFormals property must be unique.

Example

The following is an example of a specification of an InstFormals property. It is embedded in the interface of a Module component:

  INTERFACE IS
TYPE
Module
INSTFORMALS (parameter1 = "my string",
parameter2 = "this string" &
" is broken over a line",
parameter3 = NODEFAULT)
PLAYER timeget IS RoutineCall
SIGNATURE ("new_type"; "void")
END timeget
PLAYER timeshow IS RoutineCall
SIGNATURE (; "void")
END timeshow
END INTERFACE

IOMode

Description

The IOMode property is used to further specify a FileIO connector definition. It specifies the input/output mode of the FileIO connector. Such a connector can be defined for readonly, readwrite, and writeonly interaction between components.

The specification of IOMode in a FileIO connector constrains the types of the roles that can be defined in the connector. Readonly FileIO connectors must define one role each of the types Readee and Reader. Readwrite connectors must define one role each of the following types: Readee, Reader, Writee, and Writer. Writeonly connectors must define one role each of the types Writee and Writer.

WARNING: The IOMode property can be specified in a connector instantiation, but this is not recommended because the role types are fixed in the connector definition, not the instantiation. The UniCon compiler will report the appropriate errors if the IOMode specification in the instantiation does not match the set of role types in the definition.

Property Lists

The IOMode property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the IOMode property is one of the three keywords readonly, readwrite, or writeonly, optionally enclosed in double-quotes, surrounded by parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the IOMode property is readwrite.

Merge Rule

REPLACE

Subsequent specifications of the IOMode property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the IOMode property:

  1. The value part of the IOMode property must be one of the three keywords
    readonly, readwrite, and writeonly.
  2. If the IOMode of the FileIO connector is readonly, then the connector must define exactly two roles: one of type Readee, and the other of type Reader.
  3. If the IOMode of the FileIO connector is readwrite, then the connector must define exactly four roles: one each of the types Readee, Reader, Writee, and Writer.
  4. If the IOMode of the FileIO connector is writeonly, then the connector must define exactly two roles: one of type Writee, and the other of type Writer.

Example

The following is an example of a specification of an IOMode property. It is embedded in the protocol of a FileIO connector:

  CONNECTOR Unix_FileIO
PROTOCOL IS
TYPE
FileIO
IOMODE (readonly)
ROLE Readee IS Readee
ROLE Reader IS Reader
END PROTOCOL
IMPLEMENTATION IS
BUILTIN
END IMPLEMENTATION
END
Unix_FileIO

Library

Description

The Library property is used to further specify Computation, Module, SeqFile, and
SharedData components. Specifying this property sets the value of the MinAssocs property to zero for every RoutineDef, GlobalDataDef, ReadNext, and WriteNext player in these types of components. This effectively allows players of these types to go unconnected in the construction of a composite implementation of a component.

The property may be specified in the definition or instantiation of one of these components, although it makes more sense to further specify a definition of a component - whether or not a collection of routines acts like a library is usually an attribute of the source code implementation that does not change from instantiation to instantiation.

The Library property also instructs UniCon to create a Unix archive file from the constituent source and object files when the property is applied to a component with a composite implementation. This is effectively an intermediate build step, where the UniCon compiler (1) collects the sources and objects that implement the individual components in the configuration in a composite implementation, (2) compiles the sources, and (3) adds all of the objects to a Unix archive file. The UniCon compiler uses the archive file in later parts of the build process and leaves the file around for the system designer as an artifact of the build process.

Property Lists

The Library property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The Library property has no value part.

Required Rule

Optional

There is no default value for the Library property.

Merge Rule

REPLACE

For the Library property, the merge rule has no effect since there is no value part.

Semantic Checks

No semantic checks are performed since the Library property has no value part.

Example

The following is an example of a specification of a Library property. It is embedded in the interface of a Module component:

  INTERFACE IS
TYPE
Module
LIBRARY
PLAYER timeget IS RoutineDef
SIGNATURE ("new_type"; "void")
END timeget
PLAYER timeshow IS RoutineDef
SIGNATURE (; "void")
END timeshow
END INTERFACE

MapsTo

Description

The MapsTo property is used to further specify an abstraction bind in the composite implementation of a component. The value part of the property is a list of dot-separated pairs or triples of <identifier>s that name players in the composite implementation. Identifier pairs name non-PLBundle players in components that have been previously instantiated. Identifier triples name Member players in PLBundle players in previously instantiated components.

The MapsTo property associates the set of internal players specified in its value part to the external player named in the abstraction bind. An external player is a player exposed in the interface of a component, and an internal player is one that is exposed in the interface of another component that has been instantiated inside the implementation of a component. A bind, therefore, maps a player in the interface of a component to one or more players in its composite implementation.

There are two forms of the <bind> statement: the simple bind, and the abstraction bind. When a player in the interface is implemented by a single player in the implementation having the same type, then the system designer uses the simple bind syntax. This form of the bind is a simple aliasing operation.

When the player in the interface is implemented by a collection of players in the implementation, or a single player with a different type, then the system designer uses the abstraction bind syntax. An abstraction bind does not represent a simple aliasing operation. It is an association of players in the implementation to a player in the interface. The list of players in the MapsTo property represents an abstraction of some form. For example, the players may collectively represent some abstract operation as a group - an operation that is accessible via a single player in the interface of the component. In other cases, the player(s) in the MapsTo list may represent a concrete implementation of a more abstract behavior of a player in the interface (i.e., a behavior not directly supported in a given programming language). For example, a stream player in the interface of a Filter component that has a composite implementation may actually be implemented by procedure call players in the implementation (e.g., to routines like fgets or fprintf in the C language). The behavior of a stream in the interface is actually an abstraction implemented by procedure calls in the implementation in this case.

The MapsTo property is required in an abstraction bind. It is an integral part of the specification of the bind itself.

Property Lists

The MapsTo property can legally be specified in the property list in the following UniCon language element:

Value Syntax

The syntax of the value part of the MapsTo property is a semicolon-separated list of dot-separated pairs or triples of <identifier>s, enclosed in parentheses.

Required Rule

Required

Merge Rule

MERGE

More than one specification of the MapsTo property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

The following are the semantic checks performed on the value of the MapsTo property:

  1. The first <identifier> in each dot-separated pair or triple must name a component that has been previously instantiated in the composite implementation.
  2. The second <identifier> in each dot-separated pair or triple must name a player in the interface of the component instantiation named by the first <identifier>.
  3. If an item in the MapsTo list is a triple of <identifier>s, the second <identifier> must name a player of type PLBundle.
  4. If an item in the MapsTo list is a triple of <identifier>s, the third
    <identifier> must name a player in the PLBundle player named by the second <identifier>.

Example

The following are examples of the specification of the MapsTo property. They are embedded in two abstraction bind statements in the composite implementation of a Filter component:

  IMPLEMENTATION IS
USES main INTERFACE Sort_Main
USES sort INTERFACE Sort
USES libc INTERFACE Libc

BIND input TO ABSTRACTION
MAPSTO (main.libc.fgets)
END input
BIND output TO ABSTRACTION
MAPSTO (main.libc.fprintf)
END output

ESTABLISH C-PLBundler WITH
main.sort_routines AS participant
sort.sort_routines AS participant
END C-PLBundler

ESTABLISH C-PLBundler WITH
main.libc AS participant
libc.libc AS participant
END C-PLBundler
END IMPLEMENTATION

Match

Description

The Match property is used to further specify an abstraction bind and an instantiation of a connector of type PLBundler. In both cases it is used to specify pairs of players that get matched up together in the bind, or connection.

The Match property for an abstraction bind is used when the external player is of type PLBundle. Specifying the Match property in any other type of abstraction bind will be reported as an error by the UniCon compiler. This property specifies how the Member players of the PLBundle are matched to the players in the value of the MapsTo property. This matching is necessary because the UniCon compiler must know ultimately how each player in the interface of a component is implemented. This applies to the Member players of external PLBundle players as well. The Match property is used to provide the UniCon compiler with the mapping of the Member players to the MapsTo list entries.

In the abstraction bind, there are two forms of syntax for the value of the Match property. The first form is simply the keyword by_name. This is actually the default value if no Match property is specified. In this case, the UniCon compiler generates a list containing the players in the PLBundle. It then generates a list containing the players in the MapsTo property. If a player in a MapsTo property is a PLBundle, then the Member players are added to the list rather than the player itself. The UniCon compiler then processes the list of players from the MapsTo property. For each of these players, it searches the list of Member players from the external PLBundle player for a matching player (by looking for a name match). If it finds a match, the UniCon compiler attempts to bind the two players. If no match is found, the compiler does not bind them. In both cases, the compiler continues until each player in the MapsTo list has been examined. In the end, if there are any Member players in the external PLBundle that have not been bound, the UniCon compiler will report errors.

The second form of syntax for the value of the Match property for an abstraction bind is a list of relations. A relation is a comma-separated pair of player names. Each pair represents a specific match that the system designer has explicitly specified. The names of the players in each pair need not match. With this form of syntax for the Match property, the UniCon compiler binds each pair of players, regardless of whether or not the player names match. Then, it uses the Match (by_name) algorithm outlined above to form binds from the remaining players not specified in explicit matches.

The Match property for a PLBundler connector instantiation has the same two forms of value syntax as those of the abstraction bind: the value by_name, and a list of relations. The algorithm for matching with relations in a PLBundler connector instantiation is identical to the algorithm for matching with relations in an abstraction bind. The UniCon compiler treats each pair as an attempt at a connection with the appropriate connector type. For example, if a relation specifies a pair of players where one is of type RoutineDef and the other is of type RoutineCall, then the UniCon compiler will attempt to connect them with a ProcedureCall connector. The compiler will report appropriate error messages for any pairs that do not specify well-formed connections. Name mismatches are allowed in relations; the UniCon compiler will fix these mismatches at runtime by renaming both identifiers in the source code to a third, common identifier. This is done using C language macros, specified on the command line with the -D option during the source code compile of each file involved in the connection. When explicit matching using relations is completed, the
UniCon compiler attempts to create matches from the remaining players in the connection using the Match (by_name) algorithm for PLBundler connector instantiations outlined below.

For PLBundler connector instantations, the Match (by_name) algorithm is slightly different than the one for abstraction binds. This is because there may potentially be more than two sets of players involved that get matched one-for-one. There can potentially be many more than two participants in a PLBundler connection. Strewn throughout these participants, for example, may be many calls or uses of a particular routine or global data definition. A match must be made from these mini-sets of players that all share the same name. The algorithm is further compilated by the fact that not all participants in a PLBundler connection are PLBundle players; they can also be GlobalDataDef, GlobalDataUse,
RoutineCall, and RoutineDef players.

The algorithm for matching by name in a PLBundler connector instantiation proceeds as follows. Every Member player of every PLBundle participant, and every other participant in the PLBundler connection, is placed in a list. This list of players is sorted by name. The UniCon compiler then attempts to make a connection from each set of players with the same name from that list. The compiler will report errors associated with malformed connections. For example, each connection must have exactly one definition (i.e., RoutineDef or GlobalDataDef player) and at least one corresponding RoutineCall or GlobalDataUse player. Each set must also exclusively contain players of compatible types; all players must correspond to routine players, or they all must correspond to global data players.

Property Lists

The Match property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the Match property is either the keyword by_name, optionally enclosed in double-quotes, or a comma-separated list of relations, enclosed in parentheses. A relation is a comma-separated pair of player names, enclosed in parentheses. A player name can either be two or three dot-separated <identifier>s. The first
<identifier> names a component instantiation, the second names a player in the component instantiation named by the first, and the third (if present) names a Member in a PLBundle player named by the second.

Required Rule

Optional

The default value of the Match property is the keyword: by_name.

Merge Rule

MERGE

More than one specification of the Match property in a single property list is treated as a single specification with the union of all values in all of the specifications. However, if more than one Match property is specified, they must all have the same value syntax. In other words, they must all have the value by_name, or they must all be lists of relations.

Semantic Checks

The following are the semantic checks performed on the value of the Match property:

  1. If the value of the Match property is not a list of relations, it must be the keyword by_name.
If the value of the Match property is a list of relations, each of the two player names in each relation are subjected to the following semantic checks:

  1. The first <identifier> in each dot-separated pair or triple representing a player name must name a component that has been previously instantiated in the composite implementation.
  2. The second <identifier> in each dot-separated pair or triple must name a player in the interface of the component instantiation named by the first <identifier>.
  3. If an item in the Match list is a triple of <identifier>s, the second <identifier> must name a player of type PLBundle.
  4. If an item in the Match list is a triple of <identifier>s, the third
    <identifier> must name a player in the PLBundle player named by the second <identifier>.

Example

The following are examples of specifications of the Match property. Assume for the first two examples that main.sort_routines is a PLBundle that contains exactly four routine calls that have corresponding routine definitions with the same name in the PLBundle sort.sort_routines.

  ESTABLISH C-PLBundler WITH 
main.sort_routines AS participant
sort.sort_routines AS participant
/* with no Match attribute,
Match (by_name) is assumed */
END C-PLBundler
The following is equivalent to the above example:

  ESTABLISH C-PLBundler WITH 
main.sort_routines AS participant
sort.sort_routines AS participant
MATCH (by_name)
END C-PLBundler
Now, assume that main.sort_routines is a PLBundle player containing the following RoutineCall playerts: bubble, quick, merge, and sort. Also, assume that sort.sort_routines is a PLBundle player containing corresponding RoutineDef players with the following names: bubble_sort, quick_sort, merge_sort, and sort.

  ESTABLISH C-PLBundler WITH 
main.sort_routines AS participant
sort.sort_routines AS participant
MATCH ((main.sort_routines.bubble,
sort.sort_routines.bubble_sort),
(main.sort_routines.quick,
sort.sort_routines.quick_sort),
(main.sort_routines.merge,
sort.sort_routines.merge_sort))
END C-PLBundler
In the above example, the UniCon compiler uses the Match (by_name) algorithm to form a ProcedureCall connection with the sort routines from each PLBundle player.

Lastly, the example below shows the Match property in an abstraction bind. Assume that the component in which this bind is defined has an external PLBundle player named Sort_Bundle. Assume further that this player defines five RoutineDef Member players: bubble, quick, merge, sort, and topological. Assume that the player
utilities.topological is a RoutineDef player.

  BIND Sort_Bundle TO ABSTRACTION
MAPSTO
(sort.sort_routines,
utilities.topological)
MATCH ((Sort_Bundle.bubble,
sort.sort_routines.bubble_sort),
(Sort_Bundle.quick,
sort.sort_routines.quick_sort),
(Sort_Bundle.merge,
sort.sort_routines.merge_sort))
END C-PLBundler
In the above example, the UniCon compiler uses the Match (by_name) algorithm to bind Sort_Bundle.sort to sort.sort_routines.sort, and to bind Sort_Bundle.topological to utilities.topological.

MaxAssocs

Description

The MaxAssocs property is used to further specify a player definition in UniCon. It defines the maximum number of connections in which a player can be involved. To illustrate, a player with a MaxAssocs value of 2 cannot be connected more than two times in a system. This number represents a maximum, not a requirement.

WARNING: In a system described by UniCon, when two players are involved in a bind the external player inherits the number of connections made to an internal player. This may have a bearing on the MaxAssocs value that the system designer chooses for external players in components with composite implementations.

Additionally, the system designer must not choose a MaxAssocs value for an external player which represents an increase in the maximum number of connections to the internal player as specified by its MaxAssocs value. This would defeat the purpose of the
MaxAssocs value of the player to which the external player is ultimately bound - the player corresponding to the source code that implements it in the component with the primitive implementation.

Property Lists

The MaxAssocs property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value of the MaxAssocs property is a simple <integer>.

Required Rule

Optional

Each player type has its own default:

----------------------
Player Type    Default  
----------------------
GlobalDataDef  65535    
GlobalDataUse  1        
PLBundle       65535    
RPCCall        1        
RPCDef         65535    
ReadFile       1        
ReadNext       1        
RoutineCall    1        
RoutineDef     65535    
RTLoad         65535    
StreamIn       1        
StreamOut      1        
WriteFile      1        
WriteNext      1        
----------------------

Merge Rule

REPLACE

Subsequent specifications of the MaxAssocs property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the MaxAssocs property:

  1. The value of the MaxAssocs property may not be negative.
  2. The value of the MaxAssocs property cannot exceed the maximum size of an integer in the UniCon language; that value is 65535.
  3. The value of the MaxAssocs property must be at least as large as the value of a player's MinAssocs value.

Example

The following is an example of a specification of a MaxAssocs property. It is embedded in a player definition of type RoutineCall:

  PLAYER heap_sort IS RoutineCall
SIGNATURE ("int *"; "int *")
MAXASSOCS (1)
END heap_sort
The above example prevents the heap_sort RoutineCall player from being connected more than once per instantiation of the component in which it is defined.

MaxConns

Description

The MaxConns property is used to further specify a role definition in UniCon. It defines the maximum number of connections in which a role can be involved. To illustrate, a role with a MaxConns value of 2 cannot be associated with more than two players in a connection in a system. This number represents a maximum, not a requirement.

Property Lists

The MaxConns property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value of the MaxConns property is a simple <integer>.

Required Rule

Optional

Each role type has its own default:

--------------------
Role Type    Default  
--------------------
Caller       65535    
Definer      1        
Load         65535    
Participant  65535    
Readee       1        
Reader       65535    
Sink         1        
Source       1        
User         65535    
Writee       1        
Writer       65535    
--------------------

Merge Rule

REPLACE

Subsequent specifications of the MaxConns property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the MaxConns property:

  1. The value of the MaxConns property may not be negative.
  2. The value of the MaxConns property cannot exceed its default value as specified in the table above.
  3. The value of the MaxConns property must be at least as large as the value of a player's MinConns value.

Example

The following is an example of a specification of a MaxConns property. It is embedded in a role definition of type Participant:

  ROLE C-Bundler-Participant IS Participant
MAXCONNS (25)
END C-Bundler-Participant
The above example prevents the C-Bundler-Particpant Participant role from being connected more than twenty-five times per instantiation of the connector in which it is defined.

Member

Description

The Member property is used to further specify a PLBundle player definition. It is used to define players inside the PLBundle. The value associated with this property has three fields, each of which corresponds to a portion of a UniCon player definition. The first field is the player name, the second is the player type, and the third is the player property list.
PLBundle players must contain at least one member player definition, and there is no upper limit imposed for member players in a PLBundle.

The PLBundle player type in UniCon allows the system designer to create a collection of players, to attach significance to a group of routines and data in an architectural description of a system. The name PLBundle denotes a programing language bundle; the bundle may only contain players of types that have corresponding programming language implementations: GlobalDataDef, GlobalDataUse, RoutineCall, and RoutineDef players.

Each Member player in a PLBundle must be unique. In other words, there may not be duplicate member player definitions in a single PLBundle. Two member players are duplicates if the contents of their first fields are identical (the double-quotes are insignificant, so if one is a "string" and one an <identifier> they are identical if the names are the same - case of the letters is significant).

The same player may, however, be defined in multiple different PLBundle players in the same component. In this case, these Member player definitions refer to the same player in the source code implementation, so the specifications of all Member properties pertaining to this player must be identical inside all of the PLBundle players in which they appear.

This feature of the UniCon language allows the set of players in the source code implementation of a component to be grouped into overlapping subsets of players (i.e., via PLBundle player definitions) in the UniCon description of that component. The PLBundle player definitions can then become useful abstractions to the system designer, and a single player can be a member of more than one abstraction. For example, the C standard library contains over 700 players. A UniCon component definition corresponding to this library may export any number of PLBundle and non-PLBundle player definitions. A system designer may choose to define a PLBundle player for all input/output operations, for example, and another one for only low-level input/output operations. As you can imagine, the write routine definition might exist as a member in both of these bundles.

Property Lists

The Member property can legally be specified in the property list in the following UniCon language element:

Value Syntax

The syntax of the value part of the Member property consists of a sequence of three fields, separated by semicolons, enclosed in parentheses. The first and second fields consist of a single <identifier> or "string". The third field is a property list, containing properties that are separated by whitespace.

Required Rule

Required

At least one Member property specification must be present in a UniCon definition of a PLBundle player.

Merge Rule

ERROR

The merge rule value for a given property tells the UniCon compiler what to do when a duplicate specification of that property occurs in the same property list. Usually a duplicate constitutes another property specification with the same name part. For example, any two specifications of the MaxAssocs property in the same property list, regardless of the specific contents of their respective value parts, are considered duplicates. For the Member property, a specification is not a duplicate unless the value part is equivalent to the value part of a previously specified Member property. More specifically, two Member properties are duplicates if the first field in each is the same. The case of the letters in this check is significant, but the presence or absence of double-quotes is not.

Subsequent duplicate specifications of the Member property in a single property list are reported as errors. The UniCon compiler uses the first of the duplicate Member properties it encounters.

Semantic Checks

The following are the semantic checks performed on the value of the Member property:

  1. Nested Member properties are not permitted in a UniCon PLBundle player definition. Therefore, the Member property is not permitted in the property list of another Member property.
  2. The second field of the Member property specifies the type of the Member player. There are only four legal player types for a Member player definition: GlobalDataDef, GlobalDataUse, RoutineCall, and RoutineDef.
  3. Duplicate Member player definitions in a single PLBundle player are illegal. Member player definitions are duplicates if the first field (i.e., the player name) is the same in each. See the discussion above in the Merge Rule section for more details.
All of the standard checks for UniCon player definitions are applied to a Member player definition:

  1. The player type must be a valid player type.
  2. The properties in the Member property list must be legal for a player of the given type.
  3. The values of the properties in the Member property list must have legal syntax for a player of the given type.
  4. The value of the properties in the Member property list must adhere to the semantics defined for the given property in a player of the given type.
  5. All required properties for a player of the given type must be present.
  6. The MinAssocs value must not be greater than the MaxAssocs value for the Member player.

Example

The following is an example of some specifications of the Member property. They are all embedded in the definition of a PLBundle player:

  PLAYER Sort_Bundle IS PLBundle
MEMBER (bubble; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
MEMBER (quick; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
MEMBER (merge; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
MEMBER (sort; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
MEMBER (topological; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
END Sort_Bundle
In the example above, each Member property defines a Member player in the PLBundle player. Each Member player is of type RoutineDef, and each is further specified by
Signature and MinAssocs properties. The value of zero in the MinAssocs properties means that the Member players do not have to be connected in a system description. Each routine takes as input a pointer to an array of integers, and returns the same. These players describe sort routines for integers.

The PLBundle player below might be defined in the same component. It may contain some of the same Member players defined in other bundles.

  PLAYER Fast_Sort_Bundle IS PLBundle
MEMBER (quick; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
MEMBER (merge; RoutineDef;
SIGNATURE ("int *"; "int *")
MINASSOCS (0))
END Fast_Sort_Bundle

MinAssocs

Description

The MinAssocs property is used to further specify a player definition in UniCon. It defines the minimum number of connections in which a player can be involved. To illustrate, a player with a MinAssocs value of 2 must be connected at least two times in a system. This number represents a minimum, a requirement that the player be connected at least that number of times.

WARNING: In a system described by UniCon, when two players are involved in a bind the external player inherits the number of connections made to an internal player. This may have a bearing on the MinAssocs value that the system designer chooses for external players in components with composite implementations.

Additionally, the system designer must not choose a MinAssocs value for an external player which represents a decrease in the minimum number of connections to the internal player as specified by its MinAssocs value. This would defeat the purpose of the MinAssocs value of the player to which the external player is ultimately bound - the player corresponding to the source code that implements it in the component with the primitive implementation.

Property Lists

The MinAssocs property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value of the MinAssocs property is a simple <integer>.

Required Rule

Optional

Each player type has its own default:

----------------------
Player Type    Default  
----------------------
GlobalDataDef  1        
GlobalDataUse  1        
PLBundle       0        
RPCCall        1        
RPCDef         1        
ReadFile       1        
ReadNext       1        
RoutineCall    1        
RoutineDef     1        
RTLoad         0        
StreamIn       1        
StreamOut      1        
WriteFile      1        
WriteNext      1        
----------------------

Merge Rule

REPLACE

Subsequent specifications of the MinAssocs property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the MinAssocs property:

  1. The value of the MinAssocs property may not be negative.
  2. The value of the MinAssocs property cannot be less than the minimum size of an integer in the UniCon language; that value is 0.
  3. The value of the MinAssocs property must not exceed the value of a player's MaxAssocs value.

Example

The following is an example of a specification of a MinAssocs property. It is embedded in a player definition of type RoutineDef:

  PLAYER heap_sort IS RoutineDef
SIGNATURE ("int *"; "int *")
MINASSOCS (0)
END heap_sort
The above example allows the heap_sort RoutineDef player to be left unconnected in a system.

MinConns

Description

The MinConns property is used to further specify a role definition in UniCon. It defines the minimum number of connections in which a role must be involved. To illustrate, a role with a MinConns value of 2 must be associated with at least two players in a connection in a system. This number represents a minimum, a requirement that the role be connected at least that number of times.

Property Lists

The MinConns property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value of the MinConns property is a simple <integer>.

Required Rule

Optional

Each role type has its own default:

--------------------
Role Type    Default  
--------------------
Caller       1        
Definer      1        
Load         1        
Participant  2        
Readee       1        
Reader       1        
Sink         1        
Source       1        
User         1        
Writee       1        
Writer       1        
--------------------

Merge Rule

REPLACE

Subsequent specifications of the MinConns property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the MinConns property:

  1. The value of the MinConns property may not be negative.
  2. The value of the MinConns property cannot be less than its default value as specified in the table above.
  3. The value of the MinConns property must not exceed the value of a role's
    MaxConns value.

Example

The following is an example of a specification of a MinConns property. It is embedded in a role definition of type Participant:

  ROLE C-Bundler-Participant IS Participant
MINCONNS (4)
END C-Bundler-Participant
The above example requires the C-Bundler-Particpant Participant role to be associated with at least four players per instantiation of the connector in which it is defined.

OpenMode

Description

The OpenMode property is used to further specify a SeqFile component in UniCon. It specifies Unix file options to be supplied when the associated sequential file in the implementation is opened in the file system. There are three options that can be specified: append, create, and truncate. These options correspond to the three Unix open mode flags O_APPEND, O_CREAT, and O_TRUNC.

A file opened with O_APPEND causes the current file offset to be initialized to the number of bytes from the beginning of the file. Normally, when a file is opened, the current offset is initialized to zero. Reading and writing normally start at the current file offset and the offset is incremented by the number of bytes read or written. A file opened with O_TRUNC causes the contents of the file to be deleted when it is opened. A file opened with O_CREAT is created if it does not exist in the file system at the time it is opened.

The OpenMode property can be specified in both a component instantiation and a component definition. The set of values for any OpenMode properties in a SeqFile component definition are merged with the values in the OpenMode properties in instantiations of the component. This merged set is then used as the set of open mode options for the file when it is opened in the system during execution.

Property Lists

The OpenMode property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the OpenMode property is one of the three keywords append, create, or truncate, optionally enclosed in double-quotes, surrounded by parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

There is no default value for the OpenMode property. If the property is not specified, none of the three open mode options are supplied as parameters during the open.

Merge Rule

MERGE

More than one specification of the OpenMode property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

The value part of the OpenMode property must be one of the three keywords append,
create, and truncate.

Example

The following is an example of a specification of an OpenMode property. It is embedded in the interface of a SeqFile component definition:

  COMPONENT Data_File
INTERFACE IS
TYPE
SeqFile
OPENMODE (create)
RECORDFORMAT ("line")
PLAYER Next_Line IS ReadNext
END INTERFACE
IMPLEMENTATION IS
VARIANT
Data_File IN "datafile"
IMPLTYPE (Data)
END Data_File
END IMPLEMENTATION
END
Data_File
Below is another example of a specification of an OpenMode property. It is embedded in an instantiation of the above SeqFile component:

  USES My_Data_File INTERFACE Data_File
OPENMODE (truncate)
END My_Data_File
The OpenMode value for the My_Data_File SeqFile instantiation is create and truncate.

PipeType

Description

The PipeType property is used to further specify a Pipe connector in UniCon. It specifies the underlying mechanism that the UniCon compiler uses to implement the associated pipe in the system at run-time. There are two implementation mechanisms that the UniCon compiler can choose from. One is a nameless buffer inside the Unix kernel that is allocated with a call to the standard C library function pipe. The system designer selects this mechanism with the value unnamed in the PipeType property. The other mechanism is a fifo file, allocated with a call to either of the two routines mknod or mkfifo. The system designer selects this mechanism with the value named in the PipeType property.

Both an unnamed pipe buffer and a fifo file exhibit nearly identical behavior. They both are opened simultaneously for reading and writing. Both buffers are circular; when reading or writing beyond the end of the buffer, the read or write buffer pointer is reset to the beginning of the buffer and I/O continues if there is room left (when writing) or data left (when reading). Data is written to the buffer sequentially, and placed in the buffer immediately after previously written bytes. The write buffer pointer is advanced after each byte that is written. Data is read from the buffer sequentially, and the read buffer pointer is advanced after each byte that is read. Reader processes are suspended when there is no more data to be read from the buffer (i.e., both the read and write buffer pointers are in the same position in the buffer). The processes are resumed when data is written to the buffer. Writer processes are suspended when the buffer becomes full. The processes are resumed when data is read from the buffer. If all writer processes close their end of the buffer, the reader processes get the value EOF (end-of-file) during their next read operations. If all reader processes close their end of the buffer, the writer processes receive the SIGPIPE signal from the Unix operating system.

There are two main differences between the two mechanisms. The first is the size of the buffer. An unnamed pipe buffer in the Unix kernel ranges between 4K and 8K bytes, depending on the particular version of Unix. A fifo file is a named file in the file system, and therefore it has nearly unlimited size. Size is the distinctive characteristic for selecting a particular PipeType value. The second main difference is the way that the buffers are created. An unnamed buffer is created with the pipe function in the C standard library. Two file descriptors are returned to the application as a result of the call; they are both open - one for reading and one for writing. A named fifo file is created in the file system with either the mknod or mkfifo function in the C standard library (most Unix systems have the mknod function; only a few have the mkfifo function - the usage of both functions is nearly identical). Once the fifo file is created, it must be opened manually (i.e., using the open function in the C standard library) by both the reader processes and the writer processes. All reader processes will be suspended until at least one process opens the fifo file for writing, and vice versa.

Property Lists

The PipeType property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the PipeType property is one of the two keywords named or unnamed, optionally enclosed in double-quotes, surrounded by parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the PipeType property is named.

Merge Rule

REPLACE

Subsequent specifications of the PipeType property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The value part of the PipeType property must be one of the two keywords named and unnamed.

Example

The following is an example of a specification of a PipeType property. It is embedded in the protocol of a Pipe connector definition:

  CONNECTOR Unix_Pipe
PROTOCOL IS
TYPE
Pipe
PIPETYPE (unnamed)
ROLE Source IS Source
ROLE Sink IS Sink
END PROTOCOL
IMPLEMENTATION IS
BUILTIN
END IMPLEMENTATION
END
Unix_Pipe
Below is another example of a specification of a PipeType property. It is embedded in an instantiation of the above Pipe connector:

  USES My_Pipe PROTOCOL Unix_Pipe
PIPETYPE (named)
END My_Pipe
The PipeType value named in the My_Pipe Pipe instantiation overrides the PipeType value unnamed in the Unix_Pipe Pipe definition.

PortBinding

Description

The PortBinding property is used to further specify a StreamIn or StreamOut player in
UniCon.

In a Unix process, input and output is accomplished through ports. There are typically 64 ports in a Unix process, although there may be more depending upon the version of Unix. A port is represented as an integer value (the values are zero based, ranging between 0 and 63) in the source code of the process, and this value is referred to as a file descriptor.

Unix filter processes perform input and output in streams, using designated ports. The ports for streams in a Unix filter are half-duplex (when hooked to named or unnamed pipes) so a filter usually performs input and output on separate ports. The choice of port numbers is a significant part of the design of a given filter; the choices are not made randomly. Most Unix filters perform input from port 0, and output to port 1. Error messages are written using port 2. These choices are a well-known convention among Unix developers. This design allows for filters to be easily composed with pipes on the Unix command line into larger, more complex tools, that are themselves filters.

In the UniCon language, the description of a StreamIn or StreamOut player captures the system designer's intentions regarding particular streams of data in a filter process. Information such as the structure of the data in the stream and the port number over which the stream of data will flow is captured for each player. The PortBinding property is used to specify the port number over which the data in the stream will flow. This property is required in the property list of a StreamIn and StreamOut player.

Property Lists

The PortBinding property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value part of the PortBinding property is either a non-negative
<integer> enclosed in parentheses, or one of the three keywords stdin, stdout, and stderr, optionally enclosed in double-quotes, enclosed in parentheses. The case of the letters in the keywords can be upper, lower, or mixed.

Required Rule

Required

Merge Rule

REPLACE

Subsequent specifications of the PortBinding property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The value part of the PortBinding property must be a non-negative <integer> or one of the three keywords stdin, stdout, and stderr.

Example

The following are examples of specifications of PortBinding properties. They are embedded in the player definitions in a Filter component definition:

  COMPONENT Sort
INTERFACE IS
TYPE
Filter
PLAYER input IS StreamIn
SIGNATURE ("line")
PORTBINDING (stdin)
END input
PLAYER output IS StreamOut
SIGNATURE ("line")
PORTBINDING (1)
END output
PLAYER error IS StreamOut
SIGNATURE ("line")
PORTBINDING ("stderr")
END error
END INTERFACE
IMPLEMENTATION IS
VARIANT
sort IN "sort"
IMPLTYPE (Executable)
END sort
END IMPLEMENTATION
END
Sort

Priority

Description

The Priority property is used to further specify a SchedProcess component definition or instantiation in UniCon. It is used to assign a priority to a schedulable process.

Real-time applications are cyclic in nature, and usually consist of processes that must execute well-defined chunks of work at specific rates. These chunks of work usually have strict deadlines to meet within the period of the process, meaning that each process requires a certain amount of the processor resource during its period. The requirements for each schedulable process can come into conflict with each other when system designers try to schedule a set of such processes to run on a single processor. Therefore, the system of processes must be designed carefully so that each schedulable process in the application gets the right amount of processor resource during its period. When designing such an application, the system designer must pay strict attention to the amount of execution time required by each process and the rate at which each process gets reactivated. These design points are made explicit in UniCon definitions of SchedProcess components (the SegmentDef property provides the system designer with the means to specify the amount of execution time required by the schedulable process, and the TriggerDef property provides the system designer with the means to specify the rate at which a schedulable process component gets reactivated).

The system designer must also take into account the available scheduling algorithms for a processor in the real-time environment when designing a system (the Algorithm property, specified in the definition or instantiation of an RTScheduler connector, provides the system designer with the means for specifying the particular real-time scheduling algorithm in
UniCon). Each available algorithm places a set of requirements on the schedulable processes. Some algorithms, for example, require that each schedulable process execute with a particular priority at run-time. For example, in the Real-Time Mach operating system, the rate monotonic scheduling algorithm gives the highest priority process that is ready for execution access to the processor resource immediately. For this algorithm to work properly, the schedulable processes in the system must be given priorities in accordance with their rates of execution. Processes with faster rates receive higher priorities.

The Priority property provides the system designer with the means for specifying the priority at which the schedulable process will execute in the environment at run-time. The value of the property is a non-negative <integer> in the range from 0 to 31. This range reflects the legal set of priorities that a process can have in the Real-Time Mach operating system.

Property Lists

The Priority property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the Priority property is a non-negative <integer> in the range 0 to 31 (highest to lowest).

Required Rule

Optional

The default value for the Priority property is the highest priority, 0.

Merge Rule

REPLACE

Subsequent specifications of the Priority property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The value part of the Priority property must be a non-negative <integer> in the range from 0 to 31.

Example

The following is an example of a specification of a Priority property. It is embedded in the interface of a SchedProcess component definition (e.g., named RT_Client):

  INTERFACE IS
TYPE
SchedProcess
PRIORITY (3)
PROCESSOR ("TESTBED.XX.CMU.EDU")
TRIGGERDEF (external_interrupt1; 1.0)
TRIGGERDEF (external_interrupt2; 0.5)
SEGMENTDEF (work_block1; 0.02)
SEGMENTDEF (work_block2; 0.03)
SEGMENTDEF (work_block3; 0.05)
PLAYER timeget IS RPCCall
SIGNATURE ("new_type *"; "void")
END timeget
PLAYER timeshow IS RPCCall
SIGNATURE ("void"; "void")
END timeshow
END INTERFACE
Below is another example of a specification of a Priority property. It is embedded in an instantiation of the above SchedProcess component:

  USES Client INTERFACE RT_Client
PRIORITY (2)
ENTRYPOINT (client)
END Client
The Priority value 2 in the Client SchedProcess instantiation overrides the Priority value 3 in the RT_Client SchedProcess definition.

Processor

Description

The Processor property is used to further specify component definitions or instantiations of all types in UniCon. It is used to assign a component to a particular processor in the execution environment. It is also used to further specify the definition or instantiation of an RTScheduler connector. It is used to assign all of the SchedProcess components in the connection to a particular processor in the execution environment.

Although the Processor property can be specified in a component or (RTScheduler) connector definition, it is typically specified in the instantiation. This makes the definition more general and, therefore, parameterizable at instantiation time.

The UniCon compiler also uses the value of the Processor property to determine the correct processor on which to build an application executable in the environment. Components designated for a particular processor are built on that processor. UniCon uses the "rsh" remote shell command in Unix to remotely execute the Odin construction utility to build the binary executable associated with a given component.

Property Lists

The Processor property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the Processor property is a "string" or <identifier> enclosed in parentheses.

Required Rule

Optional

The default value for the Processor property is the processor on which the UniCon compiler is analyzing and building the system from the set of UniCon definitions.

Merge Rule

REPLACE

Subsequent specifications of the Processor property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

No semantic checks are performed on the value of the Processor property.

Example

The following is an example of a specification of a Processor property. It is embedded in the instantiation of an RTScheduler connector instantiation:

  ESTABLISH RTM-RealTime-Sched WITH
client.load AS load
server.load AS load
PROCESSOR (TESTBED.XX.CMU.EDU)
ALGORITHM (rate_monotonic)
TRACE (client.load.trigger,
client.load.segment1,
server.load.segment,
client.load.segment2)
END RTM-RealTime-Sched

RecordFormat

Description

The RecordFormat property is used to further specify SeqFile component definitions or instantiations in UniCon. It is used to specify the structure of the data in the sequential file associated with the SeqFile component.

A sequential file can be viewed as containing "records" of data. A record of data is a block of data that has a specific format (i.e., byte-level organization). For example, a record might have a format that is as simple as a sequence of characters, or it might have a more complex format such as a sequence of data of mixed data types (e.g., "int", "char", "double"). A sequential file can be viewed as being comprised of data in records that have a specific format. The input/output operations on a sequential file operate on the data as records, not individual bytes. The data, as records, have meaning in the application, and therefore records represent an abstraction of the data in the file.

The RecordFormat property is used to capture the organization of data in a sequential file in terms of records with a specific format. This property specifies the system designer's view of the structure of the contents of a sequential file. A specification of the RecordFormat property provides users of a SeqFile component with an indication of how the data in the file should be interpreted or used.

Property Lists

The RecordFormat property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the RecordFormat property is a list of "string"s or <identifier>s, enclosed in parentheses.

Required Rule

Optional

The default value for the RecordFormat property is "line".

Merge Rule

REPLACE

Subsequent specifications of the RecordFormat property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

No semantic checks are performed on the value of the RecordFormat property.

Example

The following is an example of a specification of a RecordFormat property. It is embedded in the interface of a SeqFile component definition:

  INTERFACE IS
TYPE
SeqFile
RECORDFORMAT ("line")
PLAYER read IS ReadNext
PLAYER write IS WriteNext
END INTERFACE
The data type "line" in the RecordFormat property indicates that the sequential file contains records that have the structure of lines (i.e., sequences of characters terminated by a carriage return). Data streams that are read from the file should be read and interpreted as lines, and data streams written to the file should be written as lines. Below is another example:

  INTERFACE IS
TYPE
SeqFile
RECORDFORMAT ("integer", "char", "double")
PLAYER read IS ReadNext
PLAYER write IS WriteNext
END INTERFACE
In the above RecordFormat property, the value contains three data type specifications. This means that the file contains data organized into records, where each record has three members of the given data types. Data streams are read/written from/to the file using this data record format.

Rename

Description

The Rename property is used to resolve name mismatches in ProcedureCall, DataAccess, and RemoteProcCall connections and in simple binds in components with composite implementations.

In a simple bind, the names and the types of the two players involved must be identical, or the UniCon compiler will report these conditions as errors and will not perform the bind. The system designer can use the Rename property in the property list of a simple bind to resolve a name mismatch, however. When the UniCon compiler encounters the Rename property in a simple bind, it allows a name mismatch to be legal in the definition, and it resolves the name mismatch in the source code implementation during the system build. The Rename property is not necessary (and therefore not legal) in the property list of an abstraction bind because name mismatches are resolved by using the Match property.

In ProcedureCall, DataAccess, and RemoteProcCall connections, the names of all players in the connection must be identical. If they are not, the UniCon compiler reports this as an error and does not perform the connection. The system designer can use the Rename property in the property list of a connector instantiation or definition to resolve a name mismatch, however. When the UniCon compiler encounters the Rename property in a
ProcedureCall, DataAccess, or RemoteProcCall connection, it does not report name mismatches as errors, and it resolves the mismatches in the source code implementation of the system. The compiler renames all of the <identifier>s in the implementation that are associated with the players in the connection to a common, generated name. It does this during system construction with C language macros supplied in the compilation step of each source code module involved in the connection (with the -D compiler option). The Rename property is only legal in connectors of type ProcedureCall, DataAccess, and RemoteProcCall.

Although the Rename property can be specified in the <protocol> property list of a connector definition, it is typically specified in the the property list of a connector instantiation (i.e., in the property list of an <establish> or an <instantiation> of a connector). If specified in a connector definition, then every instantiation of that connector will allow name mismatches to be legal. Leaving this property out of a connector definition makes it more general, and it can be parameterized with the property during an instantiation.

Property Lists

The Rename property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The Rename property has no value part.

Required Rule

Optional

There is no default value for the Rename property; it has no value part.

Merge Rule

REPLACE

The merge rule for the Rename property has no effect, since the Rename property has no value part. The UniCon compiler simply views the property has either having been specified or not.

Semantic Checks

No semantic checks are performed; the Rename property has no value part.

Example

The following is an example of a specification of a Rename property. It is embedded in the instantiation of a RemoteProcCall connector. Assume for the sake of the example that client represents a SchedProcess component instantiation containing an RPCCall player named timeget. Assume also that server represents a SchedProcess component instantiation containing the corresponding RPCDef player timeget_routine:

  ESTABLISH RTM-remote-proc-call WITH
client.timeget AS Caller
server.timeget_routine AS Definer
RENAME
IDLTYPE
(mach)
END RTM-remote-proc-call
The UniCon compiler will rename the identifiers timeget and timeget_routine in the implementation to a third, generated identifier. It will also generate the correct "glue code" for the remote procedure call connection and then build the system successfully. The Rename property must be present in order for the UniCon compiler to do the renaming. If it is not present, the compiler will report the name mismatch as an error.

Below is an example of the Rename property embedded in a simple bind. Assume for the sake of the example that this simple bind is contained in the composite implementation of a component that is exporting a RoutineDef player called timeget in the interface. Assume also that in the composite implementation, before this simple bind definition, there is an instantiation of a Module component containing a RoutineDef player called timeget_routine. Assume that the instantiation name of the Module component is clientapp:

  BIND timeget TO clientapp.timeget_routine
RENAME
END timeget The Rename property is required to resolve a name mismatch in a simple bind. If this prop erty were not specified in the example above, the UniCon compiler would report the name mismatch as an error.

RPCTypeDef

Description

The RPCTypeDef property is used to further specify Process and SchedProcess component instantiations and definitions in UniCon. It is used to describe the complex data types of some of the arguments in the signatures of RPCCall and RPCDef players to the underlying RPC facility. These data type descriptions are used in the production of glue code that facilitates message passing between processes.

The UniCon compiler uses a message passing mechanism to implement remote procedure calls (RPCs) in the source code implementation of a system. The compiler makes use of either of two well-known RPC facilities, depending upon the target operating system of the application: the Mach InterProcess Communication (IPC) facility for Mach and Real-Time Mach applications, and the RPCGen-based facility for applications running on Sun platforms.

Implementation of message passing for RPCs requires the production of glue code for both client processes and server processes performing RPCs. A client process is one that makes remote procedure calls, but does not export remote procedure definitions that can be called by other processes. A server process is one that does export remote procedure definitions. Glue code is source code that is not part of the application logic, but is required in a process to facilitate the message passing mechanism of the RPC facility. The glue code gets compiled and linked into both client and server processes that perform RPCs; it facilitates the creation, passing, and decoding of messages constructed from the arguments and return values of the routine calls.

Both RPC facilities mentioned above provide system designers with an IDL-like language to specify remote procedure definitions, which includes the data types of the arguments. These RPC facilities provide compilers for their respective languages that compile an IDL description of a set of services into the glue code needed by both client and server processes. The IDL compilers are not smart enough to be able to support complex data types of RPC arguments that can be constructed in a given programming language. The compilers usually only support simple data types like integers and character strings, and simple array types. Definitions of the complex data types, therefore, must be provided to the RPC facility, and these are usually specified in the IDL-like language in terms of the simple data types and array types.

NOTE: Since data in remote procedure calls is intended to flow between processes, data values cannot be passed by reference in the argument lists of remote routine calls. This is because the address space of a process is distinct, and not visible to another process. The values, therefore, must be passed by copy between processes. The data types of the arguments in the Signature of an RPC must reflect this restriction. Characters strings in the C language, for example, must be passed as arrays of characters, and not as pointers to character strings. Similarly pointers to other types of data are disallowed. This is why most RPC facilities support only simple data types and array types.

The RPCTypeDef property provides the system designer with the means for providing the RPC facility with definitions of the complex data types of arguments in remote procedure definitions. The UniCon compiler constructs the complex data type out of simple data types and array types in the IDL specifications of remote procedure definitions, and then uses these specifications to generate the glue code for a system.

The following is a list of standard data types in the C programming language that are recognized by the IDL compilers of both RPC facilities. If the arguments of the remote procedure calls in an application have the following type names, then no RPCTypeDef properties are necessary. The name of the type and the size (in bytes) of an object of that type are provided for each standard C type:

-----------------
C data type  Size  
-----------------
short        2     
int          4     
long         4     
float        4     
double       8     
char         1     
unsigned     4     
-----------------
The default sizes for the standard C types are the defaults for the "cc" compiler hosted on SunOS 4.1.3 systems. These defaults can be overriden (see below).

Character strings are considered complex data types to most RPC facilities, since they must be passed as arrays of characters (see above). To pass character strings as arguments in remote procedure calls, the application programmer must define complex C language data types representing arrays of the data type char. For example, character strings of length 10 can be defined as follows in an application:

  typedef char string_10_type[10];
To use this data type in an RPC, the system designer must specify an RPCTypeDef property in the property list of an instantiation or definition of the SchedProcess or Process component in which the RPCCall or RPCDef player is defined that uses the data type for one of its arguments. It is recommended that for formal arguments representing variable length character strings in remote routine definitions, a fixed length character array of maximum size be used. The RPC facility only copies character string data until it encounters the null character, so this is not an inefficient way of passing character data.

The value part of the RPCTypeDef property has three fields: the type name, the base type name, and the size, in that order. The type name is the name of the data type as it is defined in the source code implementation of the system. For example, in the Example section below, the name of the type being defined is new_type, which is the name of the type in the typedef in the C source code fragment also shown in the example.

The base type name is the name of the data type upon which the newly defined type is based. For example, if a remote procedure call contains an argument of the type my_integer, which is defined in the C language as follows:

  typedef int my_integer;
then the base type is the C standard type int. The RPCTypeDef property describing my_integer to the RPC facility would appear as follows:

  RPCTYPEDEF (my_integer; int)
The base type name can name a standard C language data type, the type name in another RPCTypeDef property in the same property list, or the keyword struct. Many complex C language data types are defined as structs containing members of other data types. If the base type name is the type name in another RPCTypeDef property, then no size specification is required in the RPCTypeDef property. UniCon uses the size specification from the RPCTypeDef property defining that type. If the base type name is a standard C language data type, no size specification is required either, since the UniCon compiler knows the default size associated with each C type. If the sizes of the standard C language types are different on the target machine for a given application than the defaults, specifying a size in the third field overrides the default that UniCon has for that type. Lastly, if the base type name is struct, then a size specification is required in the RPCTypeDef property. This must represent the size of the struct as given by the sizeof operator in the C programming language. The reason for this is that the sizeof operator takes into account the gaps between members of structs due to the compiler acquiring storage space for struct members on word boundaries.

The third field specifies the size (in bytes) that an object of the given base type name consumes. This field consists of some optional array bounds, followed by a byte size. The array bounds are integers surrounded by square brackets; there can be any number of array bound specifications, from none to an infinite number. Each array bound represents another dimension in the array type being defined, with the rightmost array bound representing the subscript that varies fastest as elements in the array are accessed in storage order. The byte size part of the third field is required, if the third field is non-empty. The byte size represents the size of an array element. If no array bounds are specified, then it represents the true size (in bytes) of on object of the base type.

Property Lists

The RPCTypeDef property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the RPCTypeDef property consists of a sequence of three fields, all separated by semicolons, with the entire sequence enclosed in parentheses. The first and second fields both consist of a single <identifier> or "string". The third field is optional, and consists of a <size item> (if the third field is omitted, the semicolon following the second field is also omitted). A <size item> consists of an optional <array item>, followed by the <size>. An <array item> consists of one or more consecutive <array index>s of the form `[` <integer> `]'. The <size> is simply an <integer>.

Required Rule

Optional

There is no default value for the RPCTypeDef property.

Merge Rule

REPLACE

The merge rule value for a given property tells the UniCon compiler what to do when a duplicate specification of that property occurs in the same property list. Usually a duplicate constitutes another property specification with the same name part. For example, any two specifications of the MaxAssocs property in the same property list, regardless of the specific contents of their respective value parts, are considered duplicates. For the
RPCTypeDef property, a specification is not a duplicate unless the value part is equivalent to the value part of a previously specified RPCTypeDef property. More specifically, two RPCTypeDef properties are duplicates if the first field in each is the same. The case of the letters in this check is significant, but the presence or absence of double-quotes is not.

Subsequent duplicate specifications of the RPCTypeDef property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following semantic checks are performed on the value of the RPCTypeDef property:

  1. The type name and the base type name cannot be identical in the value of a single RPCTypeDef property (i.e., the type name cannot redefine the base type in the same RPCTypeDef property).
  2. The base type name must be the keyword struct, the type name in another
    RPCTypeDef property in the same property list, or one of the following standard C data types: short, int, long, float, double, char, and unsigned.
  3. If the base type name is struct, a <size item> (i.e., the third field) must be specified.
  4. If the third field of the RPCTypeDef value (i.e., the <size item>) is present, the total size must be greater than 0. This means that the <size> part of the <size item> must be greater than 0.

Example

The following are examples of specifications of RPCTypeDef properties. They are embedded in the instantiation of a SchedProcess component:

  USES Server INTERFACE RTServer
PRIORITY (2)
RPCTYPEDEF (new_type; struct; 12)
RPCTYPEDEF (another_type; new_type)
RPCTYPEDEF (an_array_type; char; [12] 25)
RPCTYPESIN ("server_app.h")
END Server
The corresponding type definitions in the file "server_app.h" are as follows:

  typedef struct {
int member1;
short member2;
int member3;
} new_type;

typedef new_type another_type;

typedef char an_array_type[12][25];
On a SunOS 4.1.3 system, the new_type struct takes up 12 bytes of space, so the <size> specification is the <integer> value 12. On a SunOs 4.1.3 system, an int requires 4 bytes of storage space, and a short requires 2 bytes. The reason that the total size is 12 bytes and not 10 is because SunOs always starts new storage allocation on a
4-byte boundary. Therefore, struct member member3 does not start at byte location 6 (relative to the start of storage for the struct, and 0-offset), it starts at location 8.

RPCTypesIn

Description

The RPCTypesIn property is used to further specify Process and SchedProcess component instantiations and definitions in UniCon. It is used to describe the set of files in the file system that contain the source code data type definitions corresponding to the complex data types defined in RPCTypeDef properties in the same component.

The glue code generated to support remote procedure calls between processes (see the Description for the RPCTypeDef property) requires visibility of the type definitions for all the data types of the arguments in the signatures of the remote routine calls and definitions. The UniCon compiler, therefore, must know the location of the actual data type definitions in the source code implementation of a system so that it can pass the information along to the IDL compiler of the appropriate RPC facility in order to generate the glue code. The RPCTypesIn property allows the system designer to specify the names and locations of these files. As with the RPCTypeDef property, the RPCTypesIn property is only necessary if the data types of some of the arguments in the remote routine calls and definitions are complex data types (i.e., data types that are not one of the pre-defined simple C standard data types: short, int, long, float, double, char, and unsigned; character string data types are considered to be complex. See the Description for the RPCTypeDef property for more information).

It is recommended that all complex data type definitions be placed in C language include files, and that these files be included in the source code implementing a Process or
SchedProcess component with the #include C language preprocessor directive. This allows the data type definitions to be easily included in the generated glue code in the same way (the UniCon compiler does the inclusion automatically via the IDL specification of the remote routine definitions).

Each file name in the RPCTypesIn list can either be fully qualified with an absolute or relative path specification, or it may simply be the name of the file. During the semantic checking phase of compilation, the UniCon compiler checks for the existance of each file in the file system. If the file name does not contain path information, the UniCon compiler first looks in the current directory for the file (i.e., the current working directory in the Unix environment in which the system designer invoked the compiler). If the file is not found there, it searches all of the directories specified in the CPATH environment variable for the file. In the Unix environment, the CPATH environment variable can be set as follows:

  setenv CPATH /usr/gz/include:/usr/include:/include
After performing the above command at the Unix shell prompt, the CPATH variable contains a colon-separated list of directory paths. The UniCon compiler searches each directory until it finds the file. It searches the directories from left to right, so in the example above it would first search the directory /usr/gz/include. If the file did not exist there, the compiler would next search the directory /usr/include, and so on. If the UniCon compiler does not find the file in the current directory or in the directories in the CPATH environment variable, it reports an error message stating that the file does not exist.

NOTE: The CPATH environment variable must be set in the Unix environment prior to the invocation of the UniCon compiler.

Lastly, relative path names are interpreted beginning from the current working directory in the Unix environment in which the UniCon compiler is invoked. Relative path names in a UniCon definition are not recommended. The location from which the UniCon compiler is invoked cannot usually be guaranteed from compilation to compilation. Either absolute path names should be specified in the file name, or no path names at all.

Property Lists

The RPCTypesIn property can legally be specified in the property list in the following
UniCon language elements:

Value Syntax

The syntax of the value part of the RPCTypesIn property consists of a list of items that are <identifier>s or "string"s enclosed in parentheses.

Required Rule

Optional

There is no default value for the RPCTypesIn property.

Merge Rule

MERGE

More than one specification of the RPCTypesIn property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

Each element in the list of the RPCTypesIn property represents a file name containing type definitions that implement the complex data types defined in RPCTypeDef properties. The only semantic check made on the value of the RPCTypesIn property is to check that the files associated with the file names in the list exist in the file system.

Example

The following are examples of specifications of RPCTypesIn properties. They are embedded in the instantiation of a SchedProcess component:

  USES Server INTERFACE RTServer
PRIORITY (2)
RPCTYPEDEF (new_type; struct; 12)
RPCTYPEDEF (another_type; new_type)
RPCTYPEDEF (an_array_type; char; [12] 25)
RPCTYPESIN ("server_app1.h")
RPCTYPESIN ("/usr/gz/include/server_app2.h")
END Server

SegmentDef

Description

The SegmentDef property is used to further specify a SchedProcess component definition. It provides the system designer with the means for describing how the source code implementation of a component is decomposed into segments that have associated execution times.

A segment is an abstraction. It describes a chunk of code in the source code implementation of the schedulable process. The chunk of code it describes may take any form that the designer chooses. For example, it may describe a function, a set of functions, a portion of a single function, or even a few statements within a given function. The designer typically defines segments based on structural and execution time properties of the code in order to facilitate certain types of analyses that can be done on sets of schedulable processes in a real-time environment (e.g., a rate monotonic analysis). Segments are defined in the interface property list of SchedProcess components via the SegmentDef property. The value part of the property defines the name of the segment and associates an execution time (in seconds) with it. Work done in a schedulable process is described by a sequence of one or more segments.

Segments usually represent blocks of code in a process between points where flow of control is transferred. For example, a client process initially receives control from the operating system environment. It performs work until control is transferred either back to the operating system or to some server process (via a remote procedure call). A system designer typcally defines the code that executes between these two points as one or more discrete segments. Each of these segments has an associated execution time which is captured in the second field of the SegmentDef property that defines the segment.

Segment names are used in the value part of the SegmentSet property. This property further specifies RTLoad players by indicating which chunks of code get executed as a result of placing the associated real-time load on a processor in the real-time environment at run-time.

Segment names are also used in the value part of the Trace property. This property further specifies RTScheduler connector instantiations by describing traces of events that occur in the system of schedulable processes mediated by the connector. An event is a thread of control in a system of such processes. For example, a client process initially receives control from the operating system. This process performs some work, and it may return or it may make a remote procedure call to another process (a server process). If it makes a remote procedure call, the thread of control is transferred to the server process, which performs some work and returns (or makes another remote procedure call, and so on). Control is eventually returned back to the original client process, where work continues in a similar fashion until control is eventually returned back to the environment. This entire thread of control is called an event in UniCon, and can be described by a trace. A trace is a specification of the event. It specifies the trigger, the mechanism by which control is first given to a client schedulable process from the environment, and the sequence of segments that execute as a result of the trigger in the order in which they are executed.

The execution times associated with segments in a Trace property are used in a rate monotonic analysis (RMA) of the schedulable processes mediated by an RTScheduler connector if the algorithm of choice is the rate monotonic algorithm. The <floating point number> in the value of the SegmentDef property represents the execution time (in milliseconds) of the chunk of code.

Property Lists

The SegmentDef property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax for a SegmentDef property consists of two fields, separated by a semicolon, enclosed in parentheses. The first field is a single <identifier> or "string". The second field is a single <floating point number>.

Required Rule

Optional

There is no default value for the SegmentDef property.

Merge Rule

REPLACE

Subsequent duplicate specifications of the SegmentDef property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses). Two SegmentDef properties are duplicates if the <identifier> or "string" in the first field of both are identical. The case of the letter in the check is significant, however the absence or presence of double-quotes is not.

Semantic Checks

The following semantic checks are performed on the value of the SegmentDef property:

  1. The <floating point number> in the value part of the SegmentDef property must be greater than 0.
  2. A SchedProcess component must specify at least one SegmentDef property in the property list of the <interface> of the component.
  3. At least one segment defined in a SegmentDef property in a SchedProcess component must be referenced in a SegmentSet property in the property list of some RTLoad player in that component.

Example

The following are examples of specifications of SegmentDef properties. They are embedded in the <interface> of a definition of a SchedProcess component:

  INTERFACE IS
TYPE
SchedProcess
PROCESSOR ("cubistic.art.cs.cmu.edu")
SEGMENTDEF (work_block1; 0.04)
SEGMENTDEF (work_block2; 0.03)
PLAYER services IS RTLoad
SEGMENTSET (work_block1, work_block2)
END services
PLAYER timeget IS RPCDef
SIGNATURE ("new_type *"; "void")
END timeget
PLAYER timeshow IS RPCDef
SIGNATURE ("void"; "void")
END timeshow
END INTERFACE

SegmentSet

Description

The SegmentSet property is used to further specify an RTLoad player in UniCon.

An RTLoad player corresponds to the load that a schedulable process places on a given processor. A load is the total amount of execution time that a single schedulable process requires for execution of the code it contains that applies to a particular event (see the Description section for the RTLoad player type for more information on events). An RTLoad player consists of a trigger and a set of segments. The set of segments describes the total amount of execution time required for the portion of the event that the RTLoad player is responsible for, and the trigger describes how often the set of segments is reactivated per unit of time. Together this information specifies the load that an RTLoad player places on a processor.

The SegmentSet property is used to specify the part of the RTLoad player consisting of the set of segments. As described above, an RTLoad player specifies a load associated with a portion of an event - that portion of the event implemented by the schedulable process that contains the given RTLoad player (recall that an event can consist of code from more than one schedulable process). The SegmentSet property of an RTLoad player lists the set of segments defined in the enclosing SchedProcess component that implement the portion of the event of which the RTLoad player is a part. The segments named in the value of the SegmentSet property must each be defined in a SegmentDef property in the
<interface> property list of the component containing the RTLoad player.

More than one SegmentSet property may be specified in a single RTLoad player. The
UniCon compiler will treat these multiple specifications as a single SegmentSet property with the value portion being the union of all values in all of the specifications.

Property Lists

The SegmentSet property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax of the value part of the SegmentSet property consists of a list of items that are either <identifier>s or "string"s enclosed in parentheses.

Required Rule

Optional

There is no default value for the SegmentSet property.

Merge Rule

MERGE

More than one specification of the SegmentSet property in a single property list is treated as a single specification with the union of all values in all of the specifications.

Semantic Checks

Every <identifier> or "string" in the value part of every SegmentSet property in an RTLoad player must name a segment that is defined by a SegmentDef property in the <interface> property list of the component containing the RTLoad player.

Example

The following is an example of a specification of a SegmentSet property. It is embedded in an RTLoad player definition:

  PLAYER services IS RTLoad
SEGMENTSET (work_block1, work_block2)
END services
Also refer to the Example section for the SegmentDef property.

Signature

Description

The Signature property is used to further specify a player definition in UniCon. It is only legal in the property lists of players of the following types: GlobalDataDef,
GobalDataUse, ReadFile, RPCCall, RPCDef, RoutineCall, RoutineDef, StreamIn, StreamOut, and WriteFile. It is used to specify the data types of the arguments and the return values in routine players, the data types of global data players, and the structure of the data in stream players.

Property Lists

The Signature property can legally be specified in the property list in the following UniCon language element:

Value Syntax

The syntax of the value part of the Signature property depends upon the <player_type> in the <player> definition in which it is specified.

The syntax for the Signature property in a GlobalDataDef player is a single <identifier> or "string" surrounded by parentheses.
The syntax for the Signature property in a GlobalDataUse player is a single <identifier> or "string" surrounded by parentheses.
The syntax for the Signature property in a ReadFile player is a list of items that are either <identifier>s or "string"s, surrounded by parentheses.
The syntax for the Signature property in a RoutineCall player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a comma-separated list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present.
The syntax for the Signature property in a RoutineDef player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a comma-separated list of items that are either
<identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present.
The syntax for the Signature property in an RPCCall player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present.
The syntax for the Signature property in an RPCDef player consists of two fields, separated by a semicolon, surrounded by parentheses. Each of the fields is optional, yet one of them must be specified. The first field is a list of items that are either <identifier>s or "string"s. The second field is a single <identifier> or "string". If the first field is omitted, the semicolon is required. If the second field is omitted, the semicolon must not be present.
The syntax for the Signature property in a StreamIn player is a single <identifier> or "string", surrounded by parentheses.
The syntax for the Signature property in a StreamOut player is a single <identifier> or "string", surrounded by parentheses.
The syntax for the Signature property in a WriteFile player is a list of items that are either <identifier>s or "string"s, surrounded by parentheses.

Required Rule

Required

There is no default value for the Signature property.

Merge Rule

ERROR

Subsequent specifications of the Signature property in a single property list are reported as errors. The UniCon compiler uses the first of the duplicate Signature properties it encounters.

Semantic Checks

There are no semantic checks performed on the value of the Signature property. However, UniCon does perform signature checking in connections. All errors encountered in signature checking of players in connections are reported as Warnings, allowing the system to be constructed regardless of the mismatches.

  1. In ProcedureCall connections, the UniCon compiler compares the signature of each RoutineCall player with the signature of the RoutineDef player. The number of arguments in each signature, the data types of the arguments in corresponding positions in the argument lists, and the data types of the return values are compared. If the signatures are not identical in each comparison, UniCon reports the mismatches as errors.
  2. In RemoteProcCall connections, the UniCon compiler compares the signature of each RPCCall player with the signature of the RPCDef player. The number of arguments in each signature, the data types of the arguments in corresponding positions in the argument lists, and the data types of the return values are compared. If the signatures are not identical in each comparison, UniCon reports the mismatches as errors.
  3. In DataAccess connections, the UniCon compiler compares the signature of each GlobalDataUse player with the signature of the GlobalDataDef player. The data type constituting the signature in each player is compared. If the signatures are not identical, UniCon reports the mismatch as an error.
  4. In Pipe connections, the UniCon compiler connects StreamIn players to StreamOut players, StreamIn players to ReadNext players, and StreamOut players to WriteNext players. In the first case, the data type constituting the signature of the StreamIn player is compared with the data type of the StreamOut player. In the other two cases, the data type of the StreamIn or StreamOut player is compared with the first data type in the list of data types in the RecordFormat property of the component containing the ReadNext or WriteNext player. If the data types are not identical, UniCon reports the mismatch as an error.

Example

The following are examples of specifications of Signature properties. There is an example for every player type for which a Signature property is legal:

  PLAYER input_data_stream IS StreamIn
SIGNATURE ("line")
END input_data_stream PLAYER output_data_stream IS StreamOut
SIGNATURE ("line")
END output_data_stream PLAYER global_variable IS GlobalDataDef
SIGNATURE ("int")
END global_variable PLAYER global_variable IS GlobalDataUse
SIGNATURE ("int")
END global_variable PLAYER local_routine IS RoutineCall
SIGNATURE ("int", "char *"; "void")
END local_routine PLAYER local_routine IS RoutineDef
SIGNATURE ("int", "char *"; "void")
END local_routine PLAYER remote_routine IS RPCCall
SIGNATURE ("int", "double"; "void")
END remote_routine PLAYER remote_routine IS RPCDef
SIGNATURE ("int", "double"; "void")
END remote_routine PLAYER read IS ReadFile
SIGNATURE ("line")
END read PLAYER write IS WriteFile
SIGNATURE ("line")
END write

Trace

Description

The Trace property is used to further specify an RTScheduler connector instantiation in UniCon.

The Trace property is used to specify an event in UniCon. An event is a thread of control through a set of schedulable processes running on a common processor that is initiated by some triggering mechanism in the environment and that eventually returns back to the environment. During execution, the thread of control is passed to a client schedulable process by the environment as the result of the firing of some triggering mechanism (e.g., a timer associated with a given process expiring in the kernel causing the scheduler to interrupt the currently executing process and transfer control to the given one). The process performs some work, and then it may return or it may make a remote procedure call to another process (a server process). If it makes a remote procedure call, the thread of control is transferred to the server process, which performs some work and returns (or makes another remote procedure call, and so on). Control is eventually returned back to the original client process, where work continues in a similar fashion until control is returned back to the environment. This entire thread of control is called an event in UniCon. A trace is a specification of an event. It specifies the trigger, the mechanism by which control is first given to a client schedulable process from the environment, and the sequence of segments that execute (in the order in which they execute).

A trigger is an abstraction. As mentioned above, it describes the mechanism by which control is transferred from the environment to a schedulable process. Only client processes can define triggers, because they begin execution by receiving control from the environment. Server processes do not have triggers because they execute continuously and receive control only as the result of remote procedure calls. Since client processes execute to completion and return to the environment, they can be reactivated by the environment according to some rate (i.e., some number of times per second). Therefore, triggers have associated rates of initiation. Triggers are defined in the interface property list of SchedProcess components via the TriggerDef property. The value part of the property defines the name of the trigger and associates with it the rate (in seconds) at which the trigger is initiated.

A segment is also an abstraction. It describes a chunk of code in the implementation of the schedulable process. The chunk of code it describes may take any form that the designer chooses. For example, it may describe a function, a set of functions, a portion of a single function, or even a few statements within a given function. The designer typically defines segments based on structural and execution time properties of the code in order to facilitate certain types of analyses that can be done on sets of schedulable processes in a real-time environment. Segments are defined in the interface property list of SchedProcess components via the SegmentDef property. The value part of the property defines the name of the segment and associates an execution time (in seconds) with it. Work done in a schedulable process is described by a sequence of one or more segments.

The Trace property specifies a complete event. The value part of the property lists the trigger that initiates the event, followed by the segments that execute until control is returned to the environment (in the order that they execute). Although the SchedProcess components are what get managed by the real-time scheduler in the operating environment, the events are what are of interest to the real-time application developer. The events define the work that must be done in response to a trigger - the events have the associated periods, execution times, and deadlines. The real-time application developer designs an application so that all of the events in the system meet their respective deadlines. The SchedProcess components are assigned the appropriate work and priorities so that this will happen.

If the Algorithm property in an RTScheduler connector instantiation specifies the rate_monotonic scheduling algorithm, the UniCon compiler can facilitate a Rate Monotonic Analysis (RMA) on the events described by the Trace properties in that connector instantiation. For a RMA, the UniCon compiler collects the segment names, their execution times, and the period information for each event associated with a given processor; it also collects the priority information for each schedulable process associated with that same processor. It then formats this information and prepares a file containing input to a RMA tool which performs the analysis. This tool is invoked manually and reports a simple answer to indicate whether or not all of the events will meet their respective deadlines. The file that UniCon prepares with the input to the RMA tool is named RMA_<processor_name>, where <processor_name> is taken from the Processor property associated with the RTScheduler connector instantiation in which the Trace properties are specified. An RMA input file is generated by the UniCon compiler for each RTScheduler connector instantiation whose Algorithm property specifies a rate_monotonic scheduler.

Property Lists

The Trace property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax for the value part of the Trace property consists of a comma-separated list containing a trigger name followed by one or more segment names, surrounded by parentheses. Trigger and segment names contain three dot-separated <identifier>s. The first <identifier> names a component instantiation, the second names an RTLoad player in the component instantiation named by the first, and the third names a trigger or segment in the RTLoad player named by the second.

Required Rule

Optional

There is no default value for the Trace property.

Merge Rule

ERROR

Subsequent specifications of the Trace property in a single property list are reported as errors. The UniCon compiler uses the first of the duplicate Trace properties it encounters. A duplicate Trace property is one in which the value part contains the same list of elements as a previously specified Trace property. Each Trace property value contains the same number of elements, and the elements in corresponding positions in the lists name the same trigger or segment.

Semantic Checks

The following are the semantic checks performed on the value of the Trace property:

  1. There must be at least two elements in the list that comprises the value of a Trace property.
  2. The first identifier in each element of the list in the value of the Trace property must name a previously instantiated component in the composite implementation in which the Trace property appears.
  3. The second <identifier> must name an RTLoad player in the component instantiation named by the first.
  4. The player named by the combination of first and second <identifier>s must be associated with a role in the connector instantiation in which the Trace property is found.
  5. The first element in the list must name a trigger - the third <identifier> in that element must name a trigger in the RTLoad player named by the second.
  6. All elements in the list after the first must name a segment - the third
    <identifier> in each of these elements must name a segment in the RTLoad player named by the second.
  7. A trigger used in a Trace property cannot be an aperiodic one - the period associated with it must be greater than zero (i.e., not "asynchronous").

Example

The following are examples of specifications of Trace properties. The first is embedded in an RTScheduler connector instantation, and the second is embedded in an <establish> of an RTScheduler connector:

  USES Scheduler PROTOCOL RTM-Real-Time-Scheduler
ALGORITHM (rate_monotonic)
PROCESSOR ("TESTBED.XX.CMU.EDU")
TRACE (client.application.external_interrupt,
client.application.work_block1,
server.services.work_block1,
client.application.work_block2,
server.services.work_block2,
client.application.work_block3)
END Scheduler

CONNECT client.application TO Scheduler.load
CONNECT server.services TO Scheduler.load
The above example assumes that "client" and "server" are SchedProcess components that have been instantiated prior to the instantiation of the connector. Client has an RTLoad player named application that has a trigger named external_interrupt and three segments named work_block1, work_block2, and work_block3. Server has an RTLoad player named services that has two segments named work_block1 and work_block2. The example below makes the same assumptions.

  ESTABLISH RTM-Real-Time-Scheduler WITH
client.application AS load
server.services AS load
ALGORITHM (rate_monotonic)
PROCESSOR ("TESTBED.XX.CMU.EDU")
TRACE (client.application.external_interrupt,
client.application.work_block1,
server.services.work_block1,
client.application.work_block2,
server.services.work_block2,
client.application.work_block3)
END RTM-Real-Time-Scheduler

Trigger

Description

The Trigger property is used to further specify an RTLoad player in UniCon.

An RTLoad player corresponds to the load that a schedulable process places on a given processor. A load is the total amount of execution time that a single schedulable process requires for execution of the code it contains that applies to a particular event (see the Description section for the RTLoad player type for more information on events). An RTLoad player consists of a trigger and a set of segments. The set of segments describes the total amount of execution time required for the portion of the event that the RTLoad player is responsible for, and the trigger describes how often the set of segments is reactivated per unit of time. Together this information specifies the load that an RTLoad player places on a processor.

The Trigger property is used to specify the trigger part of the RTLoad player. An RTLoad player may only specify one Trigger. The value of the Trigger property is the name of a trigger that is defined in a TriggerDef property in the <interface> property list of the component containing the RTLoad player.

Typically, RTLoad players in client processes will contain Trigger properties, and those in server processes will not. This is because server processes are assumed to have asynchronous triggers which are not used anywhere in UniCon. Only the periodic triggers defined in client processes are used in UniCon, and they are used in the value of the Trace property (see the Description section for the TriggerDef property for more information).

Property Lists

The Trigger property can legally be specified in the property list in the following UniCon language element:

Value Syntax

The syntax of the value part of the Trigger property consists of a single <identifier> or "string" enclosed in parentheses.

Required Rule

Optional

There is no default value for the Trigger property.

Merge Rule

REPLACE

Subsequent duplicate specifications of the Trigger property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The value of a Trigger property in an RTLoad player must name a trigger that is defined by a TriggerDef property in the <interface> property list of the component containing the RTLoad player.

Example

The following is an example of a specification of a Trigger property. It is embedded in an RTLoad player definition:

  PLAYER application1 IS RTLoad
TRIGGER (external_interrupt1)
SEGMENTSET (work_block1, work_block2,
work_block3)
END application1
Also refer to the Example section for the TriggerDef property.

TriggerDef

Description

The TriggerDef property is used to further specify a SchedProcess component definition. It provides the system designer with the means for associating a SchedProcess component with a mechanism by which the schedulable process receives control from the real-time operating system environment at run-time. Additionally, the property associates a rate at which this mechanism transfers control to the schedulable process (i.e., how often control is transferred per unit of time).

In a real-time environment, client schedulable processes are periodic: they do not run forever, and they are periodically reactivated. When a client process is activated, it runs to completion and returns control to the environment. The mechanism by which control is transferred to a client process from the operating system at run-time is called a trigger in UniCon. On the other hand, server processes run continuously. Control is passed to a server process only via remote procedure calls from clients or other servers, meaning that they are aperiodic.

A trigger is an abstraction that describes any number of implementation mechanisms by which control is transferred from the environment. An example of a trigger in the run-time environment is an interrupt generated as a result of a clock timer associated with a process counting down to zero. Only client processes can define triggers, because they begin execution by receiving control from the environment. Server processes do not have triggers because they execute continuously and receive control only as a result of remote procedure calls. Since client processes execute to completion and return to the environment, they can be reactivated by the environment according to some rate (i.e., some number of times per unit of time). Therefore, triggers have associated rates of initiation. Triggers are defined in the interface property list of SchedProcess components via the TriggerDef property. The value part of the property defines the name of the trigger and associates with it the rate (in seconds) at which the trigger is initiated.

NOTE: The UniCon language does not prevent a server process from defining a trigger via a TriggerDef property; however the value of the second field in this case must be asynchronous since server processes run continuously, responding to RPC requests asynchronously.

Trigger names defined in TriggerDef properties are used in the value part of the Trigger property. This property further specifies RTLoad players by indicating which trigger in a SchedProcess component initiates the given real-time load on a processor.

Trigger names are also used in the value part of the Trace property. This property further specifies RTScheduler connector instantiations by describing traces of events that occur in the system of schedulable processes mediated by the connector. An event is a thread of control in a system of such processes. For example, a client process initially receives control from the operating system. This process performs some work, and it may return or it may make a remote procedure call to another process (a server process). If it makes a remote procedure call, the thread of control is transferred to the server process, which performs some work and returns (or makes another remote procedure call, and so on). Control is eventually returned back to the original client process, where work continues in a similar fashion until control is eventually returned back to the environment. This entire thread of control is called an event in UniCon, and can be described by a trace. A trace is a specification of the event. It specifies the trigger, the mechanism by which control is first given to a client schedulable process from the environment, and the sequence of segments that execute as a result of the trigger in the order in which they are executed.

The <floating point number> in the value of the TriggerDef property represents the period (in seconds) of the triggering mechanism. When a trigger is used in a Trace property, the UniCon compiler uses this period value to initialize the schedulable process in the real-time environment to run at the specified rate. The period associated with a trigger in a Trace property is also used in a rate monotonic analysis (RMA) of the schedulable processes mediated by an RTScheduler connector if the algorithm of choice is the rate monotonic algorithm.

Property Lists

The TriggerDef property can legally be specified in the property list in the following
UniCon language element:

Value Syntax

The syntax for a TriggerDef property consists of two fields, separated by a semicolon, enclosed in parentheses. The first field is a single <identifier> or "string". The second field is either a single <floating point number>, or the word
asynchronous.

Required Rule

Optional

There is no default value for the TriggerDef property.

Merge Rule

REPLACE

Subsequent duplicate specifications of the TriggerDef property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses). Two TriggerDef properties are duplicates if the <identifier> or "string" in the first field of both are identical. The case of the letter in the check is significant, however the absence or presence of double-quotes is not.

Semantic Checks

The following semantic checks are performed on the value of the TriggerDef property:

  1. The second field of the value of a TriggerDef property must be a <floating point number> or the word asynchronous.
  2. If the second field contains a <floating point number>, then the value of that number must be greater than 0.
  3. A "client" SchedProcess component may only specify periodic triggers with the TriggerDef property. A periodic trigger is one that represents a positive period in milliseconds. This is specified by a positive <floating point number> in the second field of a TriggerDef property. A client schedulable process may not define an asynchronous trigger. A client SchedProcess is defined to be one in which at least one RPCCall player, and no RPCDef players, is defined in the interface.
  4. A client SchedProcess component must define at least one trigger with a
    TriggerDef property in its <interface> property list.
  5. A "server" SchedProcess component may only specify aperiodic triggers with the TriggerDef property. An aperiodic trigger is one in which there is no period. The process receives control asynchronously in response to remote procedure calls from other processes. This is specified by the keyword asynchronous in the second field of a TriggerDef property. A server SchedProcess is defined to be one in which at least one RPCDef player, and any number of RPCCall players, are defined in the interface.
  6. At least one trigger defined in a TriggerDef property in a client SchedProcess component must be the value of a Trigger property in the property list of an RTLoad player in that component.

Example

The following are examples of specifications of TriggerDef properties. They are embedded in the <interface> of a definition of a SchedProcess component.:

  INTERFACE IS
TYPE
SchedProcess
PROCESSOR ("cubistic.art.cs.cmu.edu")
TRIGGERDEF (external_interrupt1; 1.0)
TRIGGERDEF (external_interrupt2; 0.5)
SEGMENTDEF (work_block1; 0.02)
SEGMENTDEF (work_block2; 0.03)
SEGMENTDEF (work_block3; 0.05)
PLAYER application1 IS RTLoad
TRIGGER (external_interrupt1)
SEGMENTSET (work_block1, work_block2,
work_block3)
END application1
PLAYER application2 IS RTLoad
TRIGGER (external_interrupt2)
SEGMENTSET (work_block1, work_block2,
work_block3)
END application2
PLAYER timeget IS RPCCall
SIGNATURE ("new_type *"; "void")
END timeget
PLAYER timeshow IS RPCCall
SIGNATURE ("void"; "void")
END timeshow
END INTERFACE

Variant

Description

The Variant property is used to further specify a component definition or instantiation. It provides the system designer with the means for specifying to the UniCon compiler which variant in a primitive implementation of a component to use during system construction.

Primitive implementations are composed of a list of variants. A variant is an alternative implementation. If a component has only one variant, the choice of alternative to use during system construction is obvious. If a component has more than one variant, the UniCon compiler must choose one of them. In this case, if the system designer does not specify a Variant property in either the component definition or its instantation, the UniCon compiler chooses the first variant in the list as the alternative implementation to use during system construction. If the system designer does specify a Variant property, the UniCon compiler uses the variant named in the value of that property as the alternative implementation.

The value of the Variant property must name a variant in the component definition that is being defined or instantiated. The Variant property is not permitted to further specify a component with a composite implementation in UniCon.

Property Lists

The Variant property can legally be specified in the property list in the following UniCon language elements:

Value Syntax

The syntax of the value part of the Variant property consists of a single <identifier> or "string", enclosed in parentheses. The case of the letters can be upper, lower, or mixed.

Required Rule

Optional

The default value for the Variant property is the name of the first variant in the list of variants in the primitive implementation of the component. If the component only has one variant, the name of that variant is the default.

Merge Rule

REPLACE

Subsequent specifications of the Variant property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses).

Semantic Checks

The following are the semantic checks performed on the value of the Variant property:

  1. The <identifier> or "string" value must name a variant in the component definition or instantiation in which the Variant property is specified.
  2. The component definition or instantiation in which the Variant property is specified must have a primitive implementation.

Example

The following are examples of specifications of Variant properties. The first is embedded in the definition of a Computation component:

  COMPONENT My_Sort_Library
INTERFACE IS
TYPE
Computation
LIBRARY
VARIANT
(sort_library)
PLAYER bubble IS RoutineDef
SIGNATURE ("int *"; "int *")
END bubble
PLAYER quick IS RoutineDef
SIGNATURE ("int *"; "int *")
END quick
PLAYER merge IS RoutineDef
SIGNATURE ("int *"; "int *")
END merge
END INTERFACE
IMPLEMENTATION IS
VARIANT
sort_library IN "libs.a"
IMPLTYPE (ObjectLibrary)
END sort_library
VARIANT debug_sort_library IN "libsdb.a"
IMPLTYPE (ObjectLibrary)
END debug_sort_library
END IMPLEMENTATION
END
My_Sort_Library
This next example is embedded in an instantiation of the above component. The Variant property in the instantiation overrides the one in the definition:

  USES sortlib INTERFACE My_Sort_Library
VARIANT (debug_sort_library)
END sortlib

User Defined Properties

Description

User-defined properties are hooks in the UniCon language for allowing users to specify additional information about a UniCon construct that is not further interpreted in the language or by the UniCon compiler. The name part of a user-defined property can be any <identifier> that is not already the name part of a pre-defined UniCon property. The value part of a property must be a <string>. This string is not parsed, nor further interpreted, by the UniCon compiler.

The information specified in a user-defined property is stored in the parse tree that the
UniCon compiler creates while processing UniCon definitions. At an appropriate step in the compilation or build process, the compiler can collect the information associated with a user-defined property and ship it off to an external tool that might need the information.

NOTE: For now, the means for communicating with external tools is builtin to the compiler. Therefore, adding a new tool to the suite of external tools that are known to UniCon requires modification of the UniCon compiler source code. Since this is not a trivial task, this may require help from the UniCon compiler developers.

As mentioned above, the UniCon compiler does not parse or further interpret the value part of a user-defined property. There are hooks in the source code of the compiler, however, for the user to supply C source code fragments to parse and check the semantics of the value part. The UniCon compiler will execute these code fragments at the appropriate times during the compilation and build process.

The UniCon compiler calls two functions when it encounters a user-defined property. The first is a function that executes user-supplied C source code fragments to parse the value part of user-defined properties. The second is a function that executes user-supplied C source code fragments to check the semantics of the value part of user-defined properties.

The first function, uni_user_parse, is the hook in the UniCon compiler for users to add C source code that parses the value of a user-defined property. If the user wishes to have the UniCon compiler parse the value of a user-defined property, (s)he must supply a parsing function with the source code of the UniCon compiler that can be compiled and linked with the other UniCon source when building it. The user adds a C source code fragment directly to the first function, uni_user_parse, in the UniCon source file uni_user_defined.c to parse the value of a user-defined property. The following is an example of such a fragment:

   if (uni_strcmp_l (av_pair->attribute_str->string,
"some_user_defined_property") == 0)
return my_user_defined_property_parser (
av_pair->value.user);
In the above example, the function uni_strcmp_l is a utility function provided by the UniCon compiler. The letter "l" in the name refers to the leftmost argument in the argument list. This function performs a string comparison using the C standard library routine strcmp, but first it converts the value of the leftmost argument to lower case letters. The UniCon compiler also provides the two functions uni_strcmp_r and uni_strcmp_b which convert the value of the rightmost argument, and the values of both arguments, to lower case letters, respectively. The return values of these three functions have the same semantics as the return value of the strcmp function.

Also, notice that my_user_defined_property_parser is a user-supplied function that parses the value of the property. All of the information about a particular property is contained in the argument named av_pair, supplied as input to the uni_user_parse routine. av_pair->attribute_str->string points to the string value that is the name part of the property, and av_pair->value.user points to the string value that is the value part of the property. The return value of the user-supplied property parser must be a pointer value. It can be a pointer to an object of any type, since UniCon does not further interpret this value.

The second function, uni_user_semantics, is the hook in the UniCon compiler for users to add C source code that checks the semantics of the value of a user-defined property. If the user wishes to have the UniCon compiler check the semantics of the value of a user-defined property, (s)he must supply a semantics checking function with the source code of the UniCon compiler that can be compiled and linked with the other UniCon source when building it. The user adds a C source code fragment directly to the second function, uni_user_semantics, in the UniCon source file uni_user_defined.c to check the semantics of the value of a user-defined property. The following is an example of such a fragment:

   if (uni_strcmp_l (av_pair->attribute_str->string,
"some_user_defined_property") == 0)
return check_my_user_defined_property_semantics (
av_pair->value.user_temp);
Notice that check_my_user_defined_property_semantics is a user-supplied function that checks the semantics of the value part of the property. Also, notice that the argument supplied to this function is av_pair->value.user_temp, rather than av_pair->value.user. This is because the function uni_user_parse places the pointer to the parsed value part of a user-defined property there. The return value of the user-supplied property semantic checker must be a pointer value. It can be a pointer to an object of any type, since UniCon does not further interpret this value.

To include the source files containing the user-supplied parsing and semantic checking functions in the build process, modify the Odinfile in the following UniCon installation directory: ...UniCon/uparse/src. Add a separate line for each file to the uparse system model in the following way. Assume you wish to add the functions in the source files my_parsers.c and my_checkers.c to the UniCon compiler. The system model used to build the original compiler looks as follows:

  %uparse.c.sm == <<
uni_error.c +define=UNI_ERROR_ROUTINE
uni_lexer.l
uni_main.c
uni_parser.y
uni_tree_builder.c
uni_semantic.c
uni_list.c
uni_user_defined.c
uni_builder.c
uni_datause.c
uni_fileio.c
uni_proccall.c
uni_rproccall.c
uni_pipe.c
uni_rts.c
uni_unparse.c
uni_utility.c +define=UNI_PROGRESS_ROUTINE
Simply add the names of the files as separate lines to the end of the system model so that it looks as follows. Be sure to include full directory path information for the new files. It is not recommended that you keep the source in the same directory with the other UniCon source. This is because when you delete an old UniCon installation in order to build a new one, you may forget your source files are there and accidentally delete them:

  %uparse.c.sm == <<
uni_error.c +define=UNI_ERROR_ROUTINE
uni_lexer.l
uni_main.c
uni_parser.y
uni_tree_builder.c
uni_semantic.c
uni_list.c
uni_user_defined.c
uni_builder.c
uni_datause.c
uni_fileio.c
uni_proccall.c
uni_rproccall.c
uni_pipe.c
uni_rts.c
uni_unparse.c
uni_utility.c +define=UNI_PROGRESS_ROUTINE
/usr/gz/my_parsers.c
/usr/gz/my_checkers.c
Then, change directory to the root of the installation directory (i.e., ...UniCon) and invoke odin to build uparse: "odin %install_uparse".

Property Lists

A user-defined property can be specified in any property list in the UniCon language.

Value Syntax

The syntax of the value part of a user-defined property is a <string>, enclosed in parentheses. The <string> is uninterpreted by the UniCon compiler. The syntax of the name part of a user-defined property is an <identifier> that is not the name part of any other UniCon property.

Required Rule

OPTIONAL

User-defined properties, of course, are always optional. If specified, however, there must be a corresponding entry for the propery in a file named "user_defined_properties" in the same directory in the file system from which the UniCon compiler is invoked (i.e., the "local" directory). The entry must be a single line with three fields. The first field is the name of the property, and the other two fields can be anything. All three fields are separated from each other by whitespace. The purpose of the second and third fields has not yet been fixed. These are place holders for future enhancements. The case of the letters for the name in the first field is insignificant.

Merge Rule

REPLACE

Subsequent specifications of a user-defined property in a single property list replace earlier specifications (i.e., the last specification is the one that the UniCon compiler uses). Two user-defined attributes are duplicates if the name part is identical (the case of the letters is insignificant) and the value part is identical (the case of the letters is significant for the value part).

Semantic Checks

The UniCon compiler does not perform syntax and semantic checks on, nor further interprets, the value of a user-defined property. However, there are hooks for the maintainer of the UniCon compiler to add C source code fragments that will parse and perform semantic checks on the value part. Please refer to the Description section above for more information.

Example

The following are examples of specifications of user-defined properties. All three examples below are real. The UniCon graphical editor uses these properties to store graphical positioning and sizing information, as well as UniCon source file location information in
UniCon textual definitions. Two of these user-defined properties are embedded in the property list of the composite implementation of the component definition. The third is embedded in the property list of a component instantiation in the composite implementation. Notice that the value parts are actually Scheme data:

  COMPONENT KWIC
INTERFACE IS
TYPE
Filter
PLAYER input IS StreamIn
SIGNATURE ("line")
PORTBINDING (stdin)
END input
PLAYER output IS StreamOut
SIGNATURE ("line")
PORTBINDING (stdout)
END output
PLAYER error IS StreamOut
SIGNATURE ("line")
PORTBINDING (stderr)
END error
END INTERFACE
IMPLEMENTATION IS
GUI-SCREEN-SIZE ("(list :real-width 800 :width-unit "" :real-height 350 :height-unit "")")
DIRECTORY ("(list "/usr/examples/ upcase.uni" "/usr/examples/cshift.uni" "/usr/examples/ data.uni" "/usr/examples/converge.uni" "/usr/examples/ sort.uni" "/usr/examples/unix-pipe.uni" "/usr/examples/ reverse-f.uni")")
USES caps INTERFACE upcase
GUI-SCREEN-POSITION ("(list :posi tion (@pos 68 123) :player-positions (list (cons "input" (cons `left 0.5)) (cons "error" (cons `right 0.6625)) (cons "output" (cons `right 0.3375))))")
END caps
(remaining definition omitted)
END IMPLEMENTATION
END
KWIC