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
3/3
4
5/1
6
7
Legality Rules
8/2
This paragraph was
deleted.{
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.
8.a/2
This paragraph
was deleted.To be honest: The
completion can be a pragma
Import, if the implementation supports it.
Static Semantics
9
9.a
Proof: Private part is defined in Section
8.
9.1/1
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 non-abstract 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
completion can be a pragma
Import, 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
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 non-inherited 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
10.a
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
12.a/1
Reason: The only
aspect_clauses representation_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.
19/2
2 {
AI95-00382-01}
Other than in an access_definition,
the name of a task unit within Within
the declaration or body of
the a
task unit
, the name 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 However,
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 has neither an assignment operation
nor 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 C.7).
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
Wording Changes from Ada 83
32.b
32.c
32.d
Extensions to Ada 95
32.e/2
Wording Changes from Ada 95
32.f/2
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
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
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.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe