Skip to content

Commit

Permalink
GDScript: Cancel suspended functions when reloading a script
Browse files Browse the repository at this point in the history
  • Loading branch information
HolonProduction committed Feb 7, 2025
1 parent 06acfcc commit a507002
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 15 deletions.
37 changes: 22 additions & 15 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ class GDScript : public Script {

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.

Expand Down
2 changes: 2 additions & 0 deletions modules/gdscript/gdscript_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions modules/gdscript/gdscript_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,13 @@ class GDScriptFunctionState : public RefCounted {
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();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
signal finished

const scr: GDScript = preload("reload_suspended_function.notest.gd")

func test():
@warning_ignore("UNSAFE_METHOD_ACCESS")
scr.test(self)
@warning_ignore("RETURN_VALUE_DISCARDED")
scr.reload(true)
finished.emit()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
static func test(a):
await a.finished
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
GDTEST_RUNTIME_ERROR
>> WARNING: Canceling suspended execution of "test" due to a script reload.

0 comments on commit a507002

Please sign in to comment.