Ada Conformity Assessment Authority      Home Conformity Assessment   Test Suite ARGAda Standard
Annotated Ada Reference Manual (Ada 2022)Legal Information
Contents   Index   References   Search   Previous   Next 

10.2 Program Execution

An Ada program consists of a set of partitions[, which can execute in parallel with one another, possibly in a separate address space, and possibly on a separate computer.] 

Post-Compilation Rules

{AI12-0439-1} {AI12-0448-1} A partition is a program or part of a program that can be invoked from outside the Ada implementation. [For example, on many systems, a partition can might be an executable file generated by the system linker.] The user can explicitly assign library units to a partition. The assignment is done in an implementation-defined manner. The compilation units included in a partition are those of the explicitly assigned library units, as well as other compilation units needed by those library units. The compilation units needed by a given compilation unit (the needed compilation unitsare determined as follows (unless specified otherwise via an implementation-defined pragma, or by some other implementation-defined means):
Discussion: From a run-time point of view, an Ada 95 partition is identical to an Ada 83 program — implementations were always allowed to provide inter-program communication mechanisms. The additional semantics of partitions is that interfaces between them can be defined to obey normal language rules (as is done in Annex E, “Distributed Systems”), whereas interfaces between separate programs had no particular semantics. 
Implementation defined: The manner of explicitly assigning library units to a partition.
Implementation defined: The implementation-defined means, if any, of specifying which compilation units are needed by a given compilation unit.
Discussion: There are no pragmas that “specify otherwise” defined by the core language. However, an implementation is allowed to provide such pragmas, and in fact Annex E, “Distributed Systems” defines some pragmas whose semantics includes reducing the set of compilation units described here. 
Term entry: needed compilation unit — compilation unit that is necessary to produce an executable partition, because some entity declared or defined within the unit is used elsewhere in the partition
{AI12-0448-1} A compilation unit is a needed compilation unit of needs itself;
{AI12-0448-1} If a compilation unit is among the needed compilation units, then so are any compilation units upon which it depends semantically;
{AI12-0448-1} If a library_unit_declaration is among the needed compilation units, then so is any corresponding library_unit_body;
{AI95-00217-06} {AI12-0448-1} If a compilation unit with stubs is among the needed compilation units, then so are any corresponding subunits;
Discussion: Note that in the environment, the stubs are replaced with the corresponding proper_bodies.
{AI95-00217-06} {AI12-0448-1} If the (implicit) declaration of the limited view of a library package is among the needed compilation units, then so is the explicit declaration of the library package.
Discussion: Note that a child unit is not included just because its parent is included — to include a child, mention it in a with_clause.
{AI95-00217-06} A package is included in a partition even if the only reference to it is in a limited_with_clause. While this isn't strictly necessary (no objects of types imported from such a unit can be created), it ensures that all incomplete types are eventually completed, and is the least surprising option. 
The user can optionally designate (in an implementation-defined manner) one subprogram as the main subprogram for the partition. A main subprogram, if specified, shall be a subprogram.
Discussion: This may seem superfluous, since it follows from the definition. But we would like to have every error message that might be generated (before run time) by an implementation correspond to some explicitly stated “shall” rule.
Of course, this does not mean that the “shall” rules correspond one-to-one with an implementation's error messages. For example, the rule that says overload resolution “shall” succeed in producing a single interpretation would correspond to many error messages in a good implementation — the implementation would want to explain to the user exactly why overload resolution failed. This is especially true for the syntax rules — they are considered part of overload resolution, but in most cases, one would expect an error message based on the particular syntax rule that was violated. 
Implementation defined: The manner of designating the main subprogram of a partition.
Ramification: An implementation cannot require the user to specify, say, all of the library units to be included. It has to support, for example, perhaps the most typical case, where the user specifies just one library unit, the main program. The implementation has to do the work of tracking down all the other ones. 
Each partition has an anonymous environment task[, which is an implicit outermost task whose execution elaborates the library_items of the environment declarative_part, and then calls the main subprogram, if there is one. A partition's execution is that of its tasks.] 
Ramification: An environment task has no master; all nonenvironment tasks have masters.
An implementation is allowed to support multiple concurrent executions of the same partition. 
{AI12-0448-1} [The order of elaboration of library units is determined primarily by the elaboration dependences.] There is an elaboration dependence of a given library_item upon another if the given library_item or any of its subunits depends semantically on the other library_item. In addition, if a given library_item or any of its subunits has a pragma Elaborate or Elaborate_All that names another library unit, then there is an elaboration dependence of the given library_item upon the body of the other library unit, and, for Elaborate_All only, upon each library_item that is a needed compilation unit of by the declaration of the other library unit. 
Discussion: {8652/0107} {AI95-00180-01} {AI95-00256-01} “Mentions” was used informally in the above rule; it was not intended to refer to the definition of mentions in 10.1.2. It was changed to “names” to make this clear.
See above for a definition of which library_items are “needed by” a given declaration.
{AI12-0417-1} Note that elaboration dependences are among library_items, whereas the other two forms of dependence are among compilation units. Note that elaboration dependence includes semantic dependence. It's a little bit sad that the pragma Elaborate_Body  aspect can't be folded into this mechanism. It follows from the definition that the elaboration dependence relationship is transitive. Note that the wording of the rule does not need to take into account a semantic dependence of a library_item or one of its subunits upon a subunit of a different library unit, because that can never happen. 
The environment task for a partition has the following structure: 
task Environment_Task;
task body Environment_Task is
    ... (1) -- The environment declarative_part
            -- (that is, the sequence of library_items) goes here.
    ... (2) -- Call the main subprogram, if there is one.
end Environment_Task;
Ramification: The name of the environment task is written in italics here to indicate that this task is anonymous.
Discussion: The model is different for a “passive partition” (see E.1). Either there is no environment task, or its sequence_of_statements is an infinite loop rather than a call on a main subprogram. 
The environment declarative_part at (1) is a sequence of declarative_items consisting of copies of the library_items included in the partition[. The order of elaboration of library_items is the order in which they appear in the environment declarative_part]:
The order of all included library_items is such that there are no forward elaboration dependences. 
Ramification: This rule is written so that if a library_item depends on itself, we don't require it to be elaborated before itself. See AI83-00113/12. This can happen only in pathological circumstances. For example, if a library subprogram_body has no corresponding subprogram_declaration, and one of the subunits of the subprogram_body mentions the subprogram_body in a with_clause, the subprogram_body will depend on itself. For another example, if a library_unit_body applies a pragma Elaborate_All to its own declaration, then the library_unit_body will depend on itself. 
{AI05-0229-1} {AI12-0417-1} Any included library_unit_declaration for which aspect Elaborate_Body is True [(including when a pragma Elaborate_Body applies)] is immediately followed by its library_unit_body, if included. 
Discussion: This implies that the body of such a library unit shall not “with” any of its own children, or anything else that depends semantically upon the declaration of the library unit. 
Proof: {AI05-0229-1} {AI12-0417-1} Pragma Elaborate_Body sets aspect Elaborate_Body, see 10.2.1.
All library_items declared pure occur before any that are not declared pure.
All preelaborated library_items occur before any that are not preelaborated. 
Discussion: Normally, if two partitions contain the same compilation unit, they each contain a separate copy of that compilation unit. See Annex E, “Distributed Systems” for cases where two partitions share the same copy of something.
There is no requirement that the main subprogram be elaborated last. In fact, it is possible to write a partition in which the main subprogram cannot be elaborated last. 
Ramification: This declarative_part has the properties required of all environments (see 10.1.4). However, the environment declarative_part of a partition will typically contain fewer compilation units than the environment declarative_part used at compile time — only the “needed” ones are included in the partition. 
There shall be a total order of the library_items that obeys the above rules. The order is otherwise implementation defined.
Discussion: {AI12-0417-1} The only way to violate this rule is to have Elaborate or, Elaborate_All pragmas, or Elaborate_Body aspects pragmas that cause circular ordering requirements, thus preventing an order that has no forward elaboration dependences. 
Implementation defined: The order of elaboration of library_items.
To be honest: {AI12-0005-1} Notwithstanding what the RM RM95 says elsewhere, each rule that requires a declaration to have a corresponding completion is considered to be a Post-Compilation Rule when the declaration is that of a library unit. 
Discussion: Such rules may be checked at “link time”, for example. Rules requiring the completion to have certain properties, on the other hand, are checked at compile time of the completion. 
The full expanded names of the library units and subunits included in a given partition shall be distinct.
Reason: This is a Post-Compilation Rule because making it a Legality Rule would violate the Language Design Principle labeled “legality determinable via semantic dependences”.
The sequence_of_statements of the environment task (see (2) above) consists of either: 
A call to the main subprogram, if the partition has one. If the main subprogram has parameters, they are passed; where the actuals come from is implementation defined. What happens to the result of a main function is also implementation defined. 
Implementation defined: Parameter passing and function return for the main subprogram.
A null_statement, if there is no main subprogram. 
Discussion: For a passive partition, either there is no environment task, or its sequence_of_statements is an infinite loop. See E.1
{AI12-0439-1} The mechanisms for building and running partitions are implementation defined. [These can might be combined into one operation, as, for example, in dynamic linking, or “load-and-go” systems.] 
Implementation defined: The mechanisms for building and running partitions.

Dynamic Semantics

The execution of a program consists of the execution of a set of partitions. Further details are implementation defined. The execution of a partition starts with the execution of its environment task, ends when the environment task terminates, and includes the executions of all tasks of the partition. [The execution of the (implicit) task_body of the environment task acts as a master for all other tasks created as part of the execution of the partition. When the environment task completes (normally or abnormally), it waits for the termination of all such tasks, and then finalizes any remaining objects of the partition.]
Ramification: The “further details” mentioned above include, for example, program termination — it is implementation defined. There is no need to define it here; it's entirely up to the implementation whether it wants to consider the program as a whole to exist beyond the existence of individual partitions. 
Implementation defined: The details of program execution, including program termination.
To be honest: The execution of the partition terminates (normally or abnormally) when the environment task terminates (normally or abnormally, respectively). 

Bounded (Run-Time) Errors

Once the environment task has awaited the termination of all other tasks of the partition, any further attempt to create a task (during finalization) is a bounded error, and may result in the raising of Program_Error either upon creation or activation of the task. If such a task is activated, it is not specified whether the task is awaited prior to termination of the environment task. 

Implementation Requirements

The implementation shall ensure that all compilation units included in a partition are consistent with one another, and are legal according to the rules of the language.
Discussion: The consistency requirement implies that a partition cannot contain two versions of the same compilation unit. That is, a partition cannot contain two different library units with the same full expanded name, nor two different bodies for the same program unit. For example, suppose we compile the following: 
package A is -- Version 1.
end A;
with A;
package B is
end B;
package A is -- Version 2.
end A;
with A;
package C is
end C;
It would be wrong for a partition containing B and C to contain both versions of A. Typically, the implementation would require the use of Version 2 of A, which might require the recompilation of B. Alternatively, the implementation might automatically recompile B when the partition is built. A third alternative would be an incremental compiler that, when Version 2 of A is compiled, automatically patches the object code for B to reflect the changes to A (if there are any relevant changes — there might not be any).
An implementation that supported fancy version management might allow the use of Version 1 in some circumstances. In no case can the implementation allow the use of both versions in the same partition (unless, of course, it can prove that the two versions are semantically identical).
The core language says nothing about inter-partition consistency; see also Annex E, “Distributed Systems”. 

Implementation Permissions

{AI05-0299-1} The kind of partition described in this subclause is known as an active partition. An implementation is allowed to support other kinds of partitions, with implementation-defined semantics.
Implementation defined: The semantics of any nonactive partitions supported by the implementation.
Discussion: Annex E, “Distributed Systems” defines the concept of passive partitions; they may be thought of as a partition without an environment task, or as one with a particularly simple form of environment task, having an infinite loop rather than a call on a main subprogram as its sequence_of_statements.
An implementation may restrict the kinds of subprograms it supports as main subprograms. However, an implementation is required to support all main subprograms that are public parameterless library procedures. 
Ramification: The implementation is required to support main subprograms that are procedures declared by generic_instantiations, as well as those that are children of library units other than Standard. Generic units are, of course, not allowed to be main subprograms, since they are not subprograms.
Note that renamings are irrelevant to this rule. This rules says which subprograms (not views) have to be supported. The implementation can choose any way it wants for the user to indicate which subprogram should be the main subprogram. An implementation might allow any name of any view, including those declared by renamings. Another implementation might require it to be the original name. Another implementation still might use the name of the source file or some such thing. 
If the environment task completes abnormally, the implementation may abort any dependent tasks. 
Reason: If the implementation does not take advantage of this permission, the normal action takes place — the environment task awaits those tasks.
The possibility of aborting them is not shown in the Environment_Task code above, because there is nowhere to put an exception_handler that can handle exceptions raised in both the environment declarative_part and the main subprogram, such that the dependent tasks can be aborted. If we put an exception_handler in the body of the environment task, then it won't handle exceptions that occur during elaboration of the environment declarative_part. If we were to move those things into a nested block_statement, with the exception_handler outside that, then the block_statement would await the library tasks we are trying to abort.
Furthermore, this is merely a permission, and is not fundamental to the model, so it is probably better to state it separately anyway.
Note that implementations (and tools like debuggers) can have modes that provide other behaviors in addition. 
NOTE 1   {AI12-0440-1} An implementation can may provide inter-partition communication mechanism(s) via special packages and pragmas. Standard pragmas for distribution and methods for specifying inter-partition communication are defined in Annex E, “Distributed Systems”. If no such mechanisms are provided, then each partition is isolated from all others, and behaves as a program in and of itself. 
Ramification: Not providing such mechanisms is equivalent to disallowing multi-partition programs.
An implementation may provide mechanisms to facilitate checking the consistency of library units elaborated in different partitions; Annex E, “Distributed Systems” does so. 
NOTE 2   {AI12-0440-1} Partitions are not required to run in separate address spaces. For example, an implementation can might support dynamic linking via the partition concept.
NOTE 3   {AI12-0417-1} {AI12-0449-1} An order of elaboration of library_items that is consistent with the partial ordering defined above does not always ensure that each library_unit_body is elaborated before any other compilation unit whose elaboration necessitates that the library_unit_body be already elaborated. (In particular, there is no requirement that the body of a library unit be elaborated as soon as possible after the library_unit_declaration is elaborated, unless the pragmas or aspects in subclause 10.2.1 are used.)
NOTE 4   {AI12-0442-1} A partition (active or otherwise) does not necessarily need not have a main subprogram. In such a case, all the work done by the partition would be done by elaboration of various library_items, and by tasks created by that elaboration. Passive partitions, which cannot have main subprograms, are defined in Annex E, “Distributed Systems”. 
Ramification: The environment task is the outermost semantic level defined by the language.
Standard has no private part. This prevents strange implementation-dependences involving private children of Standard having visibility upon Standard's private part. It doesn't matter where the body of Standard appears in the environment, since it doesn't do anything. See Annex A, “Predefined Language Environment”.
Note that elaboration dependence is carefully defined in such a way that if (say) the body of something doesn't exist yet, then there is no elaboration dependence upon the nonexistent body. (This follows from the fact that “needed by” is defined that way, and the elaboration dependences caused by a pragma Elaborate or Elaborate_All are defined in terms of “needed by”.) This property allows us to use the environment concept both at compile time and at partition-construction time/run time. 

Extensions to Ada 83

The concept of partitions is new to Ada 95.
A main subprogram is now optional. The language-defined restrictions on main subprograms are relaxed. 

Wording Changes from Ada 83

Ada 95 uses the term “main subprogram” instead of Ada 83's “main program” (which was inherited from Pascal). This is done to avoid confusion — a main subprogram is a subprogram, not a program. The program as a whole is an entirely different thing. 

Wording Changes from Ada 95

{AI95-00256-01} The mistaken use of “mentions” in the elaboration dependence rule was fixed.
{AI95-00217-06} {AI12-0448-1} The needed needs relationship was extended to include limited views. 

Contents   Index   References   Search   Previous   Next 
Ada-Europe Ada 2005 and 2012 Editions sponsored in part by Ada-Europe