Version 1.5 of ai12s/ai12-0129-1.txt
!standard 9.5.1(2) 15-02-20 AI12-0129-1/03
!standard 9.5.1(4)
!standard 9.5.1(5)
!class Amendment 14-10-03
!status work item 14-10-03
!status received 14-09-09
!priority Medium
!difficulty Easy
!subject Make protected objects more protecting
!summary
A Boolean aspect Exclusive_Functions is added to the language.
!problem
The design of containers assumes that they are not accessed
concurrently, on the ground that access can be protected with
protected objects if necessary.
However, containers provide functions that modify the state of the
container; it is therefore not possible to access these through
protected functions, as these can be called concurrently.
!proposal
Add a boolean aspect "Exclusive_Functions" for protected types and
single protected objects to forbid concurrent execution of protected
functions.
!wording
After 9.5.1(2) (i.e. at the end of the static semantics section) add:
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:
[Editor's note: The above is more complicated than the similar wording used
for aspect Priority and the like, because we want to exclude derived
protected types and protected/synchronized interfaces from the types that
are included. Priority allows the former, and excludes the latter by a
separate Legality Rule.]
Exclusive_Functions
The type of aspect Exclusive_Functions is Boolean.
[Redundant: A value of True for this aspect indicates that protected
functions behave in the same way as protected procedures with respect
to mutual exclusion (see below).]
[Redundant: If not specified (including by inheritance), the aspect
is False.]
[Editor's note: The above sentence is redundant because of AI12-0153-1; if
that AI is not adopted, then the Redundant marking should be eliminated.]
Modify 9.5.1(4):
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 protected function {and the
Exclusive_Functions aspect of the protected type is False}.
Modify 9.5.1(5):
Starting a protected action on a protected object corresponds to acquiring
the execution resource associated with the protected object, either for
concurrent read-only access if the protected action is for a call on a
protected function {and the Exclusive_Functions aspect of the
protected type is False}, or for exclusive read-write access otherwise;
!discussion
According ARM A(3/2), there is no correctness guarantee on concurrent
calls involving overlapping objects passed by reference. Indeed, most
implementations of the standard containers break when the same
container is used concurrently, even when the container is declared
constant.
The usual way of allowing concurrent access to unsafe objects is to
encapsulate them in a protected object.
However, protected functions still allow concurrent access to (a
constant view) of private objects. So the most natural way of writing
a protected container is still unsafe:
protected type Protected_Container is
procedure Insert (Key : in Key_Type; Element : in Element_Type);
function Element (Key : in Key_Type) return Element_Type;
private
Unsafe_Container : Ordered_Map_Instance.Map;
end Protected_Container;
Moreover, there is no easy way to actually realize this is unsafe,
since it compiles without warning, and concurrent read access on usual
objects is usually safe.
Programmers aware about the issue can restrict themselves to use only
protected procedures and entries, which guarantees non-concurrency on
private data:
protected type Safe_Protected_Container is
procedure Insert (Key : in Key_Type; Element : in Element_Type);
procedure Element (Key : in Key_Type; Element : out Element_Type);
private
Unsafe_Container : Ordered_Map_Instance.Map;
end Safe_Protected_Container;
However, such a procedure Element is counter-intuitive, and makes
client code heavier because contained elements can no longer be used
in a more complex expression, explicit temporary variables have to be
used instead.
Also, this construction only works when Element_Type is definite. To
use indefinite containers safely by using only protected procedures
and entries, another layer is needed, e.g. using an indefinite holder
or an access type.
Moreover, the whole workaround is fragile, since there is no way to
ensure protected functions won't be carelessly added in the future by
a programmer not aware of the rationale.
So current version of Ada doesn't seem to adequately allow concurrency
protection for objects whose read-only concurrent access is not safe,
like standard containers, but it can be the case for user types as
well.
It is much easier and foolproof to have an aspect for protected types, that
make protected function have concurrency semantics of protected
procedures, ensuring non-concurrent use of private objects, while
remaining syntactically a function.
From an implementation point of view, it would just mean that
protected function calls would use the same semaphore as protected
procedures; some implementations may even already use only one kind of
semaphores for both. Implementation burden would likely range from
null to minimal.
---
We've tried to keep wording changes to the minimum, to make it clear that this
is a very small change (essentially no more than the removal of a permission).
The wording of 9.5.1(7) (and corresponding wording in 9.5.3) is unmodified.
Protected functions with aspect Exclusive_Functions set are not the same as
protected procedures with respect to queue servicing because the state of the
protected object cannot have changed during a call to a protected function.
Locking behavior might be implemented directly in the body of a protected
type. As such, we don't allow specifying the Exclusive_Functions aspect for
derived protected types, so that the compiler doesn't need to generate a new
body with different locking. That seems like an excessive implementation
burden, especially as the intended usage would never change the aspect.
!ASIS
No impact.
!ACATS test
An ACATS C-Test should be created to check that the aspect is supported, and
that no overlapping protected function calls are allowed when it is in effect.
Even if the latter is wrong, it's likely that the test wouldn't detect it
(detecting race conditions and the like can never be done reliably since they
depend on timing), but we can at least try.
!appendix
From: Jean-Pierre Rosen
Sent: Tuesday, September 9, 2014 10:56 AM
This is my homework from the last meeting, although I subcontracted most of
it to Natacha Porté who initially raised the issue (she's the one in the CC).
[This is version /01 of the AI - Editor.]
****************************************************************
From: Tucker Taft
Sent: Tuesday, September 9, 2014 11:26 AM
To me, this does not seem completely appropriate for an "aspect." This is a
significant semantic change and should probably be reflected in a
corresponding syntax change for protected functions.
Now that we allow in-out parameters for function, perhaps something like the
following would communicate the idea:
protected type Protected_Container is
...
function Element (in out Protected_Container; Key : in Key_Type) return Element_Type;
...
****************************************************************
From: Steve Baird
Sent: Tuesday, September 9, 2014 1:16 PM
This particular proposal seems like a bad idea for several reasons:
1) Protected operation declarations do not normally mention the
protected object as an explicit parameter; this proposal is
therefore *very* different.
2) The "current instance" rule means that the name
"Protected_Container" in the proposed declaration of
Element denotes an object, not a type. (Obviously this
objection could be worked around as was done with
access_definitions).
3) Ambiguity. Is the explicit parameter instead of or in
addition to the usual implicit parameter? Again, this could
be worked around but it would be ugly.
#1 is really the main objection.
However, I agree with your objection to the original proposal.
Perhaps this could be addressed by defining a new Convention; that might also
help straighten out any interactions with interface types.
****************************************************************
From: Jean-Pierre Rosen
Sent: Tuesday, September 9, 2014 3:05 PM
> To me, this does not seem completely appropriate for an "aspect."
> This is a significant semantic change and should probably be reflected
> in a corresponding syntax change for protected functions.
Not such a big change, as it simply forces a semantic that is already allowed.
Certainly not as big as synchronization => by_entry
****************************************************************
From: Bob Duff
Sent: Tuesday, September 9, 2014 4:20 PM
I tend to agree with J-P here. What's the big deal?
****************************************************************
From: Randy Brukardt
Sent: Tuesday, September 9, 2014 4:37 PM
Me too. This is just turning off an implementation permission. Sounds like an
aspect to me.
****************************************************************
From: Steve Baird
Sent: Tuesday, September 9, 2014 4:47 PM
I withdraw my objection to the aspect proposal.
My objection would stand if we were talking about allowing functions to have
a non-constant view of the protected object, but we aren't.
****************************************************************
From: Tucker Taft
Sent: Tuesday, September 9, 2014 9:10 PM
I presumed we were wanting to be "honest" about the parameter mode for the
protected object. I suppose if we are just keeping a constant view, then the
aspect is adequate.
****************************************************************
Questions? Ask the ACAA Technical Agent