summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript.cpp
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2024-01-05 12:05:32 +0100
committerRémi Verschelde <rverschelde@gmail.com>2024-01-05 12:05:32 +0100
commitbf1de980e5c802af44caf806204886714fee6d2e (patch)
treedb749ada038bb19b89b702c9b19cf5ebebf65f1b /modules/gdscript/gdscript.cpp
parent1455159d2cb12d5320a6c99b50a5cb7c0e0513b5 (diff)
parent49bce5c9ef3be4cf51fdd6b254cce175200e54a5 (diff)
downloadredot-engine-bf1de980e5c802af44caf806204886714fee6d2e.tar.gz
Merge pull request #86569 from rune-scape/rune-fix-lambda-hotswap2
GDScript: Lambda hotswap fixes
Diffstat (limited to 'modules/gdscript/gdscript.cpp')
-rw-r--r--modules/gdscript/gdscript.cpp129
1 files changed, 38 insertions, 91 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index a999acd1bd..1f0830aa17 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1381,51 +1381,43 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
}
#endif
-GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_main_thread;
-thread_local GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_thread_local = nullptr;
-
-GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) {
- UpdatableFuncPtrElement result = {};
-
- {
- MutexLock lock(func_ptrs_to_update_thread_local->mutex);
- result.element = func_ptrs_to_update_thread_local->ptrs.push_back(p_func_ptr_ptr);
- result.func_ptr = func_ptrs_to_update_thread_local;
-
- if (likely(func_ptrs_to_update_thread_local->initialized)) {
- return result;
- }
-
- func_ptrs_to_update_thread_local->initialized = true;
+GDScript::UpdatableFuncPtr::UpdatableFuncPtr(GDScriptFunction *p_function) {
+ if (p_function == nullptr) {
+ return;
}
- MutexLock lock(func_ptrs_to_update_mutex);
- func_ptrs_to_update.push_back(func_ptrs_to_update_thread_local);
- func_ptrs_to_update_thread_local->rc++;
-
- return result;
-}
+ ptr = p_function;
+ script = ptr->get_script();
+ ERR_FAIL_NULL(script);
-void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element) {
- ERR_FAIL_NULL(p_func_ptr_element.element);
- ERR_FAIL_NULL(p_func_ptr_element.func_ptr);
- MutexLock lock(p_func_ptr_element.func_ptr->mutex);
- p_func_ptr_element.element->erase();
+ MutexLock script_lock(script->func_ptrs_to_update_mutex);
+ list_element = script->func_ptrs_to_update.push_back(this);
}
-void GDScript::_fixup_thread_function_bookkeeping() {
- // Transfer the ownership of these update items to the main thread,
- // because the current one is dying, leaving theirs orphan, dangling.
+GDScript::UpdatableFuncPtr::~UpdatableFuncPtr() {
+ ERR_FAIL_NULL(script);
- DEV_ASSERT(!Thread::is_main_thread());
+ if (list_element) {
+ MutexLock script_lock(script->func_ptrs_to_update_mutex);
+ list_element->erase();
+ list_element = nullptr;
+ }
+}
- MutexLock lock(func_ptrs_to_update_main_thread.mutex);
- MutexLock lock2(func_ptrs_to_update_thread_local->mutex);
+void GDScript::_recurse_replace_function_ptrs(const HashMap<GDScriptFunction *, GDScriptFunction *> &p_replacements) const {
+ MutexLock lock(func_ptrs_to_update_mutex);
+ for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
+ HashMap<GDScriptFunction *, GDScriptFunction *>::ConstIterator replacement = p_replacements.find(updatable->ptr);
+ if (replacement) {
+ updatable->ptr = replacement->value;
+ } else {
+ // Probably a lambda from another reload, ignore.
+ updatable->ptr = nullptr;
+ }
+ }
- while (!func_ptrs_to_update_thread_local->ptrs.is_empty()) {
- List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local->ptrs.front();
- E->transfer_to_back(&func_ptrs_to_update_main_thread.ptrs);
- func_ptrs_to_update_thread_local->transferred = true;
+ for (HashMap<StringName, Ref<GDScript>>::ConstIterator subscript = subclasses.begin(); subscript; ++subscript) {
+ subscript->value->_recurse_replace_function_ptrs(p_replacements);
}
}
@@ -1447,30 +1439,9 @@ void GDScript::clear(ClearData *p_clear_data) {
}
{
- MutexLock outer_lock(func_ptrs_to_update_mutex);
+ MutexLock lock(func_ptrs_to_update_mutex);
for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
- bool destroy = false;
- {
- MutexLock inner_lock(updatable->mutex);
- if (updatable->transferred) {
- func_ptrs_to_update_main_thread.mutex.lock();
- }
- for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) {
- *func_ptr_ptr = nullptr;
- }
- DEV_ASSERT(updatable->rc != 0);
- updatable->rc--;
- if (updatable->rc == 0) {
- destroy = true;
- }
- if (updatable->transferred) {
- func_ptrs_to_update_main_thread.mutex.unlock();
- }
- }
- if (destroy) {
- DEV_ASSERT(updatable != &func_ptrs_to_update_main_thread);
- memdelete(updatable);
- }
+ updatable->ptr = nullptr;
}
}
@@ -1543,6 +1514,13 @@ GDScript::~GDScript() {
}
destructing = true;
+ if (is_print_verbose_enabled()) {
+ MutexLock lock(func_ptrs_to_update_mutex);
+ if (!func_ptrs_to_update.is_empty()) {
+ print_line(vformat("GDScript: %d orphaned lambdas becoming invalid at destruction of script '%s'.", func_ptrs_to_update.size(), fully_qualified_name));
+ }
+ }
+
clear();
{
@@ -2091,33 +2069,6 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
named_globals.erase(p_name);
}
-void GDScriptLanguage::thread_enter() {
- GDScript::func_ptrs_to_update_thread_local = memnew(GDScript::UpdatableFuncPtr);
-}
-
-void GDScriptLanguage::thread_exit() {
- // This thread may have been created before GDScript was up
- // (which also means it can't have run any GDScript code at all).
- if (!GDScript::func_ptrs_to_update_thread_local) {
- return;
- }
-
- GDScript::_fixup_thread_function_bookkeeping();
-
- bool destroy = false;
- {
- MutexLock lock(GDScript::func_ptrs_to_update_thread_local->mutex);
- DEV_ASSERT(GDScript::func_ptrs_to_update_thread_local->rc != 0);
- GDScript::func_ptrs_to_update_thread_local->rc--;
- if (GDScript::func_ptrs_to_update_thread_local->rc == 0) {
- destroy = true;
- }
- }
- if (destroy) {
- memdelete(GDScript::func_ptrs_to_update_thread_local);
- }
-}
-
void GDScriptLanguage::init() {
//populate global constants
int gcc = CoreConstants::get_global_constant_count();
@@ -2150,8 +2101,6 @@ void GDScriptLanguage::init() {
_add_global(E.name, E.ptr);
}
- GDScript::func_ptrs_to_update_thread_local = &GDScript::func_ptrs_to_update_main_thread;
-
#ifdef TESTS_ENABLED
GDScriptTests::GDScriptTestRunner::handle_cmdline();
#endif
@@ -2201,8 +2150,6 @@ void GDScriptLanguage::finish() {
}
script_list.clear();
function_list.clear();
-
- DEV_ASSERT(GDScript::func_ptrs_to_update_main_thread.rc == 1);
}
void GDScriptLanguage::profiling_start() {