mirror of
https://github.com/godotengine/godot.git
synced 2025-11-01 06:01:14 +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() {
|
GDScript::~GDScript() {
|
||||||
if (destructing) {
|
if (destructing) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1640,21 +1661,7 @@ GDScript::~GDScript() {
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
{
|
cancel_pending_functions(false);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,9 @@ public:
|
||||||
|
|
||||||
void clear(GDScript::ClearData *p_clear_data = nullptr);
|
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_valid() const override { return valid; }
|
||||||
virtual bool is_abstract() const override { return false; } // GDScript does not support abstract classes.
|
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->clearing = true;
|
||||||
|
|
||||||
|
p_script->cancel_pending_functions(true);
|
||||||
|
|
||||||
p_script->native = Ref<GDScriptNativeClass>();
|
p_script->native = Ref<GDScriptNativeClass>();
|
||||||
p_script->base = Ref<GDScript>();
|
p_script->base = Ref<GDScript>();
|
||||||
p_script->_base = nullptr;
|
p_script->_base = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -616,6 +616,13 @@ public:
|
||||||
bool is_valid(bool p_extended_check = false) const;
|
bool is_valid(bool p_extended_check = false) const;
|
||||||
Variant resume(const Variant &p_arg = Variant());
|
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_stack();
|
||||||
void _clear_connections();
|
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