diff --git a/libraries/libstratosphere/include/stratosphere/util.hpp b/libraries/libstratosphere/include/stratosphere/util.hpp index ba8a04e57..85f0625df 100644 --- a/libraries/libstratosphere/include/stratosphere/util.hpp +++ b/libraries/libstratosphere/include/stratosphere/util.hpp @@ -19,3 +19,4 @@ #include #include #include +#include diff --git a/libraries/libstratosphere/include/stratosphere/util/util_lock_free_atomic_type.hpp b/libraries/libstratosphere/include/stratosphere/util/util_lock_free_atomic_type.hpp new file mode 100644 index 000000000..1ede59f60 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/util/util_lock_free_atomic_type.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::util { + + template + struct LockFreeAtomicType { + volatile u32 _counter; + T _value[2]; + }; + + template + void StoreToLockFreeAtomicType(LockFreeAtomicType *p, const T &value) { + /* Get the current counter. */ + auto counter = p->_counter; + + /* Increment the counter. */ + ++counter; + + /* Store the updated value. */ + p->_value[counter % 2] = value; + + /* Fence memory. */ + os::FenceMemoryStoreStore(); + + /* Set the updated counter. */ + p->_counter = counter; + } + + template + T LoadFromLockFreeAtomicType(const LockFreeAtomicType *p) { + while (true) { + /* Get the counter. */ + auto counter = p->_counter; + + /* Get the value. */ + auto value = p->_value[counter % 2]; + + /* Fence memory. */ + os::FenceMemoryLoadLoad(); + + /* Check that the counter matches. */ + if (counter == p->_counter) { + return value; + } + } + } + +}