-
-
Notifications
You must be signed in to change notification settings - Fork 21.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support threads in the script debugger #76582
Conversation
a88b1c2
to
d765290
Compare
I tried your PR. I paused my instance, while 2 threads were running in the background, but they didn't show up in the debugger. Is there something more to do? I ran that code on my main scene: extends Node
var thread_hello: Thread
var thread_world: Thread
func _ready() -> void:
thread_hello = Thread.new()
thread_world = Thread.new()
thread_hello.start(_thread_func.bind("hello", 500), Thread.PRIORITY_NORMAL)
thread_world.start(_thread_func.bind("world", 1000), Thread.PRIORITY_NORMAL)
func _thread_func(str: String, delay: int) -> void:
while true:
prints(str)
OS.delay_msec(delay)
|
f907f7d
to
114ebea
Compare
@adamscott Threads only show up in the debugger once they break with an error, otherwise they are not tracked. There is not much of a point to doing so, otherwise since the engine itself does not track the threads. If you want to know what they are doing, that will probably be possible with the threaded profiler. |
Is it possible to assign a name for the Thread? Otherwise, it may be hard to detect which thread emit an error by only number. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember to remove this line from the class reference:
Line 8 in ee86505
[b]Note:[/b] Breakpoints won't break on code if it's running in a thread. This is a current limitation of the GDScript debugger. |
Since we already have a Thread wrapper, it would be nice to add a |
Overall looks good to me. It is not that much of changes in the end. The editor side does need polish though, it is difficult to use as the pointer does not update correctly when it breaks from multiple threads. |
Done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
This comment was marked as off-topic.
This comment was marked as off-topic.
There's still reviews that need to be done before this can be merged |
Aren't we able to use breakpoints in threads with this PR? |
Yes, but 4.1 is in feature freeze now. While this PR fixes a bug, it still has a large scope and may be postponed to 4.2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the overall debugger changes are good (see my comment about locking in _get_message
).
One thing I noticed, is that breaking in a thread will spam the console with errors like:
This function in this node (/root/Control) can only be accessed from either the main thread or a thread group. Use call_deferred() instead.
As far as I can tell, this is due to the Remote Inspector trying to get the Node properties if a local reference to a node is present in the thread stack.
This is the test I used:
extends Control
var t = Thread.new()
func _tfunc():
while true:
var v1 := 1
var v2 := "Test"
print("Test")
OS.delay_msec(1000)
func _ready():
t.start(_tfunc)
func _process(delta):
var v1 := "Test"
print("Delta")
I think that the best solution here would be to change all the scene:
messages (the ones handled by SceneDebugger) to always be sent to the main thread.
EDIT: Well, it seems like it's already the case that scene:
messages are sent to the main thread, so it might be a different message that generate the object spam... I'll try to dig deeper.
EDIT2: The error seems to be coming from the stack variables serialization. We are passing full objects (and not encoded ID), and the remote inspector uses the received values directly (instead of the 2-steps process which we use when inspecting remote tree). This might require some changes to how we handle those.
This patch should fix the error spam, while still allow for remote inspection: diff --git a/core/debugger/debugger_marshalls.cpp b/core/debugger/debugger_marshalls.cpp
index 591b44869f..3e6b7501c7 100644
--- a/core/debugger/debugger_marshalls.cpp
+++ b/core/debugger/debugger_marshalls.cpp
@@ -67,6 +67,7 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
Array arr;
arr.push_back(name);
arr.push_back(type);
+ arr.push_back(value.get_type());
Variant var = value;
if (value.get_type() == Variant::OBJECT && value.get_validated_object() == nullptr) {
@@ -74,7 +75,7 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
}
int len = 0;
- Error err = encode_variant(var, nullptr, len, true);
+ Error err = encode_variant(var, nullptr, len, false);
if (err != OK) {
ERR_PRINT("Failed to encode variant.");
}
@@ -88,11 +89,12 @@ Array DebuggerMarshalls::ScriptStackVariable::serialize(int max_size) {
}
bool DebuggerMarshalls::ScriptStackVariable::deserialize(const Array &p_arr) {
- CHECK_SIZE(p_arr, 3, "ScriptStackVariable");
+ CHECK_SIZE(p_arr, 4, "ScriptStackVariable");
name = p_arr[0];
type = p_arr[1];
- value = p_arr[2];
- CHECK_END(p_arr, 3, "ScriptStackVariable");
+ var_type = p_arr[2];
+ value = p_arr[3];
+ CHECK_END(p_arr, 4, "ScriptStackVariable");
return true;
}
diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h
index 8ba93c3092..1b81623688 100644
--- a/core/debugger/debugger_marshalls.h
+++ b/core/debugger/debugger_marshalls.h
@@ -38,6 +38,7 @@ struct DebuggerMarshalls {
String name;
Variant value;
int type = -1;
+ int var_type = -1;
Array serialize(int max_size = 1 << 20); // 1 MiB default.
bool deserialize(const Array &p_arr);
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index e083e1746d..1e9b7c2c60 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -232,7 +232,7 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array) {
PropertyHint h = PROPERTY_HINT_NONE;
String hs;
- if (v.get_type() == Variant::OBJECT) {
+ if (var.var_type == Variant::OBJECT) {
v = Object::cast_to<EncodedObjectAsID>(v)->get_object_id();
h = PROPERTY_HINT_OBJECT_ID;
hs = "Object"; |
* This implementation adds threads on the side of the client (script debugger). * Some functions of the debugger are optimized. * The profile is also now thread safe using atomics. * The editor can switch between multiple threads when debugging. This PR adds threaded support for the script language debugger. Every thread has its own thread local data and it will connect to the debugger using multiple thread IDs. This means that, now, the editor can receive multiple threads entering debug mode at the same time.
@Faless @AThousandShips Thanks lots! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've checked this, not as deeply as I would have wanted due to my current limited bandwitdth. I spotted no issues. In case some bugs arise, I may be able to be of greater help in fixing them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. I tested for a bit and seems to work well.
Thanks! |
This PR adds threaded support for the script language debugger. Every thread has its own thread local data and it will connect to the debugger using multiple thread IDs. This means that, now, the editor can receive multiple threads entering debug mode at the same time.
Obligatory screenshot: