C.6 Shared Variable Control
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
[This subclause defines representation aspects that control the use of shared variables.]
Paragraphs 2 through 6 were moved to Annex J, “Obsolescent Features”.
Static Semantics
6.1/5For an object_declaration
, a component_declaration
, a full_type_declaration
, or a formal_complete_type_declaration
, the following representation aspects may be specified:
Atomic
- The type of aspect Atomic is Boolean.
Independent
- The type of aspect Independent is Boolean.
Volatile
- The type of aspect Volatile is Boolean.
Full_Access_Only
- The type of aspect Full_Access_Only is Boolean.
For a full_type_declaration
of an array type, an object_declaration
for an object of an anonymous array type, or the formal_complete_type_declaration
of a formal array type , the following representation aspects may be specified:
Atomic_Components
- The type of aspect Atomic_Components is Boolean.
Volatile_Components
- The type of aspect Volatile_Components is Boolean.
For a full_type_declaration
of a composite type, an object_declaration
for an object of an anonymous composite type, or the formal_complete_type_declaration
of a formal composite type , the following representation aspect may be specified:
Independent_Components
- The type of aspect Independent_Components is Boolean.
If any of these aspects are directly specified, the aspect_definition
shall be a static expression. If not specified for a type (including by inheritance), the Atomic, Atomic_Components, and Full_Access_Only aspects are False. If any of these aspects are specified True for a type, then the corresponding aspect is True for all objects of the type. If the Atomic aspect is specified True, then the aspects Volatile, Independent, and Volatile_Component (if defined) are True; if the Atomic_Components aspect is specified True, then the aspects Volatile, Volatile_Components, and Independent_Components are True. If the Volatile aspect is specified True, then the Volatile_Components aspect (if defined) is True, and vice versa. When not determined by one of the other aspects, or for an object by its type, the Volatile, Volatile_Components, Independent, and Independent_Components aspects are False.
An atomic type is one for which the aspect Atomic is True. An atomic object (including a component) is one for which the aspect Atomic is True, or a component of an array for which the aspect Atomic_Components is True for the associated type, or any object of an atomic type, other than objects obtained by evaluating a slice.
A volatile type is one for which the aspect Volatile is True. A volatile object (including a component) is one for which the aspect Volatile is True, or a component of an array for which the aspect Volatile_Components is True for the associated type, or any object of a volatile type. In addition, every atomic type or object is also defined to be volatile. Finally, if an object is volatile, then so are all of its subcomponents [(the same does not apply to atomic)].
When True, the aspects Independent and Independent_Components specify as independently addressable the named object or component(s), or in the case of a type, all objects or components of that type. All atomic objects and aliased objects are considered to be specified as independently addressable.
The Full_Access_Only aspect shall not be specified unless the associated type or object is volatile [(or atomic)]. A full access type is any atomic type, or a volatile type for which the aspect Full_Access_Only is True. A full access object (including a component) is any atomic object, or a volatile object for which the aspect Full_Access_Only is True for the object[ or its type]. A Full_Access_Only aspect is illegal if any subcomponent of the object or type is a full access object or is of a generic formal type.
Paragraph 9 was moved to Annex J, “Obsolescent Features”.
Legality Rules
9.1/3If aspect Independent_Components is specified for a full_type_declaration
, the declaration shall be that of an array or record type.
It is illegal to specify either of the aspects Atomic or Atomic_Components to have the value True for an object or type if the implementation cannot support the indivisible and independent reads and updates required by the aspect (see below).
It is illegal to specify the Size attribute of an atomic object, the Component_Size attribute for an array type with atomic components, or the layout attributes of an atomic component, in a way that prevents the implementation from performing the required indivisible and independent reads and updates.
If an atomic object is passed as a parameter, then the formal parameter shall either have an atomic type or allow pass by copy. If an atomic object is used as an actual for a generic formal object of mode in out, then the type of the generic formal object shall be atomic. If the prefix
of an attribute_reference
for an Access attribute denotes an atomic object [(including a component)], then the designated type of the resulting access type shall be atomic. Corresponding rules apply to volatile objects and to full access objects .
If a nonatomic subcomponent of a full access object is passed as an actual parameter in a call then the formal parameter shall allow pass by copy (and, at run time, the parameter shall be passed by copy). A nonatomic subcomponent of a full access object shall not be used as an actual for a generic formal of mode in out. The prefix
of an attribute_reference
for an Access attribute shall not denote a nonatomic subcomponent of a full access object.
If the Atomic, Atomic_Components, Volatile, Volatile_Components, Independent, Independent_Components, or Full_Access_Only aspect is True for a generic formal type, then that aspect shall be True for the actual type. If an atomic type is used as an actual for a generic formal derived type, then the ancestor of the formal type shall be atomic. A corresponding rule applies to volatile types and similarly to full access types .
If a type with volatile components is used as an actual for a generic formal array type, then the components of the formal type shall be volatile. Furthermore, if the actual type has atomic components and the formal array type has aliased components, then the components of the formal array type shall also be atomic. A corresponding rule applies when the actual type has volatile full access components.
If an aspect Volatile, Volatile_Components, Atomic, or Atomic_Components is directly specified to have the value True for a stand-alone constant object, then the aspect Import shall also be specified as True for it.
It is illegal to specify the aspect Independent or Independent_Components as True for a component, object or type if the implementation cannot provide the independent addressability required by the aspect (see 9.10).
It is illegal to specify a representation aspect for a component, object or type for which the aspect Independent or Independent_Components is True, in a way that prevents the implementation from providing the independent addressability required by the aspect.
Paragraph 14 was moved to Annex J, “Obsolescent Features”.
Dynamic Semantics
15For an atomic object (including an atomic component) all reads and updates of the object as a whole are indivisible.
All tasks of the program (on all processors) that read or update volatile variables see the same order of updates to the variables. A use of an atomic variable or other mechanism may be necessary to avoid erroneous execution and to ensure that access to nonatomic volatile variables is sequential (see 9.10).
Two actions are sequential (see 9.10) if each is the read or update of the same atomic object.
If a type is atomic or volatile and it is not a by-copy type, then the type is defined to be a by-reference type. If any subcomponent of a type is atomic or volatile, then the type is defined to be a by-reference type.
If an actual parameter is atomic or volatile, and the corresponding formal parameter is not, then the parameter is passed by copy.
All reads of or writes to any nonatomic subcomponent of a full access object are performed by reading and/or writing all of the nearest enclosing full access object.
Implementation Requirements
20/5The external effect of a program (see 1.1.3) is defined to include each read and update of a volatile or atomic object. The implementation shall not generate any memory reads or updates of atomic or volatile objects other than those specified by the program. However, there may be target-dependent cases where reading or writing a volatile but nonatomic object (typically a component) necessarily involves reading and/or writing neighboring storage, and that neighboring storage can overlap a volatile object.
- X:= V; Y:=V; cannot be allowed to be translated as Y:=V; X:=V;
- Deleting redundant loads: X:= V; X:= V; shall read the value of V from memory twice.
- Deleting redundant stores: V:= X; V:= X; shall write into V twice.
- Extra stores: V:= X+Y; should not translate to something like V:= X; V:= V+Y;
- Extra loads: X:= V; Y:= X+Z; X:=X+B; should not translate to something like Y:= V+Z; X:= V+B;
- Reordering of loads from volatile variables: X:= V1; Y:= V2; (whether or not V1 = V2) should not translate to Y:= V2; X:= V1;
- Reordering of stores to volatile variables: V1:= X; V2:= X; should not translate to V2:=X; V1:= X;
This paragraph was deleted.
Implementation Permissions
21.1/5Within the body of an instance of a generic unit that has a formal type T that is not atomic and an actual type that is atomic, if an object O of type T is declared and explicitly specified as atomic, the implementation may introduce an additional copy on passing O to a subprogram with a parameter of type T that is normally passed by reference. A corresponding permission applies to volatile parameter passing.
Implementation Advice
22/5A load or store of a volatile object whose size is a multiple of System.Storage_Unit and whose alignment is nonzero, should be implemented by accessing exactly the bits of the object and no others, except in the case of a volatile but nonatomic subcomponent of an atomic object.
A load or store of an atomic object should, where possible, be implemented by a single load or store instruction.
Incompatibilities With Ada 83
Wording Changes from Ada 95
Incompatibilities With Ada 2005
Extensions to Ada 2005
pragma
s Atomic, Atomic_Components, Volatile, and Volatile_Components are now obsolescent. Wording Changes from Ada 2005
Inconsistencies With Ada 2012
Extensions to Ada 2012
Wording Changes from Ada 2012
C.6.1 The Package System.Atomic_Operations
1/5The language-defined package System.Atomic_Operations is the parent of a set of child units that provide facilities for manipulating objects of atomic types and for supporting lock-free synchronization. The subprograms of this subsystem are Intrinsic subprograms (see 6.3.1) in order to provide convenient access to machine operations that can provide these capabilities if they are available in the target environment.
Static Semantics
2/5The library package System.Atomic_Operations has the following declaration:
package System.Atomic_Operations
with Pure, Nonblocking is
end System.Atomic_Operations;
System.Atomic_Operations serves as the parent of other language-defined library units that manipulate atomic objects; its declaration is empty.
A call to a subprogram is said to be lock-free if the subprogram is guaranteed to return from the call while keeping the processor of the logical thread of control busy for the duration of the call.
In each child package, a function Is_Lock_Free(...) is provided to check whether the operations of the child package can all be provided lock-free for a given object. Is_Lock_Free returns True if operations defined in the child package are lock-free when applied to the object denoted by Item, and Is_Lock_Free returns False otherwise.
Extensions to Ada 2012
C.6.2 The Package System.Atomic_Operations.Exchange
1/5The language-defined generic package System.Atomic_Operations.Exchange provides the following operations:
- To atomically compare the value of two atomic objects, and update the first atomic object with a desired value if both objects were found to be equal, or otherwise update the second object with the value of the first object.
- To atomically update the value of an atomic object, and then return the value that the atomic object had just prior to the update.
Static Semantics
4/5The generic library package System.Atomic_Operations.Exchange has the following declaration:
generic
type Atomic_Type is private with Atomic;
package System.Atomic_Operations.Exchange
with Pure, Nonblocking is
6/5function Atomic_Exchange (Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
7/5function Atomic_Compare_And_Exchange
(Item : aliased in out Atomic_Type;
Prior : aliased in out Atomic_Type;
Desired : Atomic_Type) return Boolean
with Convention => Intrinsic;
8/5function Is_Lock_Free (Item : aliased Atomic_Type) return Boolean
with Convention => Intrinsic;
9/5end System.Atomic_Operations.Exchange;
10/5Atomic_Exchange atomically assigns the value of Value to Item, and returns the previous value of Item.
Atomic_Compare_And_Exchange first evaluates the value of Prior. Atomic_Compare_And_Exchange then performs the following steps as part of a single indivisible operation:
- evaluates the value of Item;
- compares the value of Item with the value of Prior;
- if equal, assigns Item the value of Desired;
- otherwise, makes no change to the value of Item.
After these steps, if the value of Item and Prior did not match, Prior is assigned the original value of Item, and the function returns False. Otherwise, Prior is unaffected and the function returns True.
Examples
17/5Example of a spin lock using Atomic_Exchange:
type Atomic_Boolean is new Boolean with Atomic;
package Exchange is new
Atomic_Operations.Exchange (Atomic_Type => Atomic_Boolean);
19/5Lock : aliased Atomic_Boolean := False;
20/5...
21/5begin -- Some critical section, trying to get the lock:
22/5-- Obtain the lock
while Exchange.Atomic_Exchange (Item => Lock, Value => True) loop
null;
end loop;
23/5... -- Do stuff
24/5Lock := False; -- Release the lock
end;
Extensions to Ada 2012
C.6.3 The Package System.Atomic_Operations.Test_and_Set
1/5The language-defined package System.Atomic_Operations.Test_And_Set provides an operation to atomically set and clear an atomic flag object.
Static Semantics
2/5The library package System.Atomic_Operations.Test_And_Set has the following declaration:
package System.Atomic_Operations.Test_And_Set
with Pure, Nonblocking is
4/5type Test_And_Set_Flag is mod implementation-defined
with Atomic, Default_Value => 0, Size => implementation-defined;
5/5function Atomic_Test_And_Set
(Item : aliased in out Test_And_Set_Flag) return Boolean
with Convention => Intrinsic;
6/5procedure Atomic_Clear
(Item : aliased in out Test_And_Set_Flag)
with Convention => Intrinsic;
7/5function Is_Lock_Free
(Item : aliased Test_And_Set_Flag) return Boolean
with Convention => Intrinsic;
8/5end System.Atomic_Operations.Test_And_Set;
Test_And_Set_Flag represents the state of an atomic flag object. An atomic flag object can either be considered to be set or cleared.
Atomic_Test_And_Set performs an atomic test-and-set operation on Item. Item is set to some implementation-defined nonzero value. The function returns True if the previous contents were nonzero, and otherwise returns False.
Atomic_Clear performs an atomic clear operation on Item. After the operation, Item contains 0. This call should be used in conjunction with Atomic_Test_And_Set.
Extensions to Ada 2012
C.6.4 The Package System.Atomic_Operations.Integer_Arithmetic
1/5The language-defined generic package System.Atomic_Operations.Integer_Arithmetic provides operations to perform arithmetic atomically on objects of integer types.
Static Semantics
2/5The generic library package System.Atomic_Operations.Integer_Arithmetic has the following declaration:
generic
type Atomic_Type is range <> with Atomic;
package System.Atomic_Operations.Integer_Arithmetic
with Pure, Nonblocking is
4/5procedure Atomic_Add (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
5/5procedure Atomic_Subtract (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
6/5function Atomic_Fetch_And_Add
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
7/5function Atomic_Fetch_And_Subtract
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
8/5function Is_Lock_Free (Item : aliased Atomic_Type) return Boolean
with Convention => Intrinsic;
9/5end System.Atomic_Operations.Integer_Arithmetic;
10/5The operations of this package are defined as follows:
procedure Atomic_Add (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
Atomically performs: Item := Item + Value;
procedure Atomic_Subtract (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
Atomically performs: Item := Item - Value;
function Atomic_Fetch_And_Add
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
Atomically performs: Tmp := Item; Item := Item + Value; return Tmp;
function Atomic_Fetch_And_Subtract
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
Atomically performs: Tmp := Item; Item := Item - Value; return Tmp;
Extensions to Ada 2012
C.6.5 The Package System.Atomic_Operations.Modular_Arithmetic
1/5The language-defined generic package System.Atomic_Operations.Modular_Arithmetic provides operations to perform arithmetic atomically on objects of modular types.
Static Semantics
2/5The generic library package System.Atomic_Operations.Modular_Arithmetic has the following declaration:
generic
type Atomic_Type is mod <> with Atomic;
package System.Atomic_Operations.Modular_Arithmetic
with Pure, Nonblocking is
4/5procedure Atomic_Add (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
5/5procedure Atomic_Subtract (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
6/5function Atomic_Fetch_And_Add
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
7/5function Atomic_Fetch_And_Subtract
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
8/5function Is_Lock_Free (Item : aliased Atomic_Type) return Boolean
with Convention => Intrinsic;
9/5end System.Atomic_Operations.Modular_Arithmetic;
10/5The operations of this package are defined as follows:
procedure Atomic_Add (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
Atomically performs: Item := Item + Value;
procedure Atomic_Subtract (Item : aliased in out Atomic_Type;
Value : Atomic_Type)
with Convention => Intrinsic;
Atomically performs: Item := Item - Value;
function Atomic_Fetch_And_Add
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
Atomically performs: Tmp := Item; Item := Item + Value; return Tmp;
function Atomic_Fetch_And_Subtract
(Item : aliased in out Atomic_Type;
Value : Atomic_Type) return Atomic_Type
with Convention => Intrinsic;
Atomically performs: Tmp := Item; Item := Item - Value; return Tmp;