diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 6dbede6d7e5..04e668049c4 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -2772,7 +2772,7 @@ void _Thread::_start_func(void *ud) { Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) { - ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "Thread already started."); + ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started."); ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER); @@ -2781,7 +2781,7 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia target_method = p_method; target_instance = p_instance; userdata = p_userdata; - active = true; + active.set(); Ref<_Thread> *ud = memnew(Ref<_Thread>(this)); @@ -2799,17 +2799,17 @@ String _Thread::get_id() const { bool _Thread::is_active() const { - return active; + return active.is_set(); } Variant _Thread::wait_to_finish() { - ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion."); + ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion."); thread.wait_to_finish(); Variant r = ret; - active = false; target_method = StringName(); target_instance = NULL; userdata = Variant(); + active.clear(); return r; } @@ -2827,13 +2827,12 @@ void _Thread::_bind_methods() { } _Thread::_Thread() { - active = false; target_instance = NULL; } _Thread::~_Thread() { - ERR_FAIL_COND_MSG(active, "Reference to a Thread object was lost while the thread is still running..."); + ERR_FAIL_COND_MSG(active.is_set(), "Reference to a Thread object was lost while the thread is still running..."); } ///////////////////////////////////// diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 08f6c0b5c8c..fb7a276e934 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -40,6 +40,7 @@ #include "core/os/os.h" #include "core/os/semaphore.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" class _ResourceLoader : public Object { GDCLASS(_ResourceLoader, Object); @@ -681,7 +682,7 @@ class _Thread : public Reference { protected: Variant ret; Variant userdata; - volatile bool active; + SafeFlag active; Object *target_instance; StringName target_method; Thread thread; diff --git a/core/cowdata.h b/core/cowdata.h index 8739e5b57ef..d43688512ab 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -44,6 +44,9 @@ class CharString; template class VMap; +// CowData is relying on this to be true +static_assert(sizeof(SafeNumeric) == sizeof(uint32_t), ""); + template class CowData { template @@ -58,12 +61,12 @@ private: // internal helpers - _FORCE_INLINE_ uint32_t *_get_refcount() const { + _FORCE_INLINE_ SafeNumeric *_get_refcount() const { if (!_ptr) return NULL; - return reinterpret_cast(_ptr) - 2; + return reinterpret_cast *>(_ptr) - 2; } _FORCE_INLINE_ uint32_t *_get_size() const { @@ -193,9 +196,9 @@ void CowData::_unref(void *p_data) { if (!p_data) return; - uint32_t *refc = _get_refcount(); + SafeNumeric *refc = _get_refcount(); - if (atomic_decrement(refc) > 0) + if (refc->decrement() > 0) return; // still in use // clean up @@ -219,15 +222,15 @@ void CowData::_copy_on_write() { if (!_ptr) return; - uint32_t *refc = _get_refcount(); + SafeNumeric *refc = _get_refcount(); - if (unlikely(*refc > 1)) { + if (unlikely(refc->get() > 1)) { /* in use by more than me */ uint32_t current_size = *_get_size(); uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true); - *(mem_new - 2) = 1; //refcount + reinterpret_cast *>(mem_new - 2)->set(1); //refcount *(mem_new - 1) = current_size; //size T *_data = (T *)(mem_new); @@ -279,7 +282,7 @@ Error CowData::resize(int p_size) { uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true); ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY); *(ptr - 1) = 0; //size, currently none - *(ptr - 2) = 1; //refcount + reinterpret_cast *>(ptr - 2)->set(1); //refcount _ptr = (T *)ptr; @@ -360,7 +363,7 @@ void CowData::_ref(const CowData &p_from) { if (!p_from._ptr) return; //nothing to do - if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference + if (p_from._get_refcount()->increment() > 0) { // could reference _ptr = p_from._ptr; } } diff --git a/core/error_macros.h b/core/error_macros.h index 27d48c26b55..c9ab2d58039 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -31,7 +31,9 @@ #ifndef ERROR_MACROS_H #define ERROR_MACROS_H +#include "core/safe_refcount.h" #include "core/typedefs.h" + /** * Error macros. Unlike exceptions and asserts, these macros try to maintain consistency and stability * inside the code. It is recommended to always return processable data, so in case of an error, @@ -532,10 +534,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li */ #define WARN_DEPRECATED \ { \ - static volatile bool warning_shown = false; \ - if (!warning_shown) { \ + static SafeFlag warning_shown; \ + if (!warning_shown.is_set()) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \ - warning_shown = true; \ + warning_shown.set(); \ } \ } @@ -545,10 +547,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li */ #define WARN_DEPRECATED_MSG(m_msg) \ { \ - static volatile bool warning_shown = false; \ - if (!warning_shown) { \ + static SafeFlag warning_shown; \ + if (!warning_shown.is_set()) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, ERR_HANDLER_WARNING); \ - warning_shown = true; \ + warning_shown.set(); \ } \ } diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 152776dec40..3c755be451d 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -42,13 +42,13 @@ struct _IP_ResolverPrivate { struct QueueItem { - volatile IP::ResolverStatus status; + SafeNumeric status; IP_Address response; String hostname; IP::Type type; void clear() { - status = IP::RESOLVER_STATUS_NONE; + status.set(IP::RESOLVER_STATUS_NONE); response = IP_Address(); type = IP::TYPE_NONE; hostname = ""; @@ -64,7 +64,7 @@ struct _IP_ResolverPrivate { IP::ResolverID find_empty_id() const { for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) { - if (queue[i].status == IP::RESOLVER_STATUS_NONE) + if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE) return i; } return IP::RESOLVER_INVALID_ID; @@ -81,14 +81,14 @@ struct _IP_ResolverPrivate { for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) { - if (queue[i].status != IP::RESOLVER_STATUS_WAITING) + if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) continue; queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type); if (!queue[i].response.is_valid()) - queue[i].status = IP::RESOLVER_STATUS_ERROR; + queue[i].status.set(IP::RESOLVER_STATUS_ERROR); else - queue[i].status = IP::RESOLVER_STATUS_DONE; + queue[i].status.set(IP::RESOLVER_STATUS_DONE); } } @@ -147,10 +147,10 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ resolver->queue[id].type = p_type; if (resolver->cache.has(key) && resolver->cache[key].is_valid()) { resolver->queue[id].response = resolver->cache[key]; - resolver->queue[id].status = IP::RESOLVER_STATUS_DONE; + resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE); } else { resolver->queue[id].response = IP_Address(); - resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING; + resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING); if (resolver->thread.is_started()) resolver->sem.post(); else @@ -166,12 +166,12 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const { ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP::RESOLVER_STATUS_NONE); resolver->mutex.lock(); - if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) { + if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) { ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE"); resolver->mutex.unlock(); return IP::RESOLVER_STATUS_NONE; } - IP::ResolverStatus res = resolver->queue[p_id].status; + IP::ResolverStatus res = resolver->queue[p_id].status.get(); resolver->mutex.unlock(); return res; @@ -183,7 +183,7 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const { resolver->mutex.lock(); - if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) { + if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) { ERR_PRINTS("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet."); resolver->mutex.unlock(); return IP_Address(); @@ -201,7 +201,7 @@ void IP::erase_resolve_item(ResolverID p_id) { resolver->mutex.lock(); - resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE; + resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE); resolver->mutex.unlock(); } diff --git a/core/object.cpp b/core/object.cpp index 5a7f759806a..27d95dcf252 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -1946,7 +1946,7 @@ void *Object::get_script_instance_binding(int p_script_language_index) { if (!_script_instance_bindings[p_script_language_index]) { void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this); if (script_data) { - atomic_increment(&instance_binding_count); + instance_binding_count.increment(); _script_instance_bindings[p_script_language_index] = script_data; } } @@ -1976,7 +1976,6 @@ Object::Object() { _can_translate = true; _is_queued_for_deletion = false; _emitting = false; - instance_binding_count = 0; memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); script_instance = NULL; #ifdef DEBUG_ENABLED diff --git a/core/object.h b/core/object.h index 50e8468b2d3..8e20eea74dd 100644 --- a/core/object.h +++ b/core/object.h @@ -36,6 +36,7 @@ #include "core/map.h" #include "core/object_id.h" #include "core/os/rw_lock.h" +#include "core/safe_refcount.h" #include "core/set.h" #include "core/variant.h" #include "core/vmap.h" @@ -512,7 +513,7 @@ private: Variant _get_indexed_bind(const NodePath &p_name) const; friend class Reference; - uint32_t instance_binding_count; + SafeNumeric instance_binding_count; void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; protected: diff --git a/core/os/memory.cpp b/core/os/memory.cpp index 9a37e2194d3..5c47efc7628 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -65,11 +65,11 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d #endif #ifdef DEBUG_ENABLED -uint64_t Memory::mem_usage = 0; -uint64_t Memory::max_usage = 0; +SafeNumeric Memory::mem_usage; +SafeNumeric Memory::max_usage; #endif -uint64_t Memory::alloc_count = 0; +SafeNumeric Memory::alloc_count; void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { @@ -83,7 +83,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { ERR_FAIL_COND_V(!mem, NULL); - atomic_increment(&alloc_count); + alloc_count.increment(); if (prepad) { uint64_t *s = (uint64_t *)mem; @@ -92,8 +92,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) { uint8_t *s8 = (uint8_t *)mem; #ifdef DEBUG_ENABLED - atomic_add(&mem_usage, p_bytes); - atomic_exchange_if_greater(&max_usage, mem_usage); + uint64_t new_mem_usage = mem_usage.add(p_bytes); + max_usage.exchange_if_greater(new_mem_usage); #endif return s8 + PAD_ALIGN; } else { @@ -121,10 +121,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) { #ifdef DEBUG_ENABLED if (p_bytes > *s) { - atomic_add(&mem_usage, p_bytes - *s); - atomic_exchange_if_greater(&max_usage, mem_usage); + uint64_t new_mem_usage = mem_usage.add(p_bytes - *s); + max_usage.exchange_if_greater(new_mem_usage); } else { - atomic_sub(&mem_usage, *s - p_bytes); + mem_usage.sub(*s - p_bytes); } #endif @@ -165,14 +165,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) { bool prepad = p_pad_align; #endif - atomic_decrement(&alloc_count); + alloc_count.decrement(); if (prepad) { mem -= PAD_ALIGN; #ifdef DEBUG_ENABLED uint64_t *s = (uint64_t *)mem; - atomic_sub(&mem_usage, *s); + mem_usage.sub(*s); #endif free(mem); @@ -189,7 +189,7 @@ uint64_t Memory::get_mem_available() { uint64_t Memory::get_mem_usage() { #ifdef DEBUG_ENABLED - return mem_usage; + return mem_usage.get(); #else return 0; #endif @@ -197,7 +197,7 @@ uint64_t Memory::get_mem_usage() { uint64_t Memory::get_mem_max_usage() { #ifdef DEBUG_ENABLED - return max_usage; + return max_usage.get(); #else return 0; #endif diff --git a/core/os/memory.h b/core/os/memory.h index 1541464b869..84ff44c3a21 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -44,11 +44,11 @@ class Memory { Memory(); #ifdef DEBUG_ENABLED - static uint64_t mem_usage; - static uint64_t max_usage; + static SafeNumeric mem_usage; + static SafeNumeric max_usage; #endif - static uint64_t alloc_count; + static SafeNumeric alloc_count; public: static void *alloc_static(size_t p_bytes, bool p_pad_align = false); diff --git a/core/os/thread.cpp b/core/os/thread.cpp index 7ace779da16..ff1c03ca8e7 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -34,13 +34,15 @@ #if !defined(NO_THREADS) +#include "core/safe_refcount.h" + Error (*Thread::set_name_func)(const String &) = nullptr; void (*Thread::set_priority_func)(Thread::Priority) = nullptr; void (*Thread::init_func)() = nullptr; void (*Thread::term_func)() = nullptr; Thread::ID Thread::main_thread_id = 1; -Thread::ID Thread::last_thread_id = 1; +SafeNumeric Thread::last_thread_id{ 1 }; thread_local Thread::ID Thread::caller_id = 1; void Thread::_set_platform_funcs( @@ -79,7 +81,7 @@ void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_ std::thread empty_thread; thread.swap(empty_thread); } - id = atomic_increment(&last_thread_id); + id = last_thread_id.increment(); std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user); thread.swap(new_thread); } diff --git a/core/os/thread.h b/core/os/thread.h index 38861a568bc..837f9323c37 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -34,6 +34,7 @@ #include "core/typedefs.h" #if !defined(NO_THREADS) +#include "core/safe_refcount.h" #include #endif @@ -61,7 +62,7 @@ private: friend class Main; static ID main_thread_id; - static ID last_thread_id; + static SafeNumeric last_thread_id; ID id; static thread_local ID caller_id; diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h index 797dcc9b998..94783ddb660 100644 --- a/core/os/threaded_array_processor.h +++ b/core/os/threaded_array_processor.h @@ -40,7 +40,7 @@ template struct ThreadArrayProcessData { uint32_t elements; - uint32_t index; + SafeNumeric index; C *instance; U userdata; void (C::*method)(uint32_t, U); @@ -57,7 +57,7 @@ void process_array_thread(void *ud) { T &data = *(T *)ud; while (true) { - uint32_t index = atomic_increment(&data.index); + uint32_t index = data.index.increment(); if (index >= data.elements) break; data.process(index); @@ -71,9 +71,9 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us data.method = p_method; data.instance = p_instance; data.userdata = p_userdata; - data.index = 0; + data.index.set(0); data.elements = p_elements; - data.process(data.index); //process first, let threads increment for next + data.process(0); //process first, let threads increment for next int thread_count = OS::get_singleton()->get_processor_count(); Thread *threads = memnew_arr(Thread, thread_count); diff --git a/core/pool_vector.h b/core/pool_vector.h index 8798390d935..dc7a5fe81c3 100644 --- a/core/pool_vector.h +++ b/core/pool_vector.h @@ -33,6 +33,7 @@ #include "core/os/copymem.h" #include "core/os/memory.h" +#include "core/os/mutex.h" #include "core/os/rw_lock.h" #include "core/pool_allocator.h" #include "core/safe_refcount.h" @@ -49,7 +50,7 @@ struct MemoryPool { struct Alloc { SafeRefCount refcount; - uint32_t lock; + SafeNumeric lock; void *mem; PoolAllocator::ID pool_id; size_t size; @@ -113,7 +114,7 @@ class PoolVector { alloc->size = old_alloc->size; alloc->refcount.init(); alloc->pool_id = POOL_ALLOCATOR_INVALID_ID; - alloc->lock = 0; + alloc->lock.set(0); #ifdef DEBUG_ENABLED MemoryPool::total_memory += alloc->size; @@ -263,7 +264,7 @@ public: _FORCE_INLINE_ void _ref(MemoryPool::Alloc *p_alloc) { alloc = p_alloc; if (alloc) { - if (atomic_increment(&alloc->lock) == 1) { + if (alloc->lock.increment() == 1) { if (MemoryPool::memory_pool) { //lock it and get mem } @@ -276,7 +277,7 @@ public: _FORCE_INLINE_ void _unref() { if (alloc) { - if (atomic_decrement(&alloc->lock) == 0) { + if (alloc->lock.decrement() == 0) { if (MemoryPool::memory_pool) { //put mem back } @@ -452,7 +453,7 @@ public: return rs; } - bool is_locked() const { return alloc && alloc->lock > 0; } + bool is_locked() const { return alloc && alloc->lock.get() > 0; } inline T operator[](int p_index) const; @@ -543,7 +544,7 @@ Error PoolVector::resize(int p_size) { } else { - ERR_FAIL_COND_V_MSG(alloc->lock > 0, ERR_LOCKED, "Can't resize PoolVector if locked."); //can't resize if locked! + ERR_FAIL_COND_V_MSG(alloc->lock.get() > 0, ERR_LOCKED, "Can't resize PoolVector if locked."); //can't resize if locked! } size_t new_size = sizeof(T) * p_size; diff --git a/core/reference.cpp b/core/reference.cpp index 1ba9e6151aa..9fd732e4ba4 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -67,7 +67,7 @@ bool Reference::reference() { if (get_script_instance()) { get_script_instance()->refcount_incremented(); } - if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) { + if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { if (_script_instance_bindings[i]) { ScriptServer::get_language(i)->refcount_incremented_instance_binding(this); @@ -89,7 +89,7 @@ bool Reference::unreference() { bool script_ret = get_script_instance()->refcount_decremented(); die = die && script_ret; } - if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) { + if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { if (_script_instance_bindings[i]) { bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this); diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp deleted file mode 100644 index 376d9a99e4d..00000000000 --- a/core/safe_refcount.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/*************************************************************************/ -/* safe_refcount.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "safe_refcount.h" - -#if defined(_MSC_VER) - -/* Implementation for MSVC-Windows */ - -// don't pollute my namespace! -#include - -#define ATOMIC_CONDITIONAL_INCREMENT_BODY(m_pw, m_win_type, m_win_cmpxchg, m_cpp_type) \ - /* try to increment until it actually works */ \ - /* taken from boost */ \ - while (true) { \ - m_cpp_type tmp = static_cast(*(m_pw)); \ - if (tmp == 0) \ - return 0; /* if zero, can't add to it anymore */ \ - if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) \ - return tmp + 1; \ - } - -#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \ - while (true) { \ - m_cpp_type tmp = static_cast(*(m_pw)); \ - if (tmp >= m_val) \ - return tmp; /* already greater, or equal */ \ - if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) \ - return m_val; \ - } - -_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){ - - ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t) -} - -_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) { - - return InterlockedDecrement((LONG volatile *)pw); -} - -_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) { - - return InterlockedIncrement((LONG volatile *)pw); -} - -_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) { - - return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val; -} - -_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) { - - return InterlockedAdd((LONG volatile *)pw, val); -} - -_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){ - - ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t) -} - -_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){ - - ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t) -} - -_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) { - - return InterlockedDecrement64((LONGLONG volatile *)pw); -} - -_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) { - - return InterlockedIncrement64((LONGLONG volatile *)pw); -} - -_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) { - - return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val; -} - -_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) { - - return InterlockedAdd64((LONGLONG volatile *)pw, val); -} - -_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){ - - ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t) -} - -// The actual advertised functions; they'll call the right implementation - -uint32_t atomic_conditional_increment(volatile uint32_t *pw) { - return _atomic_conditional_increment_impl(pw); -} - -uint32_t atomic_decrement(volatile uint32_t *pw) { - return _atomic_decrement_impl(pw); -} - -uint32_t atomic_increment(volatile uint32_t *pw) { - return _atomic_increment_impl(pw); -} - -uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) { - return _atomic_sub_impl(pw, val); -} - -uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) { - return _atomic_add_impl(pw, val); -} - -uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) { - return _atomic_exchange_if_greater_impl(pw, val); -} - -uint64_t atomic_conditional_increment(volatile uint64_t *pw) { - return _atomic_conditional_increment_impl(pw); -} - -uint64_t atomic_decrement(volatile uint64_t *pw) { - return _atomic_decrement_impl(pw); -} - -uint64_t atomic_increment(volatile uint64_t *pw) { - return _atomic_increment_impl(pw); -} - -uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) { - return _atomic_sub_impl(pw, val); -} - -uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) { - return _atomic_add_impl(pw, val); -} - -uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) { - return _atomic_exchange_if_greater_impl(pw, val); -} -#endif diff --git a/core/safe_refcount.h b/core/safe_refcount.h index f37d9d7d0d5..4840d90dd06 100644 --- a/core/safe_refcount.h +++ b/core/safe_refcount.h @@ -31,181 +31,292 @@ #ifndef SAFE_REFCOUNT_H #define SAFE_REFCOUNT_H -#include "core/os/mutex.h" #include "core/typedefs.h" -#include "platform_config.h" -// Atomic functions, these are used for multithread safe reference counters! +#if !defined(NO_THREADS) -#ifdef NO_THREADS +#include -/* Bogus implementation unaware of multiprocessing */ +// Design goals for these classes: +// - No automatic conversions or arithmetic operators, +// to keep explicit the use of atomics everywhere. +// - Using acquire-release semantics, even to set the first value. +// The first value may be set relaxedly in many cases, but adding the distinction +// between relaxed and unrelaxed operation to the interface would make it needlessly +// flexible. There's negligible waste in having release semantics for the initial +// value and, as an important benefit, you can be sure the value is properly synchronized +// even with threads that are already running. template -static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) { - - if (*pw == 0) - return 0; - - (*pw)++; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) { - - (*pw)--; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) { - - (*pw)++; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) { - - (*pw) -= val; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) { - - (*pw) += val; - - return *pw; -} - -template -static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) { - - if (val > *pw) - *pw = val; - - return *pw; -} - -#elif defined(__GNUC__) - -/* Implementation for GCC & Clang */ - -// GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes. -// Clang states it supports GCC atomic builtins. - -template -static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) { - - while (true) { - T tmp = static_cast(*pw); - if (tmp == 0) - return 0; // if zero, can't add to it anymore - if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp) - return tmp + 1; - } -} - -template -static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) { - - return __sync_sub_and_fetch(pw, 1); -} - -template -static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) { - - return __sync_add_and_fetch(pw, 1); -} - -template -static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) { - - return __sync_sub_and_fetch(pw, val); -} - -template -static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) { - - return __sync_add_and_fetch(pw, val); -} - -template -static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) { - - while (true) { - T tmp = static_cast(*pw); - if (tmp >= val) - return tmp; // already greater, or equal - if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) - return val; - } -} - -#elif defined(_MSC_VER) -// For MSVC use a separate compilation unit to prevent windows.h from polluting -// the global namespace. -uint32_t atomic_conditional_increment(volatile uint32_t *pw); -uint32_t atomic_decrement(volatile uint32_t *pw); -uint32_t atomic_increment(volatile uint32_t *pw); -uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val); -uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val); -uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val); - -uint64_t atomic_conditional_increment(volatile uint64_t *pw); -uint64_t atomic_decrement(volatile uint64_t *pw); -uint64_t atomic_increment(volatile uint64_t *pw); -uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val); -uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val); -uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val); - -#else -//no threads supported? -#error Must provide atomic functions for this platform or compiler! -#endif - -struct SafeRefCount { - - uint32_t count; +class SafeNumeric { + std::atomic value; public: - // destroy() is called when weak_count_ drops to zero. + _ALWAYS_INLINE_ void set(T p_value) { + value.store(p_value, std::memory_order_release); + } + _ALWAYS_INLINE_ T get() const { + return value.load(std::memory_order_acquire); + } + + _ALWAYS_INLINE_ T increment() { + return value.fetch_add(1, std::memory_order_acq_rel) + 1; + } + + // Returns the original value instead of the new one + _ALWAYS_INLINE_ T postincrement() { + return value.fetch_add(1, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T decrement() { + return value.fetch_sub(1, std::memory_order_acq_rel) - 1; + } + + // Returns the original value instead of the new one + _ALWAYS_INLINE_ T postdecrement() { + return value.fetch_sub(1, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T add(T p_value) { + return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value; + } + + // Returns the original value instead of the new one + _ALWAYS_INLINE_ T postadd(T p_value) { + return value.fetch_add(p_value, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T sub(T p_value) { + return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value; + } + + // Returns the original value instead of the new one + _ALWAYS_INLINE_ T postsub(T p_value) { + return value.fetch_sub(p_value, std::memory_order_acq_rel); + } + + _ALWAYS_INLINE_ T exchange_if_greater(T p_value) { + while (true) { + T tmp = value.load(std::memory_order_acquire); + if (tmp >= p_value) { + return tmp; // already greater, or equal + } + if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) { + return p_value; + } + } + } + + _ALWAYS_INLINE_ T conditional_increment() { + while (true) { + T c = value.load(std::memory_order_acquire); + if (c == 0) { + return 0; + } + if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) { + return c + 1; + } + } + } + + _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) { + set(p_value); + } +}; + +class SafeFlag { + std::atomic_bool flag; + +public: + _ALWAYS_INLINE_ bool is_set() const { + return flag.load(std::memory_order_acquire); + } + + _ALWAYS_INLINE_ void set() { + flag.store(true, std::memory_order_release); + } + + _ALWAYS_INLINE_ void clear() { + flag.store(false, std::memory_order_release); + } + + _ALWAYS_INLINE_ void set_to(bool p_value) { + flag.store(p_value, std::memory_order_release); + } + + _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) { + set_to(p_value); + } +}; + +class SafeRefCount { + SafeNumeric count; + +public: _ALWAYS_INLINE_ bool ref() { // true on success - - return atomic_conditional_increment(&count) != 0; + return count.conditional_increment() != 0; } _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success - - return atomic_conditional_increment(&count); + return count.conditional_increment(); } _ALWAYS_INLINE_ bool unref() { // true if must be disposed of - - return atomic_decrement(&count) == 0; + return count.decrement() == 0; } _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of - - return atomic_decrement(&count); + return count.decrement(); } - _ALWAYS_INLINE_ uint32_t get() const { // nothrow + _ALWAYS_INLINE_ uint32_t get() const { + return count.get(); + } + _ALWAYS_INLINE_ void init(uint32_t p_value = 1) { + count.set(p_value); + } +}; + +#else + +template +class SafeNumeric { +protected: + T value; + +public: + _ALWAYS_INLINE_ void set(T p_value) { + value = p_value; + } + + _ALWAYS_INLINE_ T get() const { + return value; + } + + _ALWAYS_INLINE_ T increment() { + return ++value; + } + + _ALWAYS_INLINE_ T postincrement() { + return value++; + } + + _ALWAYS_INLINE_ T decrement() { + return --value; + } + + _ALWAYS_INLINE_ T postdecrement() { + return value--; + } + + _ALWAYS_INLINE_ T add(T p_value) { + return value += p_value; + } + + _ALWAYS_INLINE_ T postadd(T p_value) { + T old = value; + value += p_value; + return old; + } + + _ALWAYS_INLINE_ T sub(T p_value) { + return value -= p_value; + } + + _ALWAYS_INLINE_ T postsub(T p_value) { + T old = value; + value -= p_value; + return old; + } + + _ALWAYS_INLINE_ T exchange_if_greater(T p_value) { + if (value < p_value) { + value = p_value; + } + return value; + } + + _ALWAYS_INLINE_ T conditional_increment() { + if (value != 0) { + return 0; + } else { + return ++value; + } + } + + _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast(0)) : + value(p_value) { + } +}; + +class SafeFlag { +protected: + bool flag; + +public: + _ALWAYS_INLINE_ bool is_set() const { + return flag; + } + + _ALWAYS_INLINE_ void set() { + flag = true; + } + + _ALWAYS_INLINE_ void clear() { + flag = false; + } + + _ALWAYS_INLINE_ void set_to(bool p_value) { + flag = p_value; + } + + _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) : + flag(p_value) {} +}; + +class SafeRefCount { + uint32_t count; + +public: + _ALWAYS_INLINE_ bool ref() { // true on success + if (count != 0) { + ++count; + return true; + } else { + return false; + } + } + + _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success + if (count != 0) { + return ++count; + } else { + return 0; + } + } + + _ALWAYS_INLINE_ bool unref() { // true if must be disposed of + return --count == 0; + } + + _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of + return --count; + } + + _ALWAYS_INLINE_ uint32_t get() const { return count; } _ALWAYS_INLINE_ void init(uint32_t p_value = 1) { - count = p_value; } + + SafeRefCount() : + count(0) {} }; #endif + +#endif // SAFE_REFCOUNT_H diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp index 9ecbd415f69..7f5cfb3a8c9 100644 --- a/editor/audio_stream_preview.cpp +++ b/editor/audio_stream_preview.cpp @@ -158,7 +158,7 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) { preview->playback->stop(); - preview->generating = false; + preview->generating.clear(); } Ref AudioStreamPreviewGenerator::generate_preview(const Ref &p_stream) { @@ -175,7 +175,7 @@ Ref AudioStreamPreviewGenerator::generate_preview(const Ref< Preview *preview = &previews[p_stream->get_instance_id()]; preview->base_stream = p_stream; preview->playback = preview->base_stream->instance_playback(); - preview->generating = true; + preview->generating.set(); preview->id = p_stream->get_instance_id(); float len_s = preview->base_stream->get_length(); @@ -220,7 +220,7 @@ void AudioStreamPreviewGenerator::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { List to_erase; for (Map::Element *E = previews.front(); E; E = E->next()) { - if (!E->get().generating) { + if (!E->get().generating.is_set()) { if (E->get().thread) { E->get().thread->wait_to_finish(); memdelete(E->get().thread); diff --git a/editor/audio_stream_preview.h b/editor/audio_stream_preview.h index a2fa5c63c21..4725fb727c8 100644 --- a/editor/audio_stream_preview.h +++ b/editor/audio_stream_preview.h @@ -32,6 +32,7 @@ #define AUDIO_STREAM_PREVIEW_H #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "scene/main/node.h" #include "servers/audio/audio_stream.h" @@ -60,9 +61,20 @@ class AudioStreamPreviewGenerator : public Node { Ref preview; Ref base_stream; Ref playback; - volatile bool generating; + SafeFlag generating; ObjectID id; Thread *thread; + + // Needed for the bookkeeping of the Map + Preview &operator=(const Preview &p_rhs) { + preview = p_rhs.preview; + base_stream = p_rhs.base_stream; + playback = p_rhs.playback; + generating.set_to(generating.is_set()); + id = p_rhs.id; + thread = p_rhs.thread; + return *this; + } }; Map previews; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 764365f45d2..2c037594ebd 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1445,10 +1445,10 @@ void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) { void EditorFileSystem::update_script_classes() { - if (!update_script_classes_queued) + if (!update_script_classes_queued.is_set()) return; - update_script_classes_queued = false; + update_script_classes_queued.clear(); ScriptServer::global_classes_clear(); if (get_filesystem()) { _scan_script_classes(get_filesystem()); @@ -1467,11 +1467,11 @@ void EditorFileSystem::update_script_classes() { } void EditorFileSystem::_queue_update_script_classes() { - if (update_script_classes_queued) { + if (update_script_classes_queued.is_set()) { return; } - update_script_classes_queued = true; + update_script_classes_queued.set(); call_deferred("update_script_classes"); } @@ -2146,7 +2146,7 @@ EditorFileSystem::EditorFileSystem() { memdelete(da); scan_total = 0; - update_script_classes_queued = false; + update_script_classes_queued.clear(); first_scan = true; scan_changes_pending = false; revalidate_import_files = false; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 1e39f330c01..d768b919c64 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -34,8 +34,10 @@ #include "core/os/dir_access.h" #include "core/os/thread.h" #include "core/os/thread_safe.h" +#include "core/safe_refcount.h" #include "core/set.h" #include "scene/main/node.h" + class FileAccess; struct EditorProgressBG; @@ -231,7 +233,7 @@ class EditorFileSystem : public Node { }; void _scan_script_classes(EditorFileSystemDirectory *p_dir); - volatile bool update_script_classes_queued; + SafeFlag update_script_classes_queued; void _queue_update_script_classes(); String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 1d281b17d68..cf299f71dab 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5742,7 +5742,7 @@ static void _execute_thread(void *p_ud) { eta->exitcode = err; } - eta->done = true; + eta->done.set(); } int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List &p_arguments, bool p_close_on_ok, bool p_close_on_errors) { @@ -5757,13 +5757,12 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p eta.path = p_path; eta.args = p_arguments; eta.exitcode = 255; - eta.done = false; int prev_len = 0; eta.execute_output_thread.start(_execute_thread, &eta); - while (!eta.done) { + while (!eta.done.is_set()) { eta.execute_output_mutex.lock(); if (prev_len != eta.output.length()) { String to_add = eta.output.substr(prev_len, eta.output.length()); diff --git a/editor/editor_node.h b/editor/editor_node.h index 7d8768c3658..cddc0c84e49 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -31,6 +31,7 @@ #ifndef EDITOR_NODE_H #define EDITOR_NODE_H +#include "core/safe_refcount.h" #include "editor/editor_data.h" #include "editor/editor_folding.h" #include "editor/editor_run.h" @@ -109,7 +110,7 @@ public: Thread execute_output_thread; Mutex execute_output_mutex; int exitcode; - volatile bool done; + SafeFlag done; }; private: diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 303b4d16da4..18ddd05c398 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -217,8 +217,8 @@ void EditorResourcePreview::_generate_preview(Ref &r_texture, Ref< void EditorResourcePreview::_thread() { - exited = false; - while (!exit) { + exited.clear(); + while (!exit.is_set()) { preview_sem.wait(); preview_mutex.lock(); @@ -350,7 +350,7 @@ void EditorResourcePreview::_thread() { preview_mutex.unlock(); } } - exited = true; + exited.set(); } void EditorResourcePreview::queue_edited_resource_preview(const Ref &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) { @@ -462,9 +462,9 @@ void EditorResourcePreview::start() { void EditorResourcePreview::stop() { if (thread.is_started()) { - exit = true; + exit.set(); preview_sem.post(); - while (!exited) { + while (!exited.is_set()) { OS::get_singleton()->delay_usec(10000); VisualServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server } @@ -475,8 +475,6 @@ void EditorResourcePreview::stop() { EditorResourcePreview::EditorResourcePreview() { singleton = this; order = 0; - exit = false; - exited = false; } EditorResourcePreview::~EditorResourcePreview() { diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index 089158d2276..1283fabe118 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -33,6 +33,7 @@ #include "core/os/semaphore.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "scene/main/node.h" #include "scene/resources/texture.h" @@ -73,8 +74,8 @@ class EditorResourcePreview : public Node { Mutex preview_mutex; Semaphore preview_sem; Thread thread; - volatile bool exit; - volatile bool exited; + SafeFlag exit; + SafeFlag exited; struct Item { Ref preview; diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 96a0cba4855..f24feae7e70 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -308,7 +308,7 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() { void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done = true; + preview_done.set(); } void EditorMaterialPreviewPlugin::_bind_methods() { @@ -336,10 +336,10 @@ Ref EditorMaterialPreviewPlugin::generate(const RES &p_from, const Size VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture - preview_done = false; + preview_done.clear(); VS::get_singleton()->request_frame_drawn_callback(const_cast(this), "_preview_done", Variant()); - while (!preview_done) { + while (!preview_done.is_set()) { OS::get_singleton()->delay_usec(10); } @@ -699,7 +699,7 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() { void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done = true; + preview_done.set(); } void EditorMeshPreviewPlugin::_bind_methods() { @@ -737,10 +737,10 @@ Ref EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 &p VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture - preview_done = false; + preview_done.clear(); VS::get_singleton()->request_frame_drawn_callback(const_cast(this), "_preview_done", Variant()); - while (!preview_done) { + while (!preview_done.is_set()) { OS::get_singleton()->delay_usec(10); } @@ -819,7 +819,7 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() { void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done = true; + preview_done.set(); } void EditorFontPreviewPlugin::_bind_methods() { @@ -861,11 +861,11 @@ Ref EditorFontPreviewPlugin::generate_from_path(const String &p_path, c font->draw(canvas_item, pos, sampled_text); - preview_done = false; + preview_done.clear(); VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture VS::get_singleton()->request_frame_drawn_callback(const_cast(this), "_preview_done", Variant()); - while (!preview_done) { + while (!preview_done.is_set()) { OS::get_singleton()->delay_usec(10); } diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index dce3754e8f1..8d2b8d6d13f 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -33,6 +33,8 @@ #include "editor/editor_resource_preview.h" +#include "core/safe_refcount.h" + void post_process_preview(Ref p_image); class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator { @@ -92,7 +94,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - mutable volatile bool preview_done; + mutable SafeFlag preview_done; void _preview_done(const Variant &p_udata); @@ -137,7 +139,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - mutable volatile bool preview_done; + mutable SafeFlag preview_done; void _preview_done(const Variant &p_udata); @@ -160,7 +162,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator { RID viewport_texture; RID canvas; RID canvas_item; - mutable volatile bool preview_done; + mutable SafeFlag preview_done; void _preview_done(const Variant &p_udata); diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 70424c58b69..7f9a90828a9 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -33,6 +33,7 @@ #include "core/os/os.h" #include "core/os/thread.h" #include "core/print_string.h" +#include "core/safe_refcount.h" #include @@ -56,7 +57,7 @@ struct CVTTCompressionJobQueue { CVTTCompressionJobParams job_params; const CVTTCompressionRowTask *job_tasks; uint32_t num_tasks; - uint32_t current_task; + SafeNumeric current_task; }; static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const CVTTCompressionRowTask &p_row_task) { @@ -131,7 +132,7 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const static void _digest_job_queue(void *p_job_queue) { CVTTCompressionJobQueue *job_queue = static_cast(p_job_queue); - for (uint32_t next_task = atomic_increment(&job_queue->current_task); next_task <= job_queue->num_tasks; next_task = atomic_increment(&job_queue->current_task)) { + for (uint32_t next_task = job_queue->current_task.increment(); next_task <= job_queue->num_tasks; next_task = job_queue->current_task.increment()) { _digest_row_task(job_queue->job_params, job_queue->job_tasks[next_task - 1]); } } @@ -263,7 +264,7 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS PoolVector::Read tasks_rb = tasks.read(); job_queue.job_tasks = &tasks_rb[0]; - job_queue.current_task = 0; + job_queue.current_task.set(0); job_queue.num_tasks = static_cast(tasks.size()); for (int i = 0; i < num_job_threads; i++) { diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 008e9cedc4f..43e8228ca45 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -995,9 +995,6 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) { NativeScriptLanguage::NativeScriptLanguage() { NativeScriptLanguage::singleton = this; -#ifndef NO_THREADS - has_objects_to_register = false; -#endif #ifdef DEBUG_ENABLED profiling = false; @@ -1446,7 +1443,7 @@ void NativeScriptLanguage::defer_init_library(Ref lib, NativeSc MutexLock lock(mutex); libs_to_init.insert(lib); scripts_to_register.insert(script); - has_objects_to_register = true; + has_objects_to_register.set(); } #endif @@ -1539,7 +1536,7 @@ void NativeScriptLanguage::call_libraries_cb(const StringName &name) { void NativeScriptLanguage::frame() { #ifndef NO_THREADS - if (has_objects_to_register) { + if (has_objects_to_register.is_set()) { MutexLock lock(mutex); for (Set >::Element *L = libs_to_init.front(); L; L = L->next()) { init_library(L->get()); @@ -1549,7 +1546,7 @@ void NativeScriptLanguage::frame() { register_script(S->get()); } scripts_to_register.clear(); - has_objects_to_register = false; + has_objects_to_register.clear(); } #endif diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index f36a5366a0a..45ebe950e32 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -37,6 +37,7 @@ #include "core/ordered_hash_map.h" #include "core/os/thread_safe.h" #include "core/resource.h" +#include "core/safe_refcount.h" #include "core/script_language.h" #include "core/self_list.h" #include "scene/main/node.h" @@ -240,7 +241,7 @@ private: Set > libs_to_init; Set scripts_to_register; - volatile bool has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed + SafeFlag has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed void defer_init_library(Ref lib, NativeScript *script); #endif diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 6f651feb9a1..467da332622 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -36,6 +36,7 @@ #include "core/os/semaphore.h" #include "core/os/thread.h" #include "core/ring_buffer.h" +#include "core/safe_refcount.h" #include "scene/resources/video_stream.h" #include "servers/audio_server.h" @@ -114,7 +115,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { bool thread_eof; Semaphore thread_sem; Thread thread; - volatile bool thread_exit; + SafeFlag thread_exit; static void _streaming_thread(void *ud); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 9001dd2e8a2..b54c27d985e 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -37,6 +37,7 @@ #include "core/os/file_access.h" #include "core/os/os.h" #include "core/project_settings.h" +#include "core/safe_refcount.h" #include "core/version.h" #include "drivers/png/png_driver_common.h" #include "editor/editor_export.h" @@ -267,38 +268,38 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { Vector plugins; String last_plugin_names; uint64_t last_custom_build_time = 0; - volatile bool plugins_changed; + SafeFlag plugins_changed; Mutex plugins_lock; Vector devices; - volatile bool devices_changed; + SafeFlag devices_changed; Mutex device_lock; Thread check_for_changes_thread; - volatile bool quit_request; + SafeFlag quit_request; static void _check_for_changes_poll_thread(void *ud) { EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; - while (!ea->quit_request) { + while (!ea->quit_request.is_set()) { // Check for plugins updates { // Nothing to do if we already know the plugins have changed. - if (!ea->plugins_changed) { + if (!ea->plugins_changed.is_set()) { Vector loaded_plugins = get_plugins(); ea->plugins_lock.lock(); if (ea->plugins.size() != loaded_plugins.size()) { - ea->plugins_changed = true; + ea->plugins_changed.set(); } else { for (int i = 0; i < ea->plugins.size(); i++) { if (ea->plugins[i].name != loaded_plugins[i].name) { - ea->plugins_changed = true; + ea->plugins_changed.set(); break; } } } - if (ea->plugins_changed) { + if (ea->plugins_changed.is_set()) { ea->plugins = loaded_plugins; } @@ -415,7 +416,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } ea->devices = ndevices; - ea->devices_changed = true; + ea->devices_changed.set(); } ea->device_lock.unlock(); @@ -426,7 +427,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { uint64_t time = OS::get_singleton()->get_ticks_usec(); while (OS::get_singleton()->get_ticks_usec() - time < wait) { OS::get_singleton()->delay_usec(1000 * sleep); - if (ea->quit_request) + if (ea->quit_request.is_set()) break; } } @@ -1679,7 +1680,7 @@ public: print_verbose("Found Android plugin " + plugins_configs[i].name); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false)); } - plugins_changed = false; + plugins_changed.clear(); Vector abis = get_abis(); for (int i = 0; i < abis.size(); ++i) { @@ -1750,20 +1751,20 @@ public: } virtual bool should_update_export_options() { - bool export_options_changed = plugins_changed; + bool export_options_changed = plugins_changed.is_set(); if (export_options_changed) { // don't clear unless we're reporting true, to avoid race - plugins_changed = false; + plugins_changed.clear(); } return export_options_changed; } virtual bool poll_export() { - bool dc = devices_changed; + bool dc = devices_changed.is_set(); if (dc) { // don't clear unless we're reporting true, to avoid race - devices_changed = false; + devices_changed.clear(); } return dc; } @@ -3280,15 +3281,13 @@ public: run_icon.instance(); run_icon->create_from_image(img); - devices_changed = true; - - plugins_changed = true; - quit_request = false; + devices_changed.set(); + plugins_changed.set(); check_for_changes_thread.start(_check_for_changes_poll_thread, this); } ~EditorExportPlatformAndroid() { - quit_request = true; + quit_request.set(); check_for_changes_thread.wait_to_finish(); } }; diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index d773c87af13..b82a7e9f810 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -218,14 +218,14 @@ void GodotIOJavaWrapper::stop_video() { } } -// volatile because it can be changed from non-main thread and we need to +// SafeNumeric because it can be changed from non-main thread and we need to // ensure the change is immediately visible to other threads. -static volatile int virtual_keyboard_height; +static SafeNumeric virtual_keyboard_height; int GodotIOJavaWrapper::get_vk_height() { - return virtual_keyboard_height; + return virtual_keyboard_height.get(); } void GodotIOJavaWrapper::set_vk_height(int p_height) { - virtual_keyboard_height = p_height; + virtual_keyboard_height.set(p_height); } diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index ceb296f5480..3ee86f76521 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -35,6 +35,7 @@ #include "core/os/file_access.h" #include "core/os/os.h" #include "core/project_settings.h" +#include "core/safe_refcount.h" #include "core/version.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -55,9 +56,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform { Ref logo; // Plugins - volatile bool plugins_changed; + SafeFlag plugins_changed; Thread check_for_changes_thread; - volatile bool quit_request; + SafeFlag quit_request; Mutex plugins_lock; Vector plugins; @@ -144,20 +145,20 @@ class EditorExportPlatformIOS : public EditorExportPlatform { static void _check_for_changes_poll_thread(void *ud) { EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud; - while (!ea->quit_request) { + while (!ea->quit_request.is_set()) { // Nothing to do if we already know the plugins have changed. - if (!ea->plugins_changed) { + if (!ea->plugins_changed.is_set()) { ea->plugins_lock.lock(); Vector loaded_plugins = get_plugins(); if (ea->plugins.size() != loaded_plugins.size()) { - ea->plugins_changed = true; + ea->plugins_changed.set(); } else { for (int i = 0; i < ea->plugins.size(); i++) { if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) { - ea->plugins_changed = true; + ea->plugins_changed.set(); break; } } @@ -171,7 +172,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { while (OS::get_singleton()->get_ticks_usec() - time < wait) { OS::get_singleton()->delay_usec(300000); - if (ea->quit_request) { + if (ea->quit_request.is_set()) { break; } } @@ -188,10 +189,10 @@ public: virtual Ref get_logo() const { return logo; } virtual bool should_update_export_options() { - bool export_options_changed = plugins_changed; + bool export_options_changed = plugins_changed.is_set(); if (export_options_changed) { // don't clear unless we're reporting true, to avoid race - plugins_changed = false; + plugins_changed.clear(); } return export_options_changed; } @@ -371,7 +372,7 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false)); } - plugins_changed = false; + plugins_changed.clear(); plugins = found_plugins; r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false)); @@ -1836,14 +1837,13 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() { logo.instance(); logo->create_from_image(img); - plugins_changed = true; - quit_request = false; + plugins_changed.set(); check_for_changes_thread.start(_check_for_changes_poll_thread, this); } EditorExportPlatformIOS::~EditorExportPlatformIOS() { - quit_request = true; + quit_request.set(); check_for_changes_thread.wait_to_finish(); } diff --git a/platform/x11/joypad_linux.cpp b/platform/x11/joypad_linux.cpp index 6e3c1101d17..b8a7fe78a53 100644 --- a/platform/x11/joypad_linux.cpp +++ b/platform/x11/joypad_linux.cpp @@ -92,13 +92,12 @@ JoypadLinux::JoypadLinux(InputDefault *in) { #else print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads."); #endif - exit_monitor = false; input = in; joy_thread.start(joy_thread_func, this); } JoypadLinux::~JoypadLinux() { - exit_monitor = true; + exit_monitor.set(); joy_thread.wait_to_finish(); close_joypad(); } @@ -172,7 +171,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { udev_monitor_enable_receiving(mon); int fd = udev_monitor_get_fd(mon); - while (!exit_monitor) { + while (!exit_monitor.is_set()) { fd_set fds; struct timeval tv; @@ -220,7 +219,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { void JoypadLinux::monitor_joypads() { - while (!exit_monitor) { + while (!exit_monitor.is_set()) { joy_mutex.lock(); DIR *input_directory; diff --git a/platform/x11/joypad_linux.h b/platform/x11/joypad_linux.h index 21374d1b825..6d7d61395fe 100644 --- a/platform/x11/joypad_linux.h +++ b/platform/x11/joypad_linux.h @@ -74,7 +74,7 @@ private: #ifdef UDEV_ENABLED bool use_udev; #endif - bool exit_monitor; + SafeFlag exit_monitor; Mutex joy_mutex; Thread joy_thread; InputDefault *input; diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index e9348b4c0f7..1fa9264bb94 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -36,14 +36,14 @@ void AudioStreamPlayer2D::_mix_audio() { - if (!stream_playback.is_valid() || !active || + if (!stream_playback.is_valid() || !active.is_set() || (stream_paused && !stream_paused_fade_out)) { return; } - if (setseek >= 0.0) { - stream_playback->start(setseek); - setseek = -1.0; //reset seek + if (setseek.get() >= 0.0) { + stream_playback->start(setseek.get()); + setseek.set(-1.0); //reset seek } //get data @@ -58,7 +58,8 @@ void AudioStreamPlayer2D::_mix_audio() { stream_playback->mix(buffer, pitch_scale, buffer_size); //write all outputs - for (int i = 0; i < output_count; i++) { + int oc = output_count.get(); + for (int i = 0; i < oc; i++) { Output current = outputs[i]; @@ -132,14 +133,14 @@ void AudioStreamPlayer2D::_mix_audio() { prev_outputs[i] = current; } - prev_output_count = output_count; + prev_output_count = oc; //stream is no longer active, disable this. if (!stream_playback->is_playing()) { - active = false; + active.clear(); } - output_ready = false; + output_ready.clear(); stream_paused_fade_in = false; stream_paused_fade_out = false; } @@ -174,7 +175,7 @@ void AudioStreamPlayer2D::_notification(int p_what) { //update anything related to position first, if possible of course - if (!output_ready) { + if (!output_ready.is_set()) { List viewports; Ref world_2d = get_world_2d(); ERR_FAIL_COND(world_2d.is_null()); @@ -245,21 +246,21 @@ void AudioStreamPlayer2D::_notification(int p_what) { } } - output_count = new_output_count; - output_ready = true; + output_count.set(new_output_count); + output_ready.set(); } //start playing if requested - if (setplay >= 0.0) { - setseek = setplay; - active = true; - setplay = -1; + if (setplay.get() >= 0.0) { + setseek.set(setplay.get()); + active.set(); + setplay.set(-1); //do not update, this makes it easier to animate (will shut off otherwise) //_change_notify("playing"); //update property in editor } //stop playing if no longer active - if (!active) { + if (!active.is_set()) { set_physics_process_internal(false); //do not update, this makes it easier to animate (will shut off otherwise) //_change_notify("playing"); //update property in editor @@ -277,8 +278,8 @@ void AudioStreamPlayer2D::set_stream(Ref p_stream) { if (stream_playback.is_valid()) { stream_playback.unref(); stream.unref(); - active = false; - setseek = -1; + active.clear(); + setseek.set(-1); } if (p_stream.is_valid()) { @@ -323,8 +324,8 @@ void AudioStreamPlayer2D::play(float p_from_pos) { } if (stream_playback.is_valid()) { - setplay = p_from_pos; - output_ready = false; + setplay.set(p_from_pos); + output_ready.clear(); set_physics_process_internal(true); } } @@ -332,23 +333,23 @@ void AudioStreamPlayer2D::play(float p_from_pos) { void AudioStreamPlayer2D::seek(float p_seconds) { if (stream_playback.is_valid()) { - setseek = p_seconds; + setseek.set(p_seconds); } } void AudioStreamPlayer2D::stop() { if (stream_playback.is_valid()) { - active = false; + active.clear(); set_physics_process_internal(false); - setplay = -1; + setplay.set(-1); } } bool AudioStreamPlayer2D::is_playing() const { if (stream_playback.is_valid()) { - return active || setplay >= 0; + return active.is_set() || setplay.get() >= 0; } return false; @@ -357,8 +358,9 @@ bool AudioStreamPlayer2D::is_playing() const { float AudioStreamPlayer2D::get_playback_position() { if (stream_playback.is_valid()) { - if (setseek >= 0.0) { - return setseek; + float ss = setseek.get(); + if (ss >= 0.0) { + return ss; } return stream_playback->get_playback_position(); } @@ -401,7 +403,7 @@ void AudioStreamPlayer2D::_set_playing(bool p_enable) { } bool AudioStreamPlayer2D::_is_active() const { - return active; + return active.is_set(); } void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { @@ -535,14 +537,11 @@ AudioStreamPlayer2D::AudioStreamPlayer2D() { volume_db = 0; pitch_scale = 1.0; autoplay = false; - setseek = -1; - active = false; - output_count = 0; + setseek.set(-1); prev_output_count = 0; max_distance = 2000; attenuation = 1; - setplay = -1; - output_ready = false; + setplay.set(-1); area_mask = 1; stream_paused = false; stream_paused_fade_in = false; diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index d156c5120e3..23708990a16 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -31,6 +31,7 @@ #ifndef AUDIO_STREAM_PLAYER_2D_H #define AUDIO_STREAM_PLAYER_2D_H +#include "core/safe_refcount.h" #include "scene/2d/node_2d.h" #include "servers/audio/audio_stream.h" #include "servers/audio_server.h" @@ -54,8 +55,8 @@ private: }; Output outputs[MAX_OUTPUTS]; - volatile int output_count; - volatile bool output_ready; + SafeNumeric output_count; + SafeFlag output_ready; //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks) Output prev_outputs[MAX_OUTPUTS]; @@ -65,9 +66,9 @@ private: Ref stream; Vector mix_buffer; - volatile float setseek; - volatile bool active; - volatile float setplay; + SafeNumeric setseek; + SafeFlag active; + SafeNumeric setplay; float volume_db; float pitch_scale; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 474a0b0ccdc..b740c403974 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -130,15 +130,15 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig void AudioStreamPlayer3D::_mix_audio() { - if (!stream_playback.is_valid() || !active || + if (!stream_playback.is_valid() || !active.is_set() || (stream_paused && !stream_paused_fade_out)) { return; } bool started = false; - if (setseek >= 0.0) { - stream_playback->start(setseek); - setseek = -1.0; //reset seek + if (setseek.get() >= 0.0) { + stream_playback->start(setseek.get()); + setseek.set(-1.0); //reset seek started = true; } @@ -152,15 +152,15 @@ void AudioStreamPlayer3D::_mix_audio() { } // Mix if we're not paused or we're fading out - if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) { + if ((output_count.get() > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) { float output_pitch_scale = 0.0; - if (output_count) { + if (output_count.get()) { //used for doppler, not realistic but good enough - for (int i = 0; i < output_count; i++) { + for (int i = 0; i < output_count.get(); i++) { output_pitch_scale += outputs[i].pitch_scale; } - output_pitch_scale /= float(output_count); + output_pitch_scale /= float(output_count.get()); } else { output_pitch_scale = 1.0; } @@ -169,7 +169,7 @@ void AudioStreamPlayer3D::_mix_audio() { } //write all outputs - for (int i = 0; i < output_count; i++) { + for (int i = 0; i < output_count.get(); i++) { Output current = outputs[i]; @@ -284,14 +284,14 @@ void AudioStreamPlayer3D::_mix_audio() { prev_outputs[i] = current; } - prev_output_count = output_count; + prev_output_count = output_count.get(); //stream is no longer active, disable this. if (!stream_playback->is_playing()) { - active = false; + active.clear(); } - output_ready = false; + output_ready.clear(); stream_paused_fade_in = false; stream_paused_fade_out = false; } @@ -367,7 +367,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { //update anything related to position first, if possible of course - if (!output_ready) { + if (!output_ready.is_set()) { Vector3 linear_velocity; @@ -611,21 +611,21 @@ void AudioStreamPlayer3D::_notification(int p_what) { break; } - output_count = new_output_count; - output_ready = true; + output_count.set(new_output_count); + output_ready.set(); } //start playing if requested - if (setplay >= 0.0) { - setseek = setplay; - active = true; - setplay = -1; + if (setplay.get() >= 0.0) { + setseek.set(setplay.get()); + active.set(); + setplay.set(-1); //do not update, this makes it easier to animate (will shut off otherwise) ///_change_notify("playing"); //update property in editor } //stop playing if no longer active - if (!active) { + if (!active.is_set()) { set_physics_process_internal(false); //do not update, this makes it easier to animate (will shut off otherwise) //_change_notify("playing"); //update property in editor @@ -643,8 +643,8 @@ void AudioStreamPlayer3D::set_stream(Ref p_stream) { if (stream_playback.is_valid()) { stream_playback.unref(); stream.unref(); - active = false; - setseek = -1; + active.clear(); + setseek.set(-1); } if (p_stream.is_valid()) { @@ -707,8 +707,8 @@ void AudioStreamPlayer3D::play(float p_from_pos) { } if (stream_playback.is_valid()) { - setplay = p_from_pos; - output_ready = false; + setplay.set(p_from_pos); + output_ready.clear(); set_physics_process_internal(true); } } @@ -716,23 +716,23 @@ void AudioStreamPlayer3D::play(float p_from_pos) { void AudioStreamPlayer3D::seek(float p_seconds) { if (stream_playback.is_valid()) { - setseek = p_seconds; + setseek.set(p_seconds); } } void AudioStreamPlayer3D::stop() { if (stream_playback.is_valid()) { - active = false; + active.clear(); set_physics_process_internal(false); - setplay = -1; + setplay.set(-1); } } bool AudioStreamPlayer3D::is_playing() const { if (stream_playback.is_valid()) { - return active || setplay >= 0; + return active.is_set() || setplay.get() >= 0; } return false; @@ -741,8 +741,9 @@ bool AudioStreamPlayer3D::is_playing() const { float AudioStreamPlayer3D::get_playback_position() { if (stream_playback.is_valid()) { - if (setseek >= 0.0) { - return setseek; + float ss = setseek.get(); + if (ss >= 0.0) { + return ss; } return stream_playback->get_playback_position(); } @@ -785,7 +786,7 @@ void AudioStreamPlayer3D::_set_playing(bool p_enable) { } bool AudioStreamPlayer3D::_is_active() const { - return active; + return active.is_set(); } void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const { @@ -1055,13 +1056,10 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() { max_db = 3; pitch_scale = 1.0; autoplay = false; - setseek = -1; - active = false; - output_count = 0; + setseek.set(-1); prev_output_count = 0; max_distance = 0; - setplay = -1; - output_ready = false; + setplay.set(-1); area_mask = 1; emission_angle = 45; emission_angle_enabled = false; diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 2fd66d4f37d..c5b6d1cc936 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -31,6 +31,7 @@ #ifndef AUDIO_STREAM_PLAYER_3D_H #define AUDIO_STREAM_PLAYER_3D_H +#include "core/safe_refcount.h" #include "scene/3d/spatial.h" #include "scene/3d/spatial_velocity_tracker.h" #include "servers/audio/audio_filter_sw.h" @@ -89,8 +90,8 @@ private: }; Output outputs[MAX_OUTPUTS]; - volatile int output_count; - volatile bool output_ready; + SafeNumeric output_count; + SafeFlag output_ready; //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks) Output prev_outputs[MAX_OUTPUTS]; @@ -100,9 +101,9 @@ private: Ref stream; Vector mix_buffer; - volatile float setseek; - volatile bool active; - volatile float setplay; + SafeNumeric setseek; + SafeFlag active; + SafeNumeric setplay; AttenuationModel attenuation_model; float unit_db; diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 8e83b2466bb..9b4d92092c1 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -1113,7 +1113,7 @@ void CPUParticles::_update_particle_data_buffer() { ptr += 17; } - can_update = true; + can_update.set(); } update_mutex.unlock(); @@ -1142,9 +1142,9 @@ void CPUParticles::_update_render_thread() { update_mutex.lock(); - if (can_update) { + if (can_update.is_set()) { VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); - can_update = false; //wait for next time + can_update.clear(); //wait for next time } update_mutex.unlock(); @@ -1210,7 +1210,7 @@ void CPUParticles::_notification(int p_what) { ptr += 17; } - can_update = true; + can_update.set(); } } } @@ -1550,8 +1550,6 @@ CPUParticles::CPUParticles() { flags[i] = false; } - can_update = false; - set_color(Color(1, 1, 1, 1)); } diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index b88f783160c..f94e42b04fb 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -32,6 +32,7 @@ #define CPU_PARTICLES_H #include "core/rid.h" +#include "core/safe_refcount.h" #include "scene/3d/visual_instance.h" class CPUParticles : public GeometryInstance { @@ -144,7 +145,7 @@ private: Transform inv_emission_transform; - volatile bool can_update; + SafeFlag can_update; DrawOrder draw_order; diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index dce47ec82d8..cd1efa78eac 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -101,7 +101,7 @@ void AudioStreamPlayer::_mix_audio() { use_fadeout = false; } - if (!stream_playback.is_valid() || !active || + if (!stream_playback.is_valid() || !active.is_set() || (stream_paused && !stream_paused_fade)) { return; } @@ -114,25 +114,25 @@ void AudioStreamPlayer::_mix_audio() { return; } - if (setstop) { + if (setstop.is_set()) { _mix_internal(true); stream_playback->stop(); - setstop = false; + setstop.clear(); } - if (setseek >= 0.0 && !stop_has_priority) { + if (setseek.get() >= 0.0 && !stop_has_priority.is_set()) { if (stream_playback->is_playing()) { //fade out to avoid pops _mix_internal(true); } - stream_playback->start(setseek); - setseek = -1.0; //reset seek + stream_playback->start(setseek.get()); + setseek.set(-1.0); //reset seek mix_volume_db = volume_db; //reset ramp } - stop_has_priority = false; + stop_has_priority.clear(); _mix_internal(false); } @@ -149,8 +149,8 @@ void AudioStreamPlayer::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (!active || (setseek < 0 && !stream_playback->is_playing())) { - active = false; + if (!active.is_set() || (setseek.get() < 0 && !stream_playback->is_playing())) { + active.clear(); set_process_internal(false); emit_signal("finished"); } @@ -177,7 +177,7 @@ void AudioStreamPlayer::set_stream(Ref p_stream) { AudioServer::get_singleton()->lock(); - if (active && stream_playback.is_valid() && !stream_paused) { + if (active.is_set() && stream_playback.is_valid() && !stream_paused) { //changing streams out of the blue is not a great idea, but at least //lets try to somehow avoid a click @@ -204,9 +204,9 @@ void AudioStreamPlayer::set_stream(Ref p_stream) { if (stream_playback.is_valid()) { stream_playback.unref(); stream.unref(); - active = false; - setseek = -1; - setstop = false; + active.clear(); + setseek.set(-1); + setstop.clear(); } if (p_stream.is_valid()) { @@ -247,9 +247,9 @@ void AudioStreamPlayer::play(float p_from_pos) { if (stream_playback.is_valid()) { //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks - setseek = p_from_pos; - stop_has_priority = false; - active = true; + setseek.set(p_from_pos); + stop_has_priority.clear(); + active.set(); set_process_internal(true); } } @@ -257,22 +257,22 @@ void AudioStreamPlayer::play(float p_from_pos) { void AudioStreamPlayer::seek(float p_seconds) { if (stream_playback.is_valid()) { - setseek = p_seconds; + setseek.set(p_seconds); } } void AudioStreamPlayer::stop() { - if (stream_playback.is_valid() && active) { - setstop = true; - stop_has_priority = true; + if (stream_playback.is_valid() && active.is_set()) { + setstop.set(); + stop_has_priority.set(); } } bool AudioStreamPlayer::is_playing() const { if (stream_playback.is_valid()) { - return active && !setstop; //&& stream_playback->is_playing(); + return active.is_set() && !setstop.is_set(); //&& stream_playback->is_playing(); } return false; @@ -281,8 +281,9 @@ bool AudioStreamPlayer::is_playing() const { float AudioStreamPlayer::get_playback_position() { if (stream_playback.is_valid()) { - if (setseek >= 0.0) { - return setseek; + float ss = setseek.get(); + if (ss >= 0.0) { + return ss; } return stream_playback->get_playback_position(); } @@ -335,7 +336,7 @@ void AudioStreamPlayer::_set_playing(bool p_enable) { } bool AudioStreamPlayer::_is_active() const { - return active; + return active.is_set(); } void AudioStreamPlayer::set_stream_paused(bool p_pause) { @@ -435,13 +436,11 @@ AudioStreamPlayer::AudioStreamPlayer() { pitch_scale = 1.0; volume_db = 0; autoplay = false; - setseek = -1; - active = false; + setseek.set(-1); stream_paused = false; stream_paused_fade = false; mix_target = MIX_TARGET_STEREO; fadeout_buffer.resize(512); - setstop = false; use_fadeout = false; AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h index bb1c21e5271..18f5360618b 100644 --- a/scene/audio/audio_stream_player.h +++ b/scene/audio/audio_stream_player.h @@ -31,6 +31,7 @@ #ifndef AUDIO_STREAM_PLAYER_H #define AUDIO_STREAM_PLAYER_H +#include "core/safe_refcount.h" #include "scene/main/node.h" #include "servers/audio/audio_stream.h" @@ -52,10 +53,10 @@ private: Vector fadeout_buffer; bool use_fadeout; - volatile float setseek; - volatile bool active; - volatile bool setstop; - volatile bool stop_has_priority; + SafeNumeric setseek; + SafeFlag active; + SafeFlag setstop; + SafeFlag stop_has_priority; float mix_volume_db; float pitch_scale; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 84aee07105f..2e62b58efe9 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -49,7 +49,7 @@ Error HTTPRequest::_parse_url(const String &p_url) { got_response = false; body_len = -1; body.resize(0); - downloaded = 0; + downloaded.set(0); redirections = 0; String url_lower = url.to_lower(); @@ -108,10 +108,10 @@ Error HTTPRequest::request(const String &p_url, const Vector &p_custom_h requesting = true; - if (use_threads) { + if (use_threads.is_set()) { - thread_done = false; - thread_request_quit = false; + thread_done.clear(); + thread_request_quit.clear(); client->set_blocking_mode(true); thread.start(_thread_func, this); } else { @@ -137,7 +137,7 @@ void HTTPRequest::_thread_func(void *p_userdata) { if (err != OK) { hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray()); } else { - while (!hr->thread_request_quit) { + while (!hr->thread_request_quit.is_set()) { bool exit = hr->_update_connection(); if (exit) @@ -146,7 +146,7 @@ void HTTPRequest::_thread_func(void *p_userdata) { } } - hr->thread_done = true; + hr->thread_done.set(); } void HTTPRequest::cancel_request() { @@ -156,10 +156,10 @@ void HTTPRequest::cancel_request() { if (!requesting) return; - if (!use_threads) { + if (!use_threads.is_set()) { set_process_internal(false); } else { - thread_request_quit = true; + thread_request_quit.set(); thread.wait_to_finish(); } @@ -188,7 +188,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { List rheaders; client->get_response_headers(&rheaders); response_headers.resize(0); - downloaded = 0; + downloaded.set(0); for (List::Element *E = rheaders.front(); E; E = E->next()) { response_headers.push_back(E->get()); } @@ -229,7 +229,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { got_response = false; body_len = -1; body.resize(0); - downloaded = 0; + downloaded.set(0); redirections = new_redirs; *ret_value = false; return true; @@ -349,7 +349,7 @@ bool HTTPRequest::_update_connection() { client->poll(); PoolByteArray chunk = client->read_response_body_chunk(); - downloaded += chunk.size(); + downloaded.add(chunk.size()); if (file) { PoolByteArray::Read r = chunk.read(); @@ -362,14 +362,14 @@ bool HTTPRequest::_update_connection() { body.append_array(chunk); } - if (body_size_limit >= 0 && downloaded > body_size_limit) { + if (body_size_limit >= 0 && downloaded.get() > body_size_limit) { call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PoolByteArray()); return true; } if (body_len >= 0) { - if (downloaded == body_len) { + if (downloaded.get() == body_len) { call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; } @@ -404,7 +404,7 @@ void HTTPRequest::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (use_threads) + if (use_threads.is_set()) return; bool done = _update_connection(); if (done) { @@ -424,12 +424,12 @@ void HTTPRequest::_notification(int p_what) { void HTTPRequest::set_use_threads(bool p_use) { ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED); - use_threads = p_use; + use_threads.set_to(p_use); } bool HTTPRequest::is_using_threads() const { - return use_threads; + return use_threads.is_set(); } void HTTPRequest::set_body_size_limit(int p_bytes) { @@ -483,7 +483,7 @@ int HTTPRequest::get_max_redirects() const { int HTTPRequest::get_downloaded_bytes() const { - return downloaded; + return downloaded.get(); } int HTTPRequest::get_body_size() const { return body_len; @@ -577,9 +577,6 @@ HTTPRequest::HTTPRequest() { request_sent = false; requesting = false; client.instance(); - use_threads = false; - thread_done = false; - downloaded = 0; body_size_limit = -1; file = NULL; diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 0a4bd01d454..d5cdbcbed41 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -34,6 +34,7 @@ #include "core/io/http_client.h" #include "core/os/file_access.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "node.h" #include "scene/main/timer.h" @@ -74,7 +75,7 @@ private: bool request_sent; Ref client; PoolByteArray body; - volatile bool use_threads; + SafeFlag use_threads; bool got_response; int response_code; @@ -85,7 +86,7 @@ private: FileAccess *file; int body_len; - volatile int downloaded; + SafeNumeric downloaded; int body_size_limit; int redirections; @@ -103,8 +104,8 @@ private: Error _parse_url(const String &p_url); Error _request(); - volatile bool thread_done; - volatile bool thread_request_quit; + SafeFlag thread_done; + SafeFlag thread_request_quit; Thread thread; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 97001fca8cf..329cffad9f3 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1276,10 +1276,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } void VisualShader::_update_shader() const { - if (!dirty) + if (!dirty.is_set()) return; - dirty = false; + dirty.clear(); StringBuilder global_code; StringBuilder global_code_per_node; @@ -1439,11 +1439,11 @@ void VisualShader::_update_shader() const { } void VisualShader::_queue_update() { - if (dirty) { + if (dirty.is_set()) { return; } - dirty = true; + dirty.set(); call_deferred("_update_shader"); } @@ -1463,7 +1463,7 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) { } void VisualShader::rebuild() { - dirty = true; + dirty.set(); _update_shader(); } @@ -1524,7 +1524,7 @@ VisualShader::VisualShader() { graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150); } - dirty = true; + dirty.set(); } /////////////////////////////////////////////////////////// diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index aebbeec9f80..61fd96a5c27 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -90,7 +90,7 @@ private: static RenderModeEnums render_mode_enums[]; - volatile mutable bool dirty; + mutable SafeFlag dirty; void _queue_update(); union ConnectionKey { diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index d38ecf02ae2..a3a8fd2c567 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -128,7 +128,7 @@ bool AudioRBResampler::mix(AudioFrame *p_dest, int p_frames) { if (src_read > read_space) src_read = read_space; - rb_read_pos = (rb_read_pos + src_read) & rb_mask; + rb_read_pos.set((rb_read_pos.get() + src_read) & rb_mask); // Create fadeout effect for the end of stream (note that it can be because of slow writer) if (p_frames - target_todo > 0) { @@ -182,8 +182,8 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m src_mix_rate = p_src_mix_rate; target_mix_rate = p_target_mix_rate; offset = 0; - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); //avoid maybe strange noises upon load for (unsigned int i = 0; i < (rb_len * channels); i++) { @@ -205,8 +205,8 @@ void AudioRBResampler::clear() { memdelete_arr(read_buf); rb = NULL; offset = 0; - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); read_buf = NULL; } @@ -215,8 +215,8 @@ AudioRBResampler::AudioRBResampler() { rb = NULL; offset = 0; read_buf = NULL; - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); rb_bits = 0; rb_len = 0; diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h index 0e40d4bf9aa..6c43b0a9c1f 100644 --- a/servers/audio/audio_rb_resampler.h +++ b/servers/audio/audio_rb_resampler.h @@ -32,6 +32,7 @@ #define AUDIO_RB_RESAMPLER_H #include "core/os/memory.h" +#include "core/safe_refcount.h" #include "core/typedefs.h" #include "servers/audio_server.h" @@ -45,8 +46,8 @@ struct AudioRBResampler { uint32_t src_mix_rate; uint32_t target_mix_rate; - volatile int rb_read_pos; - volatile int rb_write_pos; + SafeNumeric rb_read_pos; + SafeNumeric rb_write_pos; int32_t offset; //contains the fractional remainder of the resampler enum { @@ -63,8 +64,8 @@ struct AudioRBResampler { public: _FORCE_INLINE_ void flush() { - rb_read_pos = 0; - rb_write_pos = 0; + rb_read_pos.set(0); + rb_write_pos.set(0); offset = 0; } @@ -79,8 +80,8 @@ public: _FORCE_INLINE_ int get_writer_space() const { int space, r, w; - r = rb_read_pos; - w = rb_write_pos; + r = rb_read_pos.get(); + w = rb_write_pos.get(); if (r == w) { space = rb_len - 1; @@ -96,8 +97,8 @@ public: _FORCE_INLINE_ int get_reader_space() const { int space, r, w; - r = rb_read_pos; - w = rb_write_pos; + r = rb_read_pos.get(); + w = rb_write_pos.get(); if (r == w) { space = 0; @@ -111,7 +112,7 @@ public: } _FORCE_INLINE_ bool has_data() const { - return rb && rb_read_pos != rb_write_pos; + return rb && rb_read_pos.get() != rb_write_pos.get(); } _FORCE_INLINE_ float *get_write_buffer() { return read_buf; } @@ -119,49 +120,53 @@ public: ERR_FAIL_COND(p_frames >= rb_len); + int wp = rb_write_pos.get(); + switch (channels) { case 1: { for (uint32_t i = 0; i < p_frames; i++) { - rb[rb_write_pos] = read_buf[i]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[wp] = read_buf[i]; + wp = (wp + 1) & rb_mask; } } break; case 2: { for (uint32_t i = 0; i < p_frames; i++) { - rb[(rb_write_pos << 1) + 0] = read_buf[(i << 1) + 0]; - rb[(rb_write_pos << 1) + 1] = read_buf[(i << 1) + 1]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[(wp << 1) + 0] = read_buf[(i << 1) + 0]; + rb[(wp << 1) + 1] = read_buf[(i << 1) + 1]; + wp = (wp + 1) & rb_mask; } } break; case 4: { for (uint32_t i = 0; i < p_frames; i++) { - rb[(rb_write_pos << 2) + 0] = read_buf[(i << 2) + 0]; - rb[(rb_write_pos << 2) + 1] = read_buf[(i << 2) + 1]; - rb[(rb_write_pos << 2) + 2] = read_buf[(i << 2) + 2]; - rb[(rb_write_pos << 2) + 3] = read_buf[(i << 2) + 3]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[(wp << 2) + 0] = read_buf[(i << 2) + 0]; + rb[(wp << 2) + 1] = read_buf[(i << 2) + 1]; + rb[(wp << 2) + 2] = read_buf[(i << 2) + 2]; + rb[(wp << 2) + 3] = read_buf[(i << 2) + 3]; + wp = (wp + 1) & rb_mask; } } break; case 6: { for (uint32_t i = 0; i < p_frames; i++) { - rb[(rb_write_pos * 6) + 0] = read_buf[(i * 6) + 0]; - rb[(rb_write_pos * 6) + 1] = read_buf[(i * 6) + 1]; - rb[(rb_write_pos * 6) + 2] = read_buf[(i * 6) + 2]; - rb[(rb_write_pos * 6) + 3] = read_buf[(i * 6) + 3]; - rb[(rb_write_pos * 6) + 4] = read_buf[(i * 6) + 4]; - rb[(rb_write_pos * 6) + 5] = read_buf[(i * 6) + 5]; - rb_write_pos = (rb_write_pos + 1) & rb_mask; + rb[(wp * 6) + 0] = read_buf[(i * 6) + 0]; + rb[(wp * 6) + 1] = read_buf[(i * 6) + 1]; + rb[(wp * 6) + 2] = read_buf[(i * 6) + 2]; + rb[(wp * 6) + 3] = read_buf[(i * 6) + 3]; + rb[(wp * 6) + 4] = read_buf[(i * 6) + 4]; + rb[(wp * 6) + 5] = read_buf[(i * 6) + 5]; + wp = (wp + 1) & rb_mask; } } break; } + + rb_write_pos.set(wp); } int get_channel_count() const; diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.cpp b/servers/physics_2d/physics_2d_server_wrap_mt.cpp index 046c3acd49c..76e9da280c1 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.cpp +++ b/servers/physics_2d/physics_2d_server_wrap_mt.cpp @@ -34,7 +34,7 @@ void Physics2DServerWrapMT::thread_exit() { - exit = true; + exit.set(); } void Physics2DServerWrapMT::thread_step(real_t p_delta) { @@ -56,9 +56,9 @@ void Physics2DServerWrapMT::thread_loop() { physics_2d_server->init(); - exit = false; - step_thread_up = true; - while (!exit) { + exit.clear(); + step_thread_up.set(); + while (!exit.is_set()) { // flush commands one by one, until exit is requested command_queue.wait_and_flush_one(); } @@ -110,7 +110,7 @@ void Physics2DServerWrapMT::init() { //OS::get_singleton()->release_rendering_thread(); thread.start(_thread_callback, this); - while (!step_thread_up) { + while (!step_thread_up.is_set()) { OS::get_singleton()->delay_usec(1000); } } else { @@ -149,7 +149,6 @@ Physics2DServerWrapMT::Physics2DServerWrapMT(Physics2DServer *p_contained, bool physics_2d_server = p_contained; create_thread = p_create_thread; step_pending = 0; - step_thread_up = false; pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index 0c9e560a504..1939feb2699 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -34,6 +34,7 @@ #include "core/command_queue_mt.h" #include "core/os/thread.h" #include "core/project_settings.h" +#include "core/safe_refcount.h" #include "servers/physics_2d_server.h" #ifdef DEBUG_SYNC @@ -53,9 +54,9 @@ class Physics2DServerWrapMT : public Physics2DServer { Thread::ID server_thread; Thread::ID main_thread; - volatile bool exit; + SafeFlag exit; Thread thread; - volatile bool step_thread_up; + SafeFlag step_thread_up; bool create_thread; Semaphore step_sem; diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index b5977c82a68..6c01c5a5092 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -38,6 +38,7 @@ #include "core/math/octree.h" #include "core/os/semaphore.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "core/self_list.h" #include "servers/arvr/arvr_interface.h" @@ -591,7 +592,7 @@ public: void _gi_probe_bake_thread(); static void _gi_probe_bake_threads(void *); - volatile bool probe_bake_thread_exit; + bool probe_bake_thread_exit; Thread probe_bake_thread; Semaphore probe_bake_sem; Mutex probe_bake_mutex; diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index 64288ad1565..26a61e6c9a4 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -34,12 +34,12 @@ void VisualServerWrapMT::thread_exit() { - exit = true; + exit.set(); } void VisualServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) { - if (!atomic_decrement(&draw_pending)) { + if (!draw_pending.decrement()) { visual_server->draw(p_swap_buffers, frame_step); } @@ -47,7 +47,7 @@ void VisualServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) { void VisualServerWrapMT::thread_flush() { - atomic_decrement(&draw_pending); + draw_pending.decrement(); } void VisualServerWrapMT::_thread_callback(void *_instance) { @@ -65,9 +65,9 @@ void VisualServerWrapMT::thread_loop() { visual_server->init(); - exit = false; - draw_thread_up = true; - while (!exit) { + exit.clear(); + draw_thread_up.set(); + while (!exit.is_set()) { // flush commands one by one, until exit is requested command_queue.wait_and_flush_one(); } @@ -83,7 +83,7 @@ void VisualServerWrapMT::sync() { if (create_thread) { - atomic_increment(&draw_pending); + draw_pending.increment(); command_queue.push_and_sync(this, &VisualServerWrapMT::thread_flush); } else { @@ -95,7 +95,7 @@ void VisualServerWrapMT::draw(bool p_swap_buffers, double frame_step) { if (create_thread) { - atomic_increment(&draw_pending); + draw_pending.increment(); command_queue.push(this, &VisualServerWrapMT::thread_draw, p_swap_buffers, frame_step); } else { @@ -113,7 +113,7 @@ void VisualServerWrapMT::init() { thread.start(_thread_callback, this); print_verbose("VisualServerWrapMT: Starting render thread"); } - while (!draw_thread_up) { + while (!draw_thread_up.is_set()) { OS::get_singleton()->delay_usec(1000); } print_verbose("VisualServerWrapMT: Finished render thread"); @@ -174,8 +174,6 @@ VisualServerWrapMT::VisualServerWrapMT(VisualServer *p_contained, bool p_create_ visual_server = p_contained; create_thread = p_create_thread; - draw_pending = 0; - draw_thread_up = false; pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); if (!p_create_thread) { diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 1b620c509ce..e4e6dd0da15 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -33,6 +33,7 @@ #include "core/command_queue_mt.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/visual_server.h" class VisualServerWrapMT : public VisualServer { @@ -46,12 +47,12 @@ class VisualServerWrapMT : public VisualServer { void thread_loop(); Thread::ID server_thread; - volatile bool exit; + SafeFlag exit; Thread thread; - volatile bool draw_thread_up; + SafeFlag draw_thread_up; bool create_thread; - uint64_t draw_pending; + SafeNumeric draw_pending; void thread_draw(bool p_swap_buffers, double frame_step); void thread_flush();