mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
GDScript: Cancel suspended functions when reloading a script
This commit is contained in:
parent
134da37497
commit
676e4c9013
7 changed files with 51 additions and 15 deletions
|
@ -1625,6 +1625,27 @@ void GDScript::clear(ClearData *p_clear_data) {
|
|||
}
|
||||
}
|
||||
|
||||
void GDScript::cancel_pending_functions(bool warn) {
|
||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||
|
||||
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
|
||||
// Order matters since clearing the stack may already cause
|
||||
// the GDScriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
GDScriptFunctionState *state = E->self();
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (warn) {
|
||||
WARN_PRINT("Canceling suspended execution of \"" + state->get_readable_function() + "\" due to a script reload.");
|
||||
}
|
||||
#endif
|
||||
ObjectID state_id = state->get_instance_id();
|
||||
state->_clear_connections();
|
||||
if (ObjectDB::get_instance(state_id)) {
|
||||
state->_clear_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GDScript::~GDScript() {
|
||||
if (destructing) {
|
||||
return;
|
||||
|
@ -1640,21 +1661,7 @@ GDScript::~GDScript() {
|
|||
|
||||
clear();
|
||||
|
||||
{
|
||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||
|
||||
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
|
||||
// Order matters since clearing the stack may already cause
|
||||
// the GDScriptFunctionState to be destroyed and thus removed from the list.
|
||||
pending_func_states.remove(E);
|
||||
GDScriptFunctionState *state = E->self();
|
||||
ObjectID state_id = state->get_instance_id();
|
||||
state->_clear_connections();
|
||||
if (ObjectDB::get_instance(state_id)) {
|
||||
state->_clear_stack();
|
||||
}
|
||||
}
|
||||
}
|
||||
cancel_pending_functions(false);
|
||||
|
||||
{
|
||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||
|
|
|
@ -244,6 +244,9 @@ public:
|
|||
|
||||
void clear(GDScript::ClearData *p_clear_data = nullptr);
|
||||
|
||||
// Cancels all functions of the script that are are waiting to be resumed after using await.
|
||||
void cancel_pending_functions(bool warn);
|
||||
|
||||
virtual bool is_valid() const override { return valid; }
|
||||
virtual bool is_abstract() const override { return false; } // GDScript does not support abstract classes.
|
||||
|
||||
|
|
|
@ -2660,6 +2660,8 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
|
|||
|
||||
p_script->clearing = true;
|
||||
|
||||
p_script->cancel_pending_functions(true);
|
||||
|
||||
p_script->native = Ref<GDScriptNativeClass>();
|
||||
p_script->base = Ref<GDScript>();
|
||||
p_script->_base = nullptr;
|
||||
|
|
|
@ -616,6 +616,13 @@ public:
|
|||
bool is_valid(bool p_extended_check = false) const;
|
||||
Variant resume(const Variant &p_arg = Variant());
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// Returns a human-readable representation of the function.
|
||||
String get_readable_function() {
|
||||
return state.function_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
void _clear_stack();
|
||||
void _clear_connections();
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# TODO: This test is currently disabled since it triggers some complex memory leaks. Try enabling it again once GH-101830 is fixed.
|
||||
|
||||
signal finished
|
||||
|
||||
const scr: GDScript = preload("reload_suspended_function_helper.notest.gd")
|
||||
|
||||
func test():
|
||||
@warning_ignore("UNSAFE_METHOD_ACCESS")
|
||||
scr.test(self)
|
||||
@warning_ignore("RETURN_VALUE_DISCARDED")
|
||||
scr.reload(true)
|
||||
finished.emit()
|
|
@ -0,0 +1,2 @@
|
|||
GDTEST_RUNTIME_ERROR
|
||||
>> WARNING: Canceling suspended execution of "test" due to a script reload.
|
|
@ -0,0 +1,3 @@
|
|||
static func test(a):
|
||||
await a.finished
|
||||
pass
|
Loading…
Add table
Add a link
Reference in a new issue