package GNATCOLL.Atomic is
subtype Atomic_Counter is System.Atomic_Counters.Atomic_Unsigned;
Minus_One : constant Atomic_Counter :=
System.Atomic_Counters."-" (0, 1);
function Is_Lock_Free return Boolean;
-- Whether the implementation uses the processor's atomic operations
-- or falls back on using locks
function Sync_Add_And_Fetch
(Ptr : access Atomic_Counter;
Value : Atomic_Counter) return Atomic_Counter
with Inline_Always;
-- Increment Ptr by Value. This is task safe (either using a lock or
-- intrinsic atomic operations). Returns the new value (as set, it
-- might already have been changed by another task by the time this
-- function returns.
function Sync_Sub_And_Fetch
(Ptr : access Atomic_Counter;
Value : Atomic_Counter) return Atomic_Counter
with Inline_Always;
-- Decrement Ptr by Value.
procedure Sync_Add_And_Fetch
(Ptr : access Atomic_Counter; Value : Atomic_Counter)
with Inline_Always;
procedure Sync_Sub_And_Fetch
(Ptr : access Atomic_Counter; Value : Atomic_Counter)
with Inline_Always;
-- Same as above, but ignore the return value.
procedure Increment
(Value : aliased in out Atomic_Counter) with Inline_Always;
procedure Decrement
(Value : aliased in out Atomic_Counter) with Inline_Always;
function Decrement
(Value : aliased in out Atomic_Counter) return Boolean
with Inline_Always;
-- Similar to the Sync_Add_And_Fetch and Sync_Sub_And_And, but
-- always increment or decrement by one.
-- On some systems (x86) this uses faster assembly instructions.
-- Decrement returns True if the value reaches 0.
function "+"
(Left, Right : Atomic_Counter) return Atomic_Counter is abstract;
function "-"
(Left, Right : Atomic_Counter) return Atomic_Counter is abstract;
-- Prevent standard operations on these counters
function Unsafe_Decrement (Value : in out Atomic_Counter) return Boolean
with Inline_Always;
procedure Unsafe_Increment (Value : in out Atomic_Counter)
with Inline_Always;
-- These are unsafe operations. If you have two threads, and they all try
-- to do "Unsafe_Add (A, 2)" at the same time, when A was initially 0,
-- you could end up with the following values in A:
-- 2 (both threads have read 0, then added 2)
-- 4 (thread 1 has read and incremented, then thread 2)
-- If you use the other operations above, you always end up with 4.
function ">" (Left, Right : Atomic_Counter) return Boolean
is (System.Atomic_Counters.">" (Left, Right));
-- Compare two counters.
-- Note that by the time this function returns, and in a multi threaded
-- application, either of the two counters might have changed.
function "="
(Left, Right : Atomic_Counter) return Boolean
renames System.Atomic_Counters."=";
-- Make the operator visible
generic
type Element_Type (<>) is limited private;
type Element_Access is access Element_Type;
function Sync_Bool_Compare_And_Swap
(Ptr : access Element_Access;
Oldval : Element_Access;
Newval : Element_Access) return Boolean;
-- If Ptr is equal to Oldval, set it to Newval and return True.
-- Otherwise, return False and do not modify the current value.
-- This operation is task safe and atomic.
function Sync_Bool_Compare_And_Swap_Counter
(Ptr : access Atomic_Counter;
Oldval : Atomic_Counter;
Newval : Atomic_Counter) return Boolean;
function Sync_Val_Compare_And_Swap_Counter
(Ptr : access Atomic_Counter;
Oldval : Atomic_Counter;
Newval : Atomic_Counter) return Atomic_Counter;
-- A version that works with Atomic_Counter.
-- Ptr.all is set to Newval if and only if it is currently set to Oldval.
-- Returns True if the value was changed.
-- The second version returns the initial value of Ptr.all
end GNATCOLL.Atomic;