Files
Nim/tests/stdlib/concurrency/tatomics.nim
ringabout 4fa86422c0 stdlib tests now check refc too (#21664)
* stdlib tests now check refc too

* typo

* fixes line numbers

* disable cpp

* do not touch
2023-04-21 15:37:58 +02:00

636 lines
21 KiB
Nim

discard """
matrix: "--mm:refc; --mm:orc"
"""
# test atomic operations
import std/[atomics, bitops]
import std/assertions
type
Object = object
val: int
# Atomic operations for trivial objects
block trivialLoad:
var location: Atomic[int]
location.store(1)
doAssert location.load == 1
location.store(2)
doAssert location.load(moRelaxed) == 2
location.store(3)
doAssert location.load(moAcquire) == 3
block trivialStore:
var location: Atomic[int]
location.store(1)
doAssert location.load == 1
location.store(2, moRelaxed)
doAssert location.load == 2
location.store(3, moRelease)
doAssert location.load == 3
block trivialExchange:
var location: Atomic[int]
location.store(1)
doAssert location.exchange(2) == 1
doAssert location.exchange(3, moRelaxed) == 2
doAssert location.exchange(4, moAcquire) == 3
doAssert location.exchange(5, moRelease) == 4
doAssert location.exchange(6, moAcquireRelease) == 5
doAssert location.load == 6
block trivialCompareExchangeDoesExchange:
var location: Atomic[int]
var expected = 1
location.store(1)
doAssert location.compareExchange(expected, 2)
doAssert expected == 1
doAssert location.load == 2
expected = 2
doAssert location.compareExchange(expected, 3, moRelaxed)
doAssert expected == 2
doAssert location.load == 3
expected = 3
doAssert location.compareExchange(expected, 4, moAcquire)
doAssert expected == 3
doAssert location.load == 4
expected = 4
doAssert location.compareExchange(expected, 5, moRelease)
doAssert expected == 4
doAssert location.load == 5
expected = 5
doAssert location.compareExchange(expected, 6, moAcquireRelease)
doAssert expected == 5
doAssert location.load == 6
block trivialCompareExchangeDoesNotExchange:
var location: Atomic[int]
var expected = 10
location.store(1)
doAssert not location.compareExchange(expected, 2)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 3, moRelaxed)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 4, moAcquire)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 5, moRelease)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 6, moAcquireRelease)
doAssert expected == 1
doAssert location.load == 1
block trivialCompareExchangeSuccessFailureDoesExchange:
var location: Atomic[int]
var expected = 1
location.store(1)
doAssert location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == 1
doAssert location.load == 2
expected = 2
doAssert location.compareExchange(expected, 3, moRelaxed, moRelaxed)
doAssert expected == 2
doAssert location.load == 3
expected = 3
doAssert location.compareExchange(expected, 4, moAcquire, moAcquire)
doAssert expected == 3
doAssert location.load == 4
expected = 4
doAssert location.compareExchange(expected, 5, moRelease, moRelease)
doAssert expected == 4
doAssert location.load == 5
expected = 5
doAssert location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease)
doAssert expected == 5
doAssert location.load == 6
block trivialCompareExchangeSuccessFailureDoesNotExchange:
var location: Atomic[int]
var expected = 10
location.store(1)
doAssert not location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 3, moRelaxed, moRelaxed)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 4, moAcquire, moAcquire)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 5, moRelease, moRelease)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease)
doAssert expected == 1
doAssert location.load == 1
block trivialCompareExchangeWeakDoesExchange:
var location: Atomic[int]
var expected = 1
location.store(1)
doAssert location.compareExchangeWeak(expected, 2)
doAssert expected == 1
doAssert location.load == 2
expected = 2
doAssert location.compareExchangeWeak(expected, 3, moRelaxed)
doAssert expected == 2
doAssert location.load == 3
expected = 3
doAssert location.compareExchangeWeak(expected, 4, moAcquire)
doAssert expected == 3
doAssert location.load == 4
expected = 4
doAssert location.compareExchangeWeak(expected, 5, moRelease)
doAssert expected == 4
doAssert location.load == 5
expected = 5
doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease)
doAssert expected == 5
doAssert location.load == 6
block trivialCompareExchangeWeakDoesNotExchange:
var location: Atomic[int]
var expected = 10
location.store(1)
doAssert not location.compareExchangeWeak(expected, 2)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 3, moRelaxed)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 4, moAcquire)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 5, moRelease)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease)
doAssert expected == 1
doAssert location.load == 1
block trivialCompareExchangeWeakSuccessFailureDoesExchange:
var location: Atomic[int]
var expected = 1
location.store(1)
doAssert location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == 1
doAssert location.load == 2
expected = 2
doAssert location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed)
doAssert expected == 2
doAssert location.load == 3
expected = 3
doAssert location.compareExchangeWeak(expected, 4, moAcquire, moAcquire)
doAssert expected == 3
doAssert location.load == 4
expected = 4
doAssert location.compareExchangeWeak(expected, 5, moRelease, moRelease)
doAssert expected == 4
doAssert location.load == 5
expected = 5
doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease)
doAssert expected == 5
doAssert location.load == 6
block trivialCompareExchangeWeakSuccessFailureDoesNotExchange:
var location: Atomic[int]
var expected = 10
location.store(1)
doAssert not location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 4, moAcquire, moAcquire)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 5, moRelease, moRelease)
doAssert expected == 1
doAssert location.load == 1
expected = 10
doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease)
doAssert expected == 1
doAssert location.load == 1
# Atomic operations for non-trivial objects
block objectLoad:
var location: Atomic[Object]
location.store(Object(val: 1))
doAssert location.load == Object(val: 1)
location.store(Object(val: 2))
doAssert location.load(moRelaxed) == Object(val: 2)
location.store(Object(val: 3))
doAssert location.load(moAcquire) == Object(val: 3)
block objectStore:
var location: Atomic[Object]
location.store(Object(val: 1))
doAssert location.load == Object(val: 1)
location.store(Object(val: 2), moRelaxed)
doAssert location.load == Object(val: 2)
location.store(Object(val: 3), moRelease)
doAssert location.load == Object(val: 3)
block objectExchange:
var location: Atomic[Object]
location.store(Object(val: 1))
doAssert location.exchange(Object(val: 2)) == Object(val: 1)
doAssert location.exchange(Object(val: 3), moRelaxed) == Object(val: 2)
doAssert location.exchange(Object(val: 4), moAcquire) == Object(val: 3)
doAssert location.exchange(Object(val: 5), moRelease) == Object(val: 4)
doAssert location.exchange(Object(val: 6), moAcquireRelease) == Object(val: 5)
doAssert location.load == Object(val: 6)
block objectCompareExchangeDoesExchange:
var location: Atomic[Object]
var expected = Object(val: 1)
location.store(Object(val: 1))
doAssert location.compareExchange(expected, Object(val: 2))
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 2)
expected = Object(val: 2)
doAssert location.compareExchange(expected, Object(val: 3), moRelaxed)
doAssert expected == Object(val: 2)
doAssert location.load == Object(val: 3)
expected = Object(val: 3)
doAssert location.compareExchange(expected, Object(val: 4), moAcquire)
doAssert expected == Object(val: 3)
doAssert location.load == Object(val: 4)
expected = Object(val: 4)
doAssert location.compareExchange(expected, Object(val: 5), moRelease)
doAssert expected == Object(val: 4)
doAssert location.load == Object(val: 5)
expected = Object(val: 5)
doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease)
doAssert expected == Object(val: 5)
doAssert location.load == Object(val: 6)
block objectCompareExchangeDoesNotExchange:
var location: Atomic[Object]
var expected = Object(val: 10)
location.store(Object(val: 1))
doAssert not location.compareExchange(expected, Object(val: 2))
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 4), moAcquire)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 5), moRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
block objectCompareExchangeSuccessFailureDoesExchange:
var location: Atomic[Object]
var expected = Object(val: 1)
location.store(Object(val: 1))
doAssert location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 2)
expected = Object(val: 2)
doAssert location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed)
doAssert expected == Object(val: 2)
doAssert location.load == Object(val: 3)
expected = Object(val: 3)
doAssert location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire)
doAssert expected == Object(val: 3)
doAssert location.load == Object(val: 4)
expected = Object(val: 4)
doAssert location.compareExchange(expected, Object(val: 5), moRelease, moRelease)
doAssert expected == Object(val: 4)
doAssert location.load == Object(val: 5)
expected = Object(val: 5)
doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
doAssert expected == Object(val: 5)
doAssert location.load == Object(val: 6)
block objectCompareExchangeSuccessFailureDoesNotExchange:
var location: Atomic[Object]
var expected = Object(val: 10)
location.store(Object(val: 1))
doAssert not location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 5), moRelease, moRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
block objectCompareExchangeWeakDoesExchange:
var location: Atomic[Object]
var expected = Object(val: 1)
location.store(Object(val: 1))
doAssert location.compareExchangeWeak(expected, Object(val: 2))
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 2)
expected = Object(val: 2)
doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed)
doAssert expected == Object(val: 2)
doAssert location.load == Object(val: 3)
expected = Object(val: 3)
doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire)
doAssert expected == Object(val: 3)
doAssert location.load == Object(val: 4)
expected = Object(val: 4)
doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease)
doAssert expected == Object(val: 4)
doAssert location.load == Object(val: 5)
expected = Object(val: 5)
doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease)
doAssert expected == Object(val: 5)
doAssert location.load == Object(val: 6)
block objectCompareExchangeWeakDoesNotExchange:
var location: Atomic[Object]
var expected = Object(val: 10)
location.store(Object(val: 1))
doAssert not location.compareExchangeWeak(expected, Object(val: 2))
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
block objectCompareExchangeWeakSuccessFailureDoesExchange:
var location: Atomic[Object]
var expected = Object(val: 1)
location.store(Object(val: 1))
doAssert location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 2)
expected = Object(val: 2)
doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed)
doAssert expected == Object(val: 2)
doAssert location.load == Object(val: 3)
expected = Object(val: 3)
doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire)
doAssert expected == Object(val: 3)
doAssert location.load == Object(val: 4)
expected = Object(val: 4)
doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease)
doAssert expected == Object(val: 4)
doAssert location.load == Object(val: 5)
expected = Object(val: 5)
doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
doAssert expected == Object(val: 5)
doAssert location.load == Object(val: 6)
block objectCompareExchangeWeakSuccessFailureDoesNotExchange:
var location: Atomic[Object]
var expected = Object(val: 10)
location.store(Object(val: 1))
doAssert not location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
expected = Object(val: 10)
doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
doAssert expected == Object(val: 1)
doAssert location.load == Object(val: 1)
# Numerical operations
block fetchAdd:
var location: Atomic[int]
doAssert location.fetchAdd(1) == 0
doAssert location.fetchAdd(1, moRelaxed) == 1
doAssert location.fetchAdd(1, moRelease) == 2
doAssert location.load == 3
block fetchSub:
var location: Atomic[int]
doAssert location.fetchSub(1) == 0
doAssert location.fetchSub(1, moRelaxed) == -1
doAssert location.fetchSub(1, moRelease) == -2
doAssert location.load == -3
block fetchAnd:
var location: Atomic[int]
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchAnd(j) == i)
doAssert(location.load == i.bitand(j))
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchAnd(j, moRelaxed) == i)
doAssert(location.load == i.bitand(j))
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchAnd(j, moRelease) == i)
doAssert(location.load == i.bitand(j))
block fetchOr:
var location: Atomic[int]
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchOr(j) == i)
doAssert(location.load == i.bitor(j))
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchOr(j, moRelaxed) == i)
doAssert(location.load == i.bitor(j))
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchOr(j, moRelease) == i)
doAssert(location.load == i.bitor(j))
block fetchXor:
var location: Atomic[int]
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchXor(j) == i)
doAssert(location.load == i.bitxor(j))
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchXor(j, moRelaxed) == i)
doAssert(location.load == i.bitxor(j))
for i in 0..16:
for j in 0..16:
location.store(i)
doAssert(location.fetchXor(j, moRelease) == i)
doAssert(location.load == i.bitxor(j))
block atomicInc:
var location: Atomic[int]
location.atomicInc
doAssert location.load == 1
location.atomicInc(1)
doAssert location.load == 2
location += 1
doAssert location.load == 3
block atomicDec:
var location: Atomic[int]
location.atomicDec
doAssert location.load == -1
location.atomicDec(1)
doAssert location.load == -2
location -= 1
doAssert location.load == -3
# Flag operations
block testAndSet:
var location: AtomicFlag
doAssert not location.testAndSet
doAssert location.testAndSet
doAssert location.testAndSet
location.clear()
doAssert not location.testAndSet(moRelaxed)
doAssert location.testAndSet(moRelaxed)
doAssert location.testAndSet(moRelaxed)
location.clear()
doAssert not location.testAndSet(moRelease)
doAssert location.testAndSet(moRelease)
doAssert location.testAndSet(moRelease)
block clear:
var location: AtomicFlag
discard location.testAndSet
location.clear
doAssert not location.testAndSet
location.clear(moRelaxed)
doAssert not location.testAndSet
location.clear(moRelease)
doAssert not location.testAndSet
block: # bug #18844
when not defined(cpp): # cpp pending pr #18836
type
Deprivation = object of RootObj
memes: Atomic[int]
Zoomer = object
dopamine: Deprivation
block:
var x = Deprivation()
var y = Zoomer()
doAssert x.memes.load == 0
doAssert y.dopamine.memes.load == 0
block:
var x: Deprivation
var y: Zoomer
doAssert x.memes.load == 0
doAssert y.dopamine.memes.load == 0