[Home] [Prev] [Next] [Index]

9.7 Select Statements

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 ·
An open terminate_alternative is selected if the conditions stated at the end of clause 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 36
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
[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.]

Syntax

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

3
entry_call_alternative ::=
  entry_call_statement [sequence_of_statements]

Dynamic Semantics

4
For the execution of a timed_entry_call, the entry_name and the actual parameters are evaluated, as for a simple entry call (see 9.5.3). The expiration time (see 9.6) for the call is determined by evaluating the delay_expression of the delay_alternative; the entry call is then issued.

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
Ramification: The fact that the syntax calls for an entry_call_statement means that this fact is used in overload resolution. For example, if there is a procedure X and an entry X (both with no parameters), then "select X; ..." is legal, because overload resolution knows that the entry is the one that was meant.

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
This clause comes before the one for Conditional Entry Calls, so we can define conditional entry calls in terms of timed entry calls.

9.7.3 Conditional Entry Calls

1
[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).]

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 37
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
This clause 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
triggering_statement ::= entry_call_statement | delay_statement

5
abortable_part ::= sequence_of_statements

Dynamic Semantics

6
For the execution of an asynchronous_select whose triggering_statement is an entry_call_statement, the entry_name and actual parameters are evaluated as for a simple entry call (see 9.5.3), and 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.]

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 ), 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;

Extensions to Ada 83

13.a
Asynchronous_select is new.



[Home] [Prev] [Next] [Index]

documentation@rational.com
Copyright © 1993-1998, Rational Software Corporation.   All rights reserved.