AI22-0125-1

!standard C.6.4(18/5)                                    25-01-10  AI22-0125-1/02

!standard C.6.5(18/5)

!class binding interpretation 25-01-02

!status Amendment 1-2022  25-01-10

!status WG9 Approved 25-07-18

!status ARG Approved  13-0-2  25-01-09

!status work item 25-01-02

!status received 24-11-01

!submitter Tucker Taft on behalf of Jere

!priority Medium

!difficulty Easy

!qualifier Omission

!subject Atomic_Operations and checks

!summary

Language-defined checks are performed on the result of operations defined in the Atomic_Operations packages, but those checks are not necessarily atomic with respect to the atomic operation. Users should avoid using these operations on types which require language-defined checks.

!issue

Do the operations of System.Atomic_Operations.Integer_Arithmetic include language-defined checks? (Yes.) At least one implementation does not do language-defined checks on these operations.

!recommendation

(See Summary.)

!wording

Add after C.6.4(18/5):

Implementation Permissions

An implementation may allow Item to be modified if the operation defined in an instance of  System.Atomic_Operations.Integer_Arithmetic fails a language-defined check. Additionally, an implementation may check that predicates are satisfied after the atomic operation.

AARM Reason: We want to allow the check to be made after the atomic operation, but using the results of the operation. In particular, we want the overflow checks for these operations to be possible to be performed by testing the overflow bit set by an atomic arithmetic operation of the CPU. We do not want to require the arbitrary code of predicate checks to be part of the atomic operation, as that could cause unusually long atomic operations.

AARM Ramification: Overflow and range checks will be performed, but if they fail the object value can be invalid afterwards.

Usage

The subtype used to instantiate System.Atomic_Operations.Integer_Arithmetic should not have predicates, as those probably will not be checked atomically, potentially causing incorrect check failures if another task has modified the value between the operation and the check. For the best performance, the subtype should be a base subtype so that no range check need be performed.

Add after C.6.5(18/5):

Implementation Permissions

An implementation may allow Item to be modified if an operation that is defined in an instance of  System.Atomic_Operations.Modular_Arithmetic fails a language-defined check. Additionally, an implementation may check that predicates are satisfied after the atomic operation.

AARM Reason: We want to allow the check to be made after the atomic operation, but using the results of the operation. We do not want to require the arbitrary code of predicate checks to be part of the atomic operation, as that could cause unusually long atomic operations.

AARM Ramification: Range checks will be performed, but if they fail the object value can be invalid afterwards.

Usage

The subtype used to instantiate System.Atomic_Operations.Modular_Arithmetic should not have predicates, as those probably will not be checked atomically, potentially causing incorrect check failures if another task has modified the value between the operation and the check. For the best performance, the subtype should be a base subtype so that no range check need be performed.

!discussion

While it would be possible to do the entire operation (including the checks) atomically (using an appropriate compare and swap loop), that would make it nearly impossible to use any existing atomic operations to implement them. Since these operations are primarily intended for applications with critical performance requirements (otherwise, using protected objects would be preferred), adding performance drags is not a good idea.

On the other hand, allowing the operations to completely ignore language-defined checks seems wrong. If the Ada definition is such that checks are required, ignoring them could cause major problems in analysis (where both human readers and computer analyzers could assume the checks given the form of the declarations).

Therefore, we split the baby and allow the checks to occur after the operation, and other than for overflow and range checks, non-atomically.

!example

with Ada.Text_IO; use Ada.Text_IO;
with System.Atomic_Operations.Integer_Arithmetic;
procedure Jdoodle is
    type A is new Integer with Atomic;
    package Ops is new System.Atomic_Operations.Integer_Arithmetic(A);
   
    V : aliased A := A'Last;
begin
    Ops.Atomic_Add (V, 1); -- Should raise Constraint_Error
    Put_Line (V'Image);
end Jdoodle;

!corrigendum C.6.4(18/5)

@dinsa

@xindent{Atomically performs: @fc{Tmp := Item; Item := Item - Value; @b{return} Tmp;}}

@dinss

@s8{@i{Implementation Permissions}}

An implementation may allow @fc{Item} to be modified if the operation defined in an instance of @fc{System.Atomic_Operations.Integer_Arithmetic} fails a language-defined check. Additionally, an implementation may check that predicates are satisfied after the atomic operation.

@s8{@i{Usage}}

The subtype used to instantiate @fc{System.Atomic_Operations.Integer_Arithmetic} should not have predicates, as those probably will not be checked atomically, potentially causing incorrect check failures if another task has modified the value between the operation and the check. For the best performance, the subtype should be a base subtype so that no range check need be performed.

!corrigendum C.6.5(18/5)

@dinsa

@xindent{Atomically performs: @fc{Tmp := Item; Item := Item - Value; @b{return} Tmp;}}

@dinss

@s8{@i{Implementation Permissions}}

An implementation may allow @fc{Item} to be modified if the operation defined in an instance of @fc{System.Atomic_Operations.Modular_Arithmetic} fails a language-defined check. Additionally, an implementation may check that predicates are satisfied after the atomic operation.

@s8{@i{Usage}}

The subtype used to instantiate @fc{System.Atomic_Operations.Modular_Arithmetic} should not have predicates, as those probably will not be checked atomically, potentially causing incorrect check failures if another task has modified the value between the operation and the check. For the best performance, the subtype should be a base subtype so that no range check need be performed.

!ACATS test

An ACATS C-Test should be created to verify that exceptions are raised as needed from these operations.

!appendix

This AI was created to reflect Github Issue #114 (https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues/114).