From 91833c852e47a83ed01deb26213b9d3184de736d Mon Sep 17 00:00:00 2001 From: David Snopek Date: Tue, 17 Sep 2024 14:53:39 -0500 Subject: [PATCH] Avoid `thread_local` on MacOS to prevent issues with hot reload --- include/godot_cpp/classes/wrapped.hpp | 21 ++++++++++++++++++--- include/godot_cpp/core/class_db.hpp | 3 +++ src/classes/wrapped.cpp | 15 ++++++++++++--- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index a0bcec7b..d2721081 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -40,6 +40,14 @@ #include +#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED) +#include +#define _GODOT_CPP_AVOID_THREAD_LOCAL +#define _GODOT_CPP_THREAD_LOCAL +#else +#define _GODOT_CPP_THREAD_LOCAL thread_local +#endif + namespace godot { class ClassDB; @@ -58,11 +66,15 @@ class Wrapped { template ::value, bool>> friend _ALWAYS_INLINE_ void _pre_initialize(); - thread_local static const StringName *_constructing_extension_class_name; - thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks; +#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL + static std::recursive_mutex _constructing_mutex; +#endif + + _GODOT_CPP_THREAD_LOCAL static const StringName *_constructing_extension_class_name; + _GODOT_CPP_THREAD_LOCAL static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks; #ifdef HOT_RELOAD_ENABLED - thread_local static GDExtensionObjectPtr _constructing_recreate_owner; + _GODOT_CPP_THREAD_LOCAL static GDExtensionObjectPtr _constructing_recreate_owner; #endif template @@ -121,6 +133,9 @@ public: template ::value, bool>> _ALWAYS_INLINE_ void _pre_initialize() { +#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL + Wrapped::_constructing_mutex.lock(); +#endif Wrapped::_set_construct_info(); } diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 85bc0fb7..d9dce792 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -129,6 +129,9 @@ private: static GDExtensionClassInstancePtr _recreate_instance_func(void *data, GDExtensionObjectPtr obj) { if constexpr (!std::is_abstract_v) { #ifdef HOT_RELOAD_ENABLED +#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL + std::lock_guard lk(Wrapped::_constructing_mutex); +#endif Wrapped::_constructing_recreate_owner = obj; T *new_instance = (T *)memalloc(sizeof(T)); memnew_placement(new_instance, T); diff --git a/src/classes/wrapped.cpp b/src/classes/wrapped.cpp index d397d46d..3eb17cad 100644 --- a/src/classes/wrapped.cpp +++ b/src/classes/wrapped.cpp @@ -39,11 +39,16 @@ #include namespace godot { -thread_local const StringName *Wrapped::_constructing_extension_class_name = nullptr; -thread_local const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr; + +#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL +std::recursive_mutex Wrapped::_constructing_mutex; +#endif + +_GODOT_CPP_THREAD_LOCAL const StringName *Wrapped::_constructing_extension_class_name = nullptr; +_GODOT_CPP_THREAD_LOCAL const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr; #ifdef HOT_RELOAD_ENABLED -thread_local GDExtensionObjectPtr Wrapped::_constructing_recreate_owner = nullptr; +_GODOT_CPP_THREAD_LOCAL GDExtensionObjectPtr Wrapped::_constructing_recreate_owner = nullptr; #endif const StringName *Wrapped::_get_extension_class_name() { @@ -51,6 +56,10 @@ const StringName *Wrapped::_get_extension_class_name() { } void Wrapped::_postinitialize() { +#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL + Wrapped::_constructing_mutex.unlock(); +#endif + // Only send NOTIFICATION_POSTINITIALIZE for extension classes. if (_is_extension_class()) { _notificationv(Object::NOTIFICATION_POSTINITIALIZE);