dwww Home | Show directory contents | Find package


                        9   Tasks and Synchronization


1/3 {AI05-0299-1} The execution of an Ada program consists of the execution of
one or more tasks. Each task represents a separate thread of control that
proceeds independently and concurrently between the points where it interacts
with other tasks. The various forms of task interaction are described in this
clause, and include:

1.a         To be honest: The execution of an Ada program consists of the
            execution of one or more partitions (see 10.2), each of which in
            turn consists of the execution of an environment task and zero or
            more subtasks.

2     * the activation and termination of a task;

3     * a call on a protected subprogram of a protected object, providing
        exclusive read-write access, or concurrent read-only access to shared
        data;

4     * a call on an entry, either of another task, allowing for synchronous
        communication with that task, or of a protected object, allowing for
        asynchronous communication with one or more other tasks using that
        same protected object;

5     * a timed operation, including a simple delay statement, a timed entry
        call or accept, or a timed asynchronous select statement (see next
        item);

6     * an asynchronous transfer of control as part of an asynchronous select
        statement, where a task stops what it is doing and begins execution at
        a different point in response to the completion of an entry call or
        the expiration of a delay;

7     * an abort statement, allowing one task to cause the termination of
        another task.

8   In addition, tasks can communicate indirectly by reading and updating
(unprotected) shared variables, presuming the access is properly synchronized
through some other kind of task interaction.


                              Static Semantics

9   The properties of a task are defined by a corresponding task declaration
and task_body, which together define a program unit called a task unit.


                              Dynamic Semantics

10  Over time, tasks proceed through various states. A task is initially
inactive; upon activation, and prior to its termination it is either blocked
(as part of some task interaction) or ready to run. While ready, a task
competes for the available execution resources that it requires to run.

10.a/3      Discussion: {AI05-0229-1} The means for selecting which of the
            ready tasks to run, given the currently available execution
            resources, is determined by the task dispatching policy in effect,
            which is generally implementation defined, but may be controlled
            by aspects, pragmas, and operations defined in the Real-Time Annex
            (see D.2 and D.5).

        NOTES

11      1  Concurrent task execution may be implemented on multicomputers,
        multiprocessors, or with interleaved execution on a single physical
        processor. On the other hand, whenever an implementation can determine
        that the required semantic effects can be achieved when parts of the
        execution of a given task are performed by different physical
        processors acting in parallel, it may choose to perform them in this
        way.


                         Wording Changes from Ada 83

11.a        The introduction has been rewritten.

11.b        We use the term "concurrent" rather than "parallel" when talking
            about logically independent execution of threads of control. The
            term "parallel" is reserved for referring to the situation where
            multiple physical processors run simultaneously.


9.1 Task Units and Task Objects


1   A task unit is declared by a task declaration, which has a corresponding
task_body. A task declaration may be a task_type_declaration, in which case it
declares a named task type; alternatively, it may be a
single_task_declaration, in which case it defines an anonymous task type, as
well as declaring a named task object of that type.


                                   Syntax

2/3     {AI95-00345-01} {AI05-0183-1} task_type_declaration ::= 
           task type defining_identifier [known_discriminant_part]
                [aspect_specification] [is
             [new interface_list with]
             task_definition];

3/3     {AI95-00399-01} {AI05-0183-1} single_task_declaration ::= 
           task defining_identifier 
                [aspect_specification][is
             [new interface_list with]
             task_definition];

4       task_definition ::= 
             {task_item}
          [ private
             {task_item}]
          end [task_identifier]

5/1     {8652/0009} {AI95-00137-01} task_item ::= entry_declaration
         | aspect_clause

6/3     {AI05-0267-1} task_body ::= 
           task body defining_identifier
                [aspect_specification] is
             declarative_part
           begin
             handled_sequence_of_statements
           end [task_identifier];

7       If a task_identifier appears at the end of a task_definition or
        task_body, it shall repeat the defining_identifier.

8.a/2       This paragraph was deleted.

Paragraph 8 was deleted.


                              Static Semantics

9   A task_definition defines a task type and its first subtype. The first
list of task_items of a task_definition, together with the known_discriminant_-
part, if any, is called the visible part of the task unit. [ The optional list
of task_items after the reserved word private is called the private part of
the task unit.]

9.a/3       Proof: {AI05-0299-1} Private part is defined in Clause 8.

9.1/1 {8652/0029} {AI95-00116-01} For a task declaration without a
task_definition, a task_definition without task_items is assumed.

9.2/3 {AI95-00345-01} {AI95-00397-01} {AI95-00399-01} {AI95-00419-01}
{AI05-0042-1} For a task declaration with an interface_list, the task type
inherits user-defined primitive subprograms from each progenitor type (see
3.9.4), in the same way that a derived type inherits user-defined primitive
subprograms from its progenitor types (see 3.4). If the first parameter of a
primitive inherited subprogram is of the task type or an access parameter
designating the task type, and there is an entry_declaration for a single
entry with the same identifier within the task declaration, whose profile is
type conformant with the prefixed view profile of the inherited subprogram,
the inherited subprogram is said to be implemented by the conforming task
entry using an implicitly declared nonabstract subprogram which has the same
profile as the inherited subprogram and which overrides it.

9.b/2       Ramification: The inherited subprograms can only come from an
            interface given as part of the task declaration.

9.b.1/3     Reason: {AI05-0042-1} The part about the implicitly declared
            subprogram is needed so that a subprogram implemented by an entry
            is considered to be overridden for the purpose of the other rules
            of the language. Without it, it would for instance be illegal for
            an abstract subprogram to be implemented by an entry, because the
            abstract subprogram would not be overridden. The Legality Rules
            below ensure that there is no conflict between the implicit
            overriding subprogram and a user-defined overriding subprogram.


                               Legality Rules

9.3/2 {AI95-00345-01} A task declaration requires a completion[, which shall
be a task_body,] and every task_body shall be the completion of some task
declaration.

9.c/3       To be honest: {AI05-0229-1} If the implementation supports it, the
            task body can be imported (using aspect Import, see B.1), in which
            case no explicit task_body is allowed.

9.4/2 {AI95-00345-01} {AI95-00399-01} [Each interface_subtype_mark of an
interface_list appearing within a task declaration shall denote a limited
interface type that is not a protected interface.]

9.d/2       Proof: 3.9.4 requires that an interface_list only name interface
            types, and limits the descendants of the various kinds of
            interface types. Only a limited, task, or synchronized interface
            can have a task type descendant. Nonlimited or protected
            interfaces are not allowed, as they offer operations that a task
            does not have.

9.5/3 {AI95-00397-01} {AI05-0090-1} The prefixed view profile of an explicitly
declared primitive subprogram of a tagged task type shall not be type
conformant with any entry of the task type, if the subprogram has the same
defining name as the entry and the first parameter of the subprogram is of the
task type or is an access parameter designating the task type.

9.e/2       Reason: This prevents the existence of two operations with the
            same name and profile which could be called with a prefixed view.
            If the operation was inherited, this would be illegal by the
            following rules; this rule puts inherited and noninherited
            routines on the same footing. Note that this only applies to
            tagged task types (that is, those with an interface in their
            declaration); we do that as there is no problem with prefixed view
            calls of primitive operations for "normal" task types, and having
            this rule apply to all tasks would be incompatible with Ada 95.

9.6/2 {AI95-00345-01} {AI95-00399-01} For each primitive subprogram inherited
by the type declared by a task declaration, at most one of the following shall
apply:

9.7/2   * {AI95-00345-01} the inherited subprogram is overridden with a
        primitive subprogram of the task type, in which case the overriding
        subprogram shall be subtype conformant with the inherited subprogram
        and not abstract; or

9.8/2   * {AI95-00345-01} {AI95-00397-01} the inherited subprogram is
        implemented by a single entry of the task type; in which case its
        prefixed view profile shall be subtype conformant with that of the
        task entry.

9.f/2       Ramification: An entry may implement two subprograms from the
            ancestors, one whose first parameter is of type T and one whose
            first parameter is of type access T. That doesn't cause
            implementation problems because "implemented by" (unlike "
            overridden') probably entails the creation of wrappers.

9.9/2 If neither applies, the inherited subprogram shall be a null procedure.
In addition to the places where Legality Rules normally apply (see 12.3),
these rules also apply in the private part of an instance of a generic unit.

9.g/2       Reason: Each inherited subprogram can only have a single
            implementation (either from overriding a subprogram or
            implementing an entry), and must have an implementation unless the
            subprogram is a null procedure.


                              Dynamic Semantics

10  [ The elaboration of a task declaration elaborates the task_definition.
The elaboration of a single_task_declaration also creates an object of an
(anonymous) task type.]

10.a        Proof: This is redundant with the general rules for the
            elaboration of a full_type_declaration and an object_declaration.

11  [The elaboration of a task_definition creates the task type and its first
subtype;] it also includes the elaboration of the entry_declarations in the
given order.

12/1 {8652/0009} {AI95-00137-01} As part of the initialization of a task
object, any aspect_clauses and any per-object constraints associated with
entry_declarations of the corresponding task_definition are elaborated in the
given order.

12.a/1      Reason: The only aspect_clauses defined for task entries are ones
            that specify the Address of an entry, as part of defining an
            interrupt entry. These clearly need to be elaborated per-object,
            not per-type. Normally the address will be a function of a
            discriminant, if such an Address clause is in a task type rather
            than a single task declaration, though it could rely on a
            parameterless function that allocates sequential interrupt vectors.

12.b        We do not mention representation pragmas, since each pragma may
            have its own elaboration rules.

13  The elaboration of a task_body has no effect other than to establish that
tasks of the type can from then on be activated without failing the
Elaboration_Check.

14  [The execution of a task_body is invoked by the activation of a task of
the corresponding type (see 9.2).]

15  The content of a task object of a given task type includes:

16    * The values of the discriminants of the task object, if any;

17    * An entry queue for each entry of the task object;

17.a        Ramification: "For each entry" implies one queue for each single
            entry, plus one for each entry of each entry family.

18    * A representation of the state of the associated task.

        NOTES

19/2    2  {AI95-00382-01} Other than in an access_definition, the name of a
        task unit within the declaration or body of the task unit denotes the
        current instance of the unit (see 8.6), rather than the first subtype
        of the corresponding task type (and thus the name cannot be used as a
        subtype_mark).

19.a/2      Discussion: {AI95-00382-01} It can be used as a subtype_mark in an
            anonymous access type. In addition, it is possible to refer to
            some other subtype of the task type within its body, presuming
            such a subtype has been declared between the
            task_type_declaration and the task_body.

20      3  The notation of a selected_component can be used to denote a
        discriminant of a task (see 4.1.3). Within a task unit, the name of a
        discriminant of the task type denotes the corresponding discriminant
        of the current instance of the unit.

21/2    4  {AI95-00287-01} A task type is a limited type (see 7.5), and hence
        precludes use of assignment_statements and predefined equality
        operators. If an application needs to store and exchange task
        identities, it can do so by defining an access type designating the
        corresponding task objects and by using access values for
        identification purposes. Assignment is available for such an access
        type as for any access type. Alternatively, if the implementation
        supports the Systems Programming Annex, the Identity attribute can be
        used for task identification (see C.7.1).


                                  Examples

22  Examples of declarations of task types:

23      task type Server is
           entry Next_Work_Item(WI : in Work_Item);
           entry Shut_Down;
        end Server;

24/2    {AI95-00433-01}
        task type Keyboard_Driver(ID : Keyboard_ID := New_ID) is
              new Serial_Device with  -- see 3.9.4
           entry Read (C : out Character);
           entry Write(C : in  Character);
        end Keyboard_Driver;

25  Examples of declarations of single tasks:

26      task Controller is
           entry Request(Level)(D : Item);  --  a family of entries
        end Controller;

27      task Parser is
           entry Next_Lexeme(L : in  Lexical_Element);
           entry Next_Action(A : out Parser_Action);
        end;

28      task User;  --  has no entries

29  Examples of task objects:

30      Agent    : Server;
        Teletype : Keyboard_Driver(TTY_ID);
        Pool     : array(1 .. 10) of Keyboard_Driver;

31  Example of access type designating task objects:

32      type Keyboard is access Keyboard_Driver;
        Terminal : Keyboard := new Keyboard_Driver(Term_ID);


                            Extensions to Ada 83

32.a/1      The syntax rules for task declarations are modified to allow a
            known_discriminant_part, and to allow a private part. They are
            also modified to allow entry_declarations and aspect_clauses to be
            mixed.


                         Wording Changes from Ada 83

32.b        The syntax rules for tasks have been split up according to task
            types and single tasks. In particular: The syntax rules for
            task_declaration and task_specification are removed. The syntax
            rules for task_type_declaration, single_task_declaration,
            task_definition and task_item are new.

32.c        The syntax rule for task_body now uses the nonterminal
            handled_sequence_of_statements.

32.d        The declarative_part of a task_body is now required; that doesn't
            make any real difference, because a declarative_part can be empty.


                            Extensions to Ada 95

32.e/2      {AI95-00345-01} {AI95-00397-01} {AI95-00399-01} {AI95-00419-01}
            Task types and single tasks can be derived from one or more
            interfaces. Entries of the task type can implement the primitive
            operations of an interface. Overriding_indicators can be used to
            specify whether or not an entry implements a primitive operation.


                         Wording Changes from Ada 95

32.f/2      {8652/0029} {AI95-00116-01} Corrigendum: Clarified that a task
            type has an implicit empty task_definition if none is given.

32.g/2      {8652/0009} {AI95-00137-01} Corrigendum: Changed representation
            clauses to aspect clauses to reflect that they are used for more
            than just representation.

32.h/2      {AI95-00287-01} Revised the note on operations of task types to
            reflect that limited types do have an assignment operation, but
            not copying (assignment_statements).

32.i/2      {AI95-00382-01} Revised the note on use of the name of a task type
            within itself to reflect the exception for anonymous access types.


                           Extensions to Ada 2005

32.j/3      {AI05-0183-1} {AI05-0267-1} An optional aspect_specification can
            be used in a task_type_declaration, a single_task_declaration, and
            a task_body. This is described in 13.1.1.


                        Wording Changes from Ada 2005

32.k/3      {AI05-0042-1} Correction: Clarified that an inherited procedure of
            a progenitor is overridden when it is implemented by an entry.

32.l/3      {AI05-0090-1} Correction: Added the missing defining name in the
            no conflicting primitive operation rule.


9.2 Task Execution - Task Activation



                              Dynamic Semantics

1   The execution of a task of a given task type consists of the execution of
the corresponding task_body. The initial part of this execution is called the
activation of the task; it consists of the elaboration of the
declarative_part of the task_body. Should an exception be propagated by the
elaboration of its declarative_part, the activation of the task is defined to
have failed, and it becomes a completed task.

2/2 {AI95-00416-01} A task object (which represents one task) can be a part of
a stand-alone object, of an object created by an allocator, or of an anonymous
object of a limited type, or a coextension of one of these. All tasks that are
part or coextensions of any of the stand-alone objects created by the
elaboration of object_declarations (or generic_associations of formal objects
of mode in) of a single declarative region are activated together. All tasks
that are part or coextensions of a single object that is not a stand-alone
object are activated together.

2.a         Discussion: The initialization of an object_declaration or
            allocator can indirectly include the creation of other objects
            that contain tasks. For example, the default expression for a
            subcomponent of an object created by an allocator might call a
            function that evaluates a completely different allocator. Tasks
            created by the two allocators are not activated together.

3/2 {AI95-00416-01} For the tasks of a given declarative region, the
activations are initiated within the context of the handled_sequence_of_-
statements (and its associated exception_handlers if any - see 11.2), just
prior to executing the statements of the handled_sequence_of_statements. [For
a package without an explicit body or an explicit
handled_sequence_of_statements, an implicit body or an implicit null_statement
is assumed, as defined in 7.2.]

3.a         Ramification: If Tasking_Error is raised, it can be handled by
            handlers of the handled_sequence_of_statements.

4/2 {AI95-00416-01} For tasks that are part or coextensions of a single object
that is not a stand-alone object, activations are initiated after completing
any initialization of the outermost object enclosing these tasks, prior to
performing any other operation on the outermost object. In particular, for
tasks that are part or coextensions of the object created by the evaluation of
an allocator, the activations are initiated as the last step of evaluating the
allocator, prior to returning the new access value. For tasks that are part or
coextensions of an object that is the result of a function call, the
activations are not initiated until after the function returns.

4.a/2       Discussion: {AI95-00416-01} The intent is that "temporary" objects
            with task parts (or coextensions) are treated similarly to an
            object created by an allocator. The "whole" object is initialized,
            and then all of the task parts (including the coextensions) are
            activated together. Each such "whole" object has its own task
            activation sequence, involving the activating task being suspended
            until all the new tasks complete their activation.

5   The task that created the new tasks and initiated their activations (the
activator) is blocked until all of these activations complete (successfully or
not). Once all of these activations are complete, if the activation of any of
the tasks has failed [(due to the propagation of an exception)], Tasking_Error
is raised in the activator, at the place at which it initiated the
activations. Otherwise, the activator proceeds with its execution normally.
Any tasks that are aborted prior to completing their activation are ignored
when determining whether to raise Tasking_Error.

5.a         Ramification: Note that a task created by an allocator does not
            necessarily depend on its activator; in such a case the
            activator's termination can precede the termination of the newly
            created task.

5.b         Discussion: Tasking_Error is raised only once, even if two or more
            of the tasks being activated fail their activation.

5.c/2       To be honest: {AI95-00265-01} The pragma
            Partition_Elaboration_Policy (see H.6) can be used to defer task
            activation to a later point, thus changing many of these rules.

6/3 {AI05-0045-1} If the master that directly encloses the point where the
activation of a task T would be initiated, completes before the activation of
T is initiated, T becomes terminated and is never activated. Furthermore, if a
return statement is left such that the return object is not returned to the
caller, any task that was created as a part of the return object or one of its
coextensions immediately becomes terminated and is never activated.

6.a/3       Ramification: {AI05-0045-1} The first case can only happen if the
            activation point of T is not reached due to an exception being
            raised or a task or statement being aborted. Note that this is
            exclusive; if the master completes normally and starts
            finalization, we're already past the activation point.

6.b/3       {AI05-0045-1} The second case can happen with an exception being
            raised in a return statement, by an exit or goto from an
            extended_return_statement, or by a return statement being aborted.
            Any tasks created for the return object of such a return statement
            are never activated.

        NOTES

7       5  An entry of a task can be called before the task has been activated.

8       6  If several tasks are activated together, the execution of any of
        these tasks need not await the end of the activation of the other
        tasks.

9       7  A task can become completed during its activation either because of
        an exception or because it is aborted (see 9.8).


                                  Examples

10  Example of task activation:

11      procedure P is
           A, B : Server;    --  elaborate the task objects A, B
           C    : Server;    --  elaborate the task object C
        begin
           --  the tasks A, B, C are activated together before the first statement
           ...
        end;


                         Wording Changes from Ada 83

11.a        We have replaced the term suspended with blocked, since we didn't
            want to consider a task blocked when it was simply competing for
            execution resources. "Suspended" is sometimes used more generally
            to refer to tasks that are not actually running on some processor,
            due to the lack of resources.

11.b/3      {AI05-0299-1} This subclause has been rewritten in an attempt to
            improve presentation.


                         Wording Changes from Ada 95

11.c/2      {AI95-00416-01} Adjusted the wording for activating tasks to
            handle the case of anonymous function return objects. This is
            critical; we don't want to be waiting for the tasks in a return
            object when we exit the function normally.


                        Wording Changes from Ada 2005

11.d/3      {AI05-0045-1} Correction: Corrected the wording that handles tasks
            that are never activated to ensure that no lookahead is implied
            and to make it clear that tasks created by return statements that
            never return are never activated.


9.3 Task Dependence - Termination of Tasks



                              Dynamic Semantics

1   Each task (other than an environment task - see 10.2) depends on one or
more masters (see 7.6.1), as follows:

2/4   * {AI12-0070-1} If the task is created by the evaluation of an
        allocator for a given named access type, it depends on each master
        that includes the elaboration of the declaration of the ultimate
        ancestor of the given access type.

3     * If the task is created by the elaboration of an object_declaration, it
        depends on each master that includes this elaboration.

3.1/2   * {AI95-00416-01} Otherwise, the task depends on the master of the
        outermost object of which it is a part (as determined by the
        accessibility level of that object - see 3.10.2 and 7.6.1), as well as
        on any master whose execution includes that of the master of the
        outermost object.

3.a/2       Ramification: {AI95-00416-01} The master of a task created by a
            return statement changes when the accessibility of the return
            object changes. Note that its activation happens, if at all, only
            after the function returns and all accessibility level changes
            have occurred.

4   Furthermore, if a task depends on a given master, it is defined to depend
on the task that executes the master, and (recursively) on any master of that
task.

4.a         Discussion: Don't confuse these kinds of dependences with the
            dependences among compilation units defined in 10.1.1, "
            Compilation Units - Library Units".

5   A task is said to be completed when the execution of its corresponding
task_body is completed. A task is said to be terminated when any finalization
of the task_body has been performed (see 7.6.1). [The first step of finalizing
a master (including a task_body) is to wait for the termination of any tasks
dependent on the master.] The task executing the master is blocked until all
the dependents have terminated. [Any remaining finalization is then performed
and the master is left.]

6/1 Completion of a task (and the corresponding task_body) can occur when the
task is blocked at a select_statement with an open terminate_alternative (see
9.7.1); the open terminate_alternative is selected if and only if the
following conditions are satisfied:

7/2   * {AI95-00415-01} The task depends on some completed master; and

8     * Each task that depends on the master considered is either already
        terminated or similarly blocked at a select_statement with an open
        terminate_alternative.

9   When both conditions are satisfied, the task considered becomes completed,
together with all tasks that depend on the master considered that are not yet
completed.

9.a         Ramification: Any required finalization is performed after the
            selection of terminate_alternatives. The tasks are not callable
            during the finalization. In some ways it is as though they were
            aborted.

        NOTES

10      8  The full view of a limited private type can be a task type, or can
        have subcomponents of a task type. Creation of an object of such a
        type creates dependences according to the full type.

11      9  An object_renaming_declaration defines a new view of an existing
        entity and hence creates no further dependence.

12      10  The rules given for the collective completion of a group of tasks
        all blocked on select_statements with open terminate_alternatives
        ensure that the collective completion can occur only when there are no
        remaining active tasks that could call one of the tasks being
        collectively completed.

13      11  If two or more tasks are blocked on select_statements with open
        terminate_alternatives, and become completed collectively, their
        finalization actions proceed concurrently.

14      12  The completion of a task can occur due to any of the following:

15        * the raising of an exception during the elaboration of the
            declarative_part of the corresponding task_body;

16        * the completion of the handled_sequence_of_statements of the
            corresponding task_body;

17        * the selection of an open terminate_alternative of a
            select_statement in the corresponding task_body;

18        * the abort of the task.


                                  Examples

19  Example of task dependence:

20      declare
           type Global is access Server;        --  see 9.1
           A, B : Server;
           G    : Global;
        begin
           --  activation of A and B
           declare
              type Local is access Server;
              X : Global := new Server;  --  activation of X.all
              L : Local  := new Server;  --  activation of L.all
              C : Server;
           begin
              --  activation of C
              G := X;  --  both G and X designate the same task object
              ...
           end;  --  await termination of C and L.all (but not X.all)
           ...
        end;  --  await termination of A, B, and G.all


                         Wording Changes from Ada 83

20.a        We have revised the wording to be consistent with the definition
            of master now given in 7.6.1, "Completion and Finalization".

20.b        Tasks that used to depend on library packages in Ada 83, now
            depend on the (implicit) task_body of the environment task (see
            10.2). Therefore, the environment task has to wait for them before
            performing library level finalization and terminating the
            partition. In Ada 83 the requirement to wait for tasks that
            depended on library packages was not as clear.

20.c        What was "collective termination" is now "collective completion"
            resulting from selecting terminate_alternatives. This is because
            finalization still occurs for such tasks, and this happens after
            selecting the terminate_alternative, but before termination.


                         Wording Changes from Ada 95

20.d/2      {AI95-00416-01} Added missing wording that explained the master of
            tasks that are neither object_declarations nor allocators, such as
            function returns.


                        Wording Changes from Ada 2012

20.e/4      {AI12-0070-1} Corrigendum: Ensured that the master of tasks that
            are not allocators of named access types is correctly determined.
            (Ignoring the accessibility rules of 3.10.2 could not be
            intended.)


9.4 Protected Units and Protected Objects


1   A protected object provides coordinated access to shared data, through
calls on its visible protected operations, which can be protected subprograms
or protected entries. A protected unit is declared by a protected declaration,
which has a corresponding protected_body. A protected declaration may be a
protected_type_declaration, in which case it declares a named protected type;
alternatively, it may be a single_protected_declaration, in which case it
defines an anonymous protected type, as well as declaring a named protected
object of that type.


                                   Syntax

2/3     {AI95-00345-01} {AI05-0183-1} protected_type_declaration ::= 
          protected type defining_identifier [known_discriminant_part]
                [aspect_specification] is
             [new interface_list with]
             protected_definition;

3/3     {AI95-00399-01} {AI05-0183-1} single_protected_declaration ::= 
          protected defining_identifier
                [aspect_specification] is
             [new interface_list with]
             protected_definition;

4       protected_definition ::= 
            { protected_operation_declaration }
        [ private
            { protected_element_declaration } ]
          end [protected_identifier]

5/1     {8652/0009} {AI95-00137-01} protected_operation_declaration ::= 
        subprogram_declaration
             | entry_declaration
             | aspect_clause

6       protected_element_declaration ::= protected_operation_declaration
             | component_declaration

6.a         Reason: We allow the operations and components to be mixed because
            that's how other things work (for example, package declarations).
            We have relaxed the ordering rules for the items inside
            declarative_parts and task_definitions as well.

7/3     {AI05-0267-1} protected_body ::= 
          protected body defining_identifier
                [aspect_specification] is
           { protected_operation_item }
          end [protected_identifier];

8/4     {8652/0009} {AI95-00137-01} {AI12-0147-1} protected_operation_item
         ::= subprogram_declaration
             | subprogram_body
             | null_procedure_declaration
             | expression_function_declaration
             | entry_body
             | aspect_clause

9       If a protected_identifier appears at the end of a
        protected_definition or protected_body, it shall repeat the
        defining_identifier.

10.a/2      This paragraph was deleted.

Paragraph 10 was deleted.


                              Static Semantics

11/2 {AI95-00345-01} {AI95-00401-01} A protected_definition defines a
protected type and its first subtype. The list of
protected_operation_declarations of a protected_definition, together with the
known_discriminant_part, if any, is called the visible part of the protected
unit. [ The optional list of protected_element_declarations after the reserved
word private is called the private part of the protected unit.]

11.a/3      Proof: {AI05-0299-1} Private part is defined in Clause 8.

11.1/3 {AI95-00345-01} {AI95-00397-01} {AI95-00399-01} {AI95-00419-01}
{AI05-0042-1} For a protected declaration with an interface_list, the protected
type inherits user-defined primitive subprograms from each progenitor type
(see 3.9.4), in the same way that a derived type inherits user-defined
primitive subprograms from its progenitor types (see 3.4). If the first
parameter of a primitive inherited subprogram is of the protected type or an
access parameter designating the protected type, and there is a
protected_operation_declaration for a protected subprogram or single entry
with the same identifier within the protected declaration, whose profile is
type conformant with the prefixed view profile of the inherited subprogram,
the inherited subprogram is said to be implemented by the conforming protected
subprogram or entry using an implicitly declared nonabstract subprogram which
has the same profile as the inherited subprogram and which overrides it.

11.b/2      Ramification: The inherited subprograms can only come from an
            interface given as part of the protected declaration.

11.b.1/3    Reason: {AI05-0042-1} The part about the implicitly declared
            subprogram is needed so that a subprogram implemented by an entry
            or subprogram is considered to be overridden for the purpose of
            the other rules of the language. Without it, it would for instance
            be illegal for an abstract subprogram to be implemented by an
            entry, because the abstract subprogram would not be overridden.
            The Legality Rules below ensure that there is no conflict between
            the implicit overriding subprogram and a user-defined overriding
            subprogram.


                               Legality Rules

11.2/2 {AI95-00345-01} A protected declaration requires a completion[, which
shall be a protected_body,] and every protected_body shall be the completion
of some protected declaration.

11.c/3      To be honest: {AI05-0229-1} If the implementation supports it, the
            protected body can be imported (using aspect Import, see B.1), in
            which case no explicit protected_body is allowed.

11.3/2 {AI95-00345-01} {AI95-00399-01} [Each interface_subtype_mark of an
interface_list appearing within a protected declaration shall denote a limited
interface type that is not a task interface.]

11.d/2      Proof: 3.9.4 requires that an interface_list only name interface
            types, and limits the descendants of the various kinds of
            interface types. Only a limited, protected, or synchronized
            interface can have a protected type descendant. Nonlimited or task
            interfaces are not allowed, as they offer operations that a
            protected type does not have.

11.4/3 {AI95-00397-01} {AI05-0042-1} The prefixed view profile of an
explicitly declared primitive subprogram of a tagged protected type shall not
be type conformant with any protected operation of the protected type, if the
subprogram has the same defining name as the protected operation and the first
parameter of the subprogram is of the protected type or is an access parameter
designating the protected type.

11.e/2      Reason: This prevents the existence of two operations with the
            same name and profile which could be called with a prefixed view.
            If the operation was inherited, this would be illegal by the
            following rules; this rule puts inherited and noninherited
            routines on the same footing. Note that this only applies to
            tagged protected types (that is, those with an interface in their
            declaration); we do that as there is no problem with prefixed view
            calls of primitive operations for "normal" protected types, and
            having this rule apply to all protected types would be
            incompatible with Ada 95.

11.5/2 {AI95-00345-01} {AI95-00399-01} For each primitive subprogram inherited
by the type declared by a protected declaration, at most one of the following
shall apply:

11.6/2   * {AI95-00345-01} the inherited subprogram is overridden with a
        primitive subprogram of the protected type, in which case the
        overriding subprogram shall be subtype conformant with the inherited
        subprogram and not abstract; or

11.7/2   * {AI95-00345-01} {AI95-00397-01} the inherited subprogram is
        implemented by a protected subprogram or single entry of the protected
        type, in which case its prefixed view profile shall be subtype
        conformant with that of the protected subprogram or entry.

11.8/2 If neither applies, the inherited subprogram shall be a null procedure.
In addition to the places where Legality Rules normally apply (see 12.3),
these rules also apply in the private part of an instance of a generic unit.

11.f/2      Reason: Each inherited subprogram can only have a single
            implementation (either from overriding a subprogram, implementing
            a subprogram, or implementing an entry), and must have an
            implementation unless the subprogram is a null procedure.

11.9/3 {AI95-00345-01} {AI05-0291-1} If an inherited subprogram is implemented
by a protected procedure or an entry, then the first parameter of the
inherited subprogram shall be of mode out or in out, or an access-to-variable
parameter. If an inherited subprogram is implemented by a protected function,
then the first parameter of the inherited subprogram shall be of mode in, but
not an access-to-variable parameter.

11.g/3      Reason: For a protected procedure or entry, the protected object
            can be read or written (see 9.5.1). A subprogram that is
            implemented by a protected procedure or entry must have a profile
            which reflects that in order to avoid confusion. Similarly, a
            protected function has a parameter that is a constant, and the
            inherited routine should reflect that.

11.10/2 {AI95-00397-01} If a protected subprogram declaration has an
overriding_indicator, then at the point of the declaration:

11.11/2   * if the overriding_indicator is overriding, then the subprogram
        shall implement an inherited subprogram;

11.12/2   * if the overriding_indicator is not overriding, then the subprogram
        shall not implement any inherited subprogram.

11.13/2 In addition to the places where Legality Rules normally apply (see
12.3), these rules also apply in the private part of an instance of a generic
unit.

11.h/2      Discussion: These rules are subtly different than those for
            subprograms (see 8.3.1) because there cannot be "late" inheritance
            of primitives from interfaces. Hidden (that is, private)
            interfaces are prohibited explicitly (see 7.3), as are hidden
            primitive operations (as private operations of public abstract
            types are prohibited - see 3.9.3).


                              Dynamic Semantics

12  [The elaboration of a protected declaration elaborates the
protected_definition. The elaboration of a single_protected_declaration also
creates an object of an (anonymous) protected type.]

12.a        Proof: This is redundant with the general rules for the
            elaboration of a full_type_declaration and an object_declaration.

13  [The elaboration of a protected_definition creates the protected type and
its first subtype;] it also includes the elaboration of the
component_declarations and protected_operation_declarations in the given order.

14  [As part of the initialization of a protected object, any per-object
constraints (see 3.8) are elaborated.]

14.a        Discussion: We do not mention pragmas since each pragma has its
            own elaboration rules.

15  The elaboration of a protected_body has no other effect than to establish
that protected operations of the type can from then on be called without
failing the Elaboration_Check.

16  The content of an object of a given protected type includes:

17    * The values of the components of the protected object, including
        (implicitly) an entry queue for each entry declared for the protected
        object;

17.a        Ramification: "For each entry" implies one queue for each single
            entry, plus one for each entry of each entry family.

18    * A representation of the state of the execution resource associated
        with the protected object (one such resource is associated with each
        protected object).

19  [The execution resource associated with a protected object has to be
acquired to read or update any components of the protected object; it can be
acquired (as part of a protected action - see 9.5.1) either for concurrent
read-only access, or for exclusive read-write access.]

20  As the first step of the finalization of a protected object, each call
remaining on any entry queue of the object is removed from its queue and
Program_Error is raised at the place of the corresponding
entry_call_statement.

20.a        Reason: This is analogous to the raising of Tasking_Error in
            callers of a task that completes before accepting the calls. This
            situation can only occur due to a requeue (ignoring premature
            unchecked_deallocation), since any task that has accessibility to
            a protected object is awaited before finalizing the protected
            object. For example:

20.b            procedure Main is
                    task T is
                        entry E;
                    end T;

20.c                task body T is
                        protected PO is
                            entry Ee;
                        end PO;

20.d                    protected body PO is
                            entry Ee when False is
                            begin
                                null;
                            end Ee;
                        end PO;
                    begin
                        accept E do
                            requeue PO.Ee;
                        end E;
                    end T;
                begin
                    T.E;
                end Main;

20.e/3      {AI05-0005-1} The environment task is queued on PO.Ee when PO is
            finalized.

20.f        In a real example, a server task might park callers on a local
            protected object for some useful purpose, so we didn't want to
            disallow this case.


                          Bounded (Run-Time) Errors

20.1/2 {AI95-00280-01} It is a bounded error to call an entry or subprogram of
a protected object after that object is finalized. If the error is detected,
Program_Error is raised. Otherwise, the call proceeds normally, which may
leave a task queued forever.

20.g/2      Reason: This is very similar to the finalization rule. It is a
            bounded error so that an implementation can avoid the overhead of
            the check if it can ensure that the call still will operate
            properly. Such an implementation cannot need to return resources
            (such as locks) to an executive that it needs to execute calls.

20.h/2      This case can happen (and has happened in production code) when a
            protected object is accessed from the Finalize routine of a type.
            For example:

20.i/2          with Ada.Finalization.Controlled;
                package Window_Manager is
                    ...
                    type Root_Window is new Ada.Finalization.Controlled with private;
                    type Any_Window is access all Root_Window;
                    ...
                private
                    ...
                    procedure Finalize (Object : in out Root_Window);
                    ...
                end Window_Manager;

20.j/2          package body Window_Manager is
                   protected type Lock is
                       entry Get_Lock;
                       procedure Free_Lock;
                   ...
                   end Lock;

20.k/2             Window_Lock : Lock;

20.l/2             procedure Finalize (Object : in out Root_Window) is
                   begin
                       Window_Lock.Get_Lock;
                       ...
                       Window_Lock.Free_Lock;
                   end Finalize;
                   ...
                   A_Window : Any_Window := new Root_Window;
                end Window_Manager;

20.m/2      The environment task will call Window_Lock for the object
            allocated for A_Window when the collection for Any_Window is
            finalized, which will happen after the finalization of Window_Lock
            (because finalization of the package body will occur before that
            of the package specification).

        NOTES

21/2    13  {AI95-00382-01} Within the declaration or body of a protected unit
        other than in an access_definition, the name of the protected unit
        denotes the current instance of the unit (see 8.6), rather than the
        first subtype of the corresponding protected type (and thus the name
        cannot be used as a subtype_mark).

21.a/2      Discussion: {AI95-00382-01} It can be used as a subtype_mark in an
            anonymous access type. In addition, it is possible to refer to
            some other subtype of the protected type within its body,
            presuming such a subtype has been declared between the
            protected_type_declaration and the protected_body.

22      14  A selected_component can be used to denote a discriminant of a
        protected object (see 4.1.3). Within a protected unit, the name of a
        discriminant of the protected type denotes the corresponding
        discriminant of the current instance of the unit.

23/2    15  {AI95-00287-01} A protected type is a limited type (see 7.5), and
        hence precludes use of assignment_statements and predefined equality
        operators.

24      16  The bodies of the protected operations given in the
        protected_body define the actions that take place upon calls to the
        protected operations.

25      17  The declarations in the private part are only visible within the
        private part and the body of the protected unit.

25.a        Reason: Component_declarations are disallowed in a
            protected_body because, for efficiency, we wish to allow the
            compiler to determine the size of protected objects (when not
            dynamic); the compiler cannot necessarily see the body.
            Furthermore, the semantics of initialization of such objects would
            be problematic - we do not wish to give protected objects complex
            initialization semantics similar to task activation.

25.b        The same applies to entry_declarations, since an entry involves an
            implicit component - the entry queue.


                                  Examples

26  Example of declaration of protected type and corresponding body:

27      protected type Resource is
           entry Seize;
           procedure Release;
        private
           Busy : Boolean := False;
        end Resource;

28      protected body Resource is
           entry Seize when not Busy is
           begin
              Busy := True;
           end Seize;

29         procedure Release is
           begin
              Busy := False;
           end Release;
        end Resource;

30  Example of a single protected declaration and corresponding body:

31      protected Shared_Array is
           --  Index, Item, and Item_Array are global types
           function  Component    (N : in Index) return Item;
           procedure Set_Component(N : in Index; E : in  Item);
        private
           Table : Item_Array(Index) := (others => Null_Item);
        end Shared_Array;

32      protected body Shared_Array is
           function Component(N : in Index) return Item is
           begin
              return Table(N);
           end Component;

33         procedure Set_Component(N : in Index; E : in Item) is
           begin
              Table(N) := E;
           end Set_Component;
        end Shared_Array;

34  Examples of protected objects:

35      Control  : Resource;
        Flags    : array(1 .. 100) of Resource;


                            Extensions to Ada 83

35.a/3      {AI05-0299-1} This entire subclause is new; protected units do not
            exist in Ada 83.


                            Extensions to Ada 95

35.b/2      {AI95-00345-01} {AI95-00397-01} {AI95-00399-01} {AI95-00401-01}
            {AI95-00419-01} Protected types and single protected objects can be
            derived from one or more interfaces. Operations declared in the
            protected type can implement the primitive operations of an
            interface. Overriding_indicators can be used to specify whether or
            not a protected operation implements a primitive operation.


                         Wording Changes from Ada 95

35.c/2      {8652/0009} {AI95-00137-01} Corrigendum: Changed representation
            clauses to aspect clauses to reflect that they are used for more
            than just representation.

35.d/2      {AI95-00280-01} Described what happens when an operation of a
            finalized protected object is called.

35.e/2      {AI95-00287-01} Revised the note on operations of protected types
            to reflect that limited types do have an assignment operation, but
            not copying (assignment_statements).

35.f/2      {AI95-00382-01} Revised the note on use of the name of a protected
            type within itself to reflect the exception for anonymous access
            types.


                       Incompatibilities With Ada 2005

35.g/3      {AI05-0291-1} Correction: When an inherited subprogram is
            implemented by a protected function, the first parameter has to be
            an in parameter, but not an access-to-variable type. Original Ada
            2005 allowed access-to-variable parameters in this case; the
            parameter will need to be changed to access-to-constant with the
            addition of the constant keyword.


                           Extensions to Ada 2005

35.h/3      {AI05-0183-1} {AI05-0267-1} An optional aspect_specification can
            be used in a protected_type_declaration, a
            single_protected_declaration, and a protected_body. This is
            described in 13.1.1.


                        Wording Changes from Ada 2005

35.i/3      {AI05-0042-1} Correction: Clarified that an inherited subprogram
            of a progenitor is overridden when it is implemented by an entry
            or subprogram.

35.j/3      {AI05-0090-1} Correction: Added the missing defining name in the
            no conflicting primitive operation rule.


                           Extensions to Ada 2012

35.k/4      {AI12-0147-1} Corrigendum: Null procedures and expression
            functions are allowed in protected bodies. We consider this an
            omission, as there is no reason why the convinient shorthand
            notations should not be allowed in this context.


9.5 Intertask Communication


1   The primary means for intertask communication is provided by calls on
entries and protected subprograms. Calls on protected subprograms allow
coordinated access to shared data objects. Entry calls allow for blocking the
caller until a given condition is satisfied (namely, that the corresponding
entry is open - see 9.5.3), and then communicating data or control information
directly with another task or indirectly via a shared protected object.


                              Static Semantics

2/3 {AI05-0225-1} {AI05-0291-1} When a name or prefix denotes an entry,
protected subprogram, or a prefixed view of a primitive subprogram of a
limited interface whose first parameter is a controlling parameter, the name
or prefix determines a target object, as follows:

2.a/3       To be honest: {AI05-0291-1} This wording uses "denotes" to mean
            "denotes a view of an entity" (when the term is used in Legality
            Rules), and "denotes an entity" (when the term is used in Dynamic
            Semantics rules). It does not mean "view of a declaration", as
            that would not include renames (a renames is not an entry or
            protected subprogram).

3/3   * {AI05-0291-1} If it is a direct_name or expanded name that denotes the
        declaration (or body) of the operation, then the target object is
        implicitly specified to be the current instance of the task or
        protected unit immediately enclosing the operation; a call using such
        a name is defined to be an internal call;

4/3   * {AI05-0291-1} If it is a selected_component that is not an expanded
        name, then the target object is explicitly specified to be the object
        denoted by the prefix of the name; a call using such a name is defined
        to be an external call;

4.a         Discussion: For example:

4.b             protected type Pt is
                  procedure Op1;
                  procedure Op2;
                end Pt;

4.c             PO : Pt;
                Other_Object : Some_Other_Protected_Type;

4.d             protected body Pt is
                  procedure Op1 is begin ... end Op1;

4.e               procedure Op2 is
                  begin
                    Op1; -- An internal call.
                    Pt.Op1; -- Another internal call.
                    PO.Op1; -- An external call. It the current instance is PO, then
                            -- this is a bounded error (see 9.5.1).
                    Other_Object.Some_Op; -- An external call.
                  end Op2;
                end Pt;

5/3   * {AI05-0291-1} If the name or prefix is a dereference (implicit or
        explicit) of an access-to-protected-subprogram value, then the target
        object is determined by the prefix of the Access attribute_reference
        that produced the access value originally; a call using such a name is
        defined to be an external call;

6     * If the name or prefix denotes a subprogram_renaming_declaration, then
        the target object is as determined by the name of the renamed entity.

6.1/3 {AI05-0291-1} A call on an entry or a protected subprogram either uses a
name or prefix that determines a target object implicitly, as above, or is a
call on (a non-prefixed view of) a primitive subprogram of a limited interface
whose first parameter is a controlling parameter, in which case the target
object is identified explicitly by the first parameter. This latter case is an
external call.

7   A corresponding definition of target object applies to a
requeue_statement (see 9.5.4), with a corresponding distinction between an
internal requeue and an external requeue.


                               Legality Rules

7.1/3 {AI95-00345-01} {AI05-0225-1} {AI05-0291-1} If a name or prefix
determines a target object, and the name denotes a protected entry or
procedure, then the target object shall be a variable, unless the prefix is
for an attribute_reference to the Count attribute (see 9.9).

7.a/3       Reason: {AI05-0225-1} The point is to prevent any calls to such a
            name whose target object is a constant view of a protected object,
            directly, or via an access value, renames, or generic formal
            subprogram. It is, however, legal to say P'Count in a protected
            function body, even though the protected object is a constant view
            there.

7.b/3       Ramification: {AI05-0291-1} This rule does not apply to calls that
            are not to a prefixed view. Specifically a "normal" call to a
            primitive operation of a limited interface is not covered by this
            rule. In that case, the normal parameter passing mode checks will
            prevent passing a constant protected object to an operation
            implemented by a protected entry or procedure as the mode is
            required to be in out or out.


                              Dynamic Semantics

8   Within the body of a protected operation, the current instance (see 8.6)
of the immediately enclosing protected unit is determined by the target object
specified (implicitly or explicitly) in the call (or requeue) on the protected
operation.

8.a         To be honest: The current instance is defined in the same way
            within the body of a subprogram declared immediately within a
            protected_body.

9   Any call on a protected procedure or entry of a target protected object is
defined to be an update to the object, as is a requeue on such an entry.

9.a         Reason: Read/write access to the components of a protected object
            is granted while inside the body of a protected procedure or
            entry. Also, any protected entry call can change the value of the
            Count attribute, which represents an update. Any protected
            procedure call can result in servicing the entries, which again
            might change the value of a Count attribute.


                                   Syntax

10/3    {AI05-0030-2} {AI05-0215-1} synchronization_kind ::= 
        By_Entry | By_Protected_Procedure | Optional


                              Static Semantics

11/3 {AI05-0215-1} For the declaration of a primitive procedure of a
synchronized tagged type the following language-defined representation aspect
may be specified with an aspect_specification (see 13.1.1):

12/3 Synchronization
                If specified, the aspect definition shall be a
                synchronization_kind.

12.a/3      Aspect Description for Synchronization: Defines whether a given
            primitive operation of a synchronized interface must be
            implemented by an entry or protected procedure.

13/3 {AI05-0030-2} {AI05-0215-1} Inherited subprograms inherit the
Synchronization aspect, if any, from the corresponding subprogram of the
parent or progenitor type. If an overriding operation does not have a directly
specified Synchronization aspect then the Synchronization aspect of the
inherited operation is inherited by the overriding operation.


                               Legality Rules

14/3 {AI05-0030-2} {AI05-0215-1} The synchronization_kind
By_Protected_Procedure shall not be applied to a primitive procedure of a task
interface.

15/3 {AI05-0030-2} {AI05-0215-1} A procedure for which the specified
synchronization_kind is By_Entry shall be implemented by an entry. A procedure
for which the specified synchronization_kind is By_Protected_Procedure shall
be implemented by a protected procedure. A procedure for which the specified
synchronization_kind is Optional may be implemented by an entry or by a
procedure (including a protected procedure).

16/3 {AI05-0030-2} {AI05-0215-1} If a primitive procedure overrides an
inherited operation for which the Synchronization aspect has been specified to
be By_Entry or By_Protected_Procedure, then any specification of the aspect
Synchronization applied to the overriding operation shall have the same
synchronization_kind.

17/3 {AI05-0030-2} In addition to the places where Legality Rules normally
apply (see 12.3), these rules also apply in the private part of an instance of
a generic unit.

        NOTES

18/3    18  {AI05-0030-2} {AI05-0215-1} The synchronization_kind
        By_Protected_Procedure implies that the operation will not block.


                         Wording Changes from Ada 95

18.a/2      {AI95-00345-01} Added a Legality Rule to make it crystal-clear
            that the protected object of an entry or procedure call must be a
            variable. This rule was implied by the Dynamic Semantics here,
            along with the Static Semantics of 3.3, but it is much better to
            explicitly say it. While many implementations have gotten this
            wrong, this is not an incompatibility - allowing updates of
            protected constants has always been wrong.


                           Extensions to Ada 2005

18.b/3      {AI05-0030-2} {AI05-0215-1} Added the Synchronization aspect to
            allow specifying that an interface procedure is really an entry or
            a protected procedure.


                        Wording Changes from Ada 2005

18.c/3      {AI05-0225-1} Correction: Clarified that the target object of any
            name denoted a protected procedure or entry can never be a
            constant (other than for the 'Count attribute). This closes holes
            involving calls to access-to-protected, renaming as a procedure,
            and generic formal subprograms.


9.5.1 Protected Subprograms and Protected Actions


1   A protected subprogram is a subprogram declared immediately within a
protected_definition. Protected procedures provide exclusive read-write access
to the data of a protected object; protected functions provide concurrent
read-only access to the data.

1.a         Ramification: A subprogram declared immediately within a
            protected_body is not a protected subprogram; it is an intrinsic
            subprogram. See 6.3.1, "Conformance Rules".


                              Static Semantics

2   [Within the body of a protected function (or a function declared
immediately within a protected_body), the current instance of the enclosing
protected unit is defined to be a constant (that is, its subcomponents may be
read but not updated). Within the body of a protected procedure (or a
procedure declared immediately within a protected_body), and within an
entry_body, the current instance is defined to be a variable (updating is
permitted).]

2.a.1/3     Proof: {AI05-0120-1} All constant views are defined in 3.3, "
            Objects and Named Numbers", anything not named there is a variable
            view.

2.a         Ramification: The current instance is like an implicit parameter,
            of mode in for a protected function, and of mode in out for a
            protected procedure (or protected entry).

2.1/4 {AI12-0129-1} For a type declared by a protected_type_declaration or for
the anonymous type of an object declared by a single_protected_declaration,
the following language-defined type-related representation aspect may be
specified:

2.2/4 Exclusive_Functions
                The type of aspect Exclusive_Functions is Boolean. If not
                specified (including by inheritance), the aspect is False.

2.3/4           A value of True for this aspect indicates that protected
                functions behave in the same way as protected procedures with
                respect to mutual exclusion and queue servicing (see below).

2.a.1/4     Aspect Description for Exclusive_Functions: Specifies mutual
            exclusion behavior of protected functions in a protected type.

2.4/4 {AI12-0129-1} A protected procedure or entry is an exclusive protected
operation. A protected function of a protected type P is an exclusive
protected operation if the Exclusive_Functions aspect of P is True.


                              Dynamic Semantics

3   For the execution of a call on a protected subprogram, the evaluation of
the name or prefix and of the parameter associations, and any assigning back
of in out or out parameters, proceeds as for a normal subprogram call (see
6.4). If the call is an internal call (see 9.5), the body of the subprogram is
executed as for a normal subprogram call. If the call is an external call,
then the body of the subprogram is executed as part of a new protected action
on the target protected object; the protected action completes after the body
of the subprogram is executed. [A protected action can also be started by an
entry call (see 9.5.3).]

4/4 {AI12-0129-1} A new protected action is not started on a protected object
while another protected action on the same protected object is underway,
unless both actions are the result of a call on a nonexclusive protected
function. This rule is expressible in terms of the execution resource
associated with the protected object:

5/4   * {AI12-0129-1} Starting a protected action on a protected object
        corresponds to acquiring the execution resource associated with the
        protected object, either for exclusive read-write access if the
        protected action is for a call on an exclusive protected operation, or
        for concurrent read-only access otherwise;

6     * Completing the protected action corresponds to releasing the
        associated execution resource.

7/4 {AI12-0129-1} [After performing an exclusive protected operation on a
protected object, but prior to completing the associated protected action, the
entry queues (if any) of the protected object are serviced (see 9.5.3).]


                          Bounded (Run-Time) Errors

8   During a protected action, it is a bounded error to invoke an operation
that is potentially blocking. The following are defined to be potentially
blocking operations:

8.a         Reason: Some of these operations are not directly blocking.
            However, they are still treated as bounded errors during a
            protected action, because allowing them might impose an
            undesirable implementation burden.

9     * a select_statement;

10    * an accept_statement;

11    * an entry_call_statement;

12    * a delay_statement;

13    * an abort_statement;

14    * task creation or activation;

15    * an external call on a protected subprogram (or an external requeue)
        with the same target object as that of the protected action;

15.a        Reason: This is really a deadlocking call, rather than a blocking
            call, but we include it in this list for simplicity.

16    * a call on a subprogram whose body contains a potentially blocking
        operation.

16.a        Reason: This allows an implementation to check and raise
            Program_Error as soon as a subprogram is called, rather than
            waiting to find out whether it actually reaches the potentially
            blocking operation. This in turn allows the potentially blocking
            operation check to be performed prior to run time in some
            environments.

17  If the bounded error is detected, Program_Error is raised. If not
detected, the bounded error might result in deadlock or a (nested) protected
action on the same target object.

17.a/2      Discussion: {AI95-00305-01} By "nested protected action", we mean
            that an additional protected action can be started by another task
            on the same protected object. This means that mutual exclusion may
            be broken in this bounded error case. A way to ensure that this
            does not happen is to use pragma Detect_Blocking (see H.5).

18  Certain language-defined subprograms are potentially blocking. In
particular, the subprograms of the language-defined input-output packages that
manipulate files (implicitly or explicitly) are potentially blocking. Other
potentially blocking subprograms are identified where they are defined. When
not specified as potentially blocking, a language-defined subprogram is
nonblocking.

18.a/2      Discussion: {AI95-00178-01} Any subprogram in a language-defined
            input-output package that has a file parameter or result or
            operates on a default file is considered to manipulate a file. An
            instance of a language-defined input-output generic package
            provides subprograms that are covered by this rule. The only
            subprograms in language-defined input-output packages not covered
            by this rule (and thus not potentially blocking) are the Get and
            Put routines that take string parameters defined in the packages
            nested in Text_IO.

        NOTES

19      19  If two tasks both try to start a protected action on a protected
        object, and at most one is calling a protected function, then only one
        of the tasks can proceed. Although the other task cannot proceed, it
        is not considered blocked, and it might be consuming processing
        resources while it awaits its turn. There is no language-defined
        ordering or queuing presumed for tasks competing to start a protected
        action - on a multiprocessor such tasks might use busy-waiting; for
        monoprocessor considerations, see D.3, "Priority Ceiling Locking".

19.a        Discussion: The intended implementation on a multi-processor is in
            terms of "spin locks" - the waiting task will spin.

20      20  The body of a protected unit may contain declarations and bodies
        for local subprograms. These are not visible outside the protected
        unit.

21      21  The body of a protected function can contain internal calls on
        other protected functions, but not protected procedures, because the
        current instance is a constant. On the other hand, the body of a
        protected procedure can contain internal calls on both protected
        functions and procedures.

22      22  From within a protected action, an internal call on a protected
        subprogram, or an external call on a protected subprogram with a
        different target object is not considered a potentially blocking
        operation.

22.a        Reason: This is because a task is not considered blocked while
            attempting to acquire the execution resource associated with a
            protected object. The acquisition of such a resource is rather
            considered part of the normal competition for execution resources
            between the various tasks that are ready. External calls that turn
            out to be on the same target object are considered potentially
            blocking, since they can deadlock the task indefinitely.

22.1/2  23  {AI95-00305-01} The pragma Detect_Blocking may be used to ensure
        that all executions of potentially blocking operations during a
        protected action raise Program_Error. See H.5.


                                  Examples

23  Examples of protected subprogram calls (see 9.4):

24      Shared_Array.Set_Component(N, E);
        E := Shared_Array.Component(M);
        Control.Release;


                         Wording Changes from Ada 95

24.a/2      {AI95-00305-01} Added a note pointing out the existence of
            pragma Detect_Blocking. This pragma can be used to ensure portable
            (somewhat pessimistic) behavior of protected actions by converting
            the Bounded Error into a required check.


                           Extensions to Ada 2012

24.b/4      {AI12-0129-1} Corrigendum: Aspect Exclusive_Functions is new. The
            term "exclusive protected operations" is new.


9.5.2 Entries and Accept Statements


1   Entry_declarations, with the corresponding entry_bodies or
accept_statements, are used to define potentially queued operations on tasks
and protected objects.


                                   Syntax

2/3     {AI95-00397-01} {AI05-0183-1} entry_declaration ::= 
           [overriding_indicator]
           entry defining_identifier [(discrete_subtype_definition
        )] parameter_profile
              [aspect_specification];

3       accept_statement ::= 
           accept entry_direct_name [(entry_index)] parameter_profile [do
             handled_sequence_of_statements
           end [entry_identifier]];

3.a         Reason: We cannot use defining_identifier for accept_statements.
            Although an accept_statement is sort of like a body, it can appear
            nested within a block_statement, and therefore be hidden from its
            own entry by an outer homograph.

4       entry_index ::= expression

5       entry_body ::= 
          entry defining_identifier  entry_body_formal_part  entry_barrier is
            declarative_part
          begin
            handled_sequence_of_statements
          end [entry_identifier];

5.a/2       Discussion: {AI95-00397-01} We don't allow an
            overriding_indicator on an entry_body because entries always
            implement procedures at the point of the type declaration; there
            is no late implementation. And we don't want to have to think
            about overriding_indicators on accept_statements.

6       entry_body_formal_part ::= [(entry_index_specification
        )] parameter_profile

7       entry_barrier ::= when condition

8       entry_index_specification ::= for defining_identifier
         in discrete_subtype_definition

9       If an entry_identifier appears at the end of an accept_statement, it
        shall repeat the entry_direct_name. If an entry_identifier appears at
        the end of an entry_body, it shall repeat the defining_identifier.

10      [An entry_declaration is allowed only in a protected or task
        declaration.]

10.a        Proof: This follows from the BNF.

10.1/2  {AI95-00397-01} An overriding_indicator is not allowed in an
        entry_declaration that includes a discrete_subtype_definition.

10.a.1/2    Reason: An entry family can never implement something, so allowing
            an indicator is felt by the majority of the ARG to be redundant.


                            Name Resolution Rules

11  In an accept_statement, the expected profile for the entry_direct_name is
that of the entry_declaration; the expected type for an entry_index is that of
the subtype defined by the discrete_subtype_definition of the corresponding
entry_declaration.

12  Within the handled_sequence_of_statements of an accept_statement, if a
selected_component has a prefix that denotes the corresponding
entry_declaration, then the entity denoted by the prefix is the accept_-
statement, and the selected_component is interpreted as an expanded name (see
4.1.3)[; the selector_name of the selected_component has to be the
identifier for some formal parameter of the accept_statement].

12.a        Proof: The only declarations that occur immediately within the
            declarative region of an accept_statement are those for its formal
            parameters.


                               Legality Rules

13  An entry_declaration in a task declaration shall not contain a
specification for an access parameter (see 3.10).

13.a        Reason: Access parameters for task entries would require a complex
            implementation. For example:

13.b            task T is
                   entry E(Z : access Integer); -- Illegal!
                end T;

13.c            task body T is
                begin
                   declare
                      type A is access all Integer;
                      X : A;
                      Int : aliased Integer;
                      task Inner;
                      task body Inner is
                      begin
                         T.E(Int'Access);
                      end Inner;
                   begin
                      accept E(Z : access Integer) do
                         X := A(Z); -- Accessibility_Check
                      end E;
                   end;
                end T;

13.d        Implementing the Accessibility_Check inside the accept_statement
            for E is difficult, since one does not know whether the entry
            caller is calling from inside the immediately enclosing declare
            block or from outside it. This means that the lexical nesting
            level associated with the designated object is not sufficient to
            determine whether the Accessibility_Check should pass or fail.

13.e        Note that such problems do not arise with protected entries,
            because entry_bodies are always nested immediately within the
            protected_body; they cannot be further nested as can
            accept_statements, nor can they be called from within the
            protected_body (since no entry calls are permitted inside a
            protected_body).

13.1/2 {AI95-00397-01} If an entry_declaration has an overriding_indicator,
then at the point of the declaration:

13.2/2   * if the overriding_indicator is overriding, then the entry shall
        implement an inherited subprogram;

13.3/2   * if the overriding_indicator is not overriding, then the entry shall
        not implement any inherited subprogram.

13.4/2 In addition to the places where Legality Rules normally apply (see
12.3), these rules also apply in the private part of an instance of a generic
unit.

13.f/2      Discussion: These rules are subtly different than those for
            subprograms (see 8.3.1) because there cannot be "late" inheritance
            of primitives from interfaces. Hidden (that is, private)
            interfaces are prohibited explicitly (see 7.3), as are hidden
            primitive operations (as private operations of public abstract
            types are prohibited - see 3.9.3).

14  For an accept_statement, the innermost enclosing body shall be a
task_body, and the entry_direct_name shall denote an entry_declaration in the
corresponding task declaration; the profile of the accept_statement shall
conform fully to that of the corresponding entry_declaration. An accept_-
statement shall have a parenthesized entry_index if and only if the
corresponding entry_declaration has a discrete_subtype_definition.

15  An accept_statement shall not be within another accept_statement that
corresponds to the same entry_declaration, nor within an asynchronous_select
inner to the enclosing task_body.

15.a        Reason: Accept_statements are required to be immediately within
            the enclosing task_body (as opposed to being in a nested
            subprogram) to ensure that a nested task does not attempt to
            accept the entry of its enclosing task. We considered relaxing
            this restriction, either by making the check a run-time check, or
            by allowing a nested task to accept an entry of its enclosing
            task. However, neither change seemed to provide sufficient benefit
            to justify the additional implementation burden.

15.b        Nested accept_statements for the same entry (or entry family) are
            prohibited to ensure that there is no ambiguity in the resolution
            of an expanded name for a formal parameter of the entry. This
            could be relaxed by allowing the inner one to hide the outer one
            from all visibility, but again the small added benefit didn't seem
            to justify making the change for Ada 95.

15.c        Accept_statements are not permitted within asynchronous_select
            statements to simplify the semantics and implementation: an
            accept_statement in an abortable_part could result in
            Tasking_Error being propagated from an entry call even though the
            target task was still callable; implementations that use multiple
            tasks implicitly to implement an asynchronous_select might have
            trouble supporting "up-level" accepts. Furthermore, if
            accept_statements were permitted in the abortable_part, a task
            could call its own entry and then accept it in the
            abortable_part, leading to rather unusual and possibly
            difficult-to-specify semantics.

16  An entry_declaration of a protected unit requires a completion[, which
shall be an entry_body,] and every entry_body shall be the completion of an
entry_declaration of a protected unit. The profile of the entry_body shall
conform fully to that of the corresponding declaration.

16.a        Ramification: An entry_declaration, unlike a
            subprogram_declaration, cannot be completed with a renaming_-
            declaration.

16.b/3      To be honest: {AI05-0229-1} If the implementation supports it, the
            entry body can be imported (using aspect Import, see B.1), in
            which case no explicit entry_body is allowed.

16.c        Discussion: The above applies only to protected entries, which are
            the only ones completed with entry_bodies. Task entries have
            corresponding accept_statements instead of having entry_bodies,
            and we do not consider an accept_statement to be a "
            completion," because a task entry_declaration is allowed to have zero, one,
            or more than one corresponding accept_statements.

17  An entry_body_formal_part shall have an entry_index_specification if and
only if the corresponding entry_declaration has a discrete_subtype_definition.
In this case, the discrete_subtype_definitions of the entry_declaration and
the entry_index_specification shall fully conform to one another (see 6.3.1).

18  A name that denotes a formal parameter of an entry_body is not allowed
within the entry_barrier of the entry_body.


                              Static Semantics

19  The parameter modes defined for parameters in the parameter_profile of an
entry_declaration are the same as for a subprogram_declaration and have the
same meaning (see 6.2).

19.a        Discussion: Note that access parameters are not allowed for task
            entries (see above).

20  An entry_declaration with a discrete_subtype_definition (see 3.6) declares
a family of distinct entries having the same profile, with one such entry for
each value of the entry index subtype defined by the
discrete_subtype_definition. [A name for an entry of a family takes the form
of an indexed_component, where the prefix denotes the entry_declaration for
the family, and the index value identifies the entry within the family.] The
term single entry is used to refer to any entry other than an entry of an
entry family.

21  In the entry_body for an entry family, the entry_index_specification
declares a named constant whose subtype is the entry index subtype defined by
the corresponding entry_declaration; the value of the named entry index
identifies which entry of the family was called.

21.a        Ramification: The discrete_subtype_definition of the
            entry_index_specification is not elaborated; the subtype of the
            named constant declared is defined by the
            discrete_subtype_definition of the corresponding
            entry_declaration, which is elaborated, either when the type is
            declared, or when the object is created, if its constraint is
            per-object.


                              Dynamic Semantics

22/1 {8652/0002} {AI95-00171-01} The elaboration of an entry_declaration for
an entry family consists of the elaboration of the
discrete_subtype_definition, as described in 3.8. The elaboration of an entry_-
declaration for a single entry has no effect.

22.a/3      Discussion: {AI05-0299-1} The elaboration of the declaration of a
            protected subprogram has no effect, as specified in subclause
            6.1. The default initialization of an object of a task or
            protected type is covered in 3.3.1.

23  [The actions to be performed when an entry is called are specified by the
corresponding accept_statements (if any) for an entry of a task unit, and by
the corresponding entry_body for an entry of a protected unit.]

24  For the execution of an accept_statement, the entry_index, if any, is
first evaluated and converted to the entry index subtype; this index value
identifies which entry of the family is to be accepted. Further execution of
the accept_statement is then blocked until a caller of the corresponding entry
is selected (see 9.5.3), whereupon the handled_sequence_of_statements, if any,
of the accept_statement is executed, with the formal parameters associated
with the corresponding actual parameters of the selected entry call. Upon
completion of the handled_sequence_of_statements, the accept_statement
completes and is left. When an exception is propagated from the
handled_sequence_of_statements of an accept_statement, the same exception is
also raised by the execution of the corresponding entry_call_statement.

24.a        Ramification: This is in addition to propagating it to the
            construct containing the accept_statement. In other words, for a
            rendezvous, the raising splits in two, and continues concurrently
            in both tasks.

24.b        The caller gets a new occurrence; this isn't considered
            propagation.

24.c        Note that we say "propagated from the
            handled_sequence_of_statements of an accept_statement", not "
            propagated from an accept_statement." The latter would be wrong -
            we don't want exceptions propagated by the entry_index to be sent
            to the caller (there is none yet!).

25  The above interaction between a calling task and an accepting task is
called a rendezvous. [After a rendezvous, the two tasks continue their
execution independently.]

26  [An entry_body is executed when the condition of the entry_barrier
evaluates to True and a caller of the corresponding single entry, or entry of
the corresponding entry family, has been selected (see 9.5.3).] For the
execution of the entry_body, the declarative_part of the entry_body is
elaborated, and the handled_sequence_of_statements of the body is executed, as
for the execution of a subprogram_body. The value of the named entry index, if
any, is determined by the value of the entry index specified in the
entry_name of the selected entry call (or intermediate requeue_statement - see
9.5.4).

26.a        To be honest: If the entry had been renamed as a subprogram, and
            the call was a procedure_call_statement using the name declared by
            the renaming, the entry index (if any) comes from the entry name
            specified in the subprogram_renaming_declaration.

        NOTES

27      24  A task entry has corresponding accept_statements (zero or more),
        whereas a protected entry has a corresponding entry_body (exactly one).

28      25  A consequence of the rule regarding the allowed placements of
        accept_statements is that a task can execute accept_statements only
        for its own entries.

29/2    26  {AI95-00318-02} A return statement (see 6.5) or a
        requeue_statement (see 9.5.4) may be used to complete the execution of
        an accept_statement or an entry_body.

29.a        Ramification: An accept_statement need not have a
            handled_sequence_of_statements even if the corresponding entry has
            parameters. Equally, it can have a
            handled_sequence_of_statements even if the corresponding entry has
            no parameters.

29.b        Ramification: A single entry overloads a subprogram, an
            enumeration literal, or another single entry if they have the same
            defining_identifier. Overloading is not allowed for entry family
            names. A single entry or an entry of an entry family can be
            renamed as a procedure as explained in 8.5.4.

30      27  The condition in the entry_barrier may reference anything visible
        except the formal parameters of the entry. This includes the entry
        index (if any), the components (including discriminants) of the
        protected object, the Count attribute of an entry of that protected
        object, and data global to the protected unit.

31      The restriction against referencing the formal parameters within an
        entry_barrier ensures that all calls of the same entry see the same
        barrier value. If it is necessary to look at the parameters of an
        entry call before deciding whether to handle it, the entry_barrier can
        be "when True" and the caller can be requeued (on some private entry)
        when its parameters indicate that it cannot be handled immediately.


                                  Examples

32  Examples of entry declarations:

33      entry Read(V : out Item);
        entry Seize;
        entry Request(Level)(D : Item);  --  a family of entries

34  Examples of accept statements:

35      accept Shut_Down;

36      accept Read(V : out Item) do
           V := Local_Item;
        end Read;

37      accept Request(Low)(D : Item) do
           ...
        end Request;


                            Extensions to Ada 83

37.a        The syntax rule for entry_body is new.

37.b        Accept_statements can now have exception_handlers.


                         Wording Changes from Ada 95

37.c/2      {8652/0002} {AI95-00171-01} Corrigendum: Clarified the elaboration
            of per-object constraints.

37.d/2      {AI95-00397-01} Overriding_indicators can be used on entries; this
            is only useful when a task or protected type inherits from an
            interface.


                           Extensions to Ada 2005

37.e/3      {AI05-0183-1} An optional aspect_specification can be used in an
            entry_declaration. This is described in 13.1.1.


9.5.3 Entry Calls


1   [An entry_call_statement (an entry call) can appear in various contexts.]
A simple entry call is a stand-alone statement that represents an
unconditional call on an entry of a target task or a protected object. [Entry
calls can also appear as part of select_statements (see 9.7).]


                                   Syntax

2       entry_call_statement ::= entry_name [actual_parameter_part];


                            Name Resolution Rules

3   The entry_name given in an entry_call_statement shall resolve to denote an
entry. The rules for parameter associations are the same as for subprogram
calls (see 6.4 and 6.4.1).


                              Static Semantics

4   [The entry_name of an entry_call_statement specifies (explicitly or
implicitly) the target object of the call, the entry or entry family, and the
entry index, if any (see 9.5).]


                              Dynamic Semantics

5   Under certain circumstances (detailed below), an entry of a task or
protected object is checked to see whether it is open or closed:

6/3   * {AI05-0264-1} An entry of a task is open if the task is blocked on an
        accept_statement that corresponds to the entry (see 9.5.2), or on a
        selective_accept (see 9.7.1) with an open accept_alternative that
        corresponds to the entry; otherwise, it is closed.

7/3   * {AI05-0264-1} An entry of a protected object is open if the
        condition of the entry_barrier of the corresponding entry_body
        evaluates to True; otherwise, it is closed. If the evaluation of the
        condition propagates an exception, the exception Program_Error is
        propagated to all current callers of all entries of the protected
        object.

7.a         Reason: An exception during barrier evaluation is considered
            essentially a fatal error. All current entry callers are notified
            with a Program_Error. In a fault-tolerant system, a protected
            object might provide a Reset protected procedure, or equivalent,
            to support attempts to restore such a "broken" protected object to
            a reasonable state.

7.b         Discussion: Note that the definition of when a task entry is open
            is based on the state of the (accepting) task, whereas the
            "openness" of a protected entry is defined only when it is
            explicitly checked, since the barrier expression needs to be
            evaluated. Implementation permissions are given (below) to allow
            implementations to evaluate the barrier expression more or less
            often than it is checked, but the basic semantic model presumes it
            is evaluated at the times when it is checked.

8   For the execution of an entry_call_statement, evaluation of the name and
of the parameter associations is as for a subprogram call (see 6.4). The entry
call is then issued: For a call on an entry of a protected object, a new
protected action is started on the object (see 9.5.1). The named entry is
checked to see if it is open; if open, the entry call is said to be selected
immediately, and the execution of the call proceeds as follows:

9     * For a call on an open entry of a task, the accepting task becomes
        ready and continues the execution of the corresponding
        accept_statement (see 9.5.2).

10    * For a call on an open entry of a protected object, the corresponding
        entry_body is executed (see 9.5.2) as part of the protected action.

11  If the accept_statement or entry_body completes other than by a requeue
(see 9.5.4), return is made to the caller (after servicing the entry queues -
see below); any necessary assigning back of formal to actual parameters
occurs, as for a subprogram call (see 6.4.1); such assignments take place
outside of any protected action.

11.a        Ramification: The return to the caller will generally not occur
            until the protected action completes, unless some other thread of
            control is given the job of completing the protected action and
            releasing the associated execution resource.

12  If the named entry is closed, the entry call is added to an entry queue
(as part of the protected action, for a call on a protected entry), and the
call remains queued until it is selected or cancelled; there is a separate
(logical) entry queue for each entry of a given task or protected object
[(including each entry of an entry family)].

13  When a queued call is selected, it is removed from its entry queue.
Selecting a queued call from a particular entry queue is called servicing the
entry queue. An entry with queued calls can be serviced under the following
circumstances:

14    * When the associated task reaches a corresponding accept_statement, or
        a selective_accept with a corresponding open accept_alternative;

15/4   * {AI12-0129-1} If after performing, as part of a protected action on
        the associated protected object, an exclusive protected operation on
        the object, the entry is checked and found to be open.

16  If there is at least one call on a queue corresponding to an open entry,
then one such call is selected according to the entry queuing policy in effect
(see below), and the corresponding accept_statement or entry_body is executed
as above for an entry call that is selected immediately.

17  The entry queuing policy controls selection among queued calls both for
task and protected entry queues. The default entry queuing policy is to select
calls on a given entry queue in order of arrival. If calls from two or more
queues are simultaneously eligible for selection, the default entry queuing
policy does not specify which queue is serviced first. Other entry queuing
policies can be specified by pragmas (see D.4).

18  For a protected object, the above servicing of entry queues continues
until there are no open entries with queued calls, at which point the
protected action completes.

18.a        Discussion: While servicing the entry queues of a protected
            object, no new calls can be added to any entry queue of the
            object, except due to an internal requeue (see 9.5.4). This is
            because the first step of a call on a protected entry is to start
            a new protected action, which implies acquiring (for exclusive
            read-write access) the execution resource associated with the
            protected object, which cannot be done while another protected
            action is already in progress.

19  For an entry call that is added to a queue, and that is not the
triggering_statement of an asynchronous_select (see 9.7.4), the calling task
is blocked until the call is cancelled, or the call is selected and a
corresponding accept_statement or entry_body completes without requeuing. In
addition, the calling task is blocked during a rendezvous.

19.a        Ramification: For a call on a protected entry, the caller is not
            blocked if the call is selected immediately, unless a requeue
            causes the call to be queued.

20  An attempt can be made to cancel an entry call upon an abort (see 9.8) and
as part of certain forms of select_statement (see 9.7.2, 9.7.3, and 9.7.4).
The cancellation does not take place until a point (if any) when the call is
on some entry queue, and not protected from cancellation as part of a requeue
(see 9.5.4); at such a point, the call is removed from the entry queue and the
call completes due to the cancellation. The cancellation of a call on an entry
of a protected object is a protected action[, and as such cannot take place
while any other protected action is occurring on the protected object. Like
any protected action, it includes servicing of the entry queues (in case some
entry barrier depends on a Count attribute).]

20.a/2      Implementation Note: {AI95-00114-01} In the case of an attempted
            cancellation due to abort, this removal might have to be performed
            by the calling task itself if the ceiling priority of the
            protected object is lower than the priority of the task initiating
            the abort.

21  A call on an entry of a task that has already completed its execution
raises the exception Tasking_Error at the point of the call; similarly, this
exception is raised at the point of the call if the called task completes its
execution or becomes abnormal before accepting the call or completing the
rendezvous (see 9.8). This applies equally to a simple entry call and to an
entry call as part of a select_statement.


                         Implementation Permissions

22  An implementation may perform the sequence of steps of a protected action
using any thread of control; it need not be that of the task that started the
protected action. If an entry_body completes without requeuing, then the
corresponding calling task may be made ready without waiting for the entire
protected action to complete.

22.a        Reason: These permissions are intended to allow flexibility for
            implementations on multiprocessors. On a monoprocessor, which
            thread of control executes the protected action is essentially
            invisible, since the thread is not abortable in any case, and the
            "current_task" function is not guaranteed to work during a
            protected action (see C.7.1).

23/4 {AI12-0129-1} When the entry of a protected object is checked to see
whether it is open, the implementation need not reevaluate the condition of
the corresponding entry_barrier if no variable or attribute referenced by the
condition (directly or indirectly) has been altered by the execution (or
cancellation) of a call to an exclusive protected operation of the object
since the condition was last evaluated.

23.a/4      Ramification: Changes to variables referenced by an entry barrier
            that result from actions outside of a call to an exclusive
            protected operation of the protected object need not be "noticed."
            For example, if a global variable is referenced by an entry
            barrier, it should not be altered (except as part of a protected
            action on the object) any time after the barrier is first
            evaluated. In other words, globals can be used to "parameterize" a
            protected object, but they cannot reliably be used to control it
            after the first use of the protected object.

23.b        Implementation Note: Note that even if a global variable is
            volatile, the implementation need only reevaluate a barrier if the
            global is updated during a protected action on the protected
            object. This ensures that an entry-open bit-vector implementation
            approach is possible, where the bit-vector is computed at the end
            of a protected action, rather than upon each entry call.

24  An implementation may evaluate the conditions of all entry_barriers of a
given protected object any time any entry of the object is checked to see if
it is open.

24.a        Ramification: In other words, any side effects of evaluating an
            entry barrier should be innocuous, since an entry barrier might be
            evaluated more or less often than is implied by the "official"
            dynamic semantics.

24.b        Implementation Note: It is anticipated that when the number of
            entries is known to be small, all barriers will be evaluated any
            time one of them needs to be, to produce an "entry-open
            bit-vector." The appropriate bit will be tested when the entry is
            called, and only if the bit is false will a check be made to see
            whether the bit-vector might need to be recomputed. This should
            allow an implementation to maximize the performance of a call on
            an open entry, which seems like the most important case.

24.c        In addition to the entry-open bit-vector, an "is-valid" bit is
            needed per object, which indicates whether the current bit-vector
            setting is valid. A "depends-on-Count-attribute" bit is needed per
            type. The "is-valid" bit is set to false (as are all the bits of
            the bit-vector) when the protected object is first created, as
            well as any time an exception is propagated from computing the
            bit-vector. Is-valid would also be set false any time the Count is
            changed and "depends-on-Count-attribute" is true for the type, or
            a protected procedure or entry returns indicating it might have
            updated a variable referenced in some barrier.

24.d        A single procedure can be compiled to evaluate all of the
            barriers, set the entry-open bit-vector accordingly, and set the
            is-valid bit to true. It could have a "when others" handler to set
            them all false, and call a routine to propagate Program_Error to
            all queued callers.

24.e        For protected types where the number of entries is not known to be
            small, it makes more sense to evaluate a barrier only when the
            corresponding entry is checked to see if it is open. It isn't
            worth saving the state of the entry between checks, because of the
            space that would be required. Furthermore, the entry queues
            probably want to take up space only when there is actually a
            caller on them, so rather than an array of all entry queues, a
            linked list of nonempty entry queues make the most sense in this
            case, with the first caller on each entry queue acting as the
            queue header.

25  When an attempt is made to cancel an entry call, the implementation need
not make the attempt using the thread of control of the task (or interrupt)
that initiated the cancellation; in particular, it may use the thread of
control of the caller itself to attempt the cancellation, even if this might
allow the entry call to be selected in the interim.

25.a        Reason: Because cancellation of a protected entry call is a
            protected action (which helps make the Count attribute of a
            protected entry meaningful), it might not be practical to attempt
            the cancellation from the thread of control that initiated the
            cancellation. For example, if the cancellation is due to the
            expiration of a delay, it is unlikely that the handler of the
            timer interrupt could perform the necessary protected action
            itself (due to being on the interrupt level). Similarly, if the
            cancellation is due to an abort, it is possible that the task
            initiating the abort has a priority higher than the ceiling
            priority of the protected object (for implementations that support
            ceiling priorities). Similar considerations could apply in a
            multiprocessor situation.

        NOTES

26      28  If an exception is raised during the execution of an entry_body,
        it is propagated to the corresponding caller (see 11.4).

27      29  For a call on a protected entry, the entry is checked to see if it
        is open prior to queuing the call, and again thereafter if its Count
        attribute (see 9.9) is referenced in some entry barrier.

27.a        Ramification: Given this, extra care is required if a reference to
            the Count attribute of an entry appears in the entry's own
            barrier.

27.b        Reason: An entry is checked to see if it is open prior to queuing
            to maximize the performance of a call on an open entry.

28      30  In addition to simple entry calls, the language permits timed,
        conditional, and asynchronous entry calls (see 9.7.2, 9.7.3, and see
        9.7.4).

28.a        Ramification: A task can call its own entries, but the task will
            deadlock if the call is a simple entry call.

29      31  The condition of an entry_barrier is allowed to be evaluated by an
        implementation more often than strictly necessary, even if the
        evaluation might have side effects. On the other hand, an
        implementation need not reevaluate the condition if nothing it
        references was updated by an intervening protected action on the
        protected object, even if the condition references some global
        variable that might have been updated by an action performed from
        outside of a protected action.


                                  Examples

30  Examples of entry calls:

31      Agent.Shut_Down;                      --  see 9.1
        Parser.Next_Lexeme(E);                --  see 9.1
        Pool(5).Read(Next_Char);              --  see 9.1
        Controller.Request(Low)(Some_Item);   --  see 9.1
        Flags(3).Seize;                       --  see 9.4


                        Wording Changes from Ada 2012

31.a/4      {AI12-0129-1} Corrigendum: Revised wording to talk about "
            exclusive protected operations" (see 9.5.1).


9.5.4 Requeue Statements


1   [A requeue_statement can be used to complete an accept_statement or
entry_body, while redirecting the corresponding entry call to a new (or the
same) entry queue. Such a requeue can be performed with or without allowing an
intermediate cancellation of the call, due to an abort or the expiration of a
delay. ]


                                   Syntax

2/3     {AI05-0030-2} requeue_statement ::= requeue procedure_or_entry_name
         [with abort];


                            Name Resolution Rules

3/3 {AI05-0030-2} {AI05-0215-1} The procedure_or_entry_name of a
requeue_statement shall resolve to denote a procedure or an entry (the requeue
target). The profile of the entry, or the profile or prefixed profile of the
procedure, shall either have no parameters, or be type conformant (see 6.3.1)
with the profile of the innermost enclosing entry_body or accept_statement.


                               Legality Rules

4   A requeue_statement shall be within a callable construct that is either an
entry_body or an accept_statement, and this construct shall be the innermost
enclosing body or callable construct.

5/3 {AI05-0030-2} {AI05-0215-1} If the requeue target has parameters, then its
(prefixed) profile shall be subtype conformant with the profile of the
innermost enclosing callable construct.

5.1/4 {AI12-0090-1} Given a requeue_statement where the innermost enclosing
callable construct is for an entry E1, for every [specific or class-wide
]postcondition expression P1 that applies to E1, there shall exist a
postcondition expression P2 that applies to the requeue target E2 such that

5.2/4   * P1 is fully conformant with the expression produced by replacing
        each reference in P2 to a formal parameter of E2 with a reference to
        the corresponding formal paramter of E1; and

5.3/4   * if P1 is enabled, then P2 is also enabled.

5.a/4       Discussion: Roughly speaking, the postcondition of the requeue
            target is required to imply that of the enclosing callable
            construct.

5.4/4 {AI12-0090-1} The requeue target shall not have an applicable specific
or class-wide postcondition which includes an Old attribute_reference.

5.5/4 {AI12-0090-1} If the requeue target is declared immediately within the
task_definition of a named task type or the protected_definition of a named
protected type, and if the requeue statement occurs within the body of that
type, and if the requeue is an external requeue, then the requeue target shall
not have a specific or class-wide postcondition which includes a name denoting
either the current instance of that type or any entity declared within the
declaration of that type.

5.b/4       Discussion: The above pair of rules always apply; they don't
            depend on whether or not any of the postconditions are enabled.

5.6/4 {AI05-0030-2} {AI05-0215-1} {AI12-0090-1} If the target is a procedure,
the name shall denote a renaming of an entry, or shall denote a view or a
prefixed view of a primitive subprogram of a synchronized interface, where the
first parameter of the unprefixed view of the primitive subprogram shall be a
controlling parameter, and the Synchronization aspect shall be specified with
synchronization_kind By_Entry for the primitive subprogram.

6/3 {AI05-0030-2} In a requeue_statement of an accept_statement of some task
unit, either the target object shall be a part of a formal parameter of the
accept_statement, or the accessibility level of the target object shall not be
equal to or statically deeper than any enclosing accept_statement of the task
unit. In a requeue_statement of an entry_body of some protected unit, either
the target object shall be a part of a formal parameter of the entry_body, or
the accessibility level of the target object shall not be statically deeper
than that of the entry_declaration for the entry_body.

6.a         Ramification: In the entry_body case, the intent is that the
            target object can be global, or can be a component of the
            protected unit, but cannot be a local variable of the entry_body.

6.b         Reason: These restrictions ensure that the target object of the
            requeue outlives the completion and finalization of the enclosing
            callable construct. They also prevent requeuing from a nested
            accept_statement on a parameter of an outer accept_statement,
            which could create some strange "long-distance" connections
            between an entry caller and its server.

6.c         Note that in the strange case where a task_body is nested inside
            an accept_statement, it is permissible to requeue from an
            accept_statement of the inner task_body on parameters of the outer
            accept_statement. This is not a problem because all calls on the
            inner task have to complete before returning from the outer
            accept_statement, meaning no "dangling calls" will be created.

6.d         Implementation Note: By disallowing certain requeues, we ensure
            that the normal terminate_alternative rules remain sensible, and
            that explicit clearing of the entry queues of a protected object
            during finalization is rarely necessary. In particular, such
            clearing of the entry queues is necessary only (ignoring premature
            Unchecked_Deallocation) for protected objects declared in a
            task_body (or created by an allocator for an access type declared
            in such a body) containing one or more requeue_statements.
            Protected objects declared in subprograms, or at the library
            level, will never need to have their entry queues explicitly
            cleared during finalization.


                              Dynamic Semantics

7/4 {AI05-0030-2} {AI12-0090-1} The execution of a requeue_statement proceeds
by first evaluating the procedure_or_entry_name[, including the prefix
identifying the target task or protected object and the expression identifying
the entry within an entry family, if any]. Precondition checks are then
performed as for a call to the requeue target entry or subprogram. The
entry_body or accept_statement enclosing the requeue_statement is then
completed[, finalized, and left (see 7.6.1)].

8   For the execution of a requeue on an entry of a target task, after leaving
the enclosing callable construct, the named entry is checked to see if it is
open and the requeued call is either selected immediately or queued, as for a
normal entry call (see 9.5.3).

9   For the execution of a requeue on an entry of a target protected object,
after leaving the enclosing callable construct:

10    * if the requeue is an internal requeue (that is, the requeue is back on
        an entry of the same protected object - see 9.5), the call is added to
        the queue of the named entry and the ongoing protected action
        continues (see 9.5.1);

10.a        Ramification: Note that for an internal requeue, the call is
            queued without checking whether the target entry is open. This is
            because the entry queues will be serviced before the current
            protected action completes anyway, and considering the requeued
            call immediately might allow it to "jump" ahead of existing
            callers on the same queue.

11    * if the requeue is an external requeue (that is, the target protected
        object is not implicitly the same as the current object - see 9.5), a
        protected action is started on the target object and proceeds as for a
        normal entry call (see 9.5.3).

12/4 {AI05-0030-2} {AI05-0090-1} If the requeue target named in the
requeue_statement has formal parameters, then during the execution of the
accept_statement or entry_body corresponding to the new entry and during the
checking of any preconditions of the new entry, the formal parameters denote
the same objects as did the corresponding formal parameters of the callable
construct completed by the requeue. [In any case, no parameters are specified
in a requeue_statement; any parameter passing is implicit.]

13  If the requeue_statement includes the reserved words with abort (it is a
requeue-with-abort), then:

14    * if the original entry call has been aborted (see 9.8), then the
        requeue acts as an abort completion point for the call, and the call
        is cancelled and no requeue is performed;

15    * if the original entry call was timed (or conditional), then the
        original expiration time is the expiration time for the requeued call.

16  If the reserved words with abort do not appear, then the call remains
protected against cancellation while queued as the result of the
requeue_statement.

16.a        Ramification: This protection against cancellation lasts only
            until the call completes or a subsequent requeue-with-abort is
            performed on the call.

16.b        Reason: We chose to protect a requeue, by default, against abort
            or cancellation. This seemed safer, since it is likely that extra
            steps need to be taken to allow for possible cancellation once the
            servicing of an entry call has begun. This also means that in the
            absence of with abort the usual Ada 83 behavior is preserved,
            namely that once an entry call is accepted, it cannot be cancelled
            until it completes.

        NOTES

17      32  A requeue is permitted from a single entry to an entry of an entry
        family, or vice-versa. The entry index, if any, plays no part in the
        subtype conformance check between the profiles of the two entries; an
        entry index is part of the entry_name for an entry of a family.


                                  Examples

18  Examples of requeue statements:

19      requeue Request(Medium) with abort;
                            -- requeue on a member of an entry family of the current task, see 9.1

20      requeue Flags(I).Seize;
                            -- requeue on an entry of an array component, see 9.4


                            Extensions to Ada 83

20.a        The requeue_statement is new.


                           Extensions to Ada 2005

20.b/3      {AI05-0030-2} {AI05-0215-1} Added the ability to requeue on
            operations of synchronized interfaces that are declared to be an
            entry.


                        Inconsistencies With Ada 2012

20.c/4      {AI05-0090-1} Corrigendum: We now define that any preconditions of
            the requeue target are evaluated as part of a requeue_statement.
            Original Ada 2012 did not specify this, so a program that requeues
            when the preconditions fail will raise an exception when none
            would happen in original Ada 2012. We don't expect this to be a
            problem, as in that case, the entry body would be called with some
            of its preconditions evaluating as False; the body is likely to
            assume that they are true and probably will have failed in some
            other way anyway.


                       Incompatibilities With Ada 2012

20.d/4      {AI05-0090-1} Corrigendum: If a requeue target has a different
            postcondition than the original entry, the requeue is now illegal.
            In such a case, the original postcondition would never have been
            evaluated, and assumptions that the caller relied upon might not
            be true. A requeue should be invisible to the caller with respect
            to any postconditions; thus we only allow it when the original
            entry has no postconditions or the requeue target has (at least)
            the same postconditions.


9.6 Delay Statements, Duration, and Time


1   [ A delay_statement is used to block further execution until a specified
expiration time is reached. The expiration time can be specified either as a
particular point in time (in a delay_until_statement), or in seconds from the
current time (in a delay_relative_statement). The language-defined package
Calendar provides definitions for a type Time and associated operations,
including a function Clock that returns the current time. ]


                                   Syntax

2       delay_statement ::= delay_until_statement
         | delay_relative_statement

3       delay_until_statement ::= delay until delay_expression;

4       delay_relative_statement ::= delay delay_expression;


                            Name Resolution Rules

5   The expected type for the delay_expression in a delay_relative_statement
is the predefined type Duration. The delay_expression in a
delay_until_statement is expected to be of any nonlimited type.


                               Legality Rules

6/3 {AI05-0092-1} There can be multiple time bases, each with a corresponding
clock, and a corresponding time type. The type of the delay_expression in a
delay_until_statement shall be a time type - either the type Time defined in
the language-defined package Calendar (see below), the type Time in the
package Real_Time (see D.8), or some other implementation-defined time type.

6.a         Implementation defined: Any implementation-defined time types.


                              Static Semantics

7   [There is a predefined fixed point type named Duration, declared in the
visible part of package Standard;] a value of type Duration is used to
represent the length of an interval of time, expressed in seconds. [The type
Duration is not specific to a particular time base, but can be used with any
time base.]

8/3 {AI05-0092-1} A value of the type Time in package Calendar, or of some
other time type, represents a time as reported by a corresponding clock.

9   The following language-defined library package exists:

10      
        package Ada.Calendar is
          type Time is private;

11/2    {AI95-00351-01}   subtype Year_Number  is Integer range 1901 .. 2399;
          subtype Month_Number is Integer range 1 .. 12;
          subtype Day_Number   is Integer range 1 .. 31;
          subtype Day_Duration is Duration range 0.0 .. 86_400.0;

11.a/2      Reason: {AI95-00351-01} A range of 500 years was chosen, as that
            only requires one extra bit for the year as compared to Ada 95.
            This was done to minimize disruptions with existing
            implementations. (One implementor reports that their time values
            represent nanoseconds, and this year range requires 63.77 bits to
            represent.)

12        function Clock return Time;

13        function Year   (Date : Time) return Year_Number;
          function Month  (Date : Time) return Month_Number;
          function Day    (Date : Time) return Day_Number;
          function Seconds(Date : Time) return Day_Duration;

14        procedure Split (Date  : in Time;
                           Year    : out Year_Number;
                           Month   : out Month_Number;
                           Day     : out Day_Number;
                           Seconds : out Day_Duration);

15        function Time_Of(Year  : Year_Number;
                           Month   : Month_Number;
                           Day     : Day_Number;
                           Seconds : Day_Duration := 0.0)
           return Time;

16        function "+" (Left : Time;   Right : Duration) return Time;
          function "+" (Left : Duration; Right : Time) return Time;
          function "-" (Left : Time;   Right : Duration) return Time;
          function "-" (Left : Time;   Right : Time) return Duration;

17        function "<" (Left, Right : Time) return Boolean;
          function "<="(Left, Right : Time) return Boolean;
          function ">" (Left, Right : Time) return Boolean;
          function ">="(Left, Right : Time) return Boolean;

18        Time_Error : exception;

19      private
           ... -- not specified by the language
        end Ada.Calendar;


                              Dynamic Semantics

20  For the execution of a delay_statement, the delay_expression is first
evaluated. For a delay_until_statement, the expiration time for the delay is
the value of the delay_expression, in the time base associated with the type
of the expression. For a delay_relative_statement, the expiration time is
defined as the current time, in the time base associated with relative delays,
plus the value of the delay_expression converted to the type Duration, and
then rounded up to the next clock tick. The time base associated with relative
delays is as defined in D.9, "Delay Accuracy" or is implementation defined.

20.a        Implementation defined: The time base associated with relative
            delays.

20.b        Ramification: Rounding up to the next clock tick means that the
            reading of the delay-relative clock when the delay expires should
            be no less than the current reading of the delay-relative clock
            plus the specified duration.

21  The task executing a delay_statement is blocked until the expiration time
is reached, at which point it becomes ready again. If the expiration time has
already passed, the task is not blocked.

21.a        Discussion: For a delay_relative_statement, this case corresponds
            to when the value of the delay_expression is zero or negative.

21.b        Even though the task is not blocked, it might be put back on the
            end of its ready queue. See D.2, "Priority Scheduling".

22/3 {AI05-0092-1} If an attempt is made to cancel the delay_statement [(as
part of an asynchronous_select or abort - see 9.7.4 and 9.8)], the statement
is cancelled if the expiration time has not yet passed, thereby completing the
delay_statement.

22.a        Reason: This is worded this way so that in an
            asynchronous_select where the triggering_statement is a
            delay_statement, an attempt to cancel the delay when the
            abortable_part completes is ignored if the expiration time has
            already passed, in which case the optional statements of the
            triggering_alternative are executed.

23  The time base associated with the type Time of package Calendar is
implementation defined. The function Clock of package Calendar returns a value
representing the current time for this time base. [The implementation-defined
value of the named number System.Tick (see 13.7) is an approximation of the
length of the real-time interval during which the value of Calendar.Clock
remains constant.]

23.a        Implementation defined: The time base of the type Calendar.Time.

24/2 {AI95-00351-01} The functions Year, Month, Day, and Seconds return the
corresponding values for a given value of the type Time, as appropriate to an
implementation-defined time zone; the procedure Split returns all four
corresponding values. Conversely, the function Time_Of combines a year number,
a month number, a day number, and a duration, into a value of type Time. The
operators "+" and "-" for addition and subtraction of times and durations, and
the relational operators for times, have the conventional meaning.

24.a/2      Implementation defined: The time zone used for package Calendar
            operations.

24.b/3      Ramification: {AI05-0119-1} The behavior of these values and
            subprograms if the time zone changes is also
            implementation-defined. In particular, the changes associated with
            summer time adjustments (like Daylight Savings Time in the United
            States) should be treated as a change in the
            implementation-defined time zone. The language does not specify
            whether the time zone information is stored in values of type
            Time; therefore the results of binary operators are unspecified
            when the operands are the two values with different effective time
            zones. In particular, the results of "-" may differ from the
            "real" result by the difference in the time zone adjustment.
            Similarly, the result of UTC_Time_Offset (see 9.6.1) may or may
            not reflect a time zone adjustment.

25  If Time_Of is called with a seconds value of 86_400.0, the value returned
is equal to the value of Time_Of for the next day with a seconds value of 0.0.
The value returned by the function Seconds or through the Seconds parameter of
the procedure Split is always less than 86_400.0.

26/1 {8652/0030} {AI95-00113-01} The exception Time_Error is raised by the
function Time_Of if the actual parameters do not form a proper date. This
exception is also raised by the operators "+" and "-" if the result is not
representable in the type Time or Duration, as appropriate. This exception is
also raised by the functions Year, Month, Day, and Seconds and the procedure
Split if the year number of the given date is outside of the range of the
subtype Year_Number.

26.a/1      To be honest: {8652/0106} {AI95-00160-01} By "proper date" above
            we mean that the given year has a month with the given day. For
            example, February 29th is a proper date only for a leap year. We
            do not mean to include the Seconds in this notion; in particular,
            we do not mean to require implementations to check for the "
            missing hour" that occurs when Daylight Savings Time starts in the
            spring.

26.b/2      Reason: {8652/0030} {AI95-00113-01} {AI95-00351-01} We allow Year
            and Split to raise Time_Error because the arithmetic operators are
            allowed (but not required) to produce times that are outside the
            range of years from 1901 to 2399. This is similar to the way
            integer operators may return values outside the base range of
            their type so long as the value is mathematically correct. We
            allow the functions Month, Day and Seconds to raise Time_Error so
            that they can be implemented in terms of Split.


                         Implementation Requirements

27  The implementation of the type Duration shall allow representation of time
intervals (both positive and negative) up to at least 86400 seconds (one day);
Duration'Small shall not be greater than twenty milliseconds. The
implementation of the type Time shall allow representation of all dates with
year numbers in the range of Year_Number[; it may allow representation of
other dates as well (both earlier and later).]


                         Implementation Permissions

28/3 {AI05-0092-1} An implementation may define additional time types.

29  An implementation may raise Time_Error if the value of a
delay_expression in a delay_until_statement of a select_statement represents a time
more than 90 days past the current time. The actual limit, if any, is
implementation-defined.

29.a        Implementation defined: Any limit on delay_until_statements of
            select_statements.

29.b        Implementation Note: This allows an implementation to implement
            select_statement timeouts using a representation that does not
            support the full range of a time type. In particular 90 days of
            seconds can be represented in 23 bits, allowing a signed 24-bit
            representation for the seconds part of a timeout. There is no
            similar restriction allowed for stand-alone
            delay_until_statements, as these can be implemented internally
            using a loop if necessary to accommodate a long delay.


                            Implementation Advice

30  Whenever possible in an implementation, the value of Duration'Small should
be no greater than 100 microseconds.

30.a        Implementation Note: This can be satisfied using a 32-bit 2's
            complement representation with a small of 2.0**(-14) - that is, 61
            microseconds - and a range of ± 2.0**17 - that is, 131_072.0.

30.b/2      Implementation Advice: The value of Duration'Small should be no
            greater than 100 microseconds.

31  The time base for delay_relative_statements should be monotonic; it need
not be the same time base as used for Calendar.Clock.

31.a/2      Implementation Advice: The time base for
            delay_relative_statements should be monotonic.

        NOTES

32      33  A delay_relative_statement with a negative value of the
        delay_expression is equivalent to one with a zero value.

33      34  A delay_statement may be executed by the environment task;
        consequently delay_statements may be executed as part of the
        elaboration of a library_item or the execution of the main subprogram.
        Such statements delay the environment task (see 10.2).

34      35  A delay_statement is an abort completion point and a potentially
        blocking operation, even if the task is not actually blocked.

35      36  There is no necessary relationship between System.Tick (the
        resolution of the clock of package Calendar) and Duration'Small (the
        small of type Duration).

35.a        Ramification: The inaccuracy of the delay_statement has no
            relation to System.Tick. In particular, it is possible that the
            clock used for the delay_statement is less accurate than
            Calendar.Clock.

35.b        We considered making Tick a run-time-determined quantity, to allow
            for easier configurability. However, this would not be upward
            compatible, and the desired configurability can be achieved using
            functionality defined in Annex D, "Real-Time Systems".

36      37  Additional requirements associated with delay_statements are given
        in D.9, "Delay Accuracy".


                                  Examples

37  Example of a relative delay statement:

38      delay 3.0;  -- delay 3.0 seconds

39  Example of a periodic task:

40      declare
           use Ada.Calendar;
           Next_Time : Time := Clock + Period;
                              -- Period is a global constant of type Duration
        begin
           loop               -- repeated every Period seconds
              delay until Next_Time;
              ... -- perform some actions
              Next_Time := Next_Time + Period;
           end loop;
        end;


                         Inconsistencies With Ada 83

40.a        For programs that raise Time_Error on "+" or "-" in Ada 83,the
            exception might be deferred until a call on Split or Year_Number,
            or might not be raised at all (if the offending time is never
            Split after being calculated). This should not affect typical
            programs, since they deal only with times corresponding to the
            relatively recent past or near future.


                            Extensions to Ada 83

40.b        The syntax rule for delay_statement is modified to allow
            delay_until_statements.

40.c/2      {AI95-00351-01} The type Time may represent dates with year
            numbers outside of Year_Number. Therefore, the operations "+" and
            "-" need only raise Time_Error if the result is not representable
            in Time (or Duration); also, Split or Year will now raise
            Time_Error if the year number is outside of Year_Number. This
            change is intended to simplify the implementation of "+" and "-"
            (allowing them to depend on overflow for detecting when to raise
            Time_Error) and to allow local time zone information to be
            considered at the time of Split rather than Clock (depending on
            the implementation approach). For example, in a POSIX environment,
            it is natural for the type Time to be based on GMT, and the
            results of procedure Split (and the functions Year, Month, Day,
            and Seconds) to depend on local time zone information. In other
            environments, it is more natural for the type Time to be based on
            the local time zone, with the results of Year, Month, Day, and
            Seconds being pure functions of their input.

40.d/2      This paragraph was deleted.{AI95-00351-01}


                         Inconsistencies With Ada 95

40.e/2      {AI95-00351-01} The upper bound of Year_Number has been changed to
            avoid a year 2100 problem. A program which expects years past 2099
            to raise Constraint_Error will fail in Ada 2005. We don't expect
            there to be many programs which are depending on an exception to
            be raised. A program that uses Year_Number'Last as a magic number
            may also fail if values of Time are stored outside of the program.
            Note that the lower bound of Year_Number wasn't changed, because
            it is not unusual to use that value in a constant to represent an
            unknown time.


                         Wording Changes from Ada 95

40.f/2      {8652/0002} {AI95-00171-01} Corrigendum: Clarified that Month,
            Day, and Seconds can raise Time_Error.


9.6.1 Formatting, Time Zones, and other operations for Time



                              Static Semantics

1/2 {AI95-00351-01} {AI95-00427-01} The following language-defined library
packages exist:

2/2     package Ada.Calendar.Time_Zones is

3/2        -- Time zone manipulation:

4/2        type Time_Offset is range -28*60 .. 28*60;

4.a/4       Reason: {AI12-0005-1} We want to be able to specify the difference
            between any two arbitrary time zones. You might think that 1440
            (24 hours) would be enough, but there are places (like Tonga,
            which is UTC+13hr) which are more than 12 hours different than
            UTC. Combined with summer time (known as daylight saving time in
            some parts of the world) - which switches opposite in the northern
            and southern hemispheres - and even greater differences are
            possible. We know of cases of a 26 hours difference, so we err on
            the safe side by selecting 28 hours as the limit.

5/2        Unknown_Zone_Error : exception;

6/2        function UTC_Time_Offset (Date : Time := Clock) return Time_Offset;

7/2     end Ada.Calendar.Time_Zones;

8/2     
        package Ada.Calendar.Arithmetic is

9/2        -- Arithmetic on days:

10/2       type Day_Count is range
             -366*(1+Year_Number'Last - Year_Number'First)
             ..
             366*(1+Year_Number'Last - Year_Number'First);

11/2       subtype Leap_Seconds_Count is Integer range -2047 .. 2047;

11.a/2      Reason: The maximum number of leap seconds is likely to be much
            less than this, but we don't want to reach the limit too soon if
            the earth's behavior suddenly changes. We believe that the maximum
            number is 1612, based on the current rules, but that number is too
            weird to use here.

12/2       procedure Difference (Left, Right : in Time;
                                 Days : out Day_Count;
                                 Seconds : out Duration;
                                 Leap_Seconds : out Leap_Seconds_Count);

13/2       function "+" (Left : Time; Right : Day_Count) return Time;
           function "+" (Left : Day_Count; Right : Time) return Time;
           function "-" (Left : Time; Right : Day_Count) return Time;
           function "-" (Left, Right : Time) return Day_Count;

14/2    end Ada.Calendar.Arithmetic;

15/2    
        with Ada.Calendar.Time_Zones;
        package Ada.Calendar.Formatting is

16/2       -- Day of the week:

17/2       type Day_Name is (Monday, Tuesday, Wednesday, Thursday,
               Friday, Saturday, Sunday);

18/2       function Day_of_Week (Date : Time) return Day_Name;

19/2       -- Hours:Minutes:Seconds access:

20/2       subtype Hour_Number         is Natural range 0 .. 23;
           subtype Minute_Number       is Natural range 0 .. 59;
           subtype Second_Number       is Natural range 0 .. 59;
           subtype Second_Duration     is Day_Duration range 0.0 .. 1.0;

21/2       function Year       (Date : Time;
                                Time_Zone  : Time_Zones.Time_Offset := 0)
                                   return Year_Number;

22/2       function Month      (Date : Time;
                                Time_Zone  : Time_Zones.Time_Offset := 0)
                                   return Month_Number;

23/2       function Day        (Date : Time;
                                Time_Zone  : Time_Zones.Time_Offset := 0)
                                   return Day_Number;

24/2       function Hour       (Date : Time;
                                Time_Zone  : Time_Zones.Time_Offset := 0)
                                   return Hour_Number;

25/2       function Minute     (Date : Time;
                                Time_Zone  : Time_Zones.Time_Offset := 0)
                                   return Minute_Number;

26/2       function Second     (Date : Time)
                                   return Second_Number;

27/2       function Sub_Second (Date : Time)
                                   return Second_Duration;

28/2       function Seconds_Of (Hour   :  Hour_Number;
                                Minute : Minute_Number;
                                Second : Second_Number := 0;
                                Sub_Second : Second_Duration := 0.0)
               return Day_Duration;

29/2       procedure Split (Seconds    : in Day_Duration;
                            Hour       : out Hour_Number;
                            Minute     : out Minute_Number;
                            Second     : out Second_Number;
                            Sub_Second : out Second_Duration);

30/2       function Time_Of (Year       : Year_Number;
                             Month      : Month_Number;
                             Day        : Day_Number;
                             Hour       : Hour_Number;
                             Minute     : Minute_Number;
                             Second     : Second_Number;
                             Sub_Second : Second_Duration := 0.0;
                             Leap_Second: Boolean := False;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                     return Time;

31/2       function Time_Of (Year       : Year_Number;
                             Month      : Month_Number;
                             Day        : Day_Number;
                             Seconds    : Day_Duration := 0.0;
                             Leap_Second: Boolean := False;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                     return Time;

32/2       procedure Split (Date       : in Time;
                            Year       : out Year_Number;
                            Month      : out Month_Number;
                            Day        : out Day_Number;
                            Hour       : out Hour_Number;
                            Minute     : out Minute_Number;
                            Second     : out Second_Number;
                            Sub_Second : out Second_Duration;
                            Time_Zone  : in Time_Zones.Time_Offset := 0);

33/2       procedure Split (Date       : in Time;
                            Year       : out Year_Number;
                            Month      : out Month_Number;
                            Day        : out Day_Number;
                            Hour       : out Hour_Number;
                            Minute     : out Minute_Number;
                            Second     : out Second_Number;
                            Sub_Second : out Second_Duration;
                            Leap_Second: out Boolean;
                            Time_Zone  : in Time_Zones.Time_Offset := 0);

34/2       procedure Split (Date       : in Time;
                            Year       : out Year_Number;
                            Month      : out Month_Number;
                            Day        : out Day_Number;
                            Seconds    : out Day_Duration;
                            Leap_Second: out Boolean;
                            Time_Zone  : in Time_Zones.Time_Offset := 0);

35/2       -- Simple image and value:
           function Image (Date : Time;
                           Include_Time_Fraction : Boolean := False;
                           Time_Zone  : Time_Zones.Time_Offset := 0) return String;

36/2       function Value (Date : String;
                           Time_Zone  : Time_Zones.Time_Offset := 0) return Time;

37/2       function Image (Elapsed_Time : Duration;
                           Include_Time_Fraction : Boolean := False) return String;

38/2       function Value (Elapsed_Time : String) return Duration;

39/2    end Ada.Calendar.Formatting;

40/2 {AI95-00351-01} Type Time_Offset represents the number of minutes
difference between the implementation-defined time zone used by Calendar and
another time zone.

41/2    function UTC_Time_Offset (Date : Time := Clock) return Time_Offset;

42/3        {AI95-00351-01} {AI05-0119-1} {AI05-0269-1} Returns, as a number
            of minutes, the result of subtracting the implementation-defined
            time zone of Calendar from UTC time, at the time Date. If the time
            zone of the Calendar implementation is unknown, then
            Unknown_Zone_Error is raised.

42.a.1/3    Ramification: {AI05-0119-1} In North America, the result will be
            negative; in Europe, the result will be zero or positive.

42.a/2      Discussion: The Date parameter is needed to take into account time
            differences caused by daylight-savings time and other time
            changes. This parameter is measured in the time zone of Calendar,
            if any, not necessarily the UTC time zone.

42.b/2      Other time zones can be supported with a child package. We don't
            define one because of the lack of agreement on the definition of a
            time zone.

42.c/2      The accuracy of this routine is not specified; the intent is that
            the facilities of the underlying target operating system are used
            to implement it.

43/2    procedure Difference (Left, Right : in Time;
                              Days : out Day_Count;
                              Seconds : out Duration;
                              Leap_Seconds : out Leap_Seconds_Count);

44/2        {AI95-00351-01} {AI95-00427-01} Returns the difference between
            Left and Right. Days is the number of days of difference, Seconds
            is the remainder seconds of difference excluding leap seconds, and
            Leap_Seconds is the number of leap seconds. If Left < Right, then
            Seconds <= 0.0, Days <= 0, and Leap_Seconds <= 0. Otherwise, all
            values are nonnegative. The absolute value of Seconds is always
            less than 86_400.0. For the returned values, if Days = 0, then
            Seconds + Duration(Leap_Seconds) = Calendar."-" (Left, Right).

44.a/2      Discussion: Leap_Seconds, if any, are not included in Seconds.
            However, Leap_Seconds should be included in calculations using the
            operators defined in Calendar, as is specified for "-" above.

45/2    function "+" (Left : Time; Right : Day_Count) return Time;
        function "+" (Left : Day_Count; Right : Time) return Time;

46/2        {AI95-00351-01} Adds a number of days to a time value. Time_Error
            is raised if the result is not representable as a value of type
            Time.

47/2    function "-" (Left : Time; Right : Day_Count) return Time;

48/2        {AI95-00351-01} Subtracts a number of days from a time value.
            Time_Error is raised if the result is not representable as a value
            of type Time.

49/2    function "-" (Left, Right : Time) return Day_Count;

50/2        {AI95-00351-01} Subtracts two time values, and returns the number
            of days between them. This is the same value that Difference would
            return in Days.

51/2    function Day_of_Week (Date : Time) return Day_Name;

52/2        {AI95-00351-01} Returns the day of the week for Time. This is
            based on the Year, Month, and Day values of Time.

53/2    function Year       (Date : Time;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                return Year_Number;

54/2        {AI95-00427-01} Returns the year for Date, as appropriate for the
            specified time zone offset.

55/2    function Month      (Date : Time;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                return Month_Number;

56/2        {AI95-00427-01} Returns the month for Date, as appropriate for the
            specified time zone offset.

57/2    function Day        (Date : Time;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                return Day_Number;

58/2        {AI95-00427-01} Returns the day number for Date, as appropriate
            for the specified time zone offset.

59/2    function Hour       (Date : Time;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                return Hour_Number;

60/2        {AI95-00351-01} Returns the hour for Date, as appropriate for the
            specified time zone offset.

61/2    function Minute     (Date : Time;
                             Time_Zone  : Time_Zones.Time_Offset := 0)
                                return Minute_Number;

62/2        {AI95-00351-01} Returns the minute within the hour for Date, as
            appropriate for the specified time zone offset.

63/2    function Second     (Date : Time)
                                return Second_Number;

64/2        {AI95-00351-01} {AI95-00427-01} Returns the second within the hour
            and minute for Date.

65/2    function Sub_Second (Date : Time)
                                return Second_Duration;

66/2        {AI95-00351-01} {AI95-00427-01} Returns the fraction of second for
            Date (this has the same accuracy as Day_Duration). The value
            returned is always less than 1.0.

67/2    function Seconds_Of (Hour   : Hour_Number;
                             Minute : Minute_Number;
                             Second : Second_Number := 0;
                             Sub_Second : Second_Duration := 0.0)
            return Day_Duration;

68/2        {AI95-00351-01} {AI95-00427-01} Returns a Day_Duration value for
            the combination of the given Hour, Minute, Second, and Sub_Second.
            This value can be used in Calendar.Time_Of as well as the argument
            to Calendar."+" and Calendar."-". If Seconds_Of is called with a
            Sub_Second value of 1.0, the value returned is equal to the value
            of Seconds_Of for the next second with a Sub_Second value of 0.0.

69/2    procedure Split (Seconds    : in Day_Duration;
                         Hour       : out Hour_Number;
                         Minute     : out Minute_Number;
                         Second     : out Second_Number;
                         Sub_Second : out Second_Duration);

70/3        {AI95-00351-01} {AI95-00427-01} {AI05-0238-1} Splits Seconds into
            Hour, Minute, Second and Sub_Second in such a way that the
            resulting values all belong to their respective subtypes. The
            value returned in the Sub_Second parameter is always less than
            1.0. If Seconds = 86400.0, Split propagates Time_Error.

70.a/2      Ramification: There is only one way to do the split which meets
            all of the requirements.

70.b/3      Reason: {AI05-0238-1} If Seconds = 86400.0, one of the returned
            values would have to be out of its defined range (either
            Sub_Second = 1.0 or Hour = 24 with the other value being 0). This
            doesn't seem worth breaking the invariants.

71/2    function Time_Of (Year       : Year_Number;
                          Month      : Month_Number;
                          Day        : Day_Number;
                          Hour       : Hour_Number;
                          Minute     : Minute_Number;
                          Second     : Second_Number;
                          Sub_Second : Second_Duration := 0.0;
                          Leap_Second: Boolean := False;
                          Time_Zone  : Time_Zones.Time_Offset := 0)
                                  return Time;

72/2        {AI95-00351-01} {AI95-00427-01} If Leap_Second is False, returns a
            Time built from the date and time values, relative to the
            specified time zone offset. If Leap_Second is True, returns the
            Time that represents the time within the leap second that is one
            second later than the time specified by the other parameters.
            Time_Error is raised if the parameters do not form a proper date
            or time. If Time_Of is called with a Sub_Second value of 1.0, the
            value returned is equal to the value of Time_Of for the next
            second with a Sub_Second value of 0.0.

72.a/2      Discussion: Time_Error should be raised if Leap_Second is True,
            and the date and time values do not represent the second before a
            leap second. A leap second always occurs at midnight UTC, and is
            23:59:60 UTC in ISO notation. So, if the time zone is UTC and
            Leap_Second is True, if any of Hour /= 23, Minute /= 59, or Second
            /= 59, then Time_Error should be raised. However, we do not say
            that, because other time zones will have different values where a
            leap second is allowed.

73/2    function Time_Of (Year       : Year_Number;
                          Month      : Month_Number;
                          Day        : Day_Number;
                          Seconds    : Day_Duration := 0.0;
                          Leap_Second: Boolean := False;
                          Time_Zone  : Time_Zones.Time_Offset := 0)
                                  return Time;

74/2        {AI95-00351-01} {AI95-00427-01} If Leap_Second is False, returns a
            Time built from the date and time values, relative to the
            specified time zone offset. If Leap_Second is True, returns the
            Time that represents the time within the leap second that is one
            second later than the time specified by the other parameters.
            Time_Error is raised if the parameters do not form a proper date
            or time. If Time_Of is called with a Seconds value of 86_400.0,
            the value returned is equal to the value of Time_Of for the next
            day with a Seconds value of 0.0.

75/2    procedure Split (Date       : in Time;
                         Year       : out Year_Number;
                         Month      : out Month_Number;
                         Day        : out Day_Number;
                         Hour       : out Hour_Number;
                         Minute     : out Minute_Number;
                         Second     : out Second_Number;
                         Sub_Second : out Second_Duration;
                         Leap_Second: out Boolean;
                         Time_Zone  : in Time_Zones.Time_Offset := 0);

76/2        {AI95-00351-01} {AI95-00427-01} If Date does not represent a time
            within a leap second, splits Date into its constituent parts
            (Year, Month, Day, Hour, Minute, Second, Sub_Second), relative to
            the specified time zone offset, and sets Leap_Second to False. If
            Date represents a time within a leap second, set the constituent
            parts to values corresponding to a time one second earlier than
            that given by Date, relative to the specified time zone offset,
            and sets Leap_Seconds to True. The value returned in the
            Sub_Second parameter is always less than 1.0.

77/2    procedure Split (Date       : in Time;
                         Year       : out Year_Number;
                         Month      : out Month_Number;
                         Day        : out Day_Number;
                         Hour       : out Hour_Number;
                         Minute     : out Minute_Number;
                         Second     : out Second_Number;
                         Sub_Second : out Second_Duration;
                         Time_Zone  : in Time_Zones.Time_Offset := 0);

78/2        {AI95-00351-01} {AI95-00427-01} Splits Date into its constituent
            parts (Year, Month, Day, Hour, Minute, Second, Sub_Second),
            relative to the specified time zone offset. The value returned in
            the Sub_Second parameter is always less than 1.0.

79/2    procedure Split (Date       : in Time;
                         Year       : out Year_Number;
                         Month      : out Month_Number;
                         Day        : out Day_Number;
                         Seconds    : out Day_Duration;
                         Leap_Second: out Boolean;
                         Time_Zone  : in Time_Zones.Time_Offset := 0);

80/2        {AI95-00351-01} {AI95-00427-01} If Date does not represent a time
            within a leap second, splits Date into its constituent parts
            (Year, Month, Day, Seconds), relative to the specified time zone
            offset, and sets Leap_Second to False. If Date represents a time
            within a leap second, set the constituent parts to values
            corresponding to a time one second earlier than that given by
            Date, relative to the specified time zone offset, and sets
            Leap_Seconds to True. The value returned in the Seconds parameter
            is always less than 86_400.0.

81/2    function Image (Date : Time;
                        Include_Time_Fraction : Boolean := False;
                        Time_Zone  : Time_Zones.Time_Offset := 0) return String;

82/2        {AI95-00351-01} Returns a string form of the Date relative to the
            given Time_Zone. The format is "Year-Month-Day
            Hour:Minute:Second", where the Year is a 4-digit value, and all
            others are 2-digit values, of the functions defined in Calendar
            and Calendar.Formatting, including a leading zero, if needed. The
            separators between the values are a minus, another minus, a colon,
            and a single space between the Day and Hour. If
            Include_Time_Fraction is True, the integer part of Sub_Seconds*100
            is suffixed to the string as a point followed by a 2-digit value.

82.a/2      Discussion: The Image provides a string in ISO 8601 format, the
            international standard time format. Alternative representations
            allowed in ISO 8601 are not supported here.

82.b/2      ISO 8601 allows 24:00:00 for midnight; and a seconds value of 60
            for leap seconds. These are not allowed here (the routines
            mentioned above cannot produce those results).

82.c/2      Ramification: The fractional part is truncated, not rounded. It
            would be quite hard to define the result with proper rounding, as
            it can change all of the values of the image. Values can be
            rounded up by adding an appropriate constant (0.5 if
            Include_Time_Fraction is False, 0.005 otherwise) to the time
            before taking the image.

83/2    function Value (Date : String;
                        Time_Zone  : Time_Zones.Time_Offset := 0) return Time;

84/2        {AI95-00351-01} Returns a Time value for the image given as Date,
            relative to the given time zone. Constraint_Error is raised if the
            string is not formatted as described for Image, or the function
            cannot interpret the given string as a Time value.

84.a/3      Discussion: {AI05-0005-1} The intent is that the implementation
            enforce the same range rules on the string as the appropriate
            function Time_Of, except for the hour, so "cannot interpret the
            given string as a Time value" happens when one of the values is
            out of the required range. For example, "2005-08-31 24:00:00"
            should raise Constraint_Error (the hour is out of range).

85/2    function Image (Elapsed_Time : Duration;
                        Include_Time_Fraction : Boolean := False) return String;

86/2        {AI95-00351-01} Returns a string form of the Elapsed_Time. The
            format is "Hour:Minute:Second", where all values are 2-digit
            values, including a leading zero, if needed. The separators
            between the values are colons. If Include_Time_Fraction is True,
            the integer part of Sub_Seconds*100 is suffixed to the string as a
            point followed by a 2-digit value. If Elapsed_Time < 0.0, the
            result is Image (abs Elapsed_Time, Include_Time_Fraction) prefixed
            with a minus sign. If abs Elapsed_Time represents 100 hours or
            more, the result is implementation-defined.

86.a/2      Implementation defined: The result of Calendar.Formating.Image if
            its argument represents more than 100 hours.

86.b/2      Implementation Note: This cannot be implemented (directly) by
            calling Calendar.Formatting.Split, since it may be out of the
            range of Day_Duration, and thus the number of hours may be out of
            the range of Hour_Number.

86.c        If a Duration value can represent more then 100 hours, the
            implementation will need to define a format for the return of
            Image.

87/2    function Value (Elapsed_Time : String) return Duration;

88/2        {AI95-00351-01} Returns a Duration value for the image given as
            Elapsed_Time. Constraint_Error is raised if the string is not
            formatted as described for Image, or the function cannot interpret
            the given string as a Duration value.

88.a/2      Discussion: The intent is that the implementation enforce the same
            range rules on the string as the appropriate function Time_Of,
            except for the hour, so "cannot interpret the given string as a
            Time value" happens when one of the values is out of the required
            range. For example, "10:23:60" should raise Constraint_Error (the
            seconds value is out of range).


                            Implementation Advice

89/2 {AI95-00351-01} An implementation should support leap seconds if the
target system supports them. If leap seconds are not supported, Difference
should return zero for Leap_Seconds, Split should return False for
Leap_Second, and Time_Of should raise Time_Error if Leap_Second is True.

89.a/2      Implementation Advice: Leap seconds should be supported if the
            target system supports them. Otherwise, operations in
            Calendar.Formatting should return results consistent with no leap
            seconds.

89.b/2      Discussion: An implementation can always support leap seconds when
            the target system does not; indeed, this isn't particularly hard
            (all that is required is a table of when leap seconds were
            inserted). As such, leap second support isn't "impossible or
            impractical" in the sense of 1.1.3. However, for some purposes, it
            may be important to follow the target system's lack of leap second
            support (if the target is a GPS satellite, which does not use leap
            seconds, leap second support would be a handicap to work around).
            Thus, this Implementation Advice should be read as giving
            permission to not support leap seconds on target systems that
            don't support leap seconds. Implementers should use the needs of
            their customers to determine whether or not support leap seconds
            on such targets.

        NOTES

90/2    38  {AI95-00351-01} The implementation-defined time zone of package
        Calendar may, but need not, be the local time zone. UTC_Time_Offset
        always returns the difference relative to the implementation-defined
        time zone of package Calendar. If UTC_Time_Offset does not raise
        Unknown_Zone_Error, UTC time can be safely calculated (within the
        accuracy of the underlying time-base).

90.a/2      Discussion: {AI95-00351-01} The time in the time zone known as
            Greenwich Mean Time (GMT) is generally very close to UTC time; for
            most purposes they can be treated the same. GMT is the time based
            on the rotation of the Earth; UTC is the time based on atomic
            clocks, with leap seconds periodically inserted to realign with
            GMT (because most human activities depend on the rotation of the
            Earth). At any point in time, there will be a sub-second
            difference between GMT and UTC.

91/2    39  {AI95-00351-01} Calling Split on the results of subtracting
        Duration(UTC_Time_Offset*60) from Clock provides the components
        (hours, minutes, and so on) of the UTC time. In the United States, for
        example, UTC_Time_Offset will generally be negative.

91.a/2      Discussion: This is an illustration to help specify the value of
            UTC_Time_Offset. A user should pass UTC_Time_Offset as the
            Time_Zone parameter of Split, rather than trying to make the above
            calculation.


                            Extensions to Ada 95

91.b/2      {AI95-00351-01} {AI95-00428-01} Packages Calendar.Time_Zones,
            Calendar.Arithmetic, and Calendar.Formatting are new.


                        Inconsistencies With Ada 2005

91.c/3      {AI05-0238-1} Correction: Defined that Split for Seconds raises
            Time_Error for a value of exactly 86400.0, rather than breaking
            some invariant or raising some other exception. Ada 2005 left this
            unspecified; a program that depended on what some implementation
            does might break, but such a program is not portable anyway.


                        Wording Changes from Ada 2005

91.d/3      {AI05-0119-1} Correction: Clarified the sign of UTC_Time_Offset.


9.7 Select Statements


1   [There are four forms of the select_statement. One form provides a
selective wait for one or more select_alternatives. Two provide timed and
conditional entry calls. The fourth provides asynchronous transfer of
control.]


                                   Syntax

2       select_statement ::= 
           selective_accept
          | timed_entry_call
          | conditional_entry_call
          | asynchronous_select


                                  Examples

3   Example of a select statement:

4       select
           accept Driver_Awake_Signal;
        or
           delay 30.0*Seconds;
           Stop_The_Train;
        end select;


                            Extensions to Ada 83

4.a         Asynchronous_select is new.


9.7.1 Selective Accept


1   [This form of the select_statement allows a combination of waiting for,
and selecting from, one or more alternatives. The selection may depend on
conditions associated with each alternative of the selective_accept. ]


                                   Syntax

2       selective_accept ::= 
          select
           [guard]
             select_alternative
        { or
           [guard]
             select_alternative }
        [ else
           sequence_of_statements ]
          end select;

3       guard ::= when condition =>

4       select_alternative ::= 
           accept_alternative
          | delay_alternative
          | terminate_alternative

5       accept_alternative ::= 
          accept_statement [sequence_of_statements]

6       delay_alternative ::= 
          delay_statement [sequence_of_statements]

7       terminate_alternative ::= terminate;

8       A selective_accept shall contain at least one accept_alternative. In
        addition, it can contain:

9         * a terminate_alternative (only one); or

10        * one or more delay_alternatives; or

11        * an else part (the reserved word else followed by a
            sequence_of_statements).

12      These three possibilities are mutually exclusive.


                               Legality Rules

13  If a selective_accept contains more than one delay_alternative, then all
shall be delay_relative_statements, or all shall be delay_until_statements for
the same time type.

13.a        Reason: This simplifies the implementation and the description of
            the semantics.


                              Dynamic Semantics

14  A select_alternative is said to be open if it is not immediately preceded
by a guard, or if the condition of its guard evaluates to True. It is said to
be closed otherwise.

15  For the execution of a selective_accept, any guard conditions are
evaluated; open alternatives are thus determined. For an open
delay_alternative, the delay_expression is also evaluated. Similarly, for an
open accept_alternative for an entry of a family, the entry_index is also
evaluated. These evaluations are performed in an arbitrary order, except that
a delay_expression or entry_index is not evaluated until after evaluating the
corresponding condition, if any. Selection and execution of one open
alternative, or of the else part, then completes the execution of the
selective_accept; the rules for this selection are described below.

16  Open accept_alternatives are first considered. Selection of one such
alternative takes place immediately if the corresponding entry already has
queued calls. If several alternatives can thus be selected, one of them is
selected according to the entry queuing policy in effect (see 9.5.3 and D.4).
When such an alternative is selected, the selected call is removed from its
entry queue and the handled_sequence_of_statements (if any) of the
corresponding accept_statement is executed; after the rendezvous completes any
subsequent sequence_of_statements of the alternative is executed. If no
selection is immediately possible (in the above sense) and there is no else
part, the task blocks until an open alternative can be selected.

17  Selection of the other forms of alternative or of an else part is
performed as follows:

18    * An open delay_alternative is selected when its expiration time is
        reached if no accept_alternative or other delay_alternative can be
        selected prior to the expiration time. If several delay_alternatives
        have this same expiration time, one of them is selected according to
        the queuing policy in effect (see D.4); the default queuing policy
        chooses arbitrarily among the delay_alternatives whose expiration time
        has passed.

19    * The else part is selected and its sequence_of_statements is executed
        if no accept_alternative can immediately be selected; in particular,
        if all alternatives are closed.

20/3   * {AI05-0299-1} An open terminate_alternative is selected if the
        conditions stated at the end of subclause 9.3 are satisfied.

20.a        Ramification: In the absence of a requeue_statement, the
            conditions stated are such that a terminate_alternative cannot be
            selected while there is a queued entry call for any entry of the
            task. In the presence of requeues from a task to one of its
            subtasks, it is possible that when a terminate_alternative of the
            subtask is selected, requeued calls (for closed entries only)
            might still be queued on some entry of the subtask. Tasking_Error
            will be propagated to such callers, as is usual when a task
            completes while queued callers remain.

21  The exception Program_Error is raised if all alternatives are closed and
there is no else part.

        NOTES

22      40  A selective_accept is allowed to have several open
        delay_alternatives. A selective_accept is allowed to have several open
        accept_alternatives for the same entry.


                                  Examples

23  Example of a task body with a selective accept:

24      task body Server is
           Current_Work_Item : Work_Item;
        begin
           loop
              select
                 accept Next_Work_Item(WI : in Work_Item) do
                    Current_Work_Item := WI;
                 end;
                 Process_Work_Item(Current_Work_Item);
              or
                 accept Shut_Down;
                 exit;       -- Premature shut down requested
              or
                 terminate;  -- Normal shutdown at end of scope
              end select;
           end loop;
        end Server;


                         Wording Changes from Ada 83

24.a        The name of selective_wait was changed to selective_accept to
            better describe what is being waited for. We kept
            select_alternative as is, because selective_accept_alternative was
            too easily confused with accept_alternative.


9.7.2 Timed Entry Calls


1/2 {AI95-00345-01} [A timed_entry_call issues an entry call that is cancelled
if the call (or a requeue-with-abort of the call) is not selected before the
expiration time is reached. A procedure call may appear rather than an entry
call for cases where the procedure might be implemented by an entry. ]


                                   Syntax

2       timed_entry_call ::= 
          select
           entry_call_alternative
          or
           delay_alternative
          end select;

3/2     {AI95-00345-01} entry_call_alternative ::= 
          procedure_or_entry_call [sequence_of_statements]

3.1/2   {AI95-00345-01} procedure_or_entry_call ::= 
          procedure_call_statement | entry_call_statement


                               Legality Rules

3.2/2 {AI95-00345-01} If a procedure_call_statement is used for a
procedure_or_entry_call, the procedure_name or procedure_prefix of the
procedure_call_statement shall statically denote an entry renamed as a
procedure or (a view of) a primitive subprogram of a limited interface whose
first parameter is a controlling parameter (see 3.9.2).

3.a/2       Reason: This would be a confusing way to call a procedure, so we
            only allow it when it is possible that the procedure is actually
            an entry. We could have allowed formal subprograms here, but we
            didn't because we'd have to allow all formal subprograms, and it
            would increase the difficulty of generic code sharing.

3.b/2       We say "statically denotes" because an access-to-subprogram cannot
            be primitive, and we don't have anything like access-to-entry. So
            only names of entries or procedures are possible.


                              Dynamic Semantics

4/2 {AI95-00345-01} For the execution of a timed_entry_call, the entry_name,
procedure_name, or procedure_prefix, and any actual parameters are evaluated,
as for a simple entry call (see 9.5.3) or procedure call (see 6.4). The
expiration time (see 9.6) for the call is determined by evaluating the
delay_expression of the delay_alternative. If the call is an entry call or a call on
a procedure implemented by an entry, the entry call is then issued. Otherwise,
the call proceeds as described in 6.4 for a procedure call, followed by the
sequence_of_statements of the entry_call_alternative; the
sequence_of_statements of the delay_alternative is ignored.

5   If the call is queued (including due to a requeue-with-abort), and not
selected before the expiration time is reached, an attempt to cancel the call
is made. If the call completes due to the cancellation, the optional
sequence_of_statements of the delay_alternative is executed; if the entry call
completes normally, the optional sequence_of_statements of the entry_call_-
alternative is executed.

5.a/2       This paragraph was deleted.{AI95-00345-01}


                                  Examples

6   Example of a timed entry call:

7       select
           Controller.Request(Medium)(Some_Item);
        or
           delay 45.0;
           --  controller too busy, try something else
        end select;


                         Wording Changes from Ada 83

7.a/3       {AI05-0299-1} This subclause comes before the one for Conditional
            Entry Calls, so we can define conditional entry calls in terms of
            timed entry calls.


                        Incompatibilities With Ada 95

7.b/3       {AI95-00345-01} {AI05-0005-1} A procedure call can be used as the
            entry_call_alternative in a timed or conditional entry call, if
            the procedure might actually be an entry. Since the fact that
            something is an entry could be used in resolving these calls in
            Ada 95, it is possible for timed or conditional entry calls that
            resolved in Ada 95 to be ambiguous in Ada 2005. That could happen
            if both an entry and procedure with the same name and profile
            exist, which should be rare.


9.7.3 Conditional Entry Calls


1/2 {AI95-00345-01} [A conditional_entry_call issues an entry call that is
then cancelled if it is not selected immediately (or if a requeue-with-abort
of the call is not selected immediately). A procedure call may appear rather
than an entry call for cases where the procedure might be implemented by an
entry.]

1.a         To be honest: In the case of an entry call on a protected object,
            it is OK if the entry is closed at the start of the corresponding
            protected action, so long as it opens and the call is selected
            before the end of that protected action (due to changes in the
            Count attribute).


                                   Syntax

2       conditional_entry_call ::= 
          select
           entry_call_alternative
          else
           sequence_of_statements
          end select;


                              Dynamic Semantics

3   The execution of a conditional_entry_call is defined to be equivalent to
the execution of a timed_entry_call with a delay_alternative specifying an
immediate expiration time and the same sequence_of_statements as given after
the reserved word else.

        NOTES

4       41  A conditional_entry_call may briefly increase the Count attribute
        of the entry, even if the conditional call is not selected.


                                  Examples

5   Example of a conditional entry call:

6       procedure Spin(R : in Resource) is
        begin
           loop
              select
                 R.Seize;
                 return;
              else
                 null;  --  busy waiting
              end select;
           end loop;
        end;


                         Wording Changes from Ada 83

6.a/3       {AI05-0299-1} This subclause comes after the one for Timed Entry
            Calls, so we can define conditional entry calls in terms of timed
            entry calls. We do that so that an "expiration time" is defined
            for both, thereby simplifying the definition of what happens on a
            requeue-with-abort.


9.7.4 Asynchronous Transfer of Control


1   [An asynchronous select_statement provides asynchronous transfer of
control upon completion of an entry call or the expiration of a delay.]


                                   Syntax

2       asynchronous_select ::= 
          select
           triggering_alternative
          then abort
           abortable_part
          end select;

3       triggering_alternative ::= triggering_statement
         [sequence_of_statements]

4/2     {AI95-00345-01} triggering_statement ::= procedure_or_entry_call
         | delay_statement

5       abortable_part ::= sequence_of_statements


                              Dynamic Semantics

6/2 {AI95-00345-01} For the execution of an asynchronous_select whose
triggering_statement is a procedure_or_entry_call, the entry_name,
procedure_name, or procedure_prefix, and actual parameters are evaluated as for a simple
entry call (see 9.5.3) or procedure call (see 6.4). If the call is an entry
call or a call on a procedure implemented by an entry, the entry call is
issued. If the entry call is queued (or requeued-with-abort), then the
abortable_part is executed. [If the entry call is selected immediately, and
never requeued-with-abort, then the abortable_part is never started.] If the
call is on a procedure that is not implemented by an entry, the call proceeds
as described in 6.4, followed by the sequence_of_statements of the triggering_-
alternative[; the abortable_part is never started].

7   For the execution of an asynchronous_select whose triggering_statement is
a delay_statement, the delay_expression is evaluated and the expiration time
is determined, as for a normal delay_statement. If the expiration time has not
already passed, the abortable_part is executed.

8   If the abortable_part completes and is left prior to completion of the
triggering_statement, an attempt to cancel the triggering_statement is made.
If the attempt to cancel succeeds (see 9.5.3 and 9.6), the
asynchronous_select is complete.

9   If the triggering_statement completes other than due to cancellation, the
abortable_part is aborted (if started but not yet completed - see 9.8). If the
triggering_statement completes normally, the optional sequence_of_statements
of the triggering_alternative is executed after the abortable_part is left.

9.a         Discussion: We currently don't specify when the by-copy [in] out
            parameters are assigned back into the actuals. We considered
            requiring that to happen after the abortable_part is left.
            However, that doesn't seem useful enough to justify possibly
            overspecifying the implementation approach, since some of the
            parameters are passed by reference anyway.

9.b         In an earlier description, we required that the sequence_of_-
            statements of the triggering_alternative execute after aborting
            the abortable_part, but before waiting for it to complete and
            finalize, to provide more rapid response to the triggering event
            in case the finalization was unbounded. However, various reviewers
            felt that this created unnecessary complexity in the description,
            and a potential for undesirable concurrency (and nondeterminism)
            within a single task. We have now reverted to simpler, more
            deterministic semantics, but anticipate that further discussion of
            this issue might be appropriate during subsequent reviews. One
            possibility is to leave this area implementation defined, so as to
            encourage experimentation. The user would then have to assume the
            worst about what kinds of actions are appropriate for the
            sequence_of_statements of the triggering_alternative to achieve
            portability.


                                  Examples

10  Example of a main command loop for a command interpreter:

11      loop
           select
              Terminal.Wait_For_Interrupt;
              Put_Line("Interrupted");
           then abort
              -- This will be abandoned upon terminal interrupt
              Put_Line("-> ");
              Get_Line(Command, Last);
              Process_Command(Command(1..Last));
           end select;
        end loop;

12  Example of a time-limited calculation:

13      select
           delay 5.0;
           Put_Line("Calculation does not converge");
        then abort
           -- This calculation should finish in 5.0 seconds;
           --  if not, it is assumed to diverge.
           Horribly_Complicated_Recursive_Function(X, Y);
        end select;

14/4 {AI12-0098-1} Note that these examples presume that there are abort
completion points within the execution of the abortable_part.


                            Extensions to Ada 83

14.a        Asynchronous_select is new.


                            Extensions to Ada 95

14.b/2      {AI95-00345-01} A procedure can be used as the
            triggering_statement of an asynchronous_select, if the procedure
            might actually be an entry.


9.8 Abort of a Task - Abort of a Sequence of Statements


1   [An abort_statement causes one or more tasks to become abnormal, thus
preventing any further interaction with such tasks. The completion of the
triggering_statement of an asynchronous_select causes a sequence_of_statements
to be aborted.]


                                   Syntax

2       abort_statement ::= abort task_name {, task_name};


                            Name Resolution Rules

3   Each task_name is expected to be of any task type[; they need not all be
of the same task type.]


                              Dynamic Semantics

4   For the execution of an abort_statement, the given task_names are
evaluated in an arbitrary order. Each named task is then aborted, which
consists of making the task abnormal and aborting the execution of the
corresponding task_body, unless it is already completed.

4.a/2       Ramification: {AI95-00114-01} Note that aborting those tasks is
            not defined to be an abort-deferred operation. Therefore, if one
            of the named tasks is the task executing the abort_statement, or
            if the task executing the abort_statement depends on one of the
            named tasks, then it is possible for the execution of the
            abort_statement to be aborted, thus leaving some of the tasks
            unaborted. This allows the implementation to use either a sequence
            of calls to an "abort task" run-time system primitive, or a single
            call to an "abort list of tasks" run-time system primitive.

5   When the execution of a construct is aborted (including that of a task_-
body or of a sequence_of_statements), the execution of every construct
included within the aborted execution is also aborted, except for executions
included within the execution of an abort-deferred operation; the execution of
an abort-deferred operation continues to completion without being affected by
the abort; the following are the abort-deferred operations:

6     * a protected action;

7     * waiting for an entry call to complete (after having initiated the
        attempt to cancel it - see below);

8     * waiting for the termination of dependent tasks;

9     * the execution of an Initialize procedure as the last step of the
        default initialization of a controlled object;

10    * the execution of a Finalize procedure as part of the finalization of a
        controlled object;

11    * an assignment operation to an object with a controlled part.

12  [The last three of these are discussed further in 7.6.]

12.a        Reason: Deferring abort during Initialize and finalization allows,
            for example, the result of an allocator performed in an Initialize
            operation to be assigned into an access object without being
            interrupted in the middle, which would cause storage leaks. For an
            object with several controlled parts, each individual Initialize
            is abort-deferred. Note that there is generally no semantic
            difference between making each Finalize abort-deferred, versus
            making a group of them abort-deferred, because if the task gets
            aborted, the first thing it will do is complete any remaining
            finalizations. Individual objects are finalized prior to an
            assignment operation (if nonlimited controlled) and as part of
            Unchecked_Deallocation.

12.b        Ramification: Abort is deferred during the entire assignment
            operation to an object with a controlled part, even if only some
            subcomponents are controlled. Note that this says "assignment
            operation," not "assignment_statement." Explicit calls to
            Initialize, Finalize, or Adjust are not abort-deferred.

13  When a master is aborted, all tasks that depend on that master are aborted.

14  The order in which tasks become abnormal as the result of an
abort_statement or the abort of a sequence_of_statements is not specified by
the language.

15  If the execution of an entry call is aborted, an immediate attempt is made
to cancel the entry call (see 9.5.3). If the execution of a construct is
aborted at a time when the execution is blocked, other than for an entry call,
at a point that is outside the execution of an abort-deferred operation, then
the execution of the construct completes immediately. For an abort due to an
abort_statement, these immediate effects occur before the execution of the
abort_statement completes. Other than for these immediate cases, the execution
of a construct that is aborted does not necessarily complete before the
abort_statement completes. However, the execution of the aborted construct
completes no later than its next abort completion point (if any) that occurs
outside of an abort-deferred operation; the following are abort completion
points for an execution:

16    * the point where the execution initiates the activation of another task;

17    * the end of the activation of a task;

18    * the start or end of the execution of an entry call, accept_statement,
        delay_statement, or abort_statement;

18.a        Ramification: Although the abort completion point doesn't occur
            until the end of the entry call or delay_statement, these
            operations might be cut short because an abort attempts to cancel
            them.

19    * the start of the execution of a select_statement, or of the
        sequence_of_statements of an exception_handler.

19.a        Reason: The start of an exception_handler is considered an abort
            completion point simply because it is easy for an implementation
            to check at such points.

19.b        Implementation Note: Implementations may of course check for abort
            more often than at each abort completion point; ideally, a fully
            preemptive implementation of abort will be provided. If preemptive
            abort is not supported in a given environment, then supporting the
            checking for abort as part of subprogram calls and loop iterations
            might be a useful option.


                          Bounded (Run-Time) Errors

20/3 {AI05-0264-1} An attempt to execute an asynchronous_select as part of the
execution of an abort-deferred operation is a bounded error. Similarly, an
attempt to create a task that depends on a master that is included entirely
within the execution of an abort-deferred operation is a bounded error. In
both cases, Program_Error is raised if the error is detected by the
implementation; otherwise, the operations proceed as they would outside an
abort-deferred operation, except that an abort of the abortable_part or the
created task might or might not have an effect.

20.a        Reason: An asynchronous_select relies on an abort of the
            abortable_part to effect the asynchronous transfer of control. For
            an asynchronous_select within an abort-deferred operation, the
            abort might have no effect.

20.b        Creating a task dependent on a master included within an
            abort-deferred operation is considered an error, because such
            tasks could be aborted while the abort-deferred operation was
            still progressing, undermining the purpose of abort-deferral.
            Alternatively, we could say that such tasks are abort-deferred for
            their entire execution, but that seems too easy to abuse. Note
            that task creation is already a bounded error in protected
            actions, so this additional rule only applies to local task
            creation as part of Initialize, Finalize, or Adjust.


                             Erroneous Execution

21  If an assignment operation completes prematurely due to an abort, the
assignment is said to be disrupted; the target of the assignment or its parts
can become abnormal, and certain subsequent uses of the object can be
erroneous, as explained in 13.9.1.

        NOTES

22      42  An abort_statement should be used only in situations requiring
        unconditional termination.

23      43  A task is allowed to abort any task it can name, including itself.

24      44  Additional requirements associated with abort are given in D.6
        , "Preemptive Abort".


                         Wording Changes from Ada 83

24.a/3      {AI05-0299-1} This subclause has been rewritten to accommodate the
            concept of aborting the execution of a construct, rather than just
            of a task.


9.9 Task and Entry Attributes



                              Dynamic Semantics

1   For a prefix T that is of a task type [(after any implicit dereference)],
the following attributes are defined:

2   T'Callable  Yields the value True when the task denoted by T is callable,
                and False otherwise; a task is callable unless it is completed
                or abnormal. The value of this attribute is of the predefined
                type Boolean.

3   T'Terminated
                Yields the value True if the task denoted by T is terminated,
                and False otherwise. The value of this attribute is of the
                predefined type Boolean.

4   For a prefix E that denotes an entry of a task or protected unit, the
following attribute is defined. This attribute is only allowed within the body
of the task or protected unit, but excluding, in the case of an entry of a
task unit, within any program unit that is, itself, inner to the body of the
task unit.

5   E'Count     Yields the number of calls presently queued on the entry E of
                the current instance of the unit. The value of this attribute
                is of the type universal_integer.

        NOTES

6       45  For the Count attribute, the entry can be either a single entry or
        an entry of a family. The name of the entry or entry family can be
        either a direct_name or an expanded name.

7       46  Within task units, algorithms interrogating the attribute E'Count
        should take precautions to allow for the increase of the value of this
        attribute for incoming entry calls, and its decrease, for example with
        timed_entry_calls. Also, a conditional_entry_call may briefly increase
        this value, even if the conditional call is not accepted.

8       47  Within protected units, algorithms interrogating the attribute
        E'Count in the entry_barrier for the entry E should take precautions
        to allow for the evaluation of the condition of the barrier both
        before and after queuing a given caller.


9.10 Shared Variables



                              Static Semantics

1/3 {AI05-0009-1} {AI05-0201-1} {AI05-0229-1} {AI05-0295-1} If two different
objects, including nonoverlapping parts of the same object, are independently
addressable, they can be manipulated concurrently by two different tasks
without synchronization. Any two nonoverlapping objects are independently
addressable if either object is specified as independently addressable (see
C.6). Otherwise, two nonoverlapping objects are independently addressable
except when they are both parts of a composite object for which a
nonconfirming value is specified for any of the following representation
aspects: (record) Layout, Component_Size, Pack, Atomic, or Convention; in this
case it is unspecified whether the parts are independently addressable.

1.a/3       This paragraph was deleted.

1.b/3       Implementation Note: {AI05-0229-1} Independent addressability is
            the only high level semantic effect of aspect Pack. If two objects
            are independently addressable, the implementation should allocate
            them in such a way that each can be written by the hardware
            without writing the other. For example, unless the user asks for
            it, it is generally not feasible to choose a bit-packed
            representation on a machine without an atomic bit field insertion
            instruction, because there might be tasks that update neighboring
            subcomponents concurrently, and locking operations on all
            subcomponents is generally not a good idea.

1.c/3       {AI05-0229-1} Even if Pack or one of the other above-mentioned
            aspects is specified, subcomponents should still be updated
            independently if the hardware efficiently supports it.

1.d/4       Ramification: {AI05-0009-1} {AI05-0201-1} {AI12-0001-1} An atomic
            object (including atomic components) is always independently
            addressable from any other nonoverlapping object.
            Aspect_specifications and representation items cannot change that
            fact. Note, however, that the components of an atomic object are
            not necessarily atomic.


                              Dynamic Semantics

2   [Separate tasks normally proceed independently and concurrently with one
another. However, task interactions can be used to synchronize the actions of
two or more tasks to allow, for example, meaningful communication by the
direct updating and reading of variables shared between the tasks.] The
actions of two different tasks are synchronized in this sense when an action
of one task signals an action of the other task; an action A1 is defined to
signal an action A2 under the following circumstances:

3     * If A1 and A2 are part of the execution of the same task, and the
        language rules require A1 to be performed before A2;

4     * If A1 is the action of an activator that initiates the activation of a
        task, and A2 is part of the execution of the task that is activated;

5     * If A1 is part of the activation of a task, and A2 is the action of
        waiting for completion of the activation;

6     * If A1 is part of the execution of a task, and A2 is the action of
        waiting for the termination of the task;

6.1/3   * {8652/0031} {AI95-00118-01} {AI05-0072-1} If A1 is the termination
        of a task T, and A2 is either an evaluation of the expression
        T'Terminated that results in True, or a call to
        Ada.Task_Identification.Is_Terminated with an actual parameter that
        identifies T and a result of True (see C.7.1);

7/3   * {AI05-0262-1} If A1 is the action of issuing an entry call, and A2 is
        part of the corresponding execution of the appropriate entry_body or
        accept_statement;

7.a         Ramification: Evaluating the entry_index of an accept_statement is
            not synchronized with a corresponding entry call, nor is
            evaluating the entry barrier of an entry_body.

8     * If A1 is part of the execution of an accept_statement or entry_body,
        and A2 is the action of returning from the corresponding entry call;

9     * If A1 is part of the execution of a protected procedure body or
        entry_body for a given protected object, and A2 is part of a later
        execution of an entry_body for the same protected object;

9.a         Reason: The underlying principle here is that for one action to
            "signal" a second, the second action has to follow a potentially
            blocking operation, whose blocking is dependent on the first
            action in some way. Protected procedures are not potentially
            blocking, so they can only be "signalers," they cannot be
            signaled.

9.b         Ramification: Protected subprogram calls are not defined to signal
            one another, which means that such calls alone cannot be used to
            synchronize access to shared data outside of a protected object.

9.c         Reason: The point of this distinction is so that on
            multiprocessors with inconsistent caches, the caches only need to
            be refreshed at the beginning of an entry body, and forced out at
            the end of an entry body or protected procedure that leaves an
            entry open. Protected function calls, and protected subprogram
            calls for entryless protected objects do not require full cache
            consistency. Entryless protected objects are intended to be
            treated roughly like atomic objects - each operation is
            indivisible with respect to other operations (unless both are
            reads), but such operations cannot be used to synchronize access
            to other nonvolatile shared variables.

10    * If A1 signals some action that in turn signals A2.


                             Erroneous Execution

11  Given an action of assigning to an object, and an action of reading or
updating a part of the same object (or of a neighboring object if the two are
not independently addressable), then the execution of the actions is erroneous
unless the actions are sequential. Two actions are sequential if one of the
following is true:

12    * One action signals the other;

13    * Both actions occur as part of the execution of the same task;

13.a        Reason: Any two actions of the same task are sequential, even if
            one does not signal the other because they can be executed in an
            "arbitrary" (but necessarily equivalent to some "sequential")
            order.

14    * Both actions occur as part of protected actions on the same protected
        object, and at most one of the actions is part of a call on a
        protected function of the protected object.

14.a        Reason: Because actions within protected actions do not always
            imply signaling, we have to mention them here explicitly to make
            sure that actions occurring within different protected actions of
            the same protected object are sequential with respect to one
            another (unless both are part of calls on protected functions).

14.b        Ramification: It doesn't matter whether or not the variable being
            assigned is actually a subcomponent of the protected object;
            globals can be safely updated from within the bodies of protected
            procedures or entries.

15/3 {AI05-0229-1} Aspect Atomic or aspect Atomic_Components may also be
specified to ensure that certain reads and updates are sequential - see C.6.

15.a        Ramification: If two actions are "sequential" it is known that
            their executions don't overlap in time, but it is not necessarily
            specified which occurs first. For example, all actions of a single
            task are sequential, even though the exact order of execution is
            not fully specified for all constructs.

15.b        Discussion: Note that if two assignments to the same variable are
            sequential, but neither signals the other, then the program is not
            erroneous, but it is not specified which assignment ultimately
            prevails. Such a situation usually corresponds to a programming
            mistake, but in some (rare) cases, the order makes no difference,
            and for this reason this situation is not considered erroneous nor
            even a bounded error. In Ada 83, this was considered an "
            incorrect order dependence" if the "effect" of the program was
            affected, but "effect" was never fully defined. In Ada 95, this
            situation represents a potential nonportability, and a friendly
            compiler might want to warn the programmer about the situation,
            but it is not considered an error. An example where this would
            come up would be in gathering statistics as part of referencing
            some information, where the assignments associated with statistics
            gathering don't need to be ordered since they are just
            accumulating aggregate counts, sums, products, etc.


                         Wording Changes from Ada 95

15.c/2      {8652/0031} {AI95-00118-01} Corrigendum: Clarified that a task T2
            can rely on values of variables that are updated by another task
            T1, if task T2 first verifies that T1'Terminated is True.


                        Wording Changes from Ada 2005

15.d/3      {AI05-0009-1} {AI05-0201-1} Correction: Revised the definition of
            independent addressability to exclude conforming representation
            clauses and to require that atomic and independent objects always
            have independent addressability. This should not change behavior
            that the user sees for any Ada program, so it is not an
            inconsistency.

15.e/3      {AI05-0072-1} Correction: Corrected the wording of AI95-00118-01
            to actually say what was intended (as described above).


9.11 Example of Tasking and Synchronization



                                  Examples

1   The following example defines a buffer protected object to smooth
variations between the speed of output of a producing task and the speed of
input of some consuming task. For instance, the producing task might have the
following structure:

2       task Producer;

3/2     {AI95-00433-01} task body Producer is
           Person : Person_Name; -- see 3.10.1
        begin
           loop
              ... --  simulate arrival of the next customer
              Buffer.Append_Wait(Person);
              exit when Person = null;
           end loop;
        end Producer;

4   and the consuming task might have the following structure:

5       task Consumer;

6/2     {AI95-00433-01} task body Consumer is
           Person : Person_Name;
        begin
           loop
              Buffer.Remove_First_Wait(Person);
              exit when Person = null;
              ... --  simulate serving a customer
           end loop;
        end Consumer;

7/2 {AI95-00433-01} The buffer object contains an internal array of person
names managed in a round-robin fashion. The array has two indices, an In_Index
denoting the index for the next input person name and an Out_Index denoting
the index for the next output person name.

7.1/2 {AI95-00433-01} The Buffer is defined as an extension of the
Synchronized_Queue interface (see 3.9.4), and as such promises to implement
the abstraction defined by that interface. By doing so, the Buffer can be
passed to the Transfer class-wide operation defined for objects of a type
covered by Queue'Class.

8/2     {AI95-00433-01}
        protected Buffer is new Synchronized_Queue with  -- see 3.9.4
           entry Append_Wait(Person : in Person_Name);
           entry Remove_First_Wait(Person : out Person_Name);
           function Cur_Count return Natural;
           function Max_Count return Natural;
           procedure Append(Person : in Person_Name);
           procedure Remove_First(Person : out Person_Name);
        private
           Pool      : Person_Name_Array(1 .. 100);
           Count     : Natural := 0;
           In_Index, Out_Index : Positive := 1;
        end Buffer;

9/2     {AI95-00433-01} protected body Buffer is
           entry Append_Wait(Person : in Person_Name)
              when Count < Pool'Length is
           begin
              Append(Person);
           end Append_Wait;

9.1/2   {AI95-00433-01}    procedure Append(Person : in Person_Name) is
           begin
              if Count = Pool'Length then
                 raise Queue_Error with "Buffer Full";  -- see 11.3
              end if;
              Pool(In_Index) := Person;
              In_Index       := (In_Index mod Pool'Length) + 1;
              Count          := Count + 1;
           end Append;

10/2    {AI95-00433-01}    entry Remove_First_Wait(Person : out Person_Name)
              when Count > 0 is
           begin
              Remove_First(Person);
           end Remove_First_Wait;

11/2    {AI95-00433-01}    procedure Remove_First(Person : out Person_Name) is
           begin
              if Count = 0 then
                 raise Queue_Error with "Buffer Empty"; -- see 11.3
              end if;
              Person    := Pool(Out_Index);
              Out_Index := (Out_Index mod Pool'Length) + 1;
              Count     := Count - 1;
           end Remove_First;

12/2    {AI95-00433-01}    function Cur_Count return Natural is
           begin
               return Buffer.Count;
           end Cur_Count;

13/2    {AI95-00433-01}    function Max_Count return Natural is
           begin
               return Pool'Length;
           end Max_Count;
        end Buffer;

Generated by dwww version 1.15 on Sat Jun 15 08:35:08 CEST 2024.