Browse Source

Merge pull request #1594 from dsnopek/macos-thread-local

Avoid `thread_local` on MacOS to prevent issues with hot reload
David Snopek 9 tháng trước cách đây
mục cha
commit
ca5179f7d7

+ 18 - 3
include/godot_cpp/classes/wrapped.hpp

@@ -40,6 +40,14 @@
 
 #include <godot_cpp/godot.hpp>
 
+#if defined(MACOS_ENABLED) && defined(HOT_RELOAD_ENABLED)
+#include <mutex>
+#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 <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::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 <typename T>
@@ -121,6 +133,9 @@ public:
 
 template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
 _ALWAYS_INLINE_ void _pre_initialize() {
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+	Wrapped::_constructing_mutex.lock();
+#endif
 	Wrapped::_set_construct_info<T>();
 }
 

+ 3 - 0
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<T>) {
 #ifdef HOT_RELOAD_ENABLED
+#ifdef _GODOT_CPP_AVOID_THREAD_LOCAL
+			std::lock_guard<std::recursive_mutex> lk(Wrapped::_constructing_mutex);
+#endif
 			Wrapped::_constructing_recreate_owner = obj;
 			T *new_instance = (T *)memalloc(sizeof(T));
 			memnew_placement(new_instance, T);

+ 12 - 3
src/classes/wrapped.cpp

@@ -39,11 +39,16 @@
 #include <godot_cpp/core/class_db.hpp>
 
 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);