Contents Index Previous Next
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}
{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}
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}
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).
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.
Contents Index Previous Next Legal