From fac1fd77a88cb0cb225cd1c162f9e77693249c6a Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 13 May 2026 13:30:10 +0200 Subject: [PATCH 1/5] texture: Fix copy ctor missing clear color fields This caused cached bam file corruption. --- panda/src/gobj/texture.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index c4e9bcf8772..eb89d1d9b43 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -10641,7 +10641,7 @@ do_fillin_body(CData *cdata, DatagramIterator &scan, BamReader *manager) { if (manager->get_file_minor_ver() >= 45) { cdata->_has_clear_color = scan.get_bool(); - if (cdata->_has_clear_color) { + if (cdata->_has_clear_color && manager->expect_remaining_size(scan, 16)) { cdata->_clear_color.read_datagram(scan); } } @@ -10891,6 +10891,8 @@ do_assign(const Texture::CData *copy) { _simple_x_size = copy->_simple_x_size; _simple_y_size = copy->_simple_y_size; _simple_ram_image = copy->_simple_ram_image; + _has_clear_color = copy->_has_clear_color; + _clear_color = copy->_clear_color; } /** From c79839190ccf8cf91b982ebd3b44875f65b44039 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 13 May 2026 13:37:30 +0200 Subject: [PATCH 2/5] general: Replace remaining AtomicAdjust uses with patomic See #258 --- dtool/src/dtoolbase/deletedBufferChain.h | 3 +- dtool/src/dtoolbase/neverFreeMemory.I | 6 +- dtool/src/dtoolbase/neverFreeMemory.cxx | 10 +- dtool/src/dtoolbase/neverFreeMemory.h | 3 +- dtool/src/dtoolutil/filename.cxx | 2 +- dtool/src/prc/configFlags.I | 14 +-- dtool/src/prc/configFlags.cxx | 2 +- dtool/src/prc/configFlags.h | 13 ++- dtool/src/prc/configVariableBool.h | 2 +- dtool/src/prc/configVariableDouble.h | 2 +- dtool/src/prc/configVariableEnum.h | 2 +- dtool/src/prc/configVariableFilename.h | 2 +- dtool/src/prc/configVariableInt.h | 2 +- dtool/src/prc/configVariableInt64.h | 2 +- dtool/src/prc/configVariableSearchPath.h | 2 +- dtool/src/prc/configVariableString.h | 2 +- dtool/src/prc/notifyCategory.h | 2 +- dtool/src/prc/streamWrapper.I | 4 +- dtool/src/prc/streamWrapper.h | 4 +- panda/src/event/asyncTask.I | 2 +- panda/src/event/asyncTask.cxx | 41 ++++--- panda/src/event/asyncTask.h | 6 +- panda/src/express/nodeReferenceCount.I | 26 ++--- panda/src/express/nodeReferenceCount.cxx | 6 +- panda/src/express/nodeReferenceCount.h | 2 +- panda/src/express/pointerToVoid.I | 4 +- panda/src/express/pointerToVoid.h | 3 +- panda/src/express/referenceCount.cxx | 1 - panda/src/express/referenceCount.h | 1 - .../glstuff/glGraphicsStateGuardian_src.cxx | 6 +- .../src/glstuff/glGraphicsStateGuardian_src.h | 2 +- panda/src/linmath/configVariableColor.h | 2 +- panda/src/net/connectionReader.cxx | 7 +- panda/src/net/connectionReader.h | 4 +- panda/src/pgraph/attribNodeRegistry.I | 6 +- panda/src/pgraph/attribNodeRegistry.cxx | 11 +- panda/src/pgraph/attribNodeRegistry.h | 3 +- panda/src/pgraph/transformState.I | 4 +- panda/src/pgraph/transformState.cxx | 8 +- panda/src/pgraph/transformState.h | 4 +- panda/src/pgraphnodes/lightLensNode.cxx | 6 +- panda/src/pgraphnodes/lightLensNode.h | 4 +- panda/src/pipeline/conditionVarSpinlockImpl.I | 5 +- .../src/pipeline/conditionVarSpinlockImpl.cxx | 8 +- panda/src/pipeline/conditionVarSpinlockImpl.h | 4 +- panda/src/pipeline/reMutexSpinlockImpl.I | 2 +- panda/src/pipeline/reMutexSpinlockImpl.cxx | 18 ++- panda/src/pipeline/reMutexSpinlockImpl.h | 4 +- panda/src/pipeline/thread.I | 2 +- panda/src/pipeline/thread.cxx | 2 +- panda/src/pipeline/thread.h | 3 +- .../putil/cachedTypedWritableReferenceCount.I | 32 +++--- .../cachedTypedWritableReferenceCount.cxx | 6 +- .../putil/cachedTypedWritableReferenceCount.h | 2 +- panda/src/putil/nodeCachedReferenceCount.I | 26 ++--- panda/src/putil/nodeCachedReferenceCount.cxx | 6 +- panda/src/putil/nodeCachedReferenceCount.h | 2 +- panda/src/putil/typedWritable.cxx | 32 +++--- panda/src/putil/typedWritable.h | 2 +- panda/src/putil/updateSeq.I | 106 +++++++----------- panda/src/putil/updateSeq.h | 14 +-- 61 files changed, 256 insertions(+), 258 deletions(-) diff --git a/dtool/src/dtoolbase/deletedBufferChain.h b/dtool/src/dtoolbase/deletedBufferChain.h index 1e47adc81b7..28aa036d8a6 100644 --- a/dtool/src/dtoolbase/deletedBufferChain.h +++ b/dtool/src/dtoolbase/deletedBufferChain.h @@ -17,7 +17,6 @@ #include "dtoolbase.h" #include "neverFreeMemory.h" #include "mutexImpl.h" -#include "atomicAdjust.h" #include "numeric_types.h" #include "typeHandle.h" #include "patomic.h" @@ -104,7 +103,7 @@ class EXPCL_DTOOL_DTOOLBASE DeletedBufferChain { #else // Otherwise, we need space for the integer. - static const size_t flag_reserved_bytes = sizeof(AtomicAdjust::Integer); + static const size_t flag_reserved_bytes = sizeof(patomic); #endif // USE_DELETEDCHAINFLAG friend class MemoryHook; diff --git a/dtool/src/dtoolbase/neverFreeMemory.I b/dtool/src/dtoolbase/neverFreeMemory.I index 6e5216e993d..b8d02bd8a11 100644 --- a/dtool/src/dtoolbase/neverFreeMemory.I +++ b/dtool/src/dtoolbase/neverFreeMemory.I @@ -59,10 +59,12 @@ get_total_unused() { */ INLINE NeverFreeMemory *NeverFreeMemory:: get_global_ptr() { - if (_global_ptr == nullptr) { + NeverFreeMemory *ptr = _global_ptr.load(std::memory_order_consume); + if (ptr == nullptr) { make_global_ptr(); + ptr = _global_ptr.load(std::memory_order_consume); } - return _global_ptr; + return ptr; } /** diff --git a/dtool/src/dtoolbase/neverFreeMemory.cxx b/dtool/src/dtoolbase/neverFreeMemory.cxx index bd7c1c14816..4d74f0aecd3 100644 --- a/dtool/src/dtoolbase/neverFreeMemory.cxx +++ b/dtool/src/dtoolbase/neverFreeMemory.cxx @@ -12,10 +12,9 @@ */ #include "neverFreeMemory.h" -#include "atomicAdjust.h" #include "memoryHook.h" -NeverFreeMemory * TVOLATILE NeverFreeMemory::_global_ptr; +patomic NeverFreeMemory::_global_ptr { nullptr }; // If a page has fewer than this many bytes remaining, never mind about it. static const size_t min_page_remaining_size = 16; @@ -81,9 +80,10 @@ ns_alloc(size_t size) { void NeverFreeMemory:: make_global_ptr() { NeverFreeMemory *ptr = new NeverFreeMemory; - void *result = AtomicAdjust::compare_and_exchange_ptr - ((void * TVOLATILE &)_global_ptr, nullptr, (void *)ptr); - if (result != nullptr) { + NeverFreeMemory *expected = nullptr; + if (!_global_ptr.compare_exchange_strong(expected, ptr, + std::memory_order_release, + std::memory_order_consume)) { // Someone else got there first. delete ptr; } diff --git a/dtool/src/dtoolbase/neverFreeMemory.h b/dtool/src/dtoolbase/neverFreeMemory.h index 6b1390c26ef..118614f4fb9 100644 --- a/dtool/src/dtoolbase/neverFreeMemory.h +++ b/dtool/src/dtoolbase/neverFreeMemory.h @@ -17,6 +17,7 @@ #include "dtoolbase.h" #include "mutexImpl.h" +#include "patomic.h" #include /** @@ -63,7 +64,7 @@ class EXPCL_DTOOL_DTOOLBASE NeverFreeMemory { size_t _total_alloc; size_t _total_used; MutexImpl _lock; - static NeverFreeMemory * TVOLATILE _global_ptr; + static patomic _global_ptr; }; #include "neverFreeMemory.I" diff --git a/dtool/src/dtoolutil/filename.cxx b/dtool/src/dtoolutil/filename.cxx index 31b7a264ca9..6eb4ee45bfb 100644 --- a/dtool/src/dtoolutil/filename.cxx +++ b/dtool/src/dtoolutil/filename.cxx @@ -2656,7 +2656,7 @@ get_hash() const { * (small) file with the specified contents, assuming it hasn't changed since * the last time the file was read. * - * This is designed to be similar to AtomicAdjust::compare_and_exchange(). + * This is designed to be similar to patomic::compare_exchange_strong(). * The method writes new_contents to the file, completely replacing the * original contents; but only if the original contents exactly matched * old_contents. If the file was modified, returns true. If, however, the diff --git a/dtool/src/prc/configFlags.I b/dtool/src/prc/configFlags.I index 6f35c4d8149..8aceddc0859 100644 --- a/dtool/src/prc/configFlags.I +++ b/dtool/src/prc/configFlags.I @@ -17,8 +17,8 @@ * value). */ ALWAYS_INLINE bool ConfigFlags:: -is_cache_valid(AtomicAdjust::Integer local_modified) { - return local_modified == _global_modified; +is_cache_valid(Modified local_modified) { + return local_modified == _global_modified.load(std::memory_order_acquire); } /** @@ -26,8 +26,8 @@ is_cache_valid(AtomicAdjust::Integer local_modified) { * be valid, until someone next calls invalidate_cache(). */ ALWAYS_INLINE void ConfigFlags:: -mark_cache_valid(AtomicAdjust::Integer &local_modified) { - local_modified = _global_modified; +mark_cache_valid(Modified &local_modified) { + local_modified = _global_modified.load(std::memory_order_acquire); } /** @@ -35,9 +35,9 @@ mark_cache_valid(AtomicAdjust::Integer &local_modified) { * value. This value will indicate an invalid cache in the next call to * is_cache_valid(). */ -INLINE AtomicAdjust::Integer ConfigFlags:: +INLINE ConfigFlags::Modified ConfigFlags:: initial_invalid_cache() { - return _global_modified - 1; + return _global_modified.load(std::memory_order_relaxed) - 1; } /** @@ -46,5 +46,5 @@ initial_invalid_cache() { */ INLINE void ConfigFlags:: invalidate_cache() { - AtomicAdjust::inc(_global_modified); + _global_modified.fetch_add(1, std::memory_order_release); } diff --git a/dtool/src/prc/configFlags.cxx b/dtool/src/prc/configFlags.cxx index 4613dc46153..92708053182 100644 --- a/dtool/src/prc/configFlags.cxx +++ b/dtool/src/prc/configFlags.cxx @@ -13,7 +13,7 @@ #include "configFlags.h" -TVOLATILE AtomicAdjust::Integer ConfigFlags::_global_modified; +patomic ConfigFlags::_global_modified { 0 }; /** * diff --git a/dtool/src/prc/configFlags.h b/dtool/src/prc/configFlags.h index c034760667a..5dfbc7dcbd8 100644 --- a/dtool/src/prc/configFlags.h +++ b/dtool/src/prc/configFlags.h @@ -16,7 +16,7 @@ #include "dtoolbase.h" #include "numeric_types.h" -#include "atomicAdjust.h" +#include "patomic.h" #include "memoryBase.h" /** @@ -58,14 +58,17 @@ class EXPCL_DTOOL_PRC ConfigFlags { F_dconfig = 0x00008000, }; +public: + typedef unsigned int Modified; + protected: - ALWAYS_INLINE static bool is_cache_valid(AtomicAdjust::Integer local_modified); - ALWAYS_INLINE static void mark_cache_valid(AtomicAdjust::Integer &local_modified); - INLINE static AtomicAdjust::Integer initial_invalid_cache(); + ALWAYS_INLINE static bool is_cache_valid(Modified local_modified); + ALWAYS_INLINE static void mark_cache_valid(Modified &local_modified); + INLINE static Modified initial_invalid_cache(); INLINE static void invalidate_cache(); private: - static TVOLATILE AtomicAdjust::Integer _global_modified; + static patomic _global_modified; }; std::ostream &operator << (std::ostream &out, ConfigFlags::ValueType type); diff --git a/dtool/src/prc/configVariableBool.h b/dtool/src/prc/configVariableBool.h index c6ea2194e62..fcde6c6fa0f 100644 --- a/dtool/src/prc/configVariableBool.h +++ b/dtool/src/prc/configVariableBool.h @@ -50,7 +50,7 @@ class EXPCL_DTOOL_PRC ConfigVariableBool : public ConfigVariable { private: void reload_value() const; - mutable AtomicAdjust::Integer _local_modified; + mutable Modified _local_modified; mutable bool _cache; }; diff --git a/dtool/src/prc/configVariableDouble.h b/dtool/src/prc/configVariableDouble.h index 258560c7149..0620433ac8d 100644 --- a/dtool/src/prc/configVariableDouble.h +++ b/dtool/src/prc/configVariableDouble.h @@ -54,7 +54,7 @@ class EXPCL_DTOOL_PRC ConfigVariableDouble : public ConfigVariable { void set_default_value(double default_value); private: - AtomicAdjust::Integer _local_modified; + Modified _local_modified; double _cache; }; diff --git a/dtool/src/prc/configVariableEnum.h b/dtool/src/prc/configVariableEnum.h index 80aaf23b651..21cbf493eb9 100644 --- a/dtool/src/prc/configVariableEnum.h +++ b/dtool/src/prc/configVariableEnum.h @@ -61,7 +61,7 @@ class ConfigVariableEnum : public ConfigVariable { bool _got_default_value; EnumType _default_value; - AtomicAdjust::Integer _local_modified; + Modified _local_modified; EnumType _cache; }; diff --git a/dtool/src/prc/configVariableFilename.h b/dtool/src/prc/configVariableFilename.h index 18ea1ddb8aa..1c85cdd6cb3 100644 --- a/dtool/src/prc/configVariableFilename.h +++ b/dtool/src/prc/configVariableFilename.h @@ -70,7 +70,7 @@ class EXPCL_DTOOL_PRC ConfigVariableFilename : public ConfigVariable { INLINE const Filename &get_ref_value() const; private: - AtomicAdjust::Integer _local_modified; + Modified _local_modified; Filename _cache; }; diff --git a/dtool/src/prc/configVariableInt.h b/dtool/src/prc/configVariableInt.h index 5dd569a4685..f09a3ad8fd1 100644 --- a/dtool/src/prc/configVariableInt.h +++ b/dtool/src/prc/configVariableInt.h @@ -54,7 +54,7 @@ class EXPCL_DTOOL_PRC ConfigVariableInt : public ConfigVariable { void set_default_value(int default_value); private: - AtomicAdjust::Integer _local_modified; + Modified _local_modified; int _cache; }; diff --git a/dtool/src/prc/configVariableInt64.h b/dtool/src/prc/configVariableInt64.h index 16a685ee3d4..7acce805867 100644 --- a/dtool/src/prc/configVariableInt64.h +++ b/dtool/src/prc/configVariableInt64.h @@ -55,7 +55,7 @@ class EXPCL_DTOOL_PRC ConfigVariableInt64 : public ConfigVariable { void set_default_value(int64_t default_value); private: - AtomicAdjust::Integer _local_modified; + Modified _local_modified; int64_t _cache; }; diff --git a/dtool/src/prc/configVariableSearchPath.h b/dtool/src/prc/configVariableSearchPath.h index dd55c6af264..b7cae14eee4 100644 --- a/dtool/src/prc/configVariableSearchPath.h +++ b/dtool/src/prc/configVariableSearchPath.h @@ -85,7 +85,7 @@ class EXPCL_DTOOL_PRC ConfigVariableSearchPath : public ConfigVariableBase { DSearchPath _default_value; DSearchPath _prefix, _postfix; - AtomicAdjust::Integer _local_modified; + Modified _local_modified; DSearchPath _cache; }; diff --git a/dtool/src/prc/configVariableString.h b/dtool/src/prc/configVariableString.h index 1eb0c45fab7..9ae662b6beb 100644 --- a/dtool/src/prc/configVariableString.h +++ b/dtool/src/prc/configVariableString.h @@ -57,7 +57,7 @@ class EXPCL_DTOOL_PRC ConfigVariableString : public ConfigVariable { void reload_cache(); private: - AtomicAdjust::Integer _local_modified; + Modified _local_modified; std::string _cache; }; diff --git a/dtool/src/prc/notifyCategory.h b/dtool/src/prc/notifyCategory.h index 1a0c82a37eb..e9a11afed95 100644 --- a/dtool/src/prc/notifyCategory.h +++ b/dtool/src/prc/notifyCategory.h @@ -89,7 +89,7 @@ class EXPCL_DTOOL_PRC NotifyCategory : public MemoryBase, public ConfigFlags { static long _server_delta; // not a time_t because server delta may be signed. - AtomicAdjust::Integer _local_modified; + Modified _local_modified; NotifySeverity _severity_cache; friend class Notify; diff --git a/dtool/src/prc/streamWrapper.I b/dtool/src/prc/streamWrapper.I index dcc953fa24a..f517f753442 100644 --- a/dtool/src/prc/streamWrapper.I +++ b/dtool/src/prc/streamWrapper.I @@ -64,7 +64,7 @@ release() { */ INLINE void StreamWrapperBase:: ref() const { - AtomicAdjust::inc(_ref_count); + _ref_count.fetch_add(1, std::memory_order_relaxed); } /** @@ -73,7 +73,7 @@ ref() const { */ INLINE bool StreamWrapperBase:: unref() const { - return AtomicAdjust::dec(_ref_count); + return _ref_count.fetch_sub(1, std::memory_order_release) != 1; } /** diff --git a/dtool/src/prc/streamWrapper.h b/dtool/src/prc/streamWrapper.h index c416109b246..5988ef3b187 100644 --- a/dtool/src/prc/streamWrapper.h +++ b/dtool/src/prc/streamWrapper.h @@ -16,7 +16,7 @@ #include "dtoolbase.h" #include "mutexImpl.h" -#include "atomicAdjust.h" +#include "patomic.h" /** * The base class for both IStreamWrapper and OStreamWrapper, this provides @@ -41,7 +41,7 @@ class EXPCL_DTOOL_PRC StreamWrapperBase { // This isn't really designed as a reference counted class, but it is useful // to treat it as one when dealing with substreams created by Multifile. - mutable AtomicAdjust::Integer _ref_count = 1; + mutable patomic _ref_count { 1 }; #ifdef SIMPLE_THREADS // In the SIMPLE_THREADS case, we need to use a bool flag, because MutexImpl diff --git a/panda/src/event/asyncTask.I b/panda/src/event/asyncTask.I index c9cdbeb179d..68f69b862d4 100644 --- a/panda/src/event/asyncTask.I +++ b/panda/src/event/asyncTask.I @@ -138,7 +138,7 @@ clear_name() { * Returns a number guaranteed to be unique for each different AsyncTask * object in the universe. */ -INLINE AtomicAdjust::Integer AsyncTask:: +INLINE int AsyncTask:: get_task_id() const { return _task_id; } diff --git a/panda/src/event/asyncTask.cxx b/panda/src/event/asyncTask.cxx index 85670e4cf49..371cb34abd8 100644 --- a/panda/src/event/asyncTask.cxx +++ b/panda/src/event/asyncTask.cxx @@ -20,7 +20,7 @@ using std::string; -AtomicAdjust::Integer AsyncTask::_next_task_id; +patomic AsyncTask::_next_task_id { 0 }; PStatCollector AsyncTask::_tasks_pcollector("App:Tasks"); TypeHandle AsyncTask::_type_handle; @@ -47,13 +47,8 @@ AsyncTask(const string &name) : { set_name(name); - // Carefully copy _next_task_id and increment it so that we get a unique ID. - AtomicAdjust::Integer current_id = _next_task_id; - while (AtomicAdjust::compare_and_exchange(_next_task_id, current_id, current_id + 1) != current_id) { - current_id = _next_task_id; - } - - _task_id = current_id; + // Atomically increment _next_task_id so that we get a unique ID. + _task_id = _next_task_id.fetch_add(1, std::memory_order_relaxed); } /** @@ -406,20 +401,22 @@ unlock_and_do_task() { Thread *current_thread = Thread::get_current_thread(); nassertr(current_thread->_current_task == nullptr, DS_interrupt); + TypedReferenceCount *expected = nullptr; #ifdef __GNUC__ __attribute__((unused)) #endif - void *ptr = AtomicAdjust::compare_and_exchange_ptr - (current_thread->_current_task, nullptr, (TypedReferenceCount *)this); + bool exchanged = current_thread->_current_task.compare_exchange_strong( + expected, (TypedReferenceCount *)this, + std::memory_order_release, std::memory_order_relaxed); - // If the return value is other than nullptr, someone else must have - // assigned the task first, in another thread. That shouldn't be possible. + // If the exchange didn't happen, someone else must have assigned the task + // first, in another thread. That shouldn't be possible. // But different versions of gcc appear to have problems compiling these // assertions correctly. #ifndef __GNUC__ - nassertr(ptr == nullptr, DS_interrupt); - nassertr(current_thread->_current_task == this, DS_interrupt); + nassertr(exchanged, DS_interrupt); + nassertr(current_thread->_current_task.load(std::memory_order_relaxed) == this, DS_interrupt); #endif // __GNUC__ // It's important to release the lock while the task is being serviced. @@ -441,19 +438,21 @@ unlock_and_do_task() { _chain->_time_in_frame += _dt; // Now indicate that this is no longer the current task. - nassertr(current_thread->_current_task == this, status); + nassertr(current_thread->_current_task.load(std::memory_order_relaxed) == this, status); - ptr = AtomicAdjust::compare_and_exchange_ptr - (current_thread->_current_task, (TypedReferenceCount *)this, nullptr); + expected = (TypedReferenceCount *)this; + exchanged = current_thread->_current_task.compare_exchange_strong( + expected, nullptr, + std::memory_order_release, std::memory_order_relaxed); - // If the return value is other than this, someone else must have assigned - // the task first, in another thread. That shouldn't be possible. + // If the exchange didn't happen, someone else must have assigned the task + // first, in another thread. That shouldn't be possible. // But different versions of gcc appear to have problems compiling these // assertions correctly. #ifndef __GNUC__ - nassertr(ptr == this, DS_interrupt); - nassertr(current_thread->_current_task == nullptr, DS_interrupt); + nassertr(exchanged, DS_interrupt); + nassertr(current_thread->_current_task.load(std::memory_order_relaxed) == nullptr, DS_interrupt); #endif // __GNUC__ return status; diff --git a/panda/src/event/asyncTask.h b/panda/src/event/asyncTask.h index 55c5beb4fbe..2bc29d2412c 100644 --- a/panda/src/event/asyncTask.h +++ b/panda/src/event/asyncTask.h @@ -80,7 +80,7 @@ class EXPCL_PANDA_EVENT AsyncTask : public AsyncFuture, public Namable { INLINE void clear_name(); std::string get_name_prefix() const; - INLINE AtomicAdjust::Integer get_task_id() const; + INLINE int get_task_id() const; void set_task_chain(const std::string &chain_name); INLINE const std::string &get_task_chain() const; @@ -133,7 +133,7 @@ class EXPCL_PANDA_EVENT AsyncTask : public AsyncFuture, public Namable { virtual void upon_death(AsyncTaskManager *manager, bool clean_exit); protected: - AtomicAdjust::Integer _task_id; + int _task_id; std::string _chain_name; double _delay; bool _has_delay; @@ -154,7 +154,7 @@ class EXPCL_PANDA_EVENT AsyncTask : public AsyncFuture, public Namable { double _total_dt; int _num_frames; - static AtomicAdjust::Integer _next_task_id; + static patomic _next_task_id; static PStatCollector _tasks_pcollector; PStatCollector _task_pcollector; diff --git a/panda/src/express/nodeReferenceCount.I b/panda/src/express/nodeReferenceCount.I index 66a8be1ceab..a336441aa77 100644 --- a/panda/src/express/nodeReferenceCount.I +++ b/panda/src/express/nodeReferenceCount.I @@ -24,8 +24,7 @@ TypeHandle NodeRefCountObj::_type_handle; * inheritance. */ INLINE NodeReferenceCount:: -NodeReferenceCount() { - _node_ref_count = 0; +NodeReferenceCount() : _node_ref_count(0) { } /** @@ -37,8 +36,7 @@ NodeReferenceCount() { * try. */ INLINE NodeReferenceCount:: -NodeReferenceCount(const NodeReferenceCount ©) : ReferenceCount(copy) { - _node_ref_count = 0; +NodeReferenceCount(const NodeReferenceCount ©) : ReferenceCount(copy), _node_ref_count(0) { } /** @@ -58,7 +56,7 @@ operator = (const NodeReferenceCount ©) { // to create an automatic (local variable) instance of a class that derives // from ReferenceCount. Or maybe your headers are out of sync, and you need // to make clean in direct or some higher tree. - nassertv(_node_ref_count != -100); + nassertv(_node_ref_count.load(std::memory_order_relaxed) != -100); ReferenceCount::operator = (copy); } @@ -72,17 +70,19 @@ operator = (const NodeReferenceCount ©) { */ INLINE NodeReferenceCount:: ~NodeReferenceCount() { + int ref_count = _node_ref_count.load(std::memory_order_relaxed); + // If this assertion fails, we're trying to delete an object that was just // deleted. Possibly you used a real pointer instead of a PointerTo at some // point, and the object was deleted when the PointerTo went out of scope. // Maybe you tried to create an automatic (local variable) instance of a // class that derives from ReferenceCount. Or maybe your headers are out of // sync, and you need to make clean in direct or some higher tree. - nassertv(_node_ref_count != -100); + nassertv(ref_count != -100); // If this assertion fails, the reference counts are all screwed up // altogether. Maybe some errant code stomped all over memory somewhere. - nassertv(_node_ref_count >= 0); + nassertv(ref_count >= 0); // If this assertion fails, someone tried to delete this object while its // reference count was still positive. Maybe you tried to point a PointerTo @@ -93,13 +93,13 @@ INLINE NodeReferenceCount:: // Another possibility is you inadvertently omitted a copy constructor for a // ReferenceCount object, and then bitwise copied a dynamically allocated // value--reference count and all--onto a locally allocated one. - nassertv(_node_ref_count == 0); + nassertv(ref_count == 0); #ifndef NDEBUG // Ok, all clear to delete. Now set the reference count to -100, so we'll // have a better chance of noticing if we happen to have a stray pointer to // it still out there. - _node_ref_count = -100; + _node_ref_count.store(-100, std::memory_order_relaxed); #endif } @@ -111,7 +111,7 @@ get_node_ref_count() const { #ifdef _DEBUG test_ref_count_integrity(); #endif - return (int)AtomicAdjust::get(_node_ref_count); + return _node_ref_count.load(std::memory_order_acquire); } /** @@ -125,7 +125,7 @@ node_ref() const { #endif ref(); - AtomicAdjust::inc(_node_ref_count); + _node_ref_count.fetch_add(1, std::memory_order_relaxed); } /** @@ -168,9 +168,9 @@ node_unref_only() const { // If this assertion fails, you tried to unref an object with a zero // reference count. Are you using ref() and unref() directly? Are you sure // you can't use PointerTo's? - nassertv(_node_ref_count > 0); + nassertv(_node_ref_count.load(std::memory_order_relaxed) > 0); - AtomicAdjust::dec(_node_ref_count); + _node_ref_count.fetch_sub(1, std::memory_order_release); } /** diff --git a/panda/src/express/nodeReferenceCount.cxx b/panda/src/express/nodeReferenceCount.cxx index f965f240a41..4c5a5b8383c 100644 --- a/panda/src/express/nodeReferenceCount.cxx +++ b/panda/src/express/nodeReferenceCount.cxx @@ -21,17 +21,19 @@ TypeHandle NodeReferenceCount::_type_handle; */ bool NodeReferenceCount:: do_test_ref_count_integrity() const { + int ref_count = _node_ref_count.load(std::memory_order_relaxed); + // If this assertion fails, we're trying to delete an object that was just // deleted. Possibly you used a real pointer instead of a PointerTo at some // point, and the object was deleted when the PointerTo went out of scope. // Maybe you tried to create an automatic (local variable) instance of a // class that derives from ReferenceCount. Or maybe your headers are out of // sync, and you need to make clean in direct or some higher tree. - nassertr(_node_ref_count != -100, false); + nassertr(ref_count != -100, false); // If this assertion fails, the reference counts are all screwed up // altogether. Maybe some errant code stomped all over memory somewhere. - nassertr(_node_ref_count >= 0, false); + nassertr(ref_count >= 0, false); return ReferenceCount::do_test_ref_count_integrity(); } diff --git a/panda/src/express/nodeReferenceCount.h b/panda/src/express/nodeReferenceCount.h index 0ece11b90a4..e8e1676d876 100644 --- a/panda/src/express/nodeReferenceCount.h +++ b/panda/src/express/nodeReferenceCount.h @@ -48,7 +48,7 @@ class EXPCL_PANDA_EXPRESS NodeReferenceCount : public ReferenceCount { bool do_test_ref_count_integrity() const; private: - mutable AtomicAdjust::Integer _node_ref_count; + mutable patomic _node_ref_count; public: static TypeHandle get_class_type() { diff --git a/panda/src/express/pointerToVoid.I b/panda/src/express/pointerToVoid.I index 8704ce4ce60..5f1ffba4726 100644 --- a/panda/src/express/pointerToVoid.I +++ b/panda/src/express/pointerToVoid.I @@ -76,7 +76,5 @@ operator != (const PointerToVoid &other) const { */ INLINE void PointerToVoid:: swap(PointerToVoid &other) noexcept { - AtomicAdjust::Pointer temp = _void_ptr; - _void_ptr = other._void_ptr; - other._void_ptr = temp; + std::swap(_void_ptr, other._void_ptr); } diff --git a/panda/src/express/pointerToVoid.h b/panda/src/express/pointerToVoid.h index e185911eab5..318e8dd5d2c 100644 --- a/panda/src/express/pointerToVoid.h +++ b/panda/src/express/pointerToVoid.h @@ -17,7 +17,6 @@ #include "pandabase.h" #include "pnotify.h" #include "memoryBase.h" -#include "atomicAdjust.h" #include @@ -63,7 +62,7 @@ class EXPCL_PANDA_EXPRESS PointerToVoid : public MemoryBase { // a PointerTo any class that inherits virtually from ReferenceCount. (You // can't downcast past a virtual inheritance level, but you can always // cross-cast from a void pointer.) - AtomicAdjust::Pointer _void_ptr = nullptr; + void *_void_ptr = nullptr; }; #include "pointerToVoid.I" diff --git a/panda/src/express/referenceCount.cxx b/panda/src/express/referenceCount.cxx index 0d5f98ea84b..28501b50852 100644 --- a/panda/src/express/referenceCount.cxx +++ b/panda/src/express/referenceCount.cxx @@ -12,7 +12,6 @@ */ #include "referenceCount.h" -#include "atomicAdjust.h" #include "mutexImpl.h" TypeHandle ReferenceCount::_type_handle; diff --git a/panda/src/express/referenceCount.h b/panda/src/express/referenceCount.h index b57b85d4a3e..e5aa263b39d 100644 --- a/panda/src/express/referenceCount.h +++ b/panda/src/express/referenceCount.h @@ -20,7 +20,6 @@ #include "memoryUsage.h" #include "memoryBase.h" #include "config_express.h" -#include "atomicAdjust.h" #include "numeric_types.h" #include "deletedChain.h" #include "patomic.h" diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 89d27bf6fdd..c015abd4f0e 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -107,7 +107,7 @@ static PStatCollector _create_map_pbo_pcollector("Draw:Transfer data:Texture:Cre static PStatCollector _load_texture_copy_pcollector("Draw:Transfer data:Texture:Copy/Convert"); #if defined(HAVE_CG) && !defined(OPENGLES) -AtomicAdjust::Integer CLP(GraphicsStateGuardian)::_num_gsgs_with_cg_contexts = 0; +patomic CLP(GraphicsStateGuardian)::_num_gsgs_with_cg_contexts { 0 }; small_vector CLP(GraphicsStateGuardian)::_destroyed_cg_contexts; #endif @@ -13102,7 +13102,7 @@ free_pointers() { // Don't destroy the Cg context until the last GSG that uses Cg has been // destroyed. This works around a Cg bug, see #1117. - if (!AtomicAdjust::dec(_num_gsgs_with_cg_contexts)) { + if (_num_gsgs_with_cg_contexts.fetch_sub(1, std::memory_order_acq_rel) == 1) { for (CGcontext context : _destroyed_cg_contexts) { cgDestroyContext(context); } @@ -13130,7 +13130,7 @@ get_cg_context() { } #endif - AtomicAdjust::inc(_num_gsgs_with_cg_contexts); + _num_gsgs_with_cg_contexts.fetch_add(1, std::memory_order_relaxed); _cg_context = context; } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 4514d3f04c8..844648f8d53 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -758,7 +758,7 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { #if defined(HAVE_CG) && !defined(OPENGLES) CGcontext _cg_context; - static AtomicAdjust::Integer _num_gsgs_with_cg_contexts; + static patomic _num_gsgs_with_cg_contexts; static small_vector _destroyed_cg_contexts; #endif diff --git a/panda/src/linmath/configVariableColor.h b/panda/src/linmath/configVariableColor.h index a37f9b39551..0d095bd9023 100644 --- a/panda/src/linmath/configVariableColor.h +++ b/panda/src/linmath/configVariableColor.h @@ -57,7 +57,7 @@ class EXPCL_PANDA_LINMATH ConfigVariableColor : public ConfigVariable { void set_default_value(const LColor &default_value); private: - mutable AtomicAdjust::Integer _local_modified; + mutable Modified _local_modified; mutable LColor _cache; }; diff --git a/panda/src/net/connectionReader.cxx b/panda/src/net/connectionReader.cxx index 9fbab3e1dce..07651148849 100644 --- a/panda/src/net/connectionReader.cxx +++ b/panda/src/net/connectionReader.cxx @@ -24,7 +24,6 @@ #include "mutexHolder.h" #include "lightMutexHolder.h" #include "pnotify.h" -#include "atomicAdjust.h" #include "config_downloader.h" using std::min; @@ -111,7 +110,7 @@ ConnectionReader(ConnectionManager *manager, int num_threads, _next_index = 0; _num_results = 0; - _currently_polling_thread = -1; + _currently_polling_thread.store(-1, std::memory_order_relaxed); std::string reader_thread_name = thread_name; if (thread_name.empty()) { @@ -827,7 +826,7 @@ get_next_available_socket(bool allow_block, int current_thread_index) { // First, report to anyone else who cares that we're the thread about to // do the poll. That way, if any new sockets come available while we're // polling, we can service them. - AtomicAdjust::set(_currently_polling_thread, current_thread_index); + _currently_polling_thread.store(current_thread_index, std::memory_order_relaxed); rebuild_select_list(); @@ -864,7 +863,7 @@ get_next_available_socket(bool allow_block, int current_thread_index) { } } while (!_shutdown && interrupted); - AtomicAdjust::set(_currently_polling_thread, current_thread_index); + _currently_polling_thread.store(current_thread_index, std::memory_order_relaxed); // Repeat the above until we (a) find a socket with actual noise on it, or // (b) return from PR_Poll() with no sockets available. diff --git a/panda/src/net/connectionReader.h b/panda/src/net/connectionReader.h index a1a8bdf33aa..96536d6fe64 100644 --- a/panda/src/net/connectionReader.h +++ b/panda/src/net/connectionReader.h @@ -24,7 +24,7 @@ #include "pvector.h" #include "pset.h" #include "socket_fdset.h" -#include "atomicAdjust.h" +#include "patomic.h" class NetDatagram; class ConnectionManager; @@ -160,7 +160,7 @@ class EXPCL_PANDA_NET ConnectionReader { // This is atomically updated with the index (in _threads) of the thread // that is currently waiting on the PR_Poll() call. It contains -1 if no // thread is so waiting. - AtomicAdjust::Integer _currently_polling_thread; + patomic _currently_polling_thread; friend class ConnectionManager; friend class ReaderThread; diff --git a/panda/src/pgraph/attribNodeRegistry.I b/panda/src/pgraph/attribNodeRegistry.I index 04a540466b2..406733fd789 100644 --- a/panda/src/pgraph/attribNodeRegistry.I +++ b/panda/src/pgraph/attribNodeRegistry.I @@ -16,10 +16,12 @@ */ INLINE AttribNodeRegistry *AttribNodeRegistry:: get_global_ptr() { - if (_global_ptr == nullptr) { + AttribNodeRegistry *ptr = _global_ptr.load(std::memory_order_consume); + if (ptr == nullptr) { make_global_ptr(); + ptr = _global_ptr.load(std::memory_order_consume); } - return _global_ptr; + return ptr; } /** diff --git a/panda/src/pgraph/attribNodeRegistry.cxx b/panda/src/pgraph/attribNodeRegistry.cxx index 721feb5572a..d2cd22c1ebb 100644 --- a/panda/src/pgraph/attribNodeRegistry.cxx +++ b/panda/src/pgraph/attribNodeRegistry.cxx @@ -14,7 +14,7 @@ #include "attribNodeRegistry.h" #include "lightMutexHolder.h" -AttribNodeRegistry * TVOLATILE AttribNodeRegistry::_global_ptr; +patomic AttribNodeRegistry::_global_ptr { nullptr }; /** * @@ -228,11 +228,12 @@ write(std::ostream &out) const { void AttribNodeRegistry:: make_global_ptr() { AttribNodeRegistry *ptr = new AttribNodeRegistry; - void *result = AtomicAdjust::compare_and_exchange_ptr - ((void * TVOLATILE &)_global_ptr, nullptr, (void *)ptr); - if (result != nullptr) { + AttribNodeRegistry *expected = nullptr; + if (!_global_ptr.compare_exchange_strong(expected, ptr, + std::memory_order_release, + std::memory_order_consume)) { // Someone else got there first. delete ptr; } - assert(_global_ptr != nullptr); + assert(_global_ptr.load(std::memory_order_relaxed) != nullptr); } diff --git a/panda/src/pgraph/attribNodeRegistry.h b/panda/src/pgraph/attribNodeRegistry.h index 51efa8ead05..88d09f6bd45 100644 --- a/panda/src/pgraph/attribNodeRegistry.h +++ b/panda/src/pgraph/attribNodeRegistry.h @@ -18,6 +18,7 @@ #include "nodePath.h" #include "ordered_vector.h" #include "lightMutex.h" +#include "patomic.h" /** * This global object records NodePaths that are referenced by scene graph @@ -74,7 +75,7 @@ class EXPCL_PANDA_PGRAPH AttribNodeRegistry { LightMutex _lock; - static AttribNodeRegistry * TVOLATILE _global_ptr; + static patomic _global_ptr; }; #include "attribNodeRegistry.I" diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index c05e7cc6c9e..9b60efd456a 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -37,7 +37,7 @@ compare_to(const TransformState &other) const { INLINE size_t TransformState:: get_hash() const { check_hash(); - return _hash; + return _hash.load(std::memory_order_relaxed); } /** @@ -856,7 +856,7 @@ INLINE void TransformState:: check_hash() const { // This pretends to be a const function, even though it's not, because it // only updates a transparent cache value. - if (_hash == H_unknown) { + if (_hash.load(std::memory_order_relaxed) == H_unknown) { calc_hash(); } } diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 8d7249d050f..d09ceb36bca 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -1410,7 +1410,7 @@ init_states() { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); state->_inv_mat = new (inv_mat_storage) LMatrix4(LMatrix4::ident_mat()); - state->_hash = H_identity; + state->_hash.store(H_identity, std::memory_order_relaxed); state->_flags = F_is_identity | F_singular_known | F_components_known | F_has_components | F_mat_known | F_quat_known | F_hpr_known | F_uniform_scale | F_identity_scale | F_is_2d @@ -1423,7 +1423,7 @@ init_states() { alignas(TransformState) static char storage[sizeof(TransformState)]; TransformState *state = new (storage) TransformState; state->local_object(); - state->_hash = H_invalid; + state->_hash.store(H_invalid, std::memory_order_relaxed); state->_flags = F_is_singular | F_singular_known | F_components_known | F_mat_known | F_is_invalid; state->cache_ref(); @@ -2013,7 +2013,7 @@ calc_hash() const { // cached values (only given components are considered), and (2) the hash // itself is set atomically. PStatTimer timer(_transform_hash_pcollector); - AtomicAdjust::Integer hash = 0; + size_t hash = 0; static const int significant_flags = (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d); @@ -2062,7 +2062,7 @@ calc_hash() const { // We don't care if some other thread set this in the meantime, since every // thread should have computed the same hash. - AtomicAdjust::set(_hash, hash); + _hash.store(hash, std::memory_order_relaxed); } /** diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index ca4727b25fd..26ba1ca84cd 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -381,12 +381,12 @@ class EXPCL_PANDA_PGRAPH TransformState final : public NodeCachedReferenceCount LMatrix4 _mat; LMatrix4 *_inv_mat = nullptr; - enum HashValue : AtomicAdjust::Integer { + enum HashValue : size_t { H_unknown = 0, H_identity = 1, H_invalid = 2, }; - mutable AtomicAdjust::Integer _hash = H_unknown; + mutable patomic _hash { H_unknown }; unsigned int _flags; diff --git a/panda/src/pgraphnodes/lightLensNode.cxx b/panda/src/pgraphnodes/lightLensNode.cxx index cb84c28dfbe..2caa2e7ac26 100644 --- a/panda/src/pgraphnodes/lightLensNode.cxx +++ b/panda/src/pgraphnodes/lightLensNode.cxx @@ -58,7 +58,7 @@ LightLensNode:: // If this triggers, the number of attrib_ref() didn't match the number of // attrib_unref() calls, probably indicating a bug in LightAttrib. - nassertv(AtomicAdjust::get(_attrib_count) == 0); + nassertv(_attrib_count.load(std::memory_order_acquire) == 0); } /** @@ -182,7 +182,7 @@ setup_shadow_map() { */ void LightLensNode:: attrib_ref() { - AtomicAdjust::inc(_attrib_count); + _attrib_count.fetch_add(1, std::memory_order_relaxed); } /** @@ -193,7 +193,7 @@ attrib_unref() { // When it is removed from the last LightAttrib, destroy the shadow buffers. // This is necessary to break the circular reference that the buffer holds // on this node, via the display region's camera. - if (!AtomicAdjust::dec(_attrib_count)) { + if (_attrib_count.fetch_sub(1, std::memory_order_release) == 1) { clear_shadow_buffers(); } } diff --git a/panda/src/pgraphnodes/lightLensNode.h b/panda/src/pgraphnodes/lightLensNode.h index 1d6b7720c8b..6b52c974513 100644 --- a/panda/src/pgraphnodes/lightLensNode.h +++ b/panda/src/pgraphnodes/lightLensNode.h @@ -20,7 +20,7 @@ #include "camera.h" #include "graphicsStateGuardianBase.h" #include "graphicsOutputBase.h" -#include "atomicAdjust.h" +#include "patomic.h" class ShaderGenerator; class GraphicsStateGuardian; @@ -76,7 +76,7 @@ class EXPCL_PANDA_PGRAPHNODES LightLensNode : public Light, public Camera { // This counts how many LightAttribs in the world are referencing this // LightLensNode object. - AtomicAdjust::Integer _attrib_count; + patomic _attrib_count { 0 }; public: virtual void attrib_ref(); diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.I b/panda/src/pipeline/conditionVarSpinlockImpl.I index b4747bd2207..d823e05d341 100644 --- a/panda/src/pipeline/conditionVarSpinlockImpl.I +++ b/panda/src/pipeline/conditionVarSpinlockImpl.I @@ -16,7 +16,6 @@ */ INLINE ConditionVarSpinlockImpl:: ConditionVarSpinlockImpl(MutexSpinlockImpl &mutex) : _mutex(mutex) { - _event = 0; } /** @@ -32,7 +31,7 @@ INLINE ConditionVarSpinlockImpl:: INLINE void ConditionVarSpinlockImpl:: notify() { // This will wake up all waiters on the lock. But that's allowed. - AtomicAdjust::inc(_event); + _event.fetch_add(1, std::memory_order_release); } /** @@ -40,5 +39,5 @@ notify() { */ INLINE void ConditionVarSpinlockImpl:: notify_all() { - AtomicAdjust::inc(_event); + _event.fetch_add(1, std::memory_order_release); } diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.cxx b/panda/src/pipeline/conditionVarSpinlockImpl.cxx index c5dc58ff967..ed11db253f6 100644 --- a/panda/src/pipeline/conditionVarSpinlockImpl.cxx +++ b/panda/src/pipeline/conditionVarSpinlockImpl.cxx @@ -32,10 +32,10 @@ */ void ConditionVarSpinlockImpl:: wait() { - AtomicAdjust::Integer current = _event; + unsigned int current = _event.load(std::memory_order_acquire); _mutex.unlock(); - while (AtomicAdjust::get(_event) == current) { + while (_event.load(std::memory_order_acquire) == current) { PAUSE(); } @@ -50,10 +50,10 @@ wait(double timeout) { TrueClock *clock = TrueClock::get_global_ptr(); double end_time = clock->get_short_time() + timeout; - AtomicAdjust::Integer current = _event; + unsigned int current = _event.load(std::memory_order_acquire); _mutex.unlock(); - while (AtomicAdjust::get(_event) == current && clock->get_short_time() < end_time) { + while (_event.load(std::memory_order_acquire) == current && clock->get_short_time() < end_time) { PAUSE(); } diff --git a/panda/src/pipeline/conditionVarSpinlockImpl.h b/panda/src/pipeline/conditionVarSpinlockImpl.h index 34b61645f83..bf3810c73fd 100644 --- a/panda/src/pipeline/conditionVarSpinlockImpl.h +++ b/panda/src/pipeline/conditionVarSpinlockImpl.h @@ -21,7 +21,7 @@ #include "mutexSpinlockImpl.h" #include "pnotify.h" -#include "atomicAdjust.h" +#include "patomic.h" class MutexSpinlockImpl; @@ -43,7 +43,7 @@ class EXPCL_PANDA_PIPELINE ConditionVarSpinlockImpl { private: MutexSpinlockImpl &_mutex; - TVOLATILE AtomicAdjust::Integer _event; + patomic _event { 0 }; }; #include "conditionVarSpinlockImpl.I" diff --git a/panda/src/pipeline/reMutexSpinlockImpl.I b/panda/src/pipeline/reMutexSpinlockImpl.I index 5f5e2d89c32..249ffa02e32 100644 --- a/panda/src/pipeline/reMutexSpinlockImpl.I +++ b/panda/src/pipeline/reMutexSpinlockImpl.I @@ -18,6 +18,6 @@ INLINE void ReMutexSpinlockImpl:: unlock() { assert(_counter > 0); if (!--_counter) { - AtomicAdjust::set_ptr(_locking_thread, nullptr); + _locking_thread.store(nullptr, std::memory_order_release); } } diff --git a/panda/src/pipeline/reMutexSpinlockImpl.cxx b/panda/src/pipeline/reMutexSpinlockImpl.cxx index 4ad9b124109..2c7615556d9 100644 --- a/panda/src/pipeline/reMutexSpinlockImpl.cxx +++ b/panda/src/pipeline/reMutexSpinlockImpl.cxx @@ -33,10 +33,15 @@ void ReMutexSpinlockImpl:: lock() { Thread *current_thread = Thread::get_current_thread(); - Thread *locking_thread = (Thread *)AtomicAdjust::compare_and_exchange_ptr(_locking_thread, nullptr, current_thread); - while (locking_thread != nullptr && locking_thread != current_thread) { + Thread *expected = nullptr; + while (!_locking_thread.compare_exchange_weak(expected, current_thread, + std::memory_order_acquire, + std::memory_order_relaxed)) { + if (expected == current_thread) { + break; + } PAUSE(); - locking_thread = (Thread *)AtomicAdjust::compare_and_exchange_ptr(_locking_thread, nullptr, current_thread); + expected = nullptr; } ++_counter; } @@ -47,8 +52,11 @@ lock() { bool ReMutexSpinlockImpl:: try_lock() { Thread *current_thread = Thread::get_current_thread(); - Thread *locking_thread = (Thread *)AtomicAdjust::compare_and_exchange_ptr(_locking_thread, nullptr, current_thread); - if (locking_thread == nullptr || locking_thread == current_thread) { + Thread *expected = nullptr; + if (_locking_thread.compare_exchange_strong(expected, current_thread, + std::memory_order_acquire, + std::memory_order_relaxed) || + expected == current_thread) { ++_counter; return true; } else { diff --git a/panda/src/pipeline/reMutexSpinlockImpl.h b/panda/src/pipeline/reMutexSpinlockImpl.h index 666ed832e38..761159481b8 100644 --- a/panda/src/pipeline/reMutexSpinlockImpl.h +++ b/panda/src/pipeline/reMutexSpinlockImpl.h @@ -19,7 +19,7 @@ #ifdef MUTEX_SPINLOCK -#include "atomicAdjust.h" +#include "patomic.h" class Thread; @@ -42,7 +42,7 @@ class EXPCL_PANDA_PIPELINE ReMutexSpinlockImpl { INLINE void unlock(); private: - AtomicAdjust::Pointer _locking_thread = nullptr; + patomic _locking_thread { nullptr }; unsigned int _counter = 0; }; diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index 3d3042a8e3d..e0c264458f3 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -297,7 +297,7 @@ preempt() { */ INLINE TypedReferenceCount *Thread:: get_current_task() const { - return (TypedReferenceCount *)_current_task; + return _current_task.load(std::memory_order_relaxed); } /** diff --git a/panda/src/pipeline/thread.cxx b/panda/src/pipeline/thread.cxx index 179fdba4424..706eae2a750 100644 --- a/panda/src/pipeline/thread.cxx +++ b/panda/src/pipeline/thread.cxx @@ -49,7 +49,7 @@ Thread(const std::string &name, const std::string &sync_name) : _pstats_callback = nullptr; _pipeline_stage = 0; _joinable = false; - _current_task = nullptr; + _current_task.store(nullptr, std::memory_order_relaxed); #ifdef DEBUG_THREADS _blocked_on_mutex = nullptr; diff --git a/panda/src/pipeline/thread.h b/panda/src/pipeline/thread.h index 1e6948cbc03..fcd4aea59e5 100644 --- a/panda/src/pipeline/thread.h +++ b/panda/src/pipeline/thread.h @@ -22,6 +22,7 @@ #include "threadImpl.h" #include "pnotify.h" #include "config_pipeline.h" +#include "patomic.h" #ifdef ANDROID typedef struct _JNIEnv JNIEnv; @@ -153,7 +154,7 @@ class ALIGN_64BYTE EXPCL_PANDA_PIPELINE Thread : public TypedReferenceCount, pub int _pipeline_stage; PStatsCallback *_pstats_callback; bool _joinable; - AtomicAdjust::Pointer _current_task; + patomic _current_task; int _python_index; diff --git a/panda/src/putil/cachedTypedWritableReferenceCount.I b/panda/src/putil/cachedTypedWritableReferenceCount.I index dae8502d4ba..8bc62898661 100644 --- a/panda/src/putil/cachedTypedWritableReferenceCount.I +++ b/panda/src/putil/cachedTypedWritableReferenceCount.I @@ -21,8 +21,7 @@ * inheritance. */ INLINE CachedTypedWritableReferenceCount:: -CachedTypedWritableReferenceCount() { - _cache_ref_count = 0; +CachedTypedWritableReferenceCount() : _cache_ref_count(0) { } /** @@ -34,8 +33,7 @@ CachedTypedWritableReferenceCount() { * try. */ INLINE CachedTypedWritableReferenceCount:: -CachedTypedWritableReferenceCount(const CachedTypedWritableReferenceCount ©) : TypedWritableReferenceCount(copy) { - _cache_ref_count = 0; +CachedTypedWritableReferenceCount(const CachedTypedWritableReferenceCount ©) : TypedWritableReferenceCount(copy), _cache_ref_count(0) { } /** @@ -55,7 +53,7 @@ operator = (const CachedTypedWritableReferenceCount ©) { // to create an automatic (local variable) instance of a class that derives // from ReferenceCount. Or maybe your headers are out of sync, and you need // to make clean in direct or some higher tree. - nassertv(_cache_ref_count != -100); + nassertv(_cache_ref_count.load(std::memory_order_relaxed) != -100); TypedWritableReferenceCount::operator = (copy); } @@ -69,17 +67,19 @@ operator = (const CachedTypedWritableReferenceCount ©) { */ INLINE CachedTypedWritableReferenceCount:: ~CachedTypedWritableReferenceCount() { + int ref_count = _cache_ref_count.load(std::memory_order_relaxed); + // If this assertion fails, we're trying to delete an object that was just // deleted. Possibly you used a real pointer instead of a PointerTo at some // point, and the object was deleted when the PointerTo went out of scope. // Maybe you tried to create an automatic (local variable) instance of a // class that derives from ReferenceCount. Or maybe your headers are out of // sync, and you need to make clean in direct or some higher tree. - nassertv(_cache_ref_count != -100); + nassertv(ref_count != -100); // If this assertion fails, the reference counts are all screwed up // altogether. Maybe some errant code stomped all over memory somewhere. - nassertv(_cache_ref_count >= 0); + nassertv(ref_count >= 0); // If this assertion fails, someone tried to delete this object while its // reference count was still positive. Maybe you tried to point a PointerTo @@ -90,13 +90,13 @@ INLINE CachedTypedWritableReferenceCount:: // Another possibility is you inadvertently omitted a copy constructor for a // ReferenceCount object, and then bitwise copied a dynamically allocated // value--reference count and all--onto a locally allocated one. - nassertv(_cache_ref_count == 0); + nassertv(ref_count == 0); #ifndef NDEBUG // Ok, all clear to delete. Now set the reference count to -100, so we'll // have a better chance of noticing if we happen to have a stray pointer to // it still out there. - _cache_ref_count = -100; + _cache_ref_count.store(-100, std::memory_order_relaxed); #endif } @@ -108,7 +108,7 @@ get_cache_ref_count() const { #ifdef _DEBUG test_ref_count_integrity(); #endif - return (int)AtomicAdjust::get(_cache_ref_count); + return _cache_ref_count.load(std::memory_order_acquire); } /** @@ -122,7 +122,7 @@ cache_ref() const { #endif ref(); - AtomicAdjust::inc(_cache_ref_count); + _cache_ref_count.fetch_add(1, std::memory_order_relaxed); } /** @@ -141,9 +141,9 @@ cache_unref() const { // If this assertion fails, you tried to unref an object with a zero // reference count. Are you using ref() and unref() directly? Are you sure // you can't use PointerTo's? - nassertr(_cache_ref_count > 0, 0); + nassertr(_cache_ref_count.load(std::memory_order_relaxed) > 0, 0); - AtomicAdjust::dec(_cache_ref_count); + _cache_ref_count.fetch_sub(1, std::memory_order_release); return ReferenceCount::unref(); } @@ -170,7 +170,7 @@ cache_ref_only() const { nassertv(test_ref_count_integrity()); #endif - AtomicAdjust::inc(_cache_ref_count); + _cache_ref_count.fetch_add(1, std::memory_order_relaxed); } /** @@ -187,9 +187,9 @@ cache_unref_only() const { // If this assertion fails, you tried to unref an object with a zero // reference count. Are you using ref() and unref() directly? Are you sure // you can't use PointerTo's? - nassertv(_cache_ref_count > 0); + nassertv(_cache_ref_count.load(std::memory_order_relaxed) > 0); - AtomicAdjust::dec(_cache_ref_count); + _cache_ref_count.fetch_sub(1, std::memory_order_release); } /** diff --git a/panda/src/putil/cachedTypedWritableReferenceCount.cxx b/panda/src/putil/cachedTypedWritableReferenceCount.cxx index d7ee3ed74da..d3cec9876b1 100644 --- a/panda/src/putil/cachedTypedWritableReferenceCount.cxx +++ b/panda/src/putil/cachedTypedWritableReferenceCount.cxx @@ -21,17 +21,19 @@ TypeHandle CachedTypedWritableReferenceCount::_type_handle; */ bool CachedTypedWritableReferenceCount:: do_test_ref_count_integrity() const { + int ref_count = _cache_ref_count.load(std::memory_order_relaxed); + // If this assertion fails, we're trying to delete an object that was just // deleted. Possibly you used a real pointer instead of a PointerTo at some // point, and the object was deleted when the PointerTo went out of scope. // Maybe you tried to create an automatic (local variable) instance of a // class that derives from ReferenceCount. Or maybe your headers are out of // sync, and you need to make clean in direct or some higher tree. - nassertr(_cache_ref_count != -100, false); + nassertr(ref_count != -100, false); // If this assertion fails, the reference counts are all screwed up // altogether. Maybe some errant code stomped all over memory somewhere. - nassertr(_cache_ref_count >= 0, false); + nassertr(ref_count >= 0, false); return TypedWritableReferenceCount::do_test_ref_count_integrity(); } diff --git a/panda/src/putil/cachedTypedWritableReferenceCount.h b/panda/src/putil/cachedTypedWritableReferenceCount.h index f2e9362dcae..18ee3528ab4 100644 --- a/panda/src/putil/cachedTypedWritableReferenceCount.h +++ b/panda/src/putil/cachedTypedWritableReferenceCount.h @@ -54,7 +54,7 @@ class EXPCL_PANDA_PUTIL CachedTypedWritableReferenceCount : public TypedWritable bool do_test_ref_count_integrity() const; private: - mutable AtomicAdjust::Integer _cache_ref_count; + mutable patomic _cache_ref_count; public: static TypeHandle get_class_type() { diff --git a/panda/src/putil/nodeCachedReferenceCount.I b/panda/src/putil/nodeCachedReferenceCount.I index 92abe19ce3a..a356d4a48dc 100644 --- a/panda/src/putil/nodeCachedReferenceCount.I +++ b/panda/src/putil/nodeCachedReferenceCount.I @@ -21,8 +21,7 @@ * inheritance. */ INLINE NodeCachedReferenceCount:: -NodeCachedReferenceCount() { - _node_ref_count = 0; +NodeCachedReferenceCount() : _node_ref_count(0) { } /** @@ -34,8 +33,7 @@ NodeCachedReferenceCount() { * try. */ INLINE NodeCachedReferenceCount:: -NodeCachedReferenceCount(const NodeCachedReferenceCount ©) : CachedTypedWritableReferenceCount(copy) { - _node_ref_count = 0; +NodeCachedReferenceCount(const NodeCachedReferenceCount ©) : CachedTypedWritableReferenceCount(copy), _node_ref_count(0) { } /** @@ -55,7 +53,7 @@ operator = (const NodeCachedReferenceCount ©) { // to create an automatic (local variable) instance of a class that derives // from ReferenceCount. Or maybe your headers are out of sync, and you need // to make clean in direct or some higher tree. - nassertv(_node_ref_count != -100); + nassertv(_node_ref_count.load(std::memory_order_relaxed) != -100); CachedTypedWritableReferenceCount::operator = (copy); } @@ -69,17 +67,19 @@ operator = (const NodeCachedReferenceCount ©) { */ INLINE NodeCachedReferenceCount:: ~NodeCachedReferenceCount() { + int ref_count = _node_ref_count.load(std::memory_order_relaxed); + // If this assertion fails, we're trying to delete an object that was just // deleted. Possibly you used a real pointer instead of a PointerTo at some // point, and the object was deleted when the PointerTo went out of scope. // Maybe you tried to create an automatic (local variable) instance of a // class that derives from ReferenceCount. Or maybe your headers are out of // sync, and you need to make clean in direct or some higher tree. - nassertv(_node_ref_count != -100); + nassertv(ref_count != -100); // If this assertion fails, the reference counts are all screwed up // altogether. Maybe some errant code stomped all over memory somewhere. - nassertv(_node_ref_count >= 0); + nassertv(ref_count >= 0); // If this assertion fails, someone tried to delete this object while its // reference count was still positive. Maybe you tried to point a PointerTo @@ -90,13 +90,13 @@ INLINE NodeCachedReferenceCount:: // Another possibility is you inadvertently omitted a copy constructor for a // ReferenceCount object, and then bitwise copied a dynamically allocated // value--reference count and all--onto a locally allocated one. - nassertv(_node_ref_count == 0); + nassertv(ref_count == 0); #ifndef NDEBUG // Ok, all clear to delete. Now set the reference count to -100, so we'll // have a better chance of noticing if we happen to have a stray pointer to // it still out there. - _node_ref_count = -100; + _node_ref_count.store(-100, std::memory_order_relaxed); #endif } @@ -108,7 +108,7 @@ get_node_ref_count() const { #ifdef _DEBUG test_ref_count_integrity(); #endif - return (int)AtomicAdjust::get(_node_ref_count); + return _node_ref_count.load(std::memory_order_acquire); } /** @@ -126,7 +126,7 @@ node_ref() const { #endif ref(); - AtomicAdjust::inc(((NodeCachedReferenceCount *)this)->_node_ref_count); + _node_ref_count.fetch_add(1, std::memory_order_relaxed); } /** @@ -190,7 +190,7 @@ node_unref_only() const { // If this assertion fails, you tried to unref an object with a zero // reference count. Are you using ref() and unref() directly? Are you sure // you can't use PointerTo's? - nassertv(_node_ref_count > 0); + nassertv(_node_ref_count.load(std::memory_order_relaxed) > 0); - AtomicAdjust::dec(((NodeCachedReferenceCount *)this)->_node_ref_count); + _node_ref_count.fetch_sub(1, std::memory_order_release); } diff --git a/panda/src/putil/nodeCachedReferenceCount.cxx b/panda/src/putil/nodeCachedReferenceCount.cxx index f53ff22b960..22b153c5b57 100644 --- a/panda/src/putil/nodeCachedReferenceCount.cxx +++ b/panda/src/putil/nodeCachedReferenceCount.cxx @@ -21,17 +21,19 @@ TypeHandle NodeCachedReferenceCount::_type_handle; */ bool NodeCachedReferenceCount:: do_test_ref_count_integrity() const { + int ref_count = _node_ref_count.load(std::memory_order_relaxed); + // If this assertion fails, we're trying to delete an object that was just // deleted. Possibly you used a real pointer instead of a PointerTo at some // point, and the object was deleted when the PointerTo went out of scope. // Maybe you tried to create an automatic (local variable) instance of a // class that derives from ReferenceCount. Or maybe your headers are out of // sync, and you need to make clean in direct or some higher tree. - nassertr(_node_ref_count != -100, false); + nassertr(ref_count != -100, false); // If this assertion fails, the reference counts are all screwed up // altogether. Maybe some errant code stomped all over memory somewhere. - nassertr(_node_ref_count >= 0, false); + nassertr(ref_count >= 0, false); return CachedTypedWritableReferenceCount::do_test_ref_count_integrity(); } diff --git a/panda/src/putil/nodeCachedReferenceCount.h b/panda/src/putil/nodeCachedReferenceCount.h index 1ed34650b6e..22413391c5a 100644 --- a/panda/src/putil/nodeCachedReferenceCount.h +++ b/panda/src/putil/nodeCachedReferenceCount.h @@ -71,7 +71,7 @@ class EXPCL_PANDA_PUTIL NodeCachedReferenceCount : public CachedTypedWritableRef bool do_test_ref_count_integrity() const; private: - AtomicAdjust::Integer _node_ref_count; + mutable patomic _node_ref_count; public: static TypeHandle get_class_type() { diff --git a/panda/src/putil/typedWritable.cxx b/panda/src/putil/typedWritable.cxx index 8ca4081c631..a4039b81e55 100644 --- a/panda/src/putil/typedWritable.cxx +++ b/panda/src/putil/typedWritable.cxx @@ -28,16 +28,19 @@ TypedWritable:: ~TypedWritable() { // Remove the object pointer from the BamWriters that reference it. BamWriterLink *link; + BamWriterLink *clean_link; do { - link = (BamWriterLink *)AtomicAdjust::get_ptr(_bam_writers); + link = _bam_writers.load(std::memory_order_acquire); if (link == nullptr) { // List is unlocked and empty - no writers to remove. return; } - link = (BamWriterLink *)(((uintptr_t)link) & ~(uintptr_t)0x1); - } while (link != AtomicAdjust:: - compare_and_exchange_ptr(_bam_writers, (void *)link, nullptr)); + clean_link = (BamWriterLink *)(((uintptr_t)link) & ~(uintptr_t)0x1); + } while (!_bam_writers.compare_exchange_weak(clean_link, nullptr, + std::memory_order_acquire, + std::memory_order_acquire)); + link = clean_link; while (link != nullptr) { BamWriterLink *next_link = link->_next; link->_writer->object_destructs(this); @@ -276,11 +279,12 @@ add_bam_writer(BamWriter *writer) { // This spins if the lower bit is 1, ie. if the pointer is locked. do { - begin = (BamWriterLink *)AtomicAdjust::get_ptr(_bam_writers); + begin = _bam_writers.load(std::memory_order_acquire); begin = (BamWriterLink *)(((uintptr_t)begin) & ~(uintptr_t)0x1); new_link->_next = begin; - } while (begin != AtomicAdjust:: - compare_and_exchange_ptr(_bam_writers, (void *)begin, (void *)new_link)); + } while (!_bam_writers.compare_exchange_weak(begin, new_link, + std::memory_order_release, + std::memory_order_relaxed)); } /** @@ -296,15 +300,15 @@ remove_bam_writer(BamWriter *writer) { // Grab the head pointer and lock it in one atomic operation. We lock it by // tagging the pointer. do { - begin = (BamWriterLink *)AtomicAdjust::get_ptr(_bam_writers); + begin = _bam_writers.load(std::memory_order_acquire); begin = (BamWriterLink *)(((uintptr_t)begin) & ~(uintptr_t)0x1); if (begin == nullptr) { // The list is empty, nothing to remove. return; } - } while (begin != AtomicAdjust:: - compare_and_exchange_ptr(_bam_writers, (void *)begin, - (void *)((uintptr_t)begin | (uintptr_t)0x1))); + } while (!_bam_writers.compare_exchange_weak( + begin, (BamWriterLink *)((uintptr_t)begin | (uintptr_t)0x1), + std::memory_order_acquire, std::memory_order_relaxed)); // Find the writer in the list. BamWriterLink *prev_link = nullptr; @@ -317,16 +321,16 @@ remove_bam_writer(BamWriter *writer) { if (link == nullptr) { // Not found. Just unlock and leave. - _bam_writers = (void *)begin; + _bam_writers.store(begin, std::memory_order_release); return; } if (prev_link == nullptr) { // It's the first link. Replace and unlock in one atomic op. - _bam_writers = (void *)link->_next; + _bam_writers.store(link->_next, std::memory_order_release); } else { prev_link->_next = link->_next; - _bam_writers = (void *)begin; // Unlock + _bam_writers.store(begin, std::memory_order_release); // Unlock } delete link; diff --git a/panda/src/putil/typedWritable.h b/panda/src/putil/typedWritable.h index a97d3812b19..c07f69904b8 100644 --- a/panda/src/putil/typedWritable.h +++ b/panda/src/putil/typedWritable.h @@ -84,7 +84,7 @@ class EXPCL_PANDA_PUTIL TypedWritable : public TypedObject { BamWriter *_writer; BamWriterLink *_next; }; - AtomicAdjust::Pointer _bam_writers; // Tagged pointer + patomic _bam_writers; // Tagged pointer UpdateSeq _bam_modified; diff --git a/panda/src/putil/updateSeq.I b/panda/src/putil/updateSeq.I index bc620002a0e..d3a41779af6 100644 --- a/panda/src/putil/updateSeq.I +++ b/panda/src/putil/updateSeq.I @@ -29,14 +29,14 @@ UpdateSeq() : _seq((unsigned int)SC_initial) { * */ INLINE UpdateSeq:: -UpdateSeq(const UpdateSeq ©) : _seq(AtomicAdjust::get(copy._seq)) { +UpdateSeq(const UpdateSeq ©) : _seq(copy._seq.load(std::memory_order_relaxed)) { } /** * */ -constexpr UpdateSeq:: -UpdateSeq(const UpdateSeq &&from) noexcept : _seq(from._seq) { +INLINE UpdateSeq:: +UpdateSeq(const UpdateSeq &&from) noexcept : _seq(from._seq.load(std::memory_order_relaxed)) { } /** @@ -44,7 +44,7 @@ UpdateSeq(const UpdateSeq &&from) noexcept : _seq(from._seq) { */ INLINE UpdateSeq &UpdateSeq:: operator = (const UpdateSeq ©) { - AtomicAdjust::set(_seq, AtomicAdjust::get(copy._seq)); + _seq.store(copy._seq.load(std::memory_order_relaxed), std::memory_order_relaxed); return *this; } @@ -53,7 +53,7 @@ operator = (const UpdateSeq ©) { */ INLINE void UpdateSeq:: clear() { - AtomicAdjust::set(_seq, (AtomicAdjust::Integer)SC_initial); + _seq.store((unsigned int)SC_initial, std::memory_order_relaxed); } /** @@ -61,7 +61,7 @@ clear() { */ INLINE bool UpdateSeq:: is_initial() const { - return AtomicAdjust::get(_seq) == (AtomicAdjust::Integer)SC_initial; + return _seq.load(std::memory_order_relaxed) == (unsigned int)SC_initial; } /** @@ -69,7 +69,7 @@ is_initial() const { */ INLINE bool UpdateSeq:: is_old() const { - return AtomicAdjust::get(_seq) == (AtomicAdjust::Integer)SC_old; + return _seq.load(std::memory_order_relaxed) == (unsigned int)SC_old; } /** @@ -77,7 +77,7 @@ is_old() const { */ INLINE bool UpdateSeq:: is_fresh() const { - return AtomicAdjust::get(_seq) == (AtomicAdjust::Integer)SC_fresh; + return _seq.load(std::memory_order_relaxed) == (unsigned int)SC_fresh; } /** @@ -87,7 +87,7 @@ is_fresh() const { INLINE bool UpdateSeq:: is_special() const { // This relies on the assumption that (~0 + 1) == 0. - return (((unsigned int)AtomicAdjust::get(_seq) + 1u) <= 2u); + return ((_seq.load(std::memory_order_relaxed) + 1u) <= 2u); } /** @@ -95,7 +95,7 @@ is_special() const { */ INLINE bool UpdateSeq:: operator == (const UpdateSeq &other) const { - return AtomicAdjust::get(_seq) == AtomicAdjust::get(other._seq); + return _seq.load(std::memory_order_relaxed) == other._seq.load(std::memory_order_relaxed); } /** @@ -103,7 +103,7 @@ operator == (const UpdateSeq &other) const { */ INLINE bool UpdateSeq:: operator != (const UpdateSeq &other) const { - return AtomicAdjust::get(_seq) != AtomicAdjust::get(other._seq); + return _seq.load(std::memory_order_relaxed) != other._seq.load(std::memory_order_relaxed); } /** @@ -111,7 +111,7 @@ operator != (const UpdateSeq &other) const { */ INLINE bool UpdateSeq:: operator < (const UpdateSeq &other) const { - return priv_lt(AtomicAdjust::get(_seq), AtomicAdjust::get(other._seq)); + return priv_lt(_seq.load(std::memory_order_relaxed), other._seq.load(std::memory_order_relaxed)); } /** @@ -119,7 +119,7 @@ operator < (const UpdateSeq &other) const { */ INLINE bool UpdateSeq:: operator <= (const UpdateSeq &other) const { - return priv_le(AtomicAdjust::get(_seq), AtomicAdjust::get(other._seq)); + return priv_le(_seq.load(std::memory_order_relaxed), other._seq.load(std::memory_order_relaxed)); } /** @@ -143,32 +143,22 @@ operator >= (const UpdateSeq &other) const { */ INLINE UpdateSeq UpdateSeq:: operator ++ () { - AtomicAdjust::Integer old_seq = AtomicAdjust::get(_seq); - AtomicAdjust::Integer new_seq = old_seq + 1; - if (priv_is_special(new_seq)) { - // Oops, wraparound. We don't want to confuse the new value with our - // special cases. - new_seq = (AtomicAdjust::Integer)SC_old + 1; - } - -#ifdef HAVE_THREADS - AtomicAdjust::Integer result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq); - while (result != old_seq) { - // Some other thread beat us to it; try again. - old_seq = AtomicAdjust::get(_seq); + unsigned int old_seq = _seq.load(std::memory_order_relaxed); + unsigned int new_seq; + do { new_seq = old_seq + 1; if (priv_is_special(new_seq)) { // Oops, wraparound. We don't want to confuse the new value with our // special cases. - new_seq = (AtomicAdjust::Integer)SC_old + 1; + new_seq = (unsigned int)SC_old + 1; } - result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq); - } -#else - _seq = new_seq; -#endif // HAVE_THREADS + } while (!_seq.compare_exchange_weak(old_seq, new_seq, + std::memory_order_relaxed, + std::memory_order_relaxed)); - return *this; + UpdateSeq temp; + temp._seq.store(new_seq, std::memory_order_relaxed); + return temp; } /** @@ -176,33 +166,21 @@ operator ++ () { */ INLINE UpdateSeq UpdateSeq:: operator ++ (int) { - AtomicAdjust::Integer old_seq = AtomicAdjust::get(_seq); - AtomicAdjust::Integer new_seq = old_seq + 1; - if (priv_is_special(new_seq)) { - // Oops, wraparound. We don't want to confuse the new value with our - // special cases. - new_seq = (AtomicAdjust::Integer)SC_old + 1; - } - -#ifdef HAVE_THREADS - AtomicAdjust::Integer result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq); - while (result != old_seq) { - // Some other thread beat us to it; try again. - old_seq = AtomicAdjust::get(_seq); + unsigned int old_seq = _seq.load(std::memory_order_relaxed); + unsigned int new_seq; + do { new_seq = old_seq + 1; if (priv_is_special(new_seq)) { // Oops, wraparound. We don't want to confuse the new value with our // special cases. - new_seq = (AtomicAdjust::Integer)SC_old + 1; + new_seq = (unsigned int)SC_old + 1; } - result = AtomicAdjust::compare_and_exchange(_seq, old_seq, new_seq); - } -#else - _seq = new_seq; -#endif // HAVE_THREADS + } while (!_seq.compare_exchange_weak(old_seq, new_seq, + std::memory_order_relaxed, + std::memory_order_relaxed)); UpdateSeq temp; - temp._seq = old_seq; + temp._seq.store(old_seq, std::memory_order_relaxed); return temp; } @@ -210,9 +188,9 @@ operator ++ (int) { * Returns the internal integer value associated with the UpdateSeq. Useful * for debugging only. */ -INLINE AtomicAdjust::Integer UpdateSeq:: +INLINE unsigned int UpdateSeq:: get_seq() const { - return _seq; + return _seq.load(std::memory_order_relaxed); } /** @@ -220,17 +198,17 @@ get_seq() const { */ INLINE void UpdateSeq:: output(std::ostream &out) const { - AtomicAdjust::Integer seq = AtomicAdjust::get(_seq); + unsigned int seq = _seq.load(std::memory_order_relaxed); switch (seq) { - case (AtomicAdjust::Integer)SC_initial: + case (unsigned int)SC_initial: out << "initial"; break; - case (AtomicAdjust::Integer)SC_old: + case (unsigned int)SC_old: out << "old"; break; - case (AtomicAdjust::Integer)SC_fresh: + case (unsigned int)SC_fresh: out << "fresh"; break; @@ -243,23 +221,23 @@ output(std::ostream &out) const { * The private implementation of is_special(). */ INLINE bool UpdateSeq:: -priv_is_special(AtomicAdjust::Integer seq) { +priv_is_special(unsigned int seq) { // This relies on the assumption that (~0 + 1) == 0. - return (((unsigned int)seq + 1) <= 2); + return ((seq + 1) <= 2); } /** * The private implementation of operator < (). */ INLINE bool UpdateSeq:: -priv_lt(AtomicAdjust::Integer a, AtomicAdjust::Integer b) { +priv_lt(unsigned int a, unsigned int b) { // The special cases of SC_initial or SC_old are less than all other non- // special numbers, and SC_initial is less than SC_old. The special case of // SC_fresh is greater than all other non-special numbers. For all other // cases, we use a circular comparision such that n < m iff (signed)(n - m) // < 0. return - (priv_is_special(a) || priv_is_special(b)) ? ((unsigned int)a < (unsigned int)b) : + (priv_is_special(a) || priv_is_special(b)) ? (a < b) : ((signed int)(a - b) < 0); } @@ -267,7 +245,7 @@ priv_lt(AtomicAdjust::Integer a, AtomicAdjust::Integer b) { * The private implementation of operator <= (). */ INLINE bool UpdateSeq:: -priv_le(AtomicAdjust::Integer a, AtomicAdjust::Integer b) { +priv_le(unsigned int a, unsigned int b) { return (a == b) || priv_lt(a, b); } diff --git a/panda/src/putil/updateSeq.h b/panda/src/putil/updateSeq.h index f4feed804ab..8fc8aa3280a 100644 --- a/panda/src/putil/updateSeq.h +++ b/panda/src/putil/updateSeq.h @@ -17,7 +17,7 @@ #include "pandabase.h" #include "pmutex.h" #include "mutexHolder.h" -#include "atomicAdjust.h" +#include "patomic.h" #include "numeric_types.h" /** @@ -45,7 +45,7 @@ class EXPCL_PANDA_PUTIL UpdateSeq { constexpr static UpdateSeq fresh() { return UpdateSeq(SC_fresh); } INLINE UpdateSeq(const UpdateSeq ©); - constexpr UpdateSeq(const UpdateSeq &&from) noexcept; + INLINE UpdateSeq(const UpdateSeq &&from) noexcept; INLINE UpdateSeq &operator = (const UpdateSeq ©); INLINE void clear(); @@ -65,15 +65,15 @@ class EXPCL_PANDA_PUTIL UpdateSeq { INLINE UpdateSeq operator ++ (); INLINE UpdateSeq operator ++ (int); - INLINE AtomicAdjust::Integer get_seq() const; + INLINE unsigned int get_seq() const; MAKE_PROPERTY(seq, get_seq); INLINE void output(std::ostream &out) const; private: - INLINE static bool priv_is_special(AtomicAdjust::Integer seq); - INLINE static bool priv_lt(AtomicAdjust::Integer a, AtomicAdjust::Integer b); - INLINE static bool priv_le(AtomicAdjust::Integer a, AtomicAdjust::Integer b); + INLINE static bool priv_is_special(unsigned int seq); + INLINE static bool priv_lt(unsigned int a, unsigned int b); + INLINE static bool priv_le(unsigned int a, unsigned int b); private: enum SpecialCases : unsigned int { @@ -82,7 +82,7 @@ class EXPCL_PANDA_PUTIL UpdateSeq { SC_fresh = ~(unsigned int)0, }; - AtomicAdjust::Integer _seq; + patomic _seq; }; INLINE std::ostream &operator << (std::ostream &out, const UpdateSeq &value); From d232a930c3eb89c113f60c2282eb4b58dd261e35 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 13 May 2026 13:43:05 +0200 Subject: [PATCH 3/5] dtoolbase: Remove AtomicAdjust Fixes #258 --- dtool/src/dtoolbase/CMakeLists.txt | 10 - dtool/src/dtoolbase/atomicAdjust.h | 81 -------- dtool/src/dtoolbase/atomicAdjustDummyImpl.I | 117 ----------- dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx | 15 -- dtool/src/dtoolbase/atomicAdjustDummyImpl.h | 52 ----- dtool/src/dtoolbase/atomicAdjustGccImpl.I | 119 ----------- dtool/src/dtoolbase/atomicAdjustGccImpl.h | 58 ------ dtool/src/dtoolbase/atomicAdjustI386Impl.I | 192 ------------------ dtool/src/dtoolbase/atomicAdjustI386Impl.cxx | 14 -- dtool/src/dtoolbase/atomicAdjustI386Impl.h | 57 ------ dtool/src/dtoolbase/atomicAdjustPosixImpl.I | 146 ------------- dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx | 22 -- dtool/src/dtoolbase/atomicAdjustPosixImpl.h | 61 ------ dtool/src/dtoolbase/atomicAdjustWin32Impl.I | 154 -------------- dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx | 20 -- dtool/src/dtoolbase/atomicAdjustWin32Impl.h | 67 ------ .../src/dtoolbase/p3dtoolbase_composite1.cxx | 4 - panda/src/pipeline/test_atomic.cxx | 94 --------- 18 files changed, 1283 deletions(-) delete mode 100644 dtool/src/dtoolbase/atomicAdjust.h delete mode 100644 dtool/src/dtoolbase/atomicAdjustDummyImpl.I delete mode 100644 dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx delete mode 100644 dtool/src/dtoolbase/atomicAdjustDummyImpl.h delete mode 100644 dtool/src/dtoolbase/atomicAdjustGccImpl.I delete mode 100644 dtool/src/dtoolbase/atomicAdjustGccImpl.h delete mode 100644 dtool/src/dtoolbase/atomicAdjustI386Impl.I delete mode 100644 dtool/src/dtoolbase/atomicAdjustI386Impl.cxx delete mode 100644 dtool/src/dtoolbase/atomicAdjustI386Impl.h delete mode 100644 dtool/src/dtoolbase/atomicAdjustPosixImpl.I delete mode 100644 dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx delete mode 100644 dtool/src/dtoolbase/atomicAdjustPosixImpl.h delete mode 100644 dtool/src/dtoolbase/atomicAdjustWin32Impl.I delete mode 100644 dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx delete mode 100644 dtool/src/dtoolbase/atomicAdjustWin32Impl.h delete mode 100644 panda/src/pipeline/test_atomic.cxx diff --git a/dtool/src/dtoolbase/CMakeLists.txt b/dtool/src/dtoolbase/CMakeLists.txt index a7619d77a76..382fb20819b 100644 --- a/dtool/src/dtoolbase/CMakeLists.txt +++ b/dtool/src/dtoolbase/CMakeLists.txt @@ -13,12 +13,6 @@ set(P3DTOOLBASE_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/checkPandaVersion.h ${CMAKE_CURRENT_BINARY_DIR}/pandaVersion.h addHash.I addHash.h - atomicAdjust.h - atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I - atomicAdjustGccImpl.h atomicAdjustGccImpl.I - atomicAdjustI386Impl.h atomicAdjustI386Impl.I - atomicAdjustPosixImpl.h atomicAdjustPosixImpl.I - atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I cmath.I cmath.h deletedBufferChain.h deletedBufferChain.I deletedChain.h deletedChain.I @@ -58,10 +52,6 @@ set(P3DTOOLBASE_HEADERS set(P3DTOOLBASE_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/checkPandaVersion.cxx addHash.cxx - atomicAdjustDummyImpl.cxx - atomicAdjustI386Impl.cxx - atomicAdjustPosixImpl.cxx - atomicAdjustWin32Impl.cxx deletedBufferChain.cxx dtoolbase.cxx indent.cxx diff --git a/dtool/src/dtoolbase/atomicAdjust.h b/dtool/src/dtoolbase/atomicAdjust.h deleted file mode 100644 index 014c4c44455..00000000000 --- a/dtool/src/dtoolbase/atomicAdjust.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjust.h - * @author drose - * @date 2002-08-09 - */ - -#ifndef ATOMICADJUST_H -#define ATOMICADJUST_H - -#include "dtoolbase.h" -#include "selectThreadImpl.h" - -#if defined(CPPPARSER) - -struct AtomicAdjust { - typedef long Integer; - typedef void *UnalignedPointer; - typedef UnalignedPointer Pointer; -}; - -#elif defined(THREAD_DUMMY_IMPL) || defined(THREAD_SIMPLE_IMPL) - -#include "atomicAdjustDummyImpl.h" -typedef AtomicAdjustDummyImpl AtomicAdjust; - -#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(__clang__) && (__clang_major__ >= 3) && !defined(WIN32_VC) ) -// GCC 4.7 and above has built-in __atomic functions for atomic operations. -// Clang 3.0 and above also supports them. - -#include "atomicAdjustGccImpl.h" -typedef AtomicAdjustGccImpl AtomicAdjust; - -#if (__GCC_ATOMIC_INT_LOCK_FREE + __GCC_ATOMIC_LONG_LOCK_FREE) > 0 -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1 -#endif -#if __GCC_ATOMIC_POINTER_LOCK_FREE > 0 -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1 -#endif - -#elif (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__) -// For an i386 architecture, we'll always use the i386 implementation. It -// should be safe for any OS, and it might be a bit faster than any OS- -// provided calls. - -#include "atomicAdjustI386Impl.h" -typedef AtomicAdjustI386Impl AtomicAdjust; - -// These symbols are defined if the compare_and_exchange() methods are -// implemented natively, without recourse to external locks. If these are not -// defined, users may elect to implement an operation with some other method -// than compare_and_exchange(), which might be faster. -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1 -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1 - -#elif defined(THREAD_WIN32_IMPL) - -#include "atomicAdjustWin32Impl.h" -typedef AtomicAdjustWin32Impl AtomicAdjust; - -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE 1 -#define HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR 1 - -#elif defined(THREAD_LINUX_IMPL) - -#error Linux native threads are currently implemented only for i386; use Posix threads instead. - -#elif defined(THREAD_POSIX_IMPL) - -#include "atomicAdjustPosixImpl.h" -typedef AtomicAdjustPosixImpl AtomicAdjust; - -#endif - -#endif diff --git a/dtool/src/dtoolbase/atomicAdjustDummyImpl.I b/dtool/src/dtoolbase/atomicAdjustDummyImpl.I deleted file mode 100644 index 54d6e6b860d..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustDummyImpl.I +++ /dev/null @@ -1,117 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustDummyImpl.I - * @author drose - * @date 2002-08-09 - */ - -/** - * Atomically increments the indicated variable. - */ -ALWAYS_INLINE void AtomicAdjustDummyImpl:: -inc(TVOLATILE AtomicAdjustDummyImpl::Integer &var) { - ++var; -} - -/** - * Atomically decrements the indicated variable and returns true if the new - * value is nonzero, false if it is zero. - */ -ALWAYS_INLINE bool AtomicAdjustDummyImpl:: -dec(TVOLATILE AtomicAdjustDummyImpl::Integer &var) { - return (--var) != 0; -} - -/** - * Atomically computes var += delta. It is legal for delta to be negative. - * Returns the result of the addition. - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Integer AtomicAdjustDummyImpl:: -add(TVOLATILE AtomicAdjustDummyImpl::Integer &var, AtomicAdjustDummyImpl::Integer delta) { - Integer new_value = var + delta; - var = new_value; - return new_value; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Integer AtomicAdjustDummyImpl:: -set(TVOLATILE AtomicAdjustDummyImpl::Integer &var, AtomicAdjustDummyImpl::Integer new_value) { - Integer orig_value = var; - var = new_value; - return orig_value; -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Integer AtomicAdjustDummyImpl:: -get(const TVOLATILE AtomicAdjustDummyImpl::Integer &var) { - return var; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Pointer AtomicAdjustDummyImpl:: -set_ptr(TVOLATILE AtomicAdjustDummyImpl::Pointer &var, - AtomicAdjustDummyImpl::Pointer new_value) { - Pointer orig_value = var; - var = new_value; - return orig_value; -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Pointer AtomicAdjustDummyImpl:: -get_ptr(const TVOLATILE AtomicAdjustDummyImpl::Pointer &var) { - return var; -} - -/** - * Atomic compare and exchange. - * - * If mem is equal to old_value, store new_value in mem. In either case, - * return the original value of mem. The caller can test for success by - * comparing return_value == old_value. - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Integer AtomicAdjustDummyImpl:: -compare_and_exchange(TVOLATILE AtomicAdjustDummyImpl::Integer &mem, - AtomicAdjustDummyImpl::Integer old_value, - AtomicAdjustDummyImpl::Integer new_value) { - Integer orig_value = mem; - if (mem == old_value) { - mem = new_value; - } - return orig_value; -} - -/** - * Atomic compare and exchange. - * - * As above, but works on pointers instead of integers. - */ -ALWAYS_INLINE AtomicAdjustDummyImpl::Pointer AtomicAdjustDummyImpl:: -compare_and_exchange_ptr(TVOLATILE AtomicAdjustDummyImpl::Pointer &mem, - AtomicAdjustDummyImpl::Pointer old_value, - AtomicAdjustDummyImpl::Pointer new_value) { - Pointer orig_value = mem; - if (mem == old_value) { - mem = new_value; - } - return orig_value; -} diff --git a/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx b/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx deleted file mode 100644 index aa8fc7d893d..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustDummyImpl.cxx +++ /dev/null @@ -1,15 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustDummyImpl.cxx - * @author drose - * @date 2002-08-09 - */ - -#include "selectThreadImpl.h" -#include "atomicAdjustDummyImpl.h" diff --git a/dtool/src/dtoolbase/atomicAdjustDummyImpl.h b/dtool/src/dtoolbase/atomicAdjustDummyImpl.h deleted file mode 100644 index 3257ae8dfd8..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustDummyImpl.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustDummyImpl.h - * @author drose - * @date 2002-08-09 - */ - -#ifndef ATOMICADJUSTDUMMYIMPL_H -#define ATOMICADJUSTDUMMYIMPL_H - -#include "dtoolbase.h" -#include "selectThreadImpl.h" - -#include "numeric_types.h" - -/** - * A trivial implementation for atomic adjustments for systems that don't - * require multiprogramming, and therefore don't require special atomic - * operations. - */ -class EXPCL_DTOOL_DTOOLBASE AtomicAdjustDummyImpl { -public: - typedef long Integer; - typedef void *Pointer; - - ALWAYS_INLINE static void inc(TVOLATILE Integer &var); - ALWAYS_INLINE static bool dec(TVOLATILE Integer &var); - ALWAYS_INLINE static Integer add(TVOLATILE Integer &var, Integer delta); - ALWAYS_INLINE static Integer set(TVOLATILE Integer &var, Integer new_value); - ALWAYS_INLINE static Integer get(const TVOLATILE Integer &var); - - ALWAYS_INLINE static Pointer set_ptr(TVOLATILE Pointer &var, Pointer new_value); - ALWAYS_INLINE static Pointer get_ptr(const TVOLATILE Pointer &var); - - ALWAYS_INLINE static Integer compare_and_exchange(TVOLATILE Integer &mem, - Integer old_value, - Integer new_value); - - ALWAYS_INLINE static Pointer compare_and_exchange_ptr(TVOLATILE Pointer &mem, - Pointer old_value, - Pointer new_value); -}; - -#include "atomicAdjustDummyImpl.I" - -#endif diff --git a/dtool/src/dtoolbase/atomicAdjustGccImpl.I b/dtool/src/dtoolbase/atomicAdjustGccImpl.I deleted file mode 100644 index 682b14bed31..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustGccImpl.I +++ /dev/null @@ -1,119 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustGccImpl.I - * @author rdb - * @date 2014-07-04 - */ - -/** - * Atomically increments the indicated variable. - */ -INLINE void AtomicAdjustGccImpl:: -inc(TVOLATILE AtomicAdjustGccImpl::Integer &var) { - __atomic_fetch_add(&var, 1, __ATOMIC_SEQ_CST); -} - -/** - * Atomically decrements the indicated variable and returns true if the new - * value is nonzero, false if it is zero. - */ -INLINE bool AtomicAdjustGccImpl:: -dec(TVOLATILE AtomicAdjustGccImpl::Integer &var) { - return (__atomic_sub_fetch(&var, 1, __ATOMIC_SEQ_CST) != 0); -} - -/** - * Atomically computes var += delta. It is legal for delta to be negative. - * Returns the result of the addition. - */ -INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl:: -add(TVOLATILE AtomicAdjustGccImpl::Integer &var, - AtomicAdjustGccImpl::Integer delta) { - return __atomic_add_fetch(&var, delta, __ATOMIC_SEQ_CST); -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl:: -set(TVOLATILE AtomicAdjustGccImpl::Integer &var, - AtomicAdjustGccImpl::Integer new_value) { - - return __atomic_exchange_n(&var, new_value, __ATOMIC_SEQ_CST); -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl:: -get(const TVOLATILE AtomicAdjustGccImpl::Integer &var) { - return __atomic_load_n(&var, __ATOMIC_SEQ_CST); -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -INLINE AtomicAdjustGccImpl::Pointer AtomicAdjustGccImpl:: -set_ptr(TVOLATILE AtomicAdjustGccImpl::Pointer &var, - AtomicAdjustGccImpl::Pointer new_value) { - - return __atomic_exchange_n(&var, new_value, __ATOMIC_SEQ_CST); -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -INLINE AtomicAdjustGccImpl::Pointer AtomicAdjustGccImpl:: -get_ptr(const TVOLATILE AtomicAdjustGccImpl::Pointer &var) { - return __atomic_load_n(&var, __ATOMIC_SEQ_CST); -} - -/** - * Atomic compare and exchange. - * - * If mem is equal to old_value, store new_value in mem. In either case, - * return the original value of mem. The caller can test for success by - * comparing return_value == old_value. - * - * The atomic function expressed in pseudo-code: - * - * orig_value = mem; if (mem == old_value) { mem = new_value; } return - * orig_value; - * - */ -INLINE AtomicAdjustGccImpl::Integer AtomicAdjustGccImpl:: -compare_and_exchange(TVOLATILE AtomicAdjustGccImpl::Integer &mem, - AtomicAdjustGccImpl::Integer old_value, - AtomicAdjustGccImpl::Integer new_value) { - - __atomic_compare_exchange_n(&mem, &old_value, new_value, false, - __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return old_value; -} - -/** - * Atomic compare and exchange. - * - * As above, but works on pointers instead of integers. - */ -INLINE AtomicAdjustGccImpl::Pointer AtomicAdjustGccImpl:: -compare_and_exchange_ptr(TVOLATILE AtomicAdjustGccImpl::Pointer &mem, - AtomicAdjustGccImpl::Pointer old_value, - AtomicAdjustGccImpl::Pointer new_value) { - - __atomic_compare_exchange_n(&mem, &old_value, new_value, false, - __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return old_value; -} diff --git a/dtool/src/dtoolbase/atomicAdjustGccImpl.h b/dtool/src/dtoolbase/atomicAdjustGccImpl.h deleted file mode 100644 index 57389c13494..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustGccImpl.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustGccImpl.h - * @author rdb - * @date 2014-07-04 - */ - -#ifndef ATOMICADJUSTGCCIMPL_H -#define ATOMICADJUSTGCCIMPL_H - -#include "dtoolbase.h" -#include "selectThreadImpl.h" - -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) || (defined(__clang__) && (__clang_major__ >= 3)) - -/** - * Uses GCC built-ins to implement atomic adjustments. - */ -class EXPCL_DTOOL_DTOOLBASE AtomicAdjustGccImpl { -public: -#if __GCC_ATOMIC_LONG_LOCK_FREE >= __GCC_ATOMIC_INT_LOCK_FREE - // If the long can be more lock-free than int, use it instead. - typedef __attribute__ ((aligned (__SIZEOF_LONG__))) long Integer; -#else - typedef __attribute__ ((aligned (__SIZEOF_INT__))) int Integer; -#endif - typedef void *UnalignedPointer; - typedef __attribute__ ((aligned (__SIZEOF_POINTER__))) UnalignedPointer Pointer; - - INLINE static void inc(TVOLATILE Integer &var); - INLINE static bool dec(TVOLATILE Integer &var); - INLINE static Integer add(TVOLATILE Integer &var, Integer delta); - INLINE static Integer set(TVOLATILE Integer &var, Integer new_value); - INLINE static Integer get(const TVOLATILE Integer &var); - - INLINE static Pointer set_ptr(TVOLATILE Pointer &var, Pointer new_value); - INLINE static Pointer get_ptr(const TVOLATILE Pointer &var); - - INLINE static Integer compare_and_exchange(TVOLATILE Integer &mem, - Integer old_value, - Integer new_value); - - INLINE static Pointer compare_and_exchange_ptr(TVOLATILE Pointer &mem, - Pointer old_value, - Pointer new_value); -}; - -#include "atomicAdjustGccImpl.I" - -#endif // HAVE_POSIX_THREADS - -#endif diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.I b/dtool/src/dtoolbase/atomicAdjustI386Impl.I deleted file mode 100644 index 98208c86552..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.I +++ /dev/null @@ -1,192 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustI386Impl.I - * @author drose - * @date 2006-04-01 - */ - -/** - * Atomically increments the indicated variable. - */ -INLINE void AtomicAdjustI386Impl:: -inc(TVOLATILE AtomicAdjustI386Impl::Integer &var) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); -#ifdef _M_IX86 - // Windows case - TVOLATILE Integer *var_ptr = &var; - __asm { - mov edx, var_ptr; - lock inc dword ptr [edx]; - } -#elif !defined(__EDG__) - // GCC case - __asm__ __volatile__("lock; incl %0" - :"=m" (var) - :"m" (&var)); -#endif // __EDG__ -} - -/** - * Atomically decrements the indicated variable and returns true if the new - * value is nonzero, false if it is zero. - */ -INLINE bool AtomicAdjustI386Impl:: -dec(TVOLATILE AtomicAdjustI386Impl::Integer &var) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); - unsigned char c; -#ifdef _M_IX86 - // Windows case - TVOLATILE Integer *var_ptr = &var; - __asm { - mov edx, var_ptr; - lock dec dword ptr [edx]; - sete c; - } -#elif !defined(__EDG__) - // GCC case - __asm__ __volatile__("lock; decl %0; sete %1" - :"=m" (var), "=qm" (c) - :"m" (&var) : "memory"); -#endif // __EDG__ - return (c == 0); -} - -/** - * Atomically computes var += delta. It is legal for delta to be negative. - * Returns the result of the addition. - */ -INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: -add(TVOLATILE AtomicAdjustI386Impl::Integer &var, AtomicAdjustI386Impl::Integer delta) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); - Integer orig_value = var; - Integer new_value = orig_value + delta; - while (compare_and_exchange(var, orig_value, new_value) != orig_value) { - orig_value = var; - new_value = orig_value + delta; - } - return new_value; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: -set(TVOLATILE AtomicAdjustI386Impl::Integer &var, - AtomicAdjustI386Impl::Integer new_value) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); - Integer orig_value = var; - var = new_value; - return orig_value; -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: -get(const TVOLATILE AtomicAdjustI386Impl::Integer &var) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); - return var; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl:: -set_ptr(TVOLATILE AtomicAdjustI386Impl::Pointer &var, - AtomicAdjustI386Impl::Pointer new_value) { - assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0); - Pointer orig_value = var; - var = new_value; - return orig_value; -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl:: -get_ptr(const TVOLATILE AtomicAdjustI386Impl::Pointer &var) { - assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0); - return var; -} - -/** - * Atomic compare and exchange. - * - * If mem is equal to old_value, store new_value in mem. In either case, - * return the original value of mem. The caller can test for success by - * comparing return_value == old_value. - * - * The atomic function expressed in pseudo-code: - * - * orig_value = mem; if (mem == old_value) { mem = new_value; } return - * orig_value; - * - */ -INLINE AtomicAdjustI386Impl::Integer AtomicAdjustI386Impl:: -compare_and_exchange(TVOLATILE AtomicAdjustI386Impl::Integer &mem, - AtomicAdjustI386Impl::Integer old_value, - AtomicAdjustI386Impl::Integer new_value) { - assert((((size_t)&mem) & (sizeof(Integer) - 1)) == 0); - Integer prev; -#ifdef _M_IX86 - // Windows case - TVOLATILE Integer *mem_ptr = &mem; - __asm { - mov edx, mem_ptr; - mov ecx, new_value; - mov eax, old_value; - lock cmpxchg dword ptr [edx], ecx; - mov prev, eax; - } -#elif !defined(__EDG__) - // GCC case - __asm__ __volatile__("lock; cmpxchgl %1,%2" - : "=a"(prev) - : "r"(new_value), "m"(mem), "0"(old_value) - : "memory"); -#endif // __EDG__ - return prev; -} - -/** - * Atomic compare and exchange. - * - * As above, but works on pointers instead of integers. - */ -INLINE AtomicAdjustI386Impl::Pointer AtomicAdjustI386Impl:: -compare_and_exchange_ptr(TVOLATILE AtomicAdjustI386Impl::Pointer &mem, - AtomicAdjustI386Impl::Pointer old_value, - AtomicAdjustI386Impl::Pointer new_value) { - assert((((size_t)&mem) & (sizeof(Pointer) - 1)) == 0); - Pointer prev; -#ifdef _M_IX86 - // Windows case - TVOLATILE Pointer *mem_ptr = &mem; - __asm { - mov edx, mem_ptr; - mov ecx, new_value; - mov eax, old_value; - lock cmpxchg dword ptr [edx], ecx; - mov prev, eax; - } -#elif !defined(__EDG__) - // GCC case - __asm__ __volatile__("lock; cmpxchgl %1,%2" - : "=a"(prev) - : "r"(new_value), "m"(mem), "0"(old_value) - : "memory"); -#endif // __EDG__ - return prev; -} diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.cxx b/dtool/src/dtoolbase/atomicAdjustI386Impl.cxx deleted file mode 100644 index 01fb3080229..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.cxx +++ /dev/null @@ -1,14 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustI386Impl.cxx - * @author drose - * @date 2006-03-28 - */ - -#include "atomicAdjustI386Impl.h" diff --git a/dtool/src/dtoolbase/atomicAdjustI386Impl.h b/dtool/src/dtoolbase/atomicAdjustI386Impl.h deleted file mode 100644 index 4daa335b2ae..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustI386Impl.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustI386Impl.h - * @author drose - * @date 2006-04-01 - */ - -#ifndef ATOMICADJUSTI386IMPL_H -#define ATOMICADJUSTI386IMPL_H - -#include "dtoolbase.h" -#include "selectThreadImpl.h" - -#if (defined(__i386__) || defined(_M_IX86)) && !defined(__APPLE__) && !defined(__ANDROID__) - -#include "numeric_types.h" - -/** - * Uses assembly-language calls to atomically increment and decrement. - * Although this class is named i386, it actually uses instructions that are - * specific to 486 and higher. - */ -class EXPCL_DTOOL_DTOOLBASE AtomicAdjustI386Impl { -public: - typedef ALIGN_4BYTE int32_t Integer; - typedef void *UnalignedPointer; - typedef ALIGN_4BYTE UnalignedPointer Pointer; - - INLINE static void inc(TVOLATILE Integer &var); - INLINE static bool dec(TVOLATILE Integer &var); - INLINE static Integer add(TVOLATILE Integer &var, Integer delta); - INLINE static Integer set(TVOLATILE Integer &var, Integer new_value); - INLINE static Integer get(const TVOLATILE Integer &var); - - INLINE static Pointer set_ptr(TVOLATILE Pointer &var, Pointer new_value); - INLINE static Pointer get_ptr(const TVOLATILE Pointer &var); - - INLINE static Integer compare_and_exchange(TVOLATILE Integer &mem, - Integer old_value, - Integer new_value); - - INLINE static Pointer compare_and_exchange_ptr(TVOLATILE Pointer &mem, - Pointer old_value, - Pointer new_value); -}; - -#include "atomicAdjustI386Impl.I" - -#endif // __i386__ - -#endif diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.I b/dtool/src/dtoolbase/atomicAdjustPosixImpl.I deleted file mode 100644 index 09636c39c77..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.I +++ /dev/null @@ -1,146 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustPosixImpl.I - * @author drose - * @date 2006-02-10 - */ - -/** - * Atomically increments the indicated variable. - */ -INLINE void AtomicAdjustPosixImpl:: -inc(TVOLATILE AtomicAdjustPosixImpl::Integer &var) { - pthread_mutex_lock(&_mutex); - ++var; - pthread_mutex_unlock(&_mutex); -} - -/** - * Atomically decrements the indicated variable and returns true if the new - * value is nonzero, false if it is zero. - */ -INLINE bool AtomicAdjustPosixImpl:: -dec(TVOLATILE AtomicAdjustPosixImpl::Integer &var) { - pthread_mutex_lock(&_mutex); - Integer result = --var; - pthread_mutex_unlock(&_mutex); - return (result != 0); -} - -/** - * Atomically computes var += delta. It is legal for delta to be negative. - * Returns the result of the addition. - */ -INLINE AtomicAdjustPosixImpl::Integer AtomicAdjustPosixImpl:: -add(TVOLATILE AtomicAdjustPosixImpl::Integer &var, - AtomicAdjustPosixImpl::Integer delta) { - pthread_mutex_lock(&_mutex); - Integer new_value = var + delta; - var = new_value; - pthread_mutex_unlock(&_mutex); - return new_value; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -INLINE AtomicAdjustPosixImpl::Integer AtomicAdjustPosixImpl:: -set(TVOLATILE AtomicAdjustPosixImpl::Integer &var, - AtomicAdjustPosixImpl::Integer new_value) { - pthread_mutex_lock(&_mutex); - Integer orig_value = var; - var = new_value; - pthread_mutex_unlock(&_mutex); - return orig_value; -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -INLINE AtomicAdjustPosixImpl::Integer AtomicAdjustPosixImpl:: -get(const TVOLATILE AtomicAdjustPosixImpl::Integer &var) { - pthread_mutex_lock(&_mutex); - Integer orig_value = var; - pthread_mutex_unlock(&_mutex); - return orig_value; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -INLINE AtomicAdjustPosixImpl::Pointer AtomicAdjustPosixImpl:: -set_ptr(TVOLATILE AtomicAdjustPosixImpl::Pointer &var, - AtomicAdjustPosixImpl::Pointer new_value) { - pthread_mutex_lock(&_mutex); - Pointer orig_value = var; - var = new_value; - pthread_mutex_unlock(&_mutex); - return orig_value; -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -INLINE AtomicAdjustPosixImpl::Pointer AtomicAdjustPosixImpl:: -get_ptr(const TVOLATILE AtomicAdjustPosixImpl::Pointer &var) { - pthread_mutex_lock(&_mutex); - Pointer orig_value = var; - pthread_mutex_unlock(&_mutex); - return orig_value; -} - -/** - * Atomic compare and exchange. - * - * If mem is equal to old_value, store new_value in mem. In either case, - * return the original value of mem. The caller can test for success by - * comparing return_value == old_value. - * - * The atomic function expressed in pseudo-code: - * - * orig_value = mem; if (mem == old_value) { mem = new_value; } return - * orig_value; - * - */ -INLINE AtomicAdjustPosixImpl::Integer AtomicAdjustPosixImpl:: -compare_and_exchange(TVOLATILE AtomicAdjustPosixImpl::Integer &mem, - AtomicAdjustPosixImpl::Integer old_value, - AtomicAdjustPosixImpl::Integer new_value) { - pthread_mutex_lock(&_mutex); - Integer orig_value = mem; - if (mem == old_value) { - mem = new_value; - } - pthread_mutex_unlock(&_mutex); - return orig_value; -} - -/** - * Atomic compare and exchange. - * - * As above, but works on pointers instead of integers. - */ -INLINE AtomicAdjustPosixImpl::Pointer AtomicAdjustPosixImpl:: -compare_and_exchange_ptr(TVOLATILE AtomicAdjustPosixImpl::Pointer &mem, - AtomicAdjustPosixImpl::Pointer old_value, - AtomicAdjustPosixImpl::Pointer new_value) { - pthread_mutex_lock(&_mutex); - Pointer orig_value = mem; - if (mem == old_value) { - mem = new_value; - } - pthread_mutex_unlock(&_mutex); - return orig_value; -} diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx b/dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx deleted file mode 100644 index abfe9ab1a36..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.cxx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustPosixImpl.cxx - * @author drose - * @date 2006-02-10 - */ - -#include "selectThreadImpl.h" - -#ifdef HAVE_POSIX_THREADS - -#include "atomicAdjustPosixImpl.h" - -pthread_mutex_t AtomicAdjustPosixImpl::_mutex = PTHREAD_MUTEX_INITIALIZER; - -#endif // HAVE_POSIX_THREADS diff --git a/dtool/src/dtoolbase/atomicAdjustPosixImpl.h b/dtool/src/dtoolbase/atomicAdjustPosixImpl.h deleted file mode 100644 index 8c2b2b5887d..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustPosixImpl.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustPosixImpl.h - * @author drose - * @date 2006-02-10 - */ - -#ifndef ATOMICADJUSTPOSIXIMPL_H -#define ATOMICADJUSTPOSIXIMPL_H - -#include "dtoolbase.h" -#include "selectThreadImpl.h" - -#ifdef HAVE_POSIX_THREADS - -#include "numeric_types.h" - -#include - -/** - * Uses POSIX to implement atomic adjustments. - */ -class EXPCL_DTOOL_DTOOLBASE AtomicAdjustPosixImpl { -public: - // In Posix, "long" is generally the native word size (32- or 64-bit), which - // is what we'd prefer. - typedef long Integer; - typedef void *Pointer; - - INLINE static void inc(TVOLATILE Integer &var); - INLINE static bool dec(TVOLATILE Integer &var); - INLINE static Integer add(TVOLATILE Integer &var, Integer delta); - INLINE static Integer set(TVOLATILE Integer &var, Integer new_value); - INLINE static Integer get(const TVOLATILE Integer &var); - - INLINE static Pointer set_ptr(TVOLATILE Pointer &var, Pointer new_value); - INLINE static Pointer get_ptr(const TVOLATILE Pointer &var); - - INLINE static Integer compare_and_exchange(TVOLATILE Integer &mem, - Integer old_value, - Integer new_value); - - INLINE static Pointer compare_and_exchange_ptr(TVOLATILE Pointer &mem, - Pointer old_value, - Pointer new_value); - -private: - static pthread_mutex_t _mutex; -}; - -#include "atomicAdjustPosixImpl.I" - -#endif // HAVE_POSIX_THREADS - -#endif diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.I b/dtool/src/dtoolbase/atomicAdjustWin32Impl.I deleted file mode 100644 index 851c9f05e2f..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.I +++ /dev/null @@ -1,154 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustWin32Impl.I - * @author drose - * @date 2006-02-07 - */ - -/** - * Atomically increments the indicated variable. - */ -ALWAYS_INLINE void AtomicAdjustWin32Impl:: -inc(TVOLATILE AtomicAdjustWin32Impl::Integer &var) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); -#ifdef _WIN64 - InterlockedIncrement64(&var); -#else - InterlockedIncrement(&var); -#endif // _WIN64 -} - -/** - * Atomically decrements the indicated variable and returns true if the new - * value is nonzero, false if it is zero. - */ -ALWAYS_INLINE bool AtomicAdjustWin32Impl:: -dec(TVOLATILE AtomicAdjustWin32Impl::Integer &var) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); -#ifdef _WIN64 - return (InterlockedDecrement64(&var) != 0); -#else - return (InterlockedDecrement(&var) != 0); -#endif // _WIN64 -} - -/** - * Atomically computes var += delta. It is legal for delta to be negative. - * Returns the result of the addition. - */ -INLINE AtomicAdjustWin32Impl::Integer AtomicAdjustWin32Impl:: -add(TVOLATILE AtomicAdjustWin32Impl::Integer &var, AtomicAdjustWin32Impl::Integer delta) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); -#ifdef _WIN64 - return InterlockedAdd64(&var, delta); -#else - Integer orig_value = var; - Integer new_value = orig_value + delta; - while (compare_and_exchange(var, orig_value, new_value) != orig_value) { - orig_value = var; - new_value = orig_value + delta; - } - return new_value; -#endif // _WIN64 -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -ALWAYS_INLINE AtomicAdjustWin32Impl::Integer AtomicAdjustWin32Impl:: -set(TVOLATILE AtomicAdjustWin32Impl::Integer &var, - AtomicAdjustWin32Impl::Integer new_value) { - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); -#ifdef _WIN64 - return InterlockedExchange64(&var, new_value); -#else - return InterlockedExchange(&var, new_value); -#endif // _WIN64 -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -ALWAYS_INLINE AtomicAdjustWin32Impl::Integer AtomicAdjustWin32Impl:: -get(const TVOLATILE AtomicAdjustWin32Impl::Integer &var) { - // On Intel platforms, word-aligned loads are atomic (if performed in a - // single instruction). We can't guarantee the compiler will generate a - // single instruction to load this value, but it certainly won't happen if - // its address isn't word-aligned, so make sure that's the case. - assert((((size_t)&var) & (sizeof(Integer) - 1)) == 0); - return var; -} - -/** - * Atomically changes the indicated variable and returns the original value. - */ -ALWAYS_INLINE AtomicAdjustWin32Impl::Pointer AtomicAdjustWin32Impl:: -set_ptr(TVOLATILE AtomicAdjustWin32Impl::Pointer &var, - AtomicAdjustWin32Impl::Pointer new_value) { - assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0); - return InterlockedExchangePointer(&var, new_value); -} - -/** - * Atomically retrieves the snapshot value of the indicated variable. This is - * the only guaranteed safe way to retrieve the value that other threads might - * be asynchronously setting, incrementing, or decrementing (via other - * AtomicAjust methods). - */ -ALWAYS_INLINE AtomicAdjustWin32Impl::Pointer AtomicAdjustWin32Impl:: -get_ptr(const TVOLATILE AtomicAdjustWin32Impl::Pointer &var) { - // As in get(), make sure the address is word-aligned. - assert((((size_t)&var) & (sizeof(Pointer) - 1)) == 0); - return var; -} - -/** - * Atomic compare and exchange. - * - * If mem is equal to old_value, store new_value in mem. In either case, - * return the original value of mem. The caller can test for success by - * comparing return_value == old_value. - * - * The atomic function expressed in pseudo-code: - * - * orig_value = mem; if (mem == old_value) { mem = new_value; } return - * orig_value; - * - */ -INLINE AtomicAdjustWin32Impl::Integer AtomicAdjustWin32Impl:: -compare_and_exchange(TVOLATILE AtomicAdjustWin32Impl::Integer &mem, - AtomicAdjustWin32Impl::Integer old_value, - AtomicAdjustWin32Impl::Integer new_value) { - assert((((size_t)&mem) & (sizeof(Integer) - 1)) == 0); - // Note that the AtomicAdjust parameter order is different from Windows - // convention! -#ifdef _WIN64 - return InterlockedCompareExchange64((TVOLATILE LONGLONG *)&mem, new_value, old_value); -#else - return InterlockedCompareExchange((TVOLATILE LONG *)&mem, new_value, old_value); -#endif // _WIN64 -} - -/** - * Atomic compare and exchange. - * - * As above, but works on pointers instead of integers. - */ -INLINE AtomicAdjustWin32Impl::Pointer AtomicAdjustWin32Impl:: -compare_and_exchange_ptr(TVOLATILE AtomicAdjustWin32Impl::Pointer &mem, - AtomicAdjustWin32Impl::Pointer old_value, - AtomicAdjustWin32Impl::Pointer new_value) { - assert((((size_t)&mem) & (sizeof(Pointer) - 1)) == 0); - // Note that the AtomicAdjust parameter order is different from Windows - // convention! - return InterlockedCompareExchangePointer(&mem, new_value, old_value); -} diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx b/dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx deleted file mode 100644 index 19abfd3583d..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.cxx +++ /dev/null @@ -1,20 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustWin32Impl.cxx - * @author drose - * @date 2006-02-07 - */ - -#include "selectThreadImpl.h" - -#ifdef _WIN32 - -#include "atomicAdjustWin32Impl.h" - -#endif // _WIN32 diff --git a/dtool/src/dtoolbase/atomicAdjustWin32Impl.h b/dtool/src/dtoolbase/atomicAdjustWin32Impl.h deleted file mode 100644 index f83ee0150b1..00000000000 --- a/dtool/src/dtoolbase/atomicAdjustWin32Impl.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file atomicAdjustWin32Impl.h - * @author drose - * @date 2006-02-07 - */ - -#ifndef ATOMICADJUSTWIN32IMPL_H -#define ATOMICADJUSTWIN32IMPL_H - -#include "dtoolbase.h" -#include "selectThreadImpl.h" - -#ifdef _WIN32 - -#include "numeric_types.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include - -/** - * Uses Windows native calls to implement atomic adjustments. - */ -class EXPCL_DTOOL_DTOOLBASE AtomicAdjustWin32Impl { -public: -#ifdef _WIN64 - // For 64-bit builds, we'd prefer to use a 64-bit integer. - typedef ALIGN_8BYTE LONGLONG Integer; - typedef void *UnalignedPointer; - typedef ALIGN_8BYTE UnalignedPointer Pointer; -#else - typedef ALIGN_4BYTE LONG Integer; - typedef void *UnalignedPointer; - typedef ALIGN_4BYTE UnalignedPointer Pointer; -#endif // _WIN64 - - ALWAYS_INLINE static void inc(TVOLATILE Integer &var); - ALWAYS_INLINE static bool dec(TVOLATILE Integer &var); - INLINE static Integer add(TVOLATILE Integer &var, Integer delta); - ALWAYS_INLINE static Integer set(TVOLATILE Integer &var, Integer new_value); - ALWAYS_INLINE static Integer get(const TVOLATILE Integer &var); - - ALWAYS_INLINE static Pointer set_ptr(TVOLATILE Pointer &var, Pointer new_value); - ALWAYS_INLINE static Pointer get_ptr(const TVOLATILE Pointer &var); - - INLINE static Integer compare_and_exchange(TVOLATILE Integer &mem, - Integer old_value, - Integer new_value); - - INLINE static Pointer compare_and_exchange_ptr(TVOLATILE Pointer &mem, - Pointer old_value, - Pointer new_value); -}; - -#include "atomicAdjustWin32Impl.I" - -#endif // _WIN32 - -#endif diff --git a/dtool/src/dtoolbase/p3dtoolbase_composite1.cxx b/dtool/src/dtoolbase/p3dtoolbase_composite1.cxx index 2a2ae9c1c93..8359329063c 100644 --- a/dtool/src/dtoolbase/p3dtoolbase_composite1.cxx +++ b/dtool/src/dtoolbase/p3dtoolbase_composite1.cxx @@ -1,8 +1,4 @@ #include "addHash.cxx" -#include "atomicAdjustDummyImpl.cxx" -#include "atomicAdjustI386Impl.cxx" -#include "atomicAdjustPosixImpl.cxx" -#include "atomicAdjustWin32Impl.cxx" #include "deletedBufferChain.cxx" #include "dtoolbase.cxx" #include "memoryBase.cxx" diff --git a/panda/src/pipeline/test_atomic.cxx b/panda/src/pipeline/test_atomic.cxx deleted file mode 100644 index 66ab6c5a144..00000000000 --- a/panda/src/pipeline/test_atomic.cxx +++ /dev/null @@ -1,94 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file test_atomic.cxx - * @author drose - * @date 2006-04-19 - */ - -#include "pandabase.h" -#include "thread.h" -#include "pmutex.h" -#include "mutexHolder.h" -#include "atomicAdjust.h" - -// The number of threads to spawn. -static const int number_of_threads = 4; - -// The number of iterations within each thread. -static const int number_of_iterations = 50000000; - -#define OUTPUT(stuff) { \ - MutexHolder holder(Mutex::_notify_mutex); \ - stuff; \ -} - -AtomicAdjust::Integer _inc_count = 0; -AtomicAdjust::Integer _dec_count = 0; -AtomicAdjust::Integer _net_count = 0; -AtomicAdjust::Integer _num_net_count_incremented = 0; - -class MyThread : public Thread { -public: - MyThread(const std::string &name) : Thread(name, name) - { - } - - virtual void - thread_main() { - OUTPUT(nout << *this << " beginning.\n"); - - int local_count = 0; - - for (int i = 0; i < number_of_iterations; ++i) { - AtomicAdjust::inc(_inc_count); - AtomicAdjust::dec(_dec_count); - if (AtomicAdjust::compare_and_exchange(_net_count, i, i + 1) == i) { - AtomicAdjust::inc(_num_net_count_incremented); - ++local_count; - } - } - - OUTPUT(nout << *this << " contributed " << local_count << " times.\n"); - OUTPUT(nout << *this << " ending.\n"); - } - -}; - -int -main(int argc, char *argv[]) { - nout << "Making " << number_of_threads << " threads.\n"; - - typedef pvector< PT(MyThread) > Threads; - Threads threads; - - PT(MyThread) thread = new MyThread("a"); - threads.push_back(thread); - thread->start(TP_normal, true); - - for (int i = 1; i < number_of_threads; ++i) { - char name = 'a' + i; - PT(MyThread) thread = new MyThread(std::string(1, name)); - threads.push_back(thread); - thread->start(TP_normal, true); - } - - // Now join all the threads. - Threads::iterator ti; - for (ti = threads.begin(); ti != threads.end(); ++ti) { - (*ti)->join(); - } - - nout << "inc_count = " << _inc_count << "\n" - << "dec_count = " << _dec_count << "\n" - << "net_count = " << _net_count << "\n" - << "num_net_count_incremented = " << _num_net_count_incremented << "\n"; - - Thread::prepare_for_exit(); - return (0); -} From 387f9324f55b2de1ad1a00bc34bd4181bd57f27f Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 13 May 2026 13:45:12 +0200 Subject: [PATCH 4/5] dtoolbase: Remove vestigial and now-unused TVOLATILE macro --- direct/src/directscripts/Doxyfile.cxx | 3 +-- dtool/src/dtoolbase/selectThreadImpl.h | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/direct/src/directscripts/Doxyfile.cxx b/direct/src/directscripts/Doxyfile.cxx index 11d5fc9bc2d..ecf8ff4a8bc 100644 --- a/direct/src/directscripts/Doxyfile.cxx +++ b/direct/src/directscripts/Doxyfile.cxx @@ -1979,8 +1979,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = TVOLATILE= \ - INLINE=inline \ +PREDEFINED = INLINE=inline \ ALWAYS_INLINE=inline \ PUBLISHED=public \ protected=private \ diff --git a/dtool/src/dtoolbase/selectThreadImpl.h b/dtool/src/dtoolbase/selectThreadImpl.h index 4ef55dc6f3d..33e4943b3d7 100644 --- a/dtool/src/dtoolbase/selectThreadImpl.h +++ b/dtool/src/dtoolbase/selectThreadImpl.h @@ -26,26 +26,14 @@ * synchronization classes are defined in pandasrcexpress. */ -// This keyword should be used to mark any variable which is possibly volatile -// because multiple threads might contend on it, unprotected by a mutex. It -// will be defined out in the non-threaded case. Other uses for volatile (dma -// buffers, for instance) should use the regular volatile keyword. -#define TVOLATILE volatile - #if !defined(HAVE_THREADS) || defined(CPPPARSER) // With threading disabled, use the do-nothing implementation. #define THREAD_DUMMY_IMPL 1 -// And the TVOLATILE keyword means nothing in the absence of threads. -#undef TVOLATILE -#define TVOLATILE - #elif defined(SIMPLE_THREADS) // Use the simulated threading library. #define THREAD_SIMPLE_IMPL 1 -#undef TVOLATILE -#define TVOLATILE #elif defined(_WIN32) From b114f1dacee98c1fe1d57038ade34a346b1069b2 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 13 May 2026 14:15:11 +0200 Subject: [PATCH 5/5] putil: Revert UpdateSeq being a literal type until C++17 Clang complains about this because it's stricter than other compilers. Once we switch to C++17 we can change it back. --- panda/src/putil/updateSeq.I | 4 ++-- panda/src/putil/updateSeq.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/panda/src/putil/updateSeq.I b/panda/src/putil/updateSeq.I index d3a41779af6..42f6fa4c83f 100644 --- a/panda/src/putil/updateSeq.I +++ b/panda/src/putil/updateSeq.I @@ -14,14 +14,14 @@ /** * Creates an UpdateSeq in the given state. */ -constexpr UpdateSeq:: +INLINE UpdateSeq:: UpdateSeq(unsigned int seq) : _seq(seq) { } /** * Creates an UpdateSeq in the 'initial' state. */ -constexpr UpdateSeq:: +INLINE UpdateSeq:: UpdateSeq() : _seq((unsigned int)SC_initial) { } diff --git a/panda/src/putil/updateSeq.h b/panda/src/putil/updateSeq.h index 8fc8aa3280a..3332490f634 100644 --- a/panda/src/putil/updateSeq.h +++ b/panda/src/putil/updateSeq.h @@ -36,13 +36,13 @@ */ class EXPCL_PANDA_PUTIL UpdateSeq { private: - constexpr UpdateSeq(unsigned int seq); + INLINE UpdateSeq(unsigned int seq); PUBLISHED: - constexpr UpdateSeq(); - constexpr static UpdateSeq initial() { return UpdateSeq(SC_initial); } - constexpr static UpdateSeq old() { return UpdateSeq(SC_old); } - constexpr static UpdateSeq fresh() { return UpdateSeq(SC_fresh); } + INLINE UpdateSeq(); + INLINE static UpdateSeq initial() { return UpdateSeq(SC_initial); } + INLINE static UpdateSeq old() { return UpdateSeq(SC_old); } + INLINE static UpdateSeq fresh() { return UpdateSeq(SC_fresh); } INLINE UpdateSeq(const UpdateSeq ©); INLINE UpdateSeq(const UpdateSeq &&from) noexcept;