Skip to content

Commit c0e6b5b

Browse files
NHDalyJeffBezanson
authored andcommitted
Add support for Atomic{Bool} (Fix #26542). (#26597)
Adds `Bool` to list of types supported by `Atomic{T}`. Defines all `atomic_*!` for `Bool`, except `atomic_add!` and `atomic_sub!` since `add(::Bool, ::Bool)` returns an `Int`. Also adds tests for those methods to `test/threads.jl`.
1 parent 9660a30 commit c0e6b5b

File tree

2 files changed

+34
-11
lines changed

2 files changed

+34
-11
lines changed

base/atomics.jl

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ else
2626
UInt8, UInt16, UInt32, UInt64, UInt128)
2727
end
2828
const floattypes = (Float16, Float32, Float64)
29-
# TODO: Support Bool, Ptr
30-
const atomictypes = (inttypes..., floattypes...)
29+
const arithmetictypes = (inttypes..., floattypes...)
30+
# TODO: Support Ptr
31+
const atomictypes = (arithmetictypes..., Bool)
3132
const IntTypes = Union{inttypes...}
3233
const FloatTypes = Union{floattypes...}
34+
const ArithmeticTypes = Union{arithmetictypes...}
3335
const AtomicTypes = Union{atomictypes...}
3436

3537
"""
@@ -39,8 +41,8 @@ Holds a reference to an object of type `T`, ensuring that it is only
3941
accessed atomically, i.e. in a thread-safe manner.
4042
4143
Only certain "simple" types can be used atomically, namely the
42-
primitive integer and float-point types. These are `Int8`...`Int128`,
43-
`UInt8`...`UInt128`, and `Float16`...`Float64`.
44+
primitive boolean, integer, and float-point types. These are `Bool`,
45+
`Int8`...`Int128`, `UInt8`...`UInt128`, and `Float16`...`Float64`.
4446
4547
New atomic objects can be created from a non-atomic values; if none is
4648
specified, the atomic object is initialized with zero.
@@ -130,11 +132,12 @@ julia> x[]
130132
function atomic_xchg! end
131133

132134
"""
133-
Threads.atomic_add!(x::Atomic{T}, val::T) where T
135+
Threads.atomic_add!(x::Atomic{T}, val::T) where T <: ArithmeticTypes
134136
135137
Atomically add `val` to `x`
136138
137-
Performs `x[] += val` atomically. Returns the **old** value.
139+
Performs `x[] += val` atomically. Returns the **old** value. Not defined for
140+
`Atomic{Bool}`.
138141
139142
For further details, see LLVM's `atomicrmw add` instruction.
140143
@@ -153,11 +156,12 @@ julia> x[]
153156
function atomic_add! end
154157

155158
"""
156-
Threads.atomic_sub!(x::Atomic{T}, val::T) where T
159+
Threads.atomic_sub!(x::Atomic{T}, val::T) where T <: ArithmeticTypes
157160
158161
Atomically subtract `val` from `x`
159162
160-
Performs `x[] -= val` atomically. Returns the **old** value.
163+
Performs `x[] -= val` atomically. Returns the **old** value. Not defined for
164+
`Atomic{Bool}`.
161165
162166
For further details, see LLVM's `atomicrmw sub` instruction.
163167
@@ -317,7 +321,7 @@ unsafe_convert(::Type{Ptr{T}}, x::Atomic{T}) where {T} = convert(Ptr{T}, pointer
317321
setindex!(x::Atomic{T}, v) where {T} = setindex!(x, convert(T, v))
318322

319323
const llvmtypes = IdDict{Any,String}(
320-
Bool => "i1",
324+
Bool => "i8", # julia represents bools with 8-bits for now. # TODO: is this okay?
321325
Int8 => "i8", UInt8 => "i8",
322326
Int16 => "i16", UInt16 => "i16",
323327
Int32 => "i32", UInt32 => "i32",
@@ -380,13 +384,15 @@ for typ in atomictypes
380384
unsafe_convert(Ptr{$typ}, x), cmp, new)
381385
end
382386

383-
for rmwop in [:xchg, :add, :sub, :and, :nand, :or, :xor, :max, :min]
387+
arithmetic_ops = [:add, :sub]
388+
for rmwop in [arithmetic_ops..., :xchg, :and, :nand, :or, :xor, :max, :min]
384389
rmw = string(rmwop)
385390
fn = Symbol("atomic_", rmw, "!")
386391
if (rmw == "max" || rmw == "min") && typ <: Unsigned
387392
# LLVM distinguishes signedness in the operation, not the integer type.
388393
rmw = "u" * rmw
389394
end
395+
if rmwop in arithmetic_ops && !(typ <: ArithmeticTypes) continue end
390396
if typ <: Integer
391397
@eval $fn(x::Atomic{$typ}, v::$typ) =
392398
llvmcall($"""

test/threads.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,27 @@ end
171171
end
172172

173173
# Ensure only LLVM-supported types can be atomic
174-
@test_throws TypeError Atomic{Bool}
175174
@test_throws TypeError Atomic{BigInt}
176175
@test_throws TypeError Atomic{ComplexF64}
177176

177+
function test_atomic_bools()
178+
x = Atomic{Bool}(false)
179+
# Arithmetic functions are not defined.
180+
@test_throws MethodError atomic_add!(x, true)
181+
@test_throws MethodError atomic_sub!(x, true)
182+
# All the rest are:
183+
for v in [true, false]
184+
@test x[] == atomic_xchg!(x, v)
185+
@test v == atomic_cas!(x, v, !v)
186+
end
187+
x = Atomic{Bool}(false)
188+
@test false == atomic_max!(x, true); @test x[] == true
189+
x = Atomic{Bool}(true)
190+
@test true == atomic_and!(x, false); @test x[] == false
191+
end
192+
193+
test_atomic_bools()
194+
178195
# Test atomic memory ordering with load/store
179196
mutable struct CommBuf
180197
var1::Atomic{Int}

0 commit comments

Comments
 (0)