Rationale Update for Ada 2012
Chapter 5: Tasking and real-time facilities
The major topic in this area is providing features
for multiprocessors and increasing control for scheduling.
The following Ada Issues
cover this area:
Independence and representation clauses for atomic objects
Sets of CPUs when defining dispatching domains
Default behavior of tasks on a multiprocessor with a specified dispatching
policy
The Priority aspect can be specified when
Attach_ Handler is specified
Implicit objects are considered overlapping
All properties of a usage profile are defined by pragmas
Synchronous Barriers are not allowed with Ravenscar
Real-time aspects need to specify when they are evaluated
Definition of "dispatching domain"
Pre- and postconditions and requeues
Problematic examples for ATC
A prefixed view of a By_Protected_Procedure
interface has convention protected
Overlapping objects designated by access parameters are not thread-safe
Restriction No_Tasks_Unassigned_To_CPU
Make protected objects more protecting
These changes can be grouped as follows.
First there are some clarifications and additions
to dispatching domains which were added in 2012 (
33,
48,
82).
There are also some changes to the definition of the Ravenscar profile
(
55,
73,
117)
and clarifications to some real-time aspects (
51,
81).
These are all in the Real-Time Systems annex (D).
The examples of the use of ATC (asynchronous transfer
of control) need further explanation (
98).
The question of being thread-safe in the face of
overlapping objects has always been tricky and the text in the opening
part of Annex A is modified (
52,
114).
There are some improvements to the ability to control
concurrent access in the core language (
107,
129).
The required support for aspects such as
Pack
and their interactions with atomicity is rationalized (
1).
Note that this AI is a hangover from Ada 2005.
Finally, there are changes to the core language regarding
pre- and postconditions and requeue (
90).
As defined in Ada 2012
a dispatching domain consists of a set of processors whose CPU values
are contiguous. However, this is unrealistic since CPUs are often grouped
together in other ways. Accordingly,
AI-33
adds a type
CPU_Set and two functions to the
package
System.Multiprocessors.Dispatching_Domains
thus
type CPU_Set is array (CPU range <>) of Boolean;
function Create(Set: CPU_Set) return Dispatching_Domain;
function Get_CPU_Set(Domain: Dispatching_Domain) return CPU_Set;
Moreover, the original
functions Create and Get_Last_CPU
are modified to be
function Create(First: CPU; Last: CPU_Range) return Dispatching_Domain;
function Get_Last_CPU(Domain: Dispatching_Domain) return CPU_Range;
The changes enable Last
to be zero thereby allowing for null domains. Remember that the type
CPU_Range has lower bound of zero whereas
the subtype CPU has lower bound of one. If
a domain is empty then Get_Last_CPU returns
zero and Get_First_CPU returns one.
A minor editorial change is that many instances of
Dispatching_Domain (which is a type name)
are changed to dispatching domain (the concept) by
AI-82.
An important clarification concerns the behaviour in the absence of any
use of CPU and dispatching domains. The summary of
AI-48
says that in the absence of any setting of the CPU of a task and the
creation of any dispatching domains, a partition that specifies a language-defined
dispatching policy will allow all tasks to run on all processors.
With regard to Ravenscar,
the whole essence of its intention is to enable the use of a very simple
runtime system. Accordingly, the newly added synchronous barriers should
not be allowed and so the additional restriction
No_Dependence => Ada.Synchronous_Barriers
is added to the definition
of the Ravenscar profile by
AI-73.
Furthermore, in the case of multiprocessors, in order to permit analysis
we need to ensure that all tasks (including the environment task) are
assigned to a specific CPU and especially that no task is assigned zero
which indicates
Not_A_Specific_CPU. So a new
restriction is introduced, namely
No_Tasks_Unassigned_To_CPU
and this is also added
to the definition of the Ravenscar profile (
AI-117).
Moreover, Ravenscar requires that the CPUs are denoted statically so
another restriction is introduced
No_Dynamic_CPU_Assignment
and this is also added to Ravenscar (
AI-55).
There are some clarifications
concerning aspects in the Real-Time annex. One is simply to say that
the real-time aspects of a type are evaluated when an object of the task
type is actually declared (
AI-81).
This applies to the aspects
Priority and
Interrupt_Priority
and also to
CPU. Remember that the aspects
do not necessarily have to be static, in particular they could be discriminants
of the type and different for different objects. Thus
task type Slave(N: CPU_Range)
with CPU => N;
Tom: Slave(1); Dick: Slave(2); Harry: Slave(3);
It is easy to be confused
regarding priorities and interrupt priorities. Typically, a protected
procedure used as an interrupt handler would have aspects giving the
priority and interrupt to be handled thus
procedure Handler
with Attach_Handler => Some_Interrupt,
Interrupt_Priority => Hot_Priority;
However, if the procedure
Handler
is in a protected type
Monitor then the priority
could be given on
Monitor itself using the
aspects
Priority or
Interrupt_Priority.
If no interrupt priority or priority aspect is specified, the priority
is implementation-defined but in the range of interrupt priority. (
AI-51).
The mechanism for Asynchronous
Transfer of Control (ATC) uses a form of select statement thus
select
delay ... ; -- triggering alternative
...
then abort
Do_Something; -- abortable part
end select;
This depends upon there being places in the abortable
part that are abort completion points. The examples given in the RM in
9.7.4 rely upon this and some extra explanation is added (
AI-98).
There has always been
"boilerplate" in A(3) about reentrancy. The obvious example
is that
task T1 is
begin
Put(A_File, "Text");
end T1;
task T2 is
begin
Put(A_File, "More Text");
end T2;
is not required to
work (being unsafe use of a shared variable, namely A_File).
But if we change T2 to
task T2 is
begin
Put(B_File, "More Text");
end T2;
then it is required
to work provided
A_File and
B_File
are indeed truly different files. The wording in A(3) is improved to
be more explicit with regard to parameter passing (
AI-52,
AI-114).
It now becomes
"The implementation shall ensure that each
language-defined subprogram is reentrant in the sense that concurrent
calls on any language-defined subprogram perform as specified, so long
as all objects that are denoted by parameters that could be passed by
reference or designated by parameters of an access type are nonoverlapping."
An important difference
between protected functions and protected procedures (and entries) is
that protected functions can be accessed concurrently. The principle
is that such functions should be used for interrogating state and not
to change it. However, in the case of calling functions inside a container,
they do often change state. Accordingly, to enable containers to be used
by parallel tasks and to impose control of access by protected objects,
it is necessary to be able to make protected functions behave like protected
procedures and so prevent multiple access. This can be done by a new
aspect
Exclusive_Functions which can be given
for a protected type or a single protected object. Thus we write
protected type PT
with Exclusive_Functions;
...
and then all protected functions declared within
PT have exclusive access. Note carefully that
the aspect is not permitted on individual protected functions but on
the protected type (or object) as a whole. (
AI-129).
The usual convention for a prefixed view of a subprogram
is
Intrinsic which means that
'Access
cannot be applied. However, an awkward situation has been discovered
in the case of a subprogram with aspect
Synchronization
being
By_Protected_Procedure. (Remember that
the possible values for the aspect
Synchronization
are
By_Entry,
By_Protected_Procedure,
and
Optional.) In that case the convention
is deemed to be protected so that
Access can
be applied. (
AI-107).
AI-1
is a hangover from Ada 2005. The essence of the problem is that the language
is inconsistent regarding the pragma (now aspect)
Pack.
On the one hand the text of the RM regarding packing says that entities
have to be squeezed up really tightly. On the other hand alignment properties,
atomicity and so on ought to be respected. The revised text clarifies
that
Pack should not do anything that violates
other requirements.
Finally, a bother with requeue is addressed by
AI-90
(requeue has been the source of many bothers in the past so another one
is not unexpected). This time the problem concerns pre- and postconditions.
Suppose we have entries
E1 and
E2
with pre- and postconditions. And suppose that
E1
does a requeue onto
E2. The current text is
unclear as to what exactly is checked and when. Do we avoid checking
any postcondition on
E1 and do we bypass any
precondition on
E2? Certainly not is the brief
answer. Basically we require that the postcondition on
E2
implies that on
E1 by saying that they must
fully conform. And moreover any precondition on
E2
is indeed checked when the call is requeued. Remember that parameters
are passed on unchanged and that the requeue statement does not have
any explicit parameters itself.
© 2016 John Barnes Informatics.