Version 1.5 of ai12s/ai12-0129-1.txt

Unformatted version of ai12s/ai12-0129-1.txt version 1.5
Other versions for file 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