dwww Home | Show directory contents | Find package


                                   Annex E
                                 (normative)

                             Distributed Systems


1   [This Annex defines facilities for supporting the implementation of
distributed systems using multiple partitions working cooperatively as part of
a single Ada program.]


                            Extensions to Ada 83

1.a         {extensions to Ada 83} This Annex is new to Ada 95.


                           Post-Compilation Rules

2   {processing node} {storage node} {distributed system} A distributed system
is an interconnection of one or more processing nodes (a system resource that
has both computational and storage capabilities), and zero or more storage
nodes (a system resource that has only storage capabilities, with the storage
addressable by one or more processing nodes).

3   {distributed program} A distributed program comprises one or more
partitions that execute independently (except when they communicate) in a
distributed system.

4   {configuration (of the partitions of a program)} The process of mapping
the partitions of a program to the nodes in a distributed system is called
configuring the partitions of the program.


                         Implementation Requirements

5   The implementation shall provide means for explicitly assigning library
units to a partition and for the configuring and execution of a program
consisting of multiple partitions on a distributed system; the means are
implementation defined.

5.a         Implementation defined: The means for creating and executing
            distributed programs.


                         Implementation Permissions

6   An implementation may require that the set of processing nodes of a
distributed system be homogeneous.

        NOTES

7       1  The partitions comprising a program may be executed on differently
        configured distributed systems or on a non-distributed system without
        requiring recompilation. A distributed program may be partitioned
        differently from the same set of library units without recompilation.
        The resulting execution is semantically equivalent.

8       2  A distributed program retains the same type safety as the
        equivalent single partition program.


E.1 Partitions


1   [The partitions of a distributed program are classified as either active
or passive.]


                           Post-Compilation Rules

2   {active partition} {passive partition} An active partition is a partition
as defined in 10.2. A passive partition is a partition that has no thread of
control of its own, whose library units are all preelaborated, and whose data
and subprograms are accessible to one or more active partitions.

2.a         Discussion: In most situations, a passive partition does not
            execute, and does not have a "real" environment task. Any
            execution involved in its elaboration and initialization occurs
            before it comes into existence in a distributed program (like most
            preelaborated entities). Likewise, there is no concrete meaning to
            passive partition termination.

3   A passive partition shall include only library_items that either are
declared pure or are shared passive (see 10.2.1 and E.2.1).

4   An active partition shall be configured on a processing node. A passive
partition shall be configured either on a storage node or on a processing node.

5   The configuration of the partitions of a program onto a distributed system
shall be consistent with the possibility for data references or calls between
the partitions implied by their semantic dependences. {remote access} Any
reference to data or call of a subprogram across partitions is called a remote
access.

5.a         Discussion: For example, an active partition that includes a unit
            with a semantic dependence on the declaration of another RCI
            package of some other active partition has to be connected to that
            other partition by some sort of a message passing mechanism.

5.b         A passive partition that is accessible to an active partition
            should have its storage addressable to the processor(s) of the
            active partition. The processor(s) should be able to read and
            write from/to that storage, as well as to perform "
            read-modify-write" operations (in order to support entry-less
            protected objects).


                              Dynamic Semantics

6   {elaboration (partition)} A library_item is elaborated as part of the
elaboration of each partition that includes it. If a normal library unit (see
E.2) has state, then a separate copy of the state exists in each active
partition that elaborates it. [The state evolves independently in each such
partition.]

6.a         Ramification: Normal library units cannot be included in passive
            partitions.

7   {termination (of a partition)} {abort (of a partition)}
{inaccessible partition} {accessible partition} [An active partition terminates
when its environment task terminates.] A partition becomes inaccessible if it
terminates or if it is aborted. An active partition is aborted when its
environment task is aborted. In addition, if a partition fails during its
elaboration, it becomes inaccessible to other partitions. Other
implementation-defined events can also result in a partition becoming
inaccessible.

7.a         Implementation defined: Any events that can result in a partition
            becoming inaccessible.

8/1 For a prefix D that denotes a library-level declaration, excepting a
declaration of or within a declared-pure library unit, the following attribute
is defined:

9   D'Partition_Id
                Denotes a value of the type universal_integer that identifies
                the partition in which D was elaborated. If D denotes the
                declaration of a remote call interface library unit (see
                E.2.3) the given partition is the one where the body of D was
                elaborated.


                          Bounded (Run-Time) Errors

10  {bounded error (cause) [partial]} It is a bounded error for there to be
cyclic elaboration dependences between the active partitions of a single
distributed program. {Program_Error (raised by failure of run-time check)} The
possible effects, in each of the partitions involved, are deadlock during
elaboration, or the raising of Communication_Error or Program_Error.


                         Implementation Permissions

11  An implementation may allow multiple active or passive partitions to be
configured on a single processing node, and multiple passive partitions to be
configured on a single storage node. In these cases, the scheduling policies,
treatment of priorities, and management of shared resources between these
partitions are implementation defined.

11.a        Implementation defined: The scheduling policies, treatment of
            priorities, and management of shared resources between partitions
            in certain cases.

12  An implementation may allow separate copies of an active partition to be
configured on different processing nodes, and to provide appropriate
interactions between the copies to present a consistent state of the partition
to other active partitions.

12.a        Ramification: The language does not specify the nature of these
            interactions, nor the actual level of consistency preserved.

13  In an implementation, the partitions of a distributed program need not be
loaded and elaborated all at the same time; they may be loaded and elaborated
one at a time over an extended period of time. An implementation may provide
facilities to abort and reload a partition during the execution of a
distributed program.

14  An implementation may allow the state of some of the partitions of a
distributed program to persist while other partitions of the program terminate
and are later reinvoked.

        NOTES

15      3  Library units are grouped into partitions after compile time, but
        before run time. At compile time, only the relevant library unit
        properties are identified using categorization pragmas.

16      4  The value returned by the Partition_Id attribute can be used as a
        parameter to implementation-provided subprograms in order to query
        information about the partition.


                         Wording Changes from Ada 95

16.a/2      {AI95-00226-01} Corrected wording so that a partition that has an
            elaboration problem will either deadlock or raise an exception.
            While an Ada 95 implementation could allow some partitions to
            continue to execute, they could be accessing unelaborated data,
            which is very bad (and erroneous in a practical sense). Therefore,
            this isn't listed as an inconsistency.


E.2 Categorization of Library Units


1   [Library units can be categorized according to the role they play in a
distributed program. Certain restrictions are associated with each category to
ensure that the semantics of a distributed program remain close to the
semantics for a nondistributed program.]

2   {categorization pragma [distributed]} {pragma, categorization
 [distributed]} {library unit pragma (categorization pragmas) [partial]}
{pragma, library unit (categorization pragmas) [partial]}
{categorized library unit} A categorization pragma is a library unit pragma
(see 10.1.5) that restricts the declarations, child units, or semantic
dependences of the library unit to which it applies. A categorized library
unit is a library unit to which a categorization pragma applies.

3   The pragmas Shared_Passive, Remote_Types, and Remote_Call_Interface are
categorization pragmas. In addition, for the purposes of this Annex, the
pragma Pure (see 10.2.1) is considered a categorization pragma.

4/1 {8652/0078} {AI95-00048-01} {shared passive library unit} A library
package or generic library package is called a shared passive library unit if
a Shared_Passive pragma applies to it. {remote types library unit} A library
package or generic library package is called a remote types library unit if a
Remote_Types pragma applies to it. {remote call interface} A library unit is
called a remote call interface if a Remote_Call_Interface pragma applies to
it. {normal library unit} A normal library unit is one to which no
categorization pragma applies.

4.a.1/1     Ramification: {8652/0078} {AI95-00048-01} A library subprogram can
            be a remote call interface, but it cannot be a remote types or
            shared passive library unit.

5   [The various categories of library units and the associated restrictions
are described in this clause and its subclauses. The categories are related
hierarchically in that the library units of one category can depend
semantically only on library units of that category or an earlier one, except
that the body of a remote types or remote call interface library unit is
unrestricted.

6   The overall hierarchy (including declared pure) is as follows:

7   Declared Pure
                Can depend only on other declared pure library units;

8   Shared Passive
                Can depend only on other shared passive or declared pure
                library units;

9   Remote Types
                The declaration of the library unit can depend only on other
                remote types library units, or one of the above; the body of
                the library unit is unrestricted;

10  Remote Call Interface
                The declaration of the library unit can depend only on other
                remote call interfaces, or one of the above; the body of the
                library unit is unrestricted;

11  Normal      Unrestricted.

12  Declared pure and shared passive library units are preelaborated. The
declaration of a remote types or remote call interface library unit is
required to be preelaborable. ]


                         Implementation Requirements

13/1 This paragraph was deleted.{8652/0079} {AI95-00208-01}


                         Implementation Permissions

14  Implementations are allowed to define other categorization pragmas.


                         Wording Changes from Ada 95

14.a/2      {8652/0078} {AI95-00048-01} Corrigendum: Clarified that a library
            subprogram can be a remote call interface unit.

14.b/2      {8652/0079} {AI95-00208-01} Corrigendum: Removed the requirement
            that types be represented the same in all partitions, because it
            prevents the definition of heterogeneous distributed systems and
            goes much further than required.


E.2.1 Shared Passive Library Units


1   [A shared passive library unit is used for managing global data shared
between active partitions. The restrictions on shared passive library units
prevent the data or tasks of one active partition from being accessible to
another active partition through references implicit in objects declared in
the shared passive library unit.]


                         Language Design Principles

1.a         The restrictions governing a shared passive library unit are
            designed to ensure that objects and subprograms declared in the
            package can be used safely from multiple active partitions, even
            though the active partitions live in different address spaces, and
            have separate run-time systems.


                                   Syntax

2       {categorization pragma (Shared_Passive) [partial]}
        {pragma, categorization (Shared_Passive) [partial]} The form of a
        pragma Shared_Passive is as follows:

3         pragma Shared_Passive[(library_unit_name)];


                               Legality Rules

4   {shared passive library unit} A shared passive library unit is a library
unit to which a Shared_Passive pragma applies. The following restrictions
apply to such a library unit:

5     * [it shall be preelaborable (see 10.2.1);]

5.a         Ramification: It cannot contain library-level declarations of
            protected objects with entries, nor of task objects. Task objects
            are disallowed because passive partitions don't have any threads
            of control of their own, nor any run-time system of their own.
            Protected objects with entries are disallowed because an entry
            queue contains references to calling tasks, and that would require
            in effect a pointer from a passive partition back to a task in
            some active partition.

6     * it shall depend semantically only upon declared pure or shared passive
        library units;

6.a         Reason: Shared passive packages cannot depend semantically upon
            remote types packages because the values of an access type
            declared in a remote types package refer to the local heap of the
            active partition including the remote types package.

7/1   * {8652/0080} {AI95-00003-01} it shall not contain a library-level
        declaration of an access type that designates a class-wide type, task
        type, or protected type with entry_declarations.

7.a         Reason: These kinds of access types are disallowed because the
            object designated by an access value of such a type could contain
            an implicit reference back to the active partition on whose behalf
            the designated object was created.

8   {accessibility (from shared passive library units) [partial]}
{notwithstanding} Notwithstanding the definition of accessibility given in
3.10.2, the declaration of a library unit P1 is not accessible from within the
declarative region of a shared passive library unit P2, unless the shared
passive library unit P2 depends semantically on P1.

8.a         Discussion: We considered a more complex rule, but dropped it.
            This is the simplest rule that recognizes that a shared passive
            package may outlive some other library package, unless it depends
            semantically on that package. In a nondistributed program, all
            library packages are presumed to have the same lifetime.

8.b         Implementations may define additional pragmas that force two
            library packages to be in the same partition, or to have the same
            lifetime, which would allow this rule to be relaxed in the
            presence of such pragmas.


                              Static Semantics

9   {preelaborated [partial]} A shared passive library unit is preelaborated.


                           Post-Compilation Rules

10  A shared passive library unit shall be assigned to at most one partition
within a given program.

11  {compilation units needed (shared passive library unit) [partial]}
{needed (shared passive library unit) [partial]} {notwithstanding}
Notwithstanding the rule given in 10.2, a compilation unit in a given
partition does not need (in the sense of 10.2) the shared passive library
units on which it depends semantically to be included in that same partition;
they will typically reside in separate passive partitions.


                         Wording Changes from Ada 95

11.a/2      {8652/0080} {AI95-00003-01} Corrigendum: Corrected the wording to
            allow access types in blocks in shared passive generic packages.


E.2.2 Remote Types Library Units


1   [A remote types library unit supports the definition of types intended for
use in communication between active partitions.]


                         Language Design Principles

1.a         The restrictions governing a remote types package are similar to
            those for a declared pure package. However, the restrictions are
            relaxed deliberately to allow such a package to contain
            declarations that violate the stateless property of pure packages,
            though it is presumed that any state-dependent properties are
            essentially invisible outside the package.


                                   Syntax

2       {categorization pragma (Remote_Types) [partial]}
        {pragma, categorization (Remote_Types) [partial]} The form of a
        pragma Remote_Types is as follows:

3         pragma Remote_Types[(library_unit_name)];


                               Legality Rules

4   {remote types library unit} A remote types library unit is a library unit
to which the pragma Remote_Types applies. The following restrictions apply to
the declaration of such a library unit:

5     * [it shall be preelaborable;]

6     * it shall depend semantically only on declared pure, shared passive, or
        other remote types library units;

7     * it shall not contain the declaration of any variable within the
        visible part of the library unit;

7.a         Reason: This is essentially a "methodological" restriction. A
            separate copy of a remote types package is included in each
            partition that references it, just like a normal package.
            Nevertheless, a remote types package is thought of as an "
            essentially pure" package for defining types to be used for
            interpartition communication, and it could be misleading to
            declare visible objects when no remote data access is actually
            being provided.

8/2   * {AI95-00240-01} {AI95-00366-01} the full view of each type declared in
        the visible part of the library unit that has any available stream
        attributes shall support external streaming (see 13.13.2).

8.a         Reason: This is to prevent the use of the predefined Read and
            Write attributes of an access type as part of the Read and Write
            attributes of a visible type.

8.b/2       Ramification: {AI95-00366-01} Types that do not have available
            stream attributes are excluded from this rule; that means that
            attributes do not need to be specified for most limited types. It
            is only necessary to specify attributes for nonlimited types that
            have a part that is of any access type, and for extensions of
            limited types with available stream attributes where the
            record_extension_part includes a subcomponent of an access type,
            where the access type does not have specified attributes.

9/1 {8652/0082} {AI95-00164-01} {remote access type} An access type declared
in the visible part of a remote types or remote call interface library unit is
called a remote access type. {remote access-to-subprogram type}
{remote access-to-class-wide type} Such a type shall be:

9.1/1   * {8652/0082} {AI95-00164-01} an access-to-subprogram type, or

9.2/1   * {8652/0082} {AI95-00164-01} a general access type that designates a
        class-wide limited private type or a class-wide private type extension
        all of whose ancestors are either private type extensions or limited
        private types.

9.3/1 {8652/0081} {AI95-00004-01} A type that is derived from a remote access
type is also a remote access type.

10  The following restrictions apply to the use of a remote
access-to-subprogram type:

11/2   * {AI95-00431-01} A value of a remote access-to-subprogram type shall
        be converted only to or from another (subtype-conformant) remote
        access-to-subprogram type;

12    * The prefix of an Access attribute_reference that yields a value of a
        remote access-to-subprogram type shall statically denote a
        (subtype-conformant) remote subprogram.

13  The following restrictions apply to the use of a remote
access-to-class-wide type:

14/2   * {8652/0083} {AI95-00047-01} {AI95-00240-01} {AI95-00366-01} The
        primitive subprograms of the corresponding specific limited private
        type shall only have access parameters if they are controlling formal
        parameters; each non-controlling formal parameter shall support
        external streaming (see 13.13.2);

15    * A value of a remote access-to-class-wide type shall be explicitly
        converted only to another remote access-to-class-wide type;

16/1   * A value of a remote access-to-class-wide type shall be dereferenced
        (or implicitly converted to an anonymous access type) only as part of
        a dispatching call where the value designates a controlling operand of
        the call (see E.4, "Remote Subprogram Calls").

17/2   * {AI95-00366-01} The Storage_Pool attribute is not defined for a
        remote access-to-class-wide type; the expected type for an allocator
        shall not be a remote access-to-class-wide type. A remote
        access-to-class-wide type shall not be an actual parameter for a
        generic formal access type. The Storage_Size attribute of a remote
        access-to-class-wide type yields 0; it is not allowed in an
        attribute_definition_clause.

17.a/2      Reason: All three of these restrictions are because there is no
            storage pool associated with a remote access-to-class-wide type.
            The Storage_Size is defined to be 0 so that there is no conflict
            with the rules for pure units.

        NOTES

18      5  A remote types library unit need not be pure, and the types it
        defines may include levels of indirection implemented by using access
        types. User-specified Read and Write attributes (see 13.13.2) provide
        for sending values of such a type between active partitions, with
        Write marshalling the representation, and Read unmarshalling any
        levels of indirection.


                        Incompatibilities With Ada 95

18.a/2      {AI95-00240-01} {incompatibilities with Ada 95} Amendment
            Correction: The wording was changed from "user-specified" to "
            available" attributes. (This was then further changed, see below.)
            This means that an access type with the attributes specified in
            the private part would originally have been sufficient to allow
            the access type to be used in a remote type, but that is no longer
            allowed. Similarly, the attributes of a remote type that has
            access components have to be specified in the visible part. These
            changes were made so that the rules were consistent with the rules
            introduced for the Corrigendum for stream attributes; moreover,
            legality should not depend on the contents of the private part.


                            Extensions to Ada 95

18.b/2      {AI95-00366-01} {extensions to Ada 95} Remote types that cannot be
            streamed (that is, have no available stream attributes) do not
            require the specification of stream attributes. This is necessary
            so that most extensions of Limited_Controlled do not need stream
            attributes defined (otherwise there would be a signficant
            incompatibility, as Limited_Controlled would need stream
            attributes, and then all extensions of it also would need stream
            attributes).


                         Wording Changes from Ada 95

18.c/2      {8652/0081} {AI95-00004-01} Corrigendum: Added missing wording so
            that a type derived from a remote access type is also a remote
            access type.

18.d/2      {8652/0083} {AI95-00047-01} Corrigendum: Clarified that
            user-defined Read and Write attributes are required for the
            primitive subprograms corresponding to a remote
            access-to-class-wide type.

18.e/2      {8652/0082} {AI95-00164-01} Corrigendum: Added missing wording so
            that a remote access type can designate an appropriate private
            extension.

18.f/2      {AI95-00366-01} Changed the wording to use the newly defined term
            type that supports external streaming, so that various issues with
            access types in pure units and implicitly declared attributes for
            type extensions are properly handled.

18.g/2      {AI95-00366-01} Defined Storage_Size to be 0 for remote
            access-to-class-wide types, rather than having it undefined. This
            eliminates issues with pure units requiring a defined storage size.

18.h/2      {AI95-00431-01} Corrected the wording so that a value of a local
            access-to-subprogram type cannot be converted to a remote
            access-to-subprogram type, as intended (and required by the
            ACATS).


E.2.3 Remote Call Interface Library Units


1   [A remote call interface library unit can be used as an interface for
remote procedure calls (RPCs) (or remote function calls) between active
partitions.]


                         Language Design Principles

1.a         The restrictions governing a remote call interface library unit
            are intended to ensure that the values of the actual parameters in
            a remote call can be meaningfully sent between two active
            partitions.


                                   Syntax

2       {categorization pragma (Remote_Call_Interface) [partial]}
        {pragma, categorization (Remote_Call_Interface) [partial]} The form of
        a pragma Remote_Call_Interface is as follows:

3         pragma Remote_Call_Interface[(library_unit_name)];

4       The form of a pragma All_Calls_Remote is as follows:

5         pragma All_Calls_Remote[(library_unit_name)];

6       {library unit pragma (All_Calls_Remote) [partial]}
        {pragma, library unit (All_Calls_Remote) [partial]} A pragma
        All_Calls_Remote is a library unit pragma.


                               Legality Rules

7/1 {8652/0078} {AI95-00048-01} {remote call interface} {RCI (library unit)}
{RCI (package)} {RCI (generic)} {remote subprogram} A remote call interface
(RCI) is a library unit to which the pragma Remote_Call_Interface applies. A
subprogram declared in the visible part of such a library unit, or declared by
such a library unit, is called a remote subprogram.

8   The declaration of an RCI library unit shall be preelaborable (see
10.2.1), and shall depend semantically only upon declared pure, shared
passive, remote types, or other remote call interface library units.

9/1 {8652/0078} {AI95-00048-01} In addition, the following restrictions apply
to an RCI library unit:

10/1   * {8652/0078} {AI95-00048-01} its visible part shall not contain the
        declaration of a variable;

10.a/1      Reason: {8652/0078} {AI95-00048-01} Remote call interface units do
            not provide remote data access. A shared passive package has to be
            used for that.

11/1   * {8652/0078} {AI95-00048-01} its visible part shall not contain the
        declaration of a limited type;

11.a/2      Reason: {AI95-00240-01} {AI95-00366-01} We disallow the
            declaration of task and protected types, since calling an entry or
            a protected subprogram implicitly passes an object of a limited
            type (the target task or protected object). We disallow other
            limited types since we require that such types have available Read
            and Write attributes, but we certainly don't want the Read and
            Write attributes themselves to involve remote calls (thereby
            defeating their purpose of marshalling the value for remote
            calls).

12/1   * {8652/0078} {AI95-00048-01} its visible part shall not contain a
        nested generic_declaration;

12.a        Reason: This is disallowed because the body of the nested generic
            would presumably have access to data inside the body of the RCI
            package, and if instantiated in a different partition, remote data
            access might result, which is not supported.

13/1   * {8652/0078} {AI95-00048-01} it shall not be, nor shall its visible
        part contain, the declaration of a subprogram to which a pragma Inline
        applies;

14/2   * {8652/0078} {AI95-00048-01} {AI95-00240-01} {AI95-00366-01} it shall
        not be, nor shall its visible part contain, a subprogram (or
        access-to-subprogram) declaration whose profile has [an access
        parameter or] a parameter of a type that does not support external
        streaming (see 13.13.2);

15    * any public child of the library unit shall be a remote call interface
        library unit.

15.a        Reason: No restrictions apply to the private part of an RCI
            package, and since a public child can "see" the private part of
            its parent, such a child must itself have a Remote_Call_Interface
            pragma, and be assigned to the same partition (see below).

15.b        Discussion: We considered making the public child of an RCI
            package implicitly RCI, but it seemed better to require an
            explicit pragma to avoid any confusion.

15.c        Note that there is no need for a private child to be an RCI
            package, since it can only be seen from the body of its parent or
            its siblings, all of which are required to be in the same active
            partition.

16  If a pragma All_Calls_Remote applies to a library unit, the library unit
shall be a remote call interface.


                           Post-Compilation Rules

17  A remote call interface library unit shall be assigned to at most one
partition of a given program. A remote call interface library unit whose
parent is also an RCI library unit shall be assigned only to the same
partition as its parent.

17.a/1      Implementation Note: {8652/0078} {AI95-00048-01} The declaration
            of an RCI unit, with a calling-stub body, is automatically
            included in all active partitions with compilation units that
            depend on it. However the whole RCI library unit, including its
            (non-stub) body, will only be in one of the active partitions.

18  {compilation units needed (remote call interface) [partial]}
{needed (remote call interface) [partial]} {notwithstanding} Notwithstanding
the rule given in 10.2, a compilation unit in a given partition that
semantically depends on the declaration of an RCI library unit, needs (in the
sense of 10.2) only the declaration of the RCI library unit, not the body, to
be included in that same partition. [Therefore, the body of an RCI library
unit is included only in the partition to which the RCI library unit is
explicitly assigned.]


                         Implementation Requirements

19/1 {8652/0078} {AI95-00048-01} If a pragma All_Calls_Remote applies to a
given RCI library unit, then the implementation shall route any call to a
subprogram of the RCI unit from outside the declarative region of the unit
through the Partition Communication Subsystem (PCS); see E.5. Calls to such
subprograms from within the declarative region of the unit are defined to be
local and shall not go through the PCS.

19.a/1      Discussion: {8652/0078} {AI95-00048-01} Without this pragma, it is
            presumed that most implementations will make direct calls if the
            call originates in the same partition as that of the RCI unit.
            With this pragma, all calls from outside the subsystem rooted at
            the RCI unit are treated like calls from outside the partition,
            ensuring that the PCS is involved in all such calls (for
            debugging, redundancy, etc.).

19.b        Reason: There is no point to force local calls (or calls from
            children) to go through the PCS, since on the target system, these
            calls are always local, and all the units are in the same active
            partition.


                         Implementation Permissions

20  An implementation need not support the Remote_Call_Interface pragma nor
the All_Calls_Remote pragma. [Explicit message-based communication between
active partitions can be supported as an alternative to RPC.]

20.a        Ramification: Of course, it is pointless to support the
            All_Calls_Remote pragma if the Remote_Call_Interface pragma (or
            some approximate equivalent) is not supported.


                        Incompatibilities With Ada 95

20.b/2      {AI95-00240-01} {incompatibilities with Ada 95} Amendment
            Correction: The wording was changed from "user-specified" to "
            available" attributes. (This was then further changed, see below.)
            This means that a type with the attributes specified in the
            private part would originally have been allowed as a formal
            parameter of an RCI subprogram, but that is no longer allowed.
            This change was made so that the rules were consistent with the
            rules introduced for the Corrigendum for stream attributes;
            moreover, legality should not depend on the contents of the
            private part.


                         Wording Changes from Ada 95

20.c/2      {8652/0078} {AI95-00048-01} Corrigendum: Changed the wording to
            allow a library subprogram to be a remote call interface unit.

20.d/2      {AI95-00366-01} Changed the wording to use the newly defined term
            type that supports external streaming, so that various issues with
            access types in pure units and implicitly declared attributes for
            type extensions are properly handled.


E.3 Consistency of a Distributed System


1   [This clause defines attributes and rules associated with verifying the
consistency of a distributed program. ]


                         Language Design Principles

1.a         The rules guarantee that remote call interface and shared passive
            packages are consistent among all partitions prior to the
            execution of a distributed program, so that the semantics of the
            distributed program are well defined.


                              Static Semantics

2/1 For a prefix P that statically denotes a program unit, the following
attributes are defined:

3   P'Version   Yields a value of the predefined type String that identifies
                the version of the compilation unit that contains the
                declaration of the program unit.

4   P'Body_Version
                Yields a value of the predefined type String that identifies
                the version of the compilation unit that contains the body
                (but not any subunits) of the program unit.

5/1 {8652/0084} {AI95-00104-01} {version (of a compilation unit)} The version
of a compilation unit changes whenever the compilation unit changes in a
semantically significant way. This International Standard does not define the
exact meaning of "semantically significant". It is unspecified whether there
are other events (such as recompilation) that result in the version of a
compilation unit changing. {unspecified [partial]}

5.a/1       This paragraph was deleted.

5.1/1 {8652/0084} {AI95-00104-01} If P is not a library unit, and P has no
completion, then P'Body_Version returns the Body_Version of the innermost
program unit enclosing the declaration of P. If P is a library unit, and P has
no completion, then P'Body_Version returns a value that is different from
Body_Version of any version of P that has a completion.


                          Bounded (Run-Time) Errors

6   {bounded error (cause) [partial]} {unit consistency} In a distributed
program, a library unit is consistent if the same version of its declaration
is used throughout. It is a bounded error to elaborate a partition of a
distributed program that contains a compilation unit that depends on a
different version of the declaration of a shared passive or RCI library unit
than that included in the partition to which the shared passive or RCI library
unit was assigned. {Program_Error (raised by failure of run-time check)} As a
result of this error, Program_Error can be raised in one or both partitions
during elaboration; in any case, the partitions become inaccessible to one
another.

6.a         Ramification: Because a version changes if anything on which it
            depends undergoes a version change, requiring consistency for
            shared passive and remote call interface library units is
            sufficient to ensure consistency for the declared pure and remote
            types library units that define the types used for the objects and
            parameters through which interpartition communication takes place.

6.b         Note that we do not require matching Body_Versions; it is
            irrelevant for shared passive and remote call interface packages,
            since only one copy of their body exists in a distributed program
            (in the absence of implicit replication), and we allow the bodies
            to differ for declared pure and remote types packages from
            partition to partition, presuming that the differences are due to
            required error corrections that took place during the execution of
            a long-running distributed program. The Body_Version attribute
            provides a means for performing stricter consistency checks.


                         Wording Changes from Ada 95

6.c/2       {8652/0084} {AI95-00104-01} Corrigendum: Clarified the meaning of
            'Version and 'Body_Version.


E.4 Remote Subprogram Calls


1   {remote subprogram call} {asynchronous remote procedure call
 [distributed]} {calling partition} {called partition}
{remote subprogram binding} A remote subprogram call is a subprogram call that
invokes the execution of a subprogram in another partition. The partition that
originates the remote subprogram call is the calling partition, and the
partition that executes the corresponding subprogram body is the called
partition. Some remote procedure calls are allowed to return prior to the
completion of subprogram execution. These are called asynchronous remote
procedure calls.

2   There are three different ways of performing a remote subprogram call:

3     * As a direct call on a (remote) subprogram explicitly declared in a
        remote call interface;

4     * As an indirect call through a value of a remote access-to-subprogram
        type;

5     * As a dispatching call with a controlling operand designated by a value
        of a remote access-to-class-wide type.

6   The first way of calling corresponds to a static binding between the
calling and the called partition. The latter two ways correspond to a dynamic
binding between the calling and the called partition.

7   A remote call interface library unit (see E.2.3) defines the remote
subprograms or remote access types used for remote subprogram calls.


                         Language Design Principles

7.a         Remote subprogram calls are standardized since the RPC paradigm is
            widely-used, and establishing an interface to it in the annex will
            increase the portability and reusability of distributed programs.


                               Legality Rules

8   In a dispatching call with two or more controlling operands, if one
controlling operand is designated by a value of a remote access-to-class-wide
type, then all shall be.


                              Dynamic Semantics

9   {marshalling} {unmarshalling} {execution (remote subprogram call)
 [partial]} For the execution of a remote subprogram call, subprogram
parameters (and later the results, if any) are passed using a stream-oriented
representation (see 13.13.1) [which is suitable for transmission between
partitions]. This action is called marshalling. Unmarshalling is the reverse
action of reconstructing the parameters or results from the stream-oriented
representation. [Marshalling is performed initially as part of the remote
subprogram call in the calling partition; unmarshalling is done in the called
partition. After the remote subprogram completes, marshalling is performed in
the called partition, and finally unmarshalling is done in the calling
partition.]

10  {calling stub} {receiving stub} A calling stub is the sequence of code
that replaces the subprogram body of a remotely called subprogram in the
calling partition. A receiving stub is the sequence of code (the "wrapper")
that receives a remote subprogram call on the called partition and invokes the
appropriate subprogram body.

10.a        Discussion: The use of the term stub in this annex should not be
            confused with body_stub as defined in 10.1.3. The term stub is
            used here because it is a commonly understood term when talking
            about the RPC paradigm.

11  {at-most-once execution} Remote subprogram calls are executed at most
once, that is, if the subprogram call returns normally, then the called
subprogram's body was executed exactly once.

12  The task executing a remote subprogram call blocks until the subprogram in
the called partition returns, unless the call is asynchronous. For an
asynchronous remote procedure call, the calling task can become ready before
the procedure in the called partition returns.

13  {cancellation of a remote subprogram call} If a construct containing a
remote call is aborted, the remote subprogram call is cancelled. Whether the
execution of the remote subprogram is immediately aborted as a result of the
cancellation is implementation defined.

13.a        Implementation defined: Whether the execution of the remote
            subprogram is immediately aborted as a result of cancellation.

14  If a remote subprogram call is received by a called partition before the
partition has completed its elaboration, the call is kept pending until the
called partition completes its elaboration (unless the call is cancelled by
the calling partition prior to that).

15  If an exception is propagated by a remotely called subprogram, and the
call is not an asynchronous call, the corresponding exception is reraised at
the point of the remote subprogram call. For an asynchronous call, if the
remote procedure call returns prior to the completion of the remotely called
subprogram, any exception is lost.

16  The exception Communication_Error (see E.5) is raised if a remote call
cannot be completed due to difficulties in communicating with the called
partition.

17  {potentially blocking operation (remote subprogram call) [partial]}
{blocking, potentially (remote subprogram call) [partial]} All forms of remote
subprogram calls are potentially blocking operations (see 9.5.1).

17.a        Reason: Asynchronous remote procedure calls are potentially
            blocking since the implementation may require waiting for the
            availability of shared resources to initiate the remote call.

18/1 {8652/0085} {AI95-00215-01} {Accessibility_Check [partial]}
{check, language-defined (Accessibility_Check)} In a remote subprogram call
with a formal parameter of a class-wide type, a check is made that the tag of
the actual parameter identifies a tagged type declared in a declared-pure or
shared passive library unit, or in the visible part of a remote types or
remote call interface library unit.
{Program_Error (raised by failure of run-time check)} Program_Error is raised
if this check fails. In a remote function call which returns a class-wide
type, the same check is made on the function result.

18.a/1      Discussion: {8652/0085} {AI95-00215-01} This check makes certain
            that the specific type passed or returned in an RPC satisfies the
            rules for a "communicable" type. Normally this is guaranteed by
            the compile-time restrictions on remote call interfaces. However,
            with class-wide types, it is possible to pass an object whose tag
            identifies a type declared outside the "safe" packages.

18.b        This is considered an accessibility_check since only the types
            declared in "safe" packages are considered truly "global"
            (cross-partition). Other types are local to a single partition.
            This is analogous to the "accessibility" of global vs. local
            declarations in a single-partition program.

18.c        This rule replaces a rule from an early version of Ada 9X which
            was given in the subclause on Remote Types Library Units (now
            E.2.2, "Remote Types Library Units"). That rule tried to prevent
            "bad" types from being sent by arranging for their tags to
            mismatch between partitions. However, that interfered with other
            uses of tags. The new rule allows tags to agree in all partitions,
            even for those types which are not "safe" to pass in an RPC.

19  {Partition_Check [partial]} {check, language-defined (Partition_Check)} In
a dispatching call with two or more controlling operands that are designated
by values of a remote access-to-class-wide type, a check is made [(in addition
to the normal Tag_Check - see 11.5)] that all the remote access-to-class-wide
values originated from Access attribute_references that were evaluated by
tasks of the same active partition.
{Constraint_Error (raised by failure of run-time check)} Constraint_Error is
raised if this check fails.

19.a        Implementation Note: When a remote access-to-class-wide value is
            created by an Access attribute_reference, the identity of the
            active partition that evaluated the attribute_reference should be
            recorded in the representation of the remote access value.


                         Implementation Requirements

20  The implementation of remote subprogram calls shall conform to the PCS
interface as defined by the specification of the language-defined package
System.RPC (see E.5). The calling stub shall use the Do_RPC procedure unless
the remote procedure call is asynchronous in which case Do_APC shall be used.
On the receiving side, the corresponding receiving stub shall be invoked by
the RPC-receiver.

20.a        Implementation Note: One possible implementation model is as
            follows:

20.b        The code for calls to subprograms declared in an RCI package is
            generated normally, that is, the call-site is the same as for a
            local subprogram call. The code for the remotely callable
            subprogram bodies is also generated normally. Subprogram's
            prologue and epilogue are the same as for a local call.

20.c        When compiling the specification of an RCI package, the compiler
            generates calling stubs for each visible subprogram. Similarly,
            when compiling the body of an RCI package, the compiler generates
            receiving stubs for each visible subprogram together with the
            appropriate tables to allow the RPC-receiver to locate the correct
            receiving stub.

20.d        For the statically bound remote calls, the identity of the remote
            partition is statically determined (it is resolved at
            configuration/link time).

20.e        The calling stub operates as follows:

20.f          * It allocates (or reuses) a stream of Params_Stream_Type of
                Initial_Size, and initializes it by repeatedly calling Write
                operations, first to identify which remote subprogram in the
                receiving partition is being called, and then to pass the
                incoming value of each of the in and in out parameters of the
                call.

20.g          * It allocates (or reuses) a stream for the Result, unless a
                pragma Asynchronous is applied to the procedure.

20.h          * It calls Do_RPC unless a pragma Asynchronous is applied to the
                procedure in which case it calls Do_APC. An access value
                designating the message stream allocated and initialized above
                is passed as the Params parameter. An access value designating
                the Result stream is passed as the Result parameter.

20.i          * If the pragma Asynchronous is not specified for the procedure,
                Do_RPC blocks until a reply message arrives, and then returns
                to the calling stub. The stub returns after extracting from
                the Result stream, using Read operations, the in out and out
                parameters or the function result. If the reply message
                indicates that the execution of the remote subprogram
                propagated an exception, the exception is propagated from
                Do_RPC to the calling stub, and thence to the point of the
                original remote subprogram call. If Do_RPC detects that
                communication with the remote partition has failed, it
                propagates Communication_Error.

20.j        On the receiving side, the RPC-receiver procedure operates as
            follows:

20.k          * It is called from the PCS when a remote-subprogram-call
                message is received. The call originates in some remote call
                receiver task executed and managed in the context of the PCS.

20.l          * It extracts information from the stream to identify the
                appropriate receiving stub.

20.m          * The receiving stub extracts the in and in out parameters using
                Read from the stream designated by the Params parameter.

20.n          * The receiving stub calls the actual subprogram body and, upon
                completion of the subprogram, uses Write to insert the results
                into the stream pointed to by the Result parameter. The
                receiving stub returns to the RPC-receiver procedure which in
                turn returns to the PCS. If the actual subprogram body
                propagates an exception, it is propagated by the RPC-receiver
                to the PCS, which handles the exception, and indicates in the
                reply message that the execution of the subprogram body
                propagated an exception. The exception occurrence can be
                represented in the reply message using the Write attribute of
                Ada.Exceptions.Exception_Occurrence.

20.o        For remote access-to-subprogram types:

20.p        A value of a remote access-to-subprogram type can be represented
            by the following components: a reference to the remote partition,
            an index to the package containing the remote subprogram, and an
            index to the subprogram within the package. The values of these
            components are determined at run time when the remote access value
            is created. These three components serve the same purpose when
            calling Do_APC/RPC, as in the statically bound remote calls; the
            only difference is that they are evaluated dynamically.

20.q        For remote access-to-class-wide types:

20.r        For each remote access-to-class-wide type, a calling stub is
            generated for each dispatching operation of the designated type.
            In addition, receiving stubs are generated to perform the remote
            dispatching operations in the called partition. The appropriate
            subprogram_body is determined as for a local dispatching call once
            the receiving stub has been reached.

20.s        A value of a remote access-to-class-wide type can be represented
            with the following components: a reference to the remote
            partition, an index to a table (created one per each such access
            type) containing addresses of all the dispatching operations of
            the designated type, and an access value designating the actual
            remote object.

20.t        Alternatively, a remote access-to-class-wide value can be
            represented as a normal access value, pointing to a "stub" object
            which in turn contains the information mentioned above. A call on
            any dispatching operation of such a stub object does the remote
            call, if necessary, using the information in the stub object to
            locate the target partition, etc. This approach has the advantage
            that less special-casing is required in the compiler. All access
            values can remain just a simple address.

20.u        {Constraint_Error (raised by failure of run-time check)} For a
            call to Do_RPC or Do_APC: The partition ID of all controlling
            operands are checked for equality (a Constraint_Error is raised if
            this check fails). The partition ID value is used for the
            Partition parameter. An index into the tagged-type-descriptor is
            created. This index points to the receiving stub of the class-wide
            operation. This index and the index to the table (described above)
            are written to the stream. Then, the actual parameters are
            marshalled into the message stream. For a controlling operand,
            only the access value designating the remote object is required
            (the other two components are already present in the other
            parameters).

20.v        On the called partition (after the RPC-receiver has transferred
            control to the appropriate receiving stub) the parameters are
            first unmarshalled. Then, the tags of the controlling operands
            (obtained by dereferencing the pointer to the object) are checked
            for equality.
            {Constraint_Error (raised by failure of run-time check)} If the
            check fails Constraint_Error is raised and propagated back to the
            calling partition, unless it is a result of an asynchronous call.
            Finally, a dispatching call to the specific subprogram (based on
            the controlling object's tag) is made. Note that since this
            subprogram is not in an RCI package, no specific stub is generated
            for it, it is called normally from the dispatching stub.

20.1/1 {8652/0086} {AI95-00159-01} With respect to shared variables in shared
passive library units, the execution of the corresponding subprogram body of a
synchronous remote procedure call is considered to be part of the execution of
the calling task. The execution of the corresponding subprogram body of an
asynchronous remote procedure call proceeds in parallel with the calling task
and does not signal the next action of the calling task (see 9.10).

        NOTES

21      6  A given active partition can both make and receive remote
        subprogram calls. Thus, an active partition can act as both a client
        and a server.

22      7  If a given exception is propagated by a remote subprogram call, but
        the exception does not exist in the calling partition, the exception
        can be handled by an others choice or be propagated to and handled by
        a third partition.

22.a        Discussion: This situation can happen in a case of dynamically
            nested remote subprogram calls, where an intermediate call
            executes in a partition that does not include the library unit
            that defines the exception.


                         Wording Changes from Ada 95

22.b/2      {8652/0086} {AI95-00159-01} Corrigendum: Added rules so that tasks
            can safely access shared passive objects.

22.c/2      {8652/0085} {AI95-00215-01} Corrigendum: Clarified that the check
            on class-wide types also applies to values returned from remote
            subprogram call functions.


E.4.1 Pragma Asynchronous


1   [This subclause introduces the pragma Asynchronous which allows a remote
subprogram call to return prior to completion of the execution of the
corresponding remote subprogram body.]


                                   Syntax

2       The form of a pragma Asynchronous is as follows:

3         pragma Asynchronous(local_name);


                               Legality Rules

4   The local_name of a pragma Asynchronous shall denote either:

5     * One or more remote procedures; the formal parameters of the
        procedure(s) shall all be of mode in;

6     * The first subtype of a remote access-to-procedure type; the formal
        parameters of the designated profile of the type shall all be of mode
        in;

7     * The first subtype of a remote access-to-class-wide type.


                              Static Semantics

8   {representation pragma (Asynchronous) [partial]}
{pragma, representation (Asynchronous) [partial]} A pragma Asynchronous is a
representation pragma. When applied to a type, it specifies the type-related
asynchronous aspect of the type.


                              Dynamic Semantics

9   {remote procedure call (asynchronous)}
{asynchronous (remote procedure call)} A remote call is asynchronous if it is a
call to a procedure, or a call through a value of an access-to-procedure type,
to which a pragma Asynchronous applies. In addition, if a pragma Asynchronous
applies to a remote access-to-class-wide type, then a dispatching call on a
procedure with a controlling operand designated by a value of the type is
asynchronous if the formal parameters of the procedure are all of mode in.


                         Implementation Requirements

10  Asynchronous remote procedure calls shall be implemented such that the
corresponding body executes at most once as a result of the call.

10.a        To be honest: It is not clear that this rule can be tested or even
            defined formally.


E.4.2 Example of Use of a Remote Access-to-Class-Wide Type



                                  Examples

1   Example of using a remote access-to-class-wide type to achieve dynamic
binding across active partitions:

2       package Tapes is
           pragma Pure(Tapes);
           type Tape is abstract tagged limited private;
           -- Primitive dispatching operations where
           -- Tape is controlling operand
           procedure Copy (From, To : access Tape; Num_Recs : in Natural) is abstract;
           procedure Rewind (T : access Tape) is abstract;
           -- More operations
        private
           type Tape is ...
        end Tapes;

3       with Tapes;
        package Name_Server is
           pragma Remote_Call_Interface;
           -- Dynamic binding to remote operations is achieved
           -- using the access-to-limited-class-wide type Tape_Ptr
           type Tape_Ptr is access all Tapes.Tape'Class;
           -- The following statically bound remote operations
           -- allow for a name-server capability in this example
           function  Find     (Name : String) return Tape_Ptr;
           procedure Register (Name : in String; T : in Tape_Ptr);
           procedure Remove   (T : in Tape_Ptr);
           -- More operations
        end Name_Server;

4       package Tape_Driver is
          -- Declarations are not shown, they are irrelevant here
        end Tape_Driver;

5       with Tapes, Name_Server;
        package body Tape_Driver is
           type New_Tape is new Tapes.Tape with ...
           procedure Copy
            (From, To : access New_Tape; Num_Recs: in Natural) is
           begin
             . . .
           end Copy;
           procedure Rewind (T : access New_Tape) is
           begin
              . . .
           end Rewind;
           -- Objects remotely accessible through use
           -- of Name_Server operations
           Tape1, Tape2 : aliased New_Tape;
        begin
           Name_Server.Register ("NINE-TRACK",  Tape1'Access);
           Name_Server.Register ("SEVEN-TRACK", Tape2'Access);
        end Tape_Driver;

6       with Tapes, Name_Server;
        -- Tape_Driver is not needed and thus not mentioned in the with_clause
        procedure Tape_Client is
           T1, T2 : Name_Server.Tape_Ptr;
        begin
           T1 := Name_Server.Find ("NINE-TRACK");
           T2 := Name_Server.Find ("SEVEN-TRACK");
           Tapes.Rewind (T1);
           Tapes.Rewind (T2);
           Tapes.Copy (T1, T2, 3);
        end Tape_Client;

7   Notes on the example:

7.a         Discussion: The example does not show the case where tapes are
            removed from or added to the system. In the former case, an
            appropriate exception needs to be defined to instruct the client
            to use another tape. In the latter, the Name_Server should have a
            query function visible to the clients to inform them about the
            availability of the tapes in the system.

8/1 This paragraph was deleted.

9     * The package Tapes provides the necessary declarations of the type and
        its primitive operations.

10    * Name_Server is a remote call interface package and is elaborated in a
        separate active partition to provide the necessary naming services
        (such as Register and Find) to the entire distributed program through
        remote subprogram calls.

11    * Tape_Driver is a normal package that is elaborated in a partition
        configured on the processing node that is connected to the tape
        device(s). The abstract operations are overridden to support the
        locally declared tape devices (Tape1, Tape2). The package is not
        visible to its clients, but it exports the tape devices (as remote
        objects) through the services of the Name_Server. This allows for tape
        devices to be dynamically added, removed or replaced without requiring
        the modification of the clients' code.

12    * The Tape_Client procedure references only declarations in the Tapes
        and Name_Server packages. Before using a tape for the first time, it
        needs to query the Name_Server for a system-wide identity for that
        tape. From then on, it can use that identity to access the tape device.

13    * Values of remote access type Tape_Ptr include the necessary
        information to complete the remote dispatching operations that result
        from dereferencing the controlling operands T1 and T2.


E.5 Partition Communication Subsystem


1/2 {AI95-00273-01} {partition communication subsystem (PCS)}
{PCS (partition communication subsystem)} [The Partition Communication
Subsystem (PCS) provides facilities for supporting communication between the
active partitions of a distributed program. The package System.RPC is a
language-defined interface to the PCS.]

1.a         Reason: The prefix RPC is used rather than RSC because the term
            remote procedure call and its acronym are more familiar.


                              Static Semantics

2   The following language-defined library package exists:

3       with Ada.Streams; -- see 13.13.1
        package System.RPC is

4          type Partition_Id is range 0 .. implementation-defined;

5          Communication_Error : exception;

6          type Params_Stream_Type (
              Initial_Size : Ada.Streams.Stream_Element_Count) is new
              Ada.Streams.Root_Stream_Type with private;

7          procedure Read(
              Stream : in out Params_Stream_Type;
              Item : out Ada.Streams.Stream_Element_Array;
              Last : out Ada.Streams.Stream_Element_Offset);

8          procedure Write(
              Stream : in out Params_Stream_Type;
              Item : in Ada.Streams.Stream_Element_Array);

9          -- Synchronous call
           procedure Do_RPC(
              Partition  : in Partition_Id;
              Params     : access Params_Stream_Type;
              Result     : access Params_Stream_Type);

10         -- Asynchronous call
           procedure Do_APC(
              Partition  : in Partition_Id;
              Params     : access Params_Stream_Type);

11         -- The handler for incoming RPCs
           type RPC_Receiver is access procedure(
              Params     : access Params_Stream_Type;
              Result     : access Params_Stream_Type);

12         procedure Establish_RPC_Receiver(
              Partition : in Partition_Id;
              Receiver  : in RPC_Receiver);

13      private
           ... -- not specified by the language
        end System.RPC;

14  A value of the type Partition_Id is used to identify a partition.

14.a/2      Implementation defined: The range of type System.RPC.Partition_Id.

15  An object of the type Params_Stream_Type is used for identifying the
particular remote subprogram that is being called, as well as marshalling and
unmarshalling the parameters or result of a remote subprogram call, as part of
sending them between partitions.

16  [The Read and Write procedures override the corresponding abstract
operations for the type Params_Stream_Type.]


                              Dynamic Semantics

17  The Do_RPC and Do_APC procedures send a message to the active partition
identified by the Partition parameter.

17.a        Implementation Note: It is assumed that the RPC interface is above
            the message-passing layer of the network protocol stack and is
            implemented in terms of it.

18  After sending the message, Do_RPC blocks the calling task until a reply
message comes back from the called partition or some error is detected by the
underlying communication system in which case Communication_Error is raised at
the point of the call to Do_RPC.

18.a        Reason: Only one exception is defined in System.RPC, although many
            sources of errors might exist. This is so because it is not always
            possible to distinguish among these errors. In particular, it is
            often impossible to tell the difference between a failing
            communication link and a failing processing node. Additional
            information might be associated with a particular
            Exception_Occurrence for a Communication_Error.

19  Do_APC operates in the same way as Do_RPC except that it is allowed to
return immediately after sending the message.

20  Upon normal return, the stream designated by the Result parameter of
Do_RPC contains the reply message.

21  {elaboration (partition) [partial]} The procedure
System.RPC.Establish_RPC_Receiver is called once, immediately after
elaborating the library units of an active partition (that is, right after the
elaboration of the partition) if the partition includes an RCI library unit,
but prior to invoking the main subprogram, if any. The Partition parameter is
the Partition_Id of the active partition being elaborated. {RPC-receiver} The
Receiver parameter designates an implementation-provided procedure called the
RPC-receiver which will handle all RPCs received by the partition from the
PCS. Establish_RPC_Receiver saves a reference to the RPC-receiver; when a
message is received at the called partition, the RPC-receiver is called with
the Params stream containing the message. When the RPC-receiver returns, the
contents of the stream designated by Result is placed in a message and sent
back to the calling partition.

21.a        Implementation Note: It is defined by the PCS implementation
            whether one or more threads of control should be available to
            process incoming messages and to wait for their completion.

21.b        Implementation Note: At link-time, the linker provides the
            RPC-receiver and the necessary tables to support it. A call on
            Establish_RPC_Receiver is inserted just before the call on the
            main subprogram.

21.c        Reason: The interface between the PCS (the System.RPC package) and
            the RPC-receiver is defined to be dynamic in order to allow the
            elaboration sequence to notify the PCS that all packages have been
            elaborated and that it is safe to call the receiving stubs. It is
            not guaranteed that the PCS units will be the last to be
            elaborated, so some other indication that elaboration is complete
            is needed.

22  If a call on Do_RPC is aborted, a cancellation message is sent to the
called partition, to request that the execution of the remotely called
subprogram be aborted.

22.a        To be honest: The full effects of this message are dependent on
            the implementation of the PCS.

23  {potentially blocking operation (RPC operations) [partial]}
{blocking, potentially (RPC operations) [partial]} The subprograms declared in
System.RPC are potentially blocking operations.


                         Implementation Requirements

24  The implementation of the RPC-receiver shall be reentrant[, thereby
allowing concurrent calls on it from the PCS to service concurrent remote
subprogram calls into the partition].

24.a        Reason: There seems no reason to allow the implementation of
            RPC-receiver to be nonreentrant, even though we don't require that
            every implementation of the PCS actually perform concurrent calls
            on the RPC-receiver.

24.1/1 {8652/0087} {AI95-00082-01} An implementation shall not restrict the
replacement of the body of System.RPC. An implementation shall not restrict
children of System.RPC. [The related implementation permissions in the
introduction to Annex A do not apply.]

24.a.1/1    Reason: The point of System.RPC is to let the user tailor the
            communications mechanism without requiring changes to or other
            cooperation from the compiler. However, implementations can
            restrict the replacement of language-defined units. This
            requirement overrides that permission for System.RPC.

24.2/1 {8652/0087} {AI95-00082-01} If the implementation of System.RPC is
provided by the user, an implementation shall support remote subprogram calls
as specified.

24.b/2      Discussion: {AI95-00273-01} If the implementation takes advantage
            of the implementation permission to use a different specification
            for System.RPC, it still needs to use it for remote subprogram
            calls, and allow the user to replace the body of System.RPC. It
            just isn't guaranteed to be portable to do so in Ada 2005 - an
            advantage which was more theoretical than real anyway.


                         Documentation Requirements

25  The implementation of the PCS shall document whether the RPC-receiver is
invoked from concurrent tasks. If there is an upper limit on the number of
such tasks, this limit shall be documented as well, together with the
mechanisms to configure it (if this is supported).

25.a/2      This paragraph was deleted.

25.a.1/2    Documentation Requirement: Whether the RPC-receiver is invoked
            from concurrent tasks, and if so, the number of such tasks.


                         Implementation Permissions

26  The PCS is allowed to contain implementation-defined interfaces for
explicit message passing, broadcasting, etc. Similarly, it is allowed to
provide additional interfaces to query the state of some remote partition
(given its partition ID) or of the PCS itself, to set timeouts and retry
parameters, to get more detailed error status, etc. These additional
interfaces should be provided in child packages of System.RPC.

26.a        Implementation defined: Implementation-defined interfaces in the
            PCS.

27  A body for the package System.RPC need not be supplied by the
implementation.

27.a        Reason: It is presumed that a body for the package System.RPC
            might be extremely environment specific. Therefore, we do not
            require that a body be provided by the (compiler) implementation.
            The user will have to write a body, or acquire one, appropriate
            for the target environment.

27.1/2 {AI95-00273-01} An alternative declaration is allowed for package
System.RPC as long as it provides a set of operations that is substantially
equivalent to the specification defined in this clause.

27.b/2      Reason: Experience has proved that the definition of System.RPC
            given here is inadequate for interfacing to existing distribution
            mechanisms (such as CORBA), especially on heterogeneous systems.
            Rather than mandate a change in the mechanism (which would break
            existing systems), require implementations to support multiple
            mechanisms (which is impractical), or prevent the use of Annex E
            facilities with existing systems (which would be silly), we simply
            make this facility optional.

27.c/2      One of the purposes behind System.RPC was that knowledgeable
            users, rather than compiler vendors, could create this package
            tailored to their networks. Experience has shown that users get
            their RPC from vendors anyway; users have not taken advantage of
            the flexibility provided by this defined interface. Moreover, one
            could compare this defined interface to requiring Ada compilers to
            use a defined interface to implement tasking. No one thinks that
            the latter is a good idea, why should anyone believe that the
            former is?

27.d/2      Therefore, this clause is made optional. We considered deleting
            the clause outright, but we still require that users may replace
            the package (whatever its interface). Also, it still provides a
            useful guide to the implementation of this feature.


                            Implementation Advice

28  Whenever possible, the PCS on the called partition should allow for
multiple tasks to call the RPC-receiver with different messages and should
allow them to block until the corresponding subprogram body returns.

28.a/2      Implementation Advice: The PCS should allow for multiple tasks to
            call the RPC-receiver.

29  The Write operation on a stream of type Params_Stream_Type should raise
Storage_Error if it runs out of space trying to write the Item into the
stream.

29.a.1/2    Implementation Advice: The System.RPC.Write operation should raise
            Storage_Error if it runs out of space when writing an item.

29.a        Implementation Note: An implementation could also dynamically
            allocate more space as needed, only propagating Storage_Error if
            the allocator it calls raises Storage_Error. This storage could be
            managed through a controlled component of the stream object, to
            ensure that it is reclaimed when the stream object is finalized.

        NOTES

30      8  The package System.RPC is not designed for direct calls by user
        programs. It is instead designed for use in the implementation of
        remote subprograms calls, being called by the calling stubs generated
        for a remote call interface library unit to initiate a remote call,
        and in turn calling back to an RPC-receiver that dispatches to the
        receiving stubs generated for the body of a remote call interface, to
        handle a remote call received from elsewhere.


                        Incompatibilities With Ada 95

30.a/2      {AI95-00273-01} {incompatibilities with Ada 95} The specification
            of System.RPC can now be tailored for an implementation. If a
            program replaces the body of System.RPC with a user-defined body,
            it might not compile in a given implementation of Ada 2005 (if the
            specification of System.RPC has been changed).


                         Wording Changes from Ada 95

30.b/2      {8652/0087} {AI95-00082-01} Corrigendum: Clarified that the user
            can replace System.RPC.

Generated by dwww version 1.15 on Wed May 22 19:16:51 CEST 2024.