Skip to content

Commit 4248411

Browse files
committed
Merge pull request #102521 from HolonProduction/cancel-await
GDScript: Cancel suspended functions when reloading a script
2 parents 36991ab + 676e4c9 commit 4248411

File tree

7 files changed

+51
-15
lines changed

7 files changed

+51
-15
lines changed

modules/gdscript/gdscript.cpp

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,27 @@ void GDScript::clear(ClearData *p_clear_data) {
16231623
}
16241624
}
16251625

1626+
void GDScript::cancel_pending_functions(bool warn) {
1627+
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
1628+
1629+
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
1630+
// Order matters since clearing the stack may already cause
1631+
// the GDScriptFunctionState to be destroyed and thus removed from the list.
1632+
pending_func_states.remove(E);
1633+
GDScriptFunctionState *state = E->self();
1634+
#ifdef DEBUG_ENABLED
1635+
if (warn) {
1636+
WARN_PRINT("Canceling suspended execution of \"" + state->get_readable_function() + "\" due to a script reload.");
1637+
}
1638+
#endif
1639+
ObjectID state_id = state->get_instance_id();
1640+
state->_clear_connections();
1641+
if (ObjectDB::get_instance(state_id)) {
1642+
state->_clear_stack();
1643+
}
1644+
}
1645+
}
1646+
16261647
GDScript::~GDScript() {
16271648
if (destructing) {
16281649
return;
@@ -1638,21 +1659,7 @@ GDScript::~GDScript() {
16381659

16391660
clear();
16401661

1641-
{
1642-
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
1643-
1644-
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
1645-
// Order matters since clearing the stack may already cause
1646-
// the GDScriptFunctionState to be destroyed and thus removed from the list.
1647-
pending_func_states.remove(E);
1648-
GDScriptFunctionState *state = E->self();
1649-
ObjectID state_id = state->get_instance_id();
1650-
state->_clear_connections();
1651-
if (ObjectDB::get_instance(state_id)) {
1652-
state->_clear_stack();
1653-
}
1654-
}
1655-
}
1662+
cancel_pending_functions(false);
16561663

16571664
{
16581665
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);

modules/gdscript/gdscript.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ class GDScript : public Script {
243243

244244
void clear(GDScript::ClearData *p_clear_data = nullptr);
245245

246+
// Cancels all functions of the script that are are waiting to be resumed after using await.
247+
void cancel_pending_functions(bool warn);
248+
246249
virtual bool is_valid() const override { return valid; }
247250
virtual bool is_abstract() const override { return false; } // GDScript does not support abstract classes.
248251

modules/gdscript/gdscript_compiler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2659,6 +2659,8 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP
26592659

26602660
p_script->clearing = true;
26612661

2662+
p_script->cancel_pending_functions(true);
2663+
26622664
p_script->native = Ref<GDScriptNativeClass>();
26632665
p_script->base = Ref<GDScript>();
26642666
p_script->_base = nullptr;

modules/gdscript/gdscript_function.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,13 @@ class GDScriptFunctionState : public RefCounted {
615615
bool is_valid(bool p_extended_check = false) const;
616616
Variant resume(const Variant &p_arg = Variant());
617617

618+
#ifdef DEBUG_ENABLED
619+
// Returns a human-readable representation of the function.
620+
String get_readable_function() {
621+
return state.function_name;
622+
}
623+
#endif
624+
618625
void _clear_stack();
619626
void _clear_connections();
620627

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# TODO: This test is currently disabled since it triggers some complex memory leaks. Try enabling it again once GH-101830 is fixed.
2+
3+
signal finished
4+
5+
const scr: GDScript = preload("reload_suspended_function_helper.notest.gd")
6+
7+
func test():
8+
@warning_ignore("UNSAFE_METHOD_ACCESS")
9+
scr.test(self)
10+
@warning_ignore("RETURN_VALUE_DISCARDED")
11+
scr.reload(true)
12+
finished.emit()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
GDTEST_RUNTIME_ERROR
2+
>> WARNING: Canceling suspended execution of "test" due to a script reload.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
static func test(a):
2+
await a.finished
3+
pass

0 commit comments

Comments
 (0)