Godot has some operations that are bound to certain threads, and you can searching ERR_THREAD_GUARD, ERR_MAIN_THREAD_GUARD, ERR_READ_THREAD_GUARD, and ERR_READ_THREAD_GUARD_V for methods in Node that we need to cover.
This for example shows up in connect of a signal, in particular when using the emitted pattern, as it requires that the method be involved not on the main thread, but on its thread group.
The following patch is a prototype that shows how this can work, and should be generalized to the generator, and we will need a list of APIs that we track with this thread information, so the generator produces the correct fences (main thread vs thread group):
commit 7814f48d7b546df9b2bbe602c6554aeeb0f825bb (HEAD -> signalOnThread, origin/signalOnThread)
Author: Miguel de Icaza <miguel@gnome.org>
Date: Thu May 16 17:18:16 2024 -0400
Potential fix, as we need to invoke connect from its thread group
diff --git a/Sources/SwiftGodot/Core/SignalSupport.swift b/Sources/SwiftGodot/Core/SignalSupport.swift
index 558c7e7..045a953 100644
--- a/Sources/SwiftGodot/Core/SignalSupport.swift
+++ b/Sources/SwiftGodot/Core/SignalSupport.swift
@@ -117,9 +117,18 @@ public class SimpleSignal {
}
let callable = Callable(object: signalProxy, method: SignalProxy.proxyName)
- let r = target.connect(signal: signalName, callable: callable, flags: UInt32 (flags.rawValue))
- if r != .ok {
- print ("Warning, error connecting to signal \(signalName.description): \(r)")
+ if let tn = target as? Node {
+ _ = tn.callDeferredThreadGroup (
+ method: "connect",
+ Variant (signalName),
+ Variant (callable),
+ Variant (flags.rawValue)
+ )
+ } else {
+ let r = target.connect(signal: signalName, callable: callable, flags: UInt32 (flags.rawValue))
+ if r != .ok {
+ print ("Warning, error connecting to signal \(signalName.description): \(r)")
+ }
}
return signalProxy
}
E 0:00:03:0953 connect: Caller thread can't call this function in this node (/root/Control/AnimatedRichTextLabel/@AnimationPlayer@3). Use call_deferred() or call_thread_group() instead.
<C++ Error> Condition "!is_accessible_from_caller_thread()" is true. Returning: (ERR_INVALID_PARAMETER)
<C++ Source> scene/main/node.cpp:3936 @ connect()
Because the animationFinished.emitted is a shortcut that called that from the wrong thread (the code lives in SignalSupport, but also will live in other signals)
We probably should cache the "connect" StringName above.
Godot has some operations that are bound to certain threads, and you can searching
ERR_THREAD_GUARD
,ERR_MAIN_THREAD_GUARD
,ERR_READ_THREAD_GUARD
, andERR_READ_THREAD_GUARD_V
for methods inNode
that we need to cover.This for example shows up in
connect
of a signal, in particular when using the emitted pattern, as it requires that the method be involved not on the main thread, but on its thread group.The following patch is a prototype that shows how this can work, and should be generalized to the generator, and we will need a list of APIs that we track with this thread information, so the generator produces the correct fences (main thread vs thread group):
This manifest when using this idiom:
Will trigger this error:
Because the
animationFinished.emitted
is a shortcut that called that from the wrong thread (the code lives in SignalSupport, but also will live in other signals)We probably should cache the "connect" StringName above.