From b6a01bf42c9ec177d7e2fdad45d95322e32ec7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Mon, 23 Oct 2017 08:27:03 -0700 Subject: [PATCH] Added atomicFetchAndAddsat/Subsat. --- include/bx/bx.h | 8 +++++++ include/bx/cpu.h | 8 +++++++ include/bx/inline/bx.inl | 12 ++++++++++ include/bx/inline/cpu.inl | 30 +++++++++++++++++++++++++ src/string.cpp | 6 ----- tests/atomic_test.cpp | 46 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 tests/atomic_test.cpp diff --git a/include/bx/bx.h b/include/bx/bx.h index d07a624..c5e374e 100644 --- a/include/bx/bx.h +++ b/include/bx/bx.h @@ -44,6 +44,14 @@ namespace bx /// void xchg(void* _a, void* _b, size_t _numBytes); + /// + template + Ty min(const Ty& _a, const Ty& _b); + + /// + template + Ty max(const Ty& _a, const Ty& _b); + // http://cnicholson.net/2011/01/stupid-c-tricks-a-better-sizeof_array/ template char (&COUNTOF_REQUIRES_ARRAY_ARGUMENT(const T(&)[N]) )[N]; diff --git a/include/bx/cpu.h b/include/bx/cpu.h index fdf8e7e..40e67b6 100644 --- a/include/bx/cpu.h +++ b/include/bx/cpu.h @@ -50,6 +50,14 @@ namespace bx template Ty atomicFetchTestAndSub(volatile Ty* _ptr, Ty _test, Ty _value); + /// + template + Ty atomicFetchAndAddsat(volatile Ty* _ptr, Ty _value, Ty _max); + + /// + template + Ty atomicFetchAndSubsat(volatile Ty* _ptr, Ty _value, Ty _min); + /// void* atomicExchangePtr(void** _ptr, void* _new); diff --git a/include/bx/inline/bx.inl b/include/bx/inline/bx.inl index f8e9c63..ed6f63b 100644 --- a/include/bx/inline/bx.inl +++ b/include/bx/inline/bx.inl @@ -32,4 +32,16 @@ namespace bx Ty tmp = _a; _a = _b; _b = tmp; } + template + inline Ty min(const Ty& _a, const Ty& _b) + { + return _a < _b ? _a : _b; + } + + template + inline Ty max(const Ty& _a, const Ty& _b) + { + return _a > _b ? _a : _b; + } + } // namespace bx diff --git a/include/bx/inline/cpu.inl b/include/bx/inline/cpu.inl index 7d1dfbd..f4d8aa7 100644 --- a/include/bx/inline/cpu.inl +++ b/include/bx/inline/cpu.inl @@ -290,6 +290,36 @@ namespace bx return oldVal; } + template + Ty atomicFetchAndAddsat(volatile Ty* _ptr, Ty _value, Ty _max) + { + Ty oldVal; + Ty newVal = *_ptr; + do + { + oldVal = newVal; + newVal = atomicCompareAndSwap(_ptr, oldVal, newVal >= _max ? _max : min(_max, newVal+_value) ); + + } while (oldVal != newVal && oldVal != _max); + + return oldVal; + } + + template + Ty atomicFetchAndSubsat(volatile Ty* _ptr, Ty _value, Ty _min) + { + Ty oldVal; + Ty newVal = *_ptr; + do + { + oldVal = newVal; + newVal = atomicCompareAndSwap(_ptr, oldVal, newVal <= _min ? _min : max(_min, newVal-_value) ); + + } while (oldVal != newVal && oldVal != _min); + + return oldVal; + } + inline void* atomicExchangePtr(void** _ptr, void* _new) { #if BX_COMPILER_MSVC diff --git a/src/string.cpp b/src/string.cpp index eadd5c8..c9851c3 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -165,12 +165,6 @@ namespace bx return _ch; } - template - inline Ty min(Ty _a, Ty _b) - { - return _a > _b ? _b : _a; - } - template inline int32_t strCmp(const char* _lhs, int32_t _lhsMax, const char* _rhs, int32_t _rhsMax) { diff --git a/tests/atomic_test.cpp b/tests/atomic_test.cpp new file mode 100644 index 0000000..81b3318 --- /dev/null +++ b/tests/atomic_test.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2017 Branimir Karadzic. All rights reserved. + * License: https://github.com/bkaradzic/bx#license-bsd-2-clause + */ + +#include "test.h" +#include + +TEST_CASE("atomic", "") +{ + uint32_t test = 1337; + uint32_t fetched; + + fetched = bx::atomicFetchAndAdd(&test, 52u); + REQUIRE(fetched == 1337); + REQUIRE(test == 1389); + + fetched = bx::atomicAddAndFetch(&test, 64u); + REQUIRE(fetched == 1453); + REQUIRE(test == 1453); + + fetched = bx::atomicFetchAndSub(&test, 64u); + REQUIRE(fetched == 1453); + REQUIRE(test == 1389); + + fetched = bx::atomicSubAndFetch(&test, 52u); + REQUIRE(fetched == 1337); + REQUIRE(test == 1337); + + fetched = bx::atomicFetchAndAddsat(&test, 52u, 1453u); + REQUIRE(fetched == 1337); + REQUIRE(test == 1389); + + fetched = bx::atomicFetchAndAddsat(&test, 1000u, 1453u); + REQUIRE(fetched == 1389); + REQUIRE(test == 1453); + + fetched = bx::atomicFetchAndSubsat(&test, 64u, 1337u); + REQUIRE(fetched == 1453); + REQUIRE(test == 1389); + + fetched = bx::atomicFetchAndSubsat(&test, 1000u, 1337u); + REQUIRE(fetched == 1389); + REQUIRE(test == 1337); + +}