1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- System.Atomic_Operations.Integer_Arithmetic --
9 -- Copyright (C) 2019-2024, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with System
.Atomic_Primitives
; use System
.Atomic_Primitives
;
33 with System
.Atomic_Operations
.Exchange
;
36 package body System
.Atomic_Operations
.Integer_Arithmetic
is
38 package Exchange
is new System
.Atomic_Operations
.Exchange
(Atomic_Type
);
45 (Item
: aliased in out Atomic_Type
;
48 Ignore
: constant Atomic_Type
:= Atomic_Fetch_And_Add
(Item
, Value
);
57 procedure Atomic_Subtract
58 (Item
: aliased in out Atomic_Type
;
61 Ignore
: constant Atomic_Type
:= Atomic_Fetch_And_Subtract
(Item
, Value
);
66 --------------------------
67 -- Atomic_Fetch_And_Add --
68 --------------------------
70 function Atomic_Fetch_And_Add
71 (Item
: aliased in out Atomic_Type
;
72 Value
: Atomic_Type
) return Atomic_Type
74 pragma Warnings
(Off
);
75 function Atomic_Fetch_Add
76 (Ptr
: System
.Address
; Val
: Atomic_Type
; Model
: Mem_Model
:= Seq_Cst
)
78 pragma Import
(Intrinsic
, Atomic_Fetch_Add
, "__atomic_fetch_add");
82 -- Use the direct intrinsics when possible, and fallback to
83 -- compare-and-exchange otherwise.
85 if Atomic_Type
'Base'Last = Atomic_Type'Last
86 and then Atomic_Type'Base'First
= Atomic_Type
'First
87 and then Atomic_Type
'Last = 2**(Atomic_Type
'Object_Size - 1) - 1
89 if Atomic_Type
'Object_Size in 8 |
16 |
32 |
64 then
90 return Atomic_Fetch_Add
(Item
'Address, Value
);
97 Old_Value
: aliased Atomic_Type
:= Item
;
98 New_Value
: Atomic_Type
:= Old_Value
+ Value
;
100 -- Keep iterating until the exchange succeeds
102 while not Exchange
.Atomic_Compare_And_Exchange
103 (Item
, Old_Value
, New_Value
)
105 New_Value
:= Old_Value
+ Value
;
111 end Atomic_Fetch_And_Add
;
113 -------------------------------
114 -- Atomic_Fetch_And_Subtract --
115 -------------------------------
117 function Atomic_Fetch_And_Subtract
118 (Item
: aliased in out Atomic_Type
;
119 Value
: Atomic_Type
) return Atomic_Type
121 pragma Warnings
(Off
);
122 function Atomic_Fetch_Sub
123 (Ptr
: System
.Address
; Val
: Atomic_Type
; Model
: Mem_Model
:= Seq_Cst
)
125 pragma Import
(Intrinsic
, Atomic_Fetch_Sub
, "__atomic_fetch_sub");
126 pragma Warnings
(On
);
129 -- Use the direct intrinsics when possible, and fallback to
130 -- compare-and-exchange otherwise.
132 if Atomic_Type
'Base'Last = Atomic_Type'Last
133 and then Atomic_Type'Base'First
= Atomic_Type
'First
134 and then Atomic_Type
'Last = 2**(Atomic_Type
'Object_Size - 1) - 1
136 if Atomic_Type
'Object_Size in 8 |
16 |
32 |
64 then
137 return Atomic_Fetch_Sub
(Item
'Address, Value
);
144 Old_Value
: aliased Atomic_Type
:= Item
;
145 New_Value
: Atomic_Type
:= Old_Value
- Value
;
147 -- Keep iterating until the exchange succeeds
149 while not Exchange
.Atomic_Compare_And_Exchange
150 (Item
, Old_Value
, New_Value
)
152 New_Value
:= Old_Value
- Value
;
158 end Atomic_Fetch_And_Subtract
;
164 function Is_Lock_Free
(Item
: aliased Atomic_Type
) return Boolean is
165 pragma Unreferenced
(Item
);
166 use type Interfaces
.C
.size_t
;
168 return Atomic_Always_Lock_Free
(Atomic_Type
'Object_Size / 8);
171 end System
.Atomic_Operations
.Integer_Arithmetic
;