summaryrefslogtreecommitdiffstats
path: root/editor/debugger/script_editor_debugger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/debugger/script_editor_debugger.cpp')
-rw-r--r--editor/debugger/script_editor_debugger.cpp207
1 files changed, 138 insertions, 69 deletions
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 8985387043..2c40f0e120 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -71,10 +71,12 @@
using CameraOverride = EditorDebuggerNode::CameraOverride;
-void ScriptEditorDebugger::_put_msg(String p_message, Array p_data) {
+void ScriptEditorDebugger::_put_msg(String p_message, Array p_data, uint64_t p_thread_id) {
+ ERR_FAIL_COND(p_thread_id == Thread::UNASSIGNED_ID);
if (is_session_active()) {
Array msg;
msg.push_back(p_message);
+ msg.push_back(p_thread_id);
msg.push_back(p_data);
peer->put_message(msg);
}
@@ -98,31 +100,31 @@ void ScriptEditorDebugger::debug_skip_breakpoints() {
Array msg;
msg.push_back(skip_breakpoints_value);
- _put_msg("set_skip_breakpoints", msg);
+ _put_msg("set_skip_breakpoints", msg, debugging_thread_id != Thread::UNASSIGNED_ID ? debugging_thread_id : Thread::MAIN_ID);
}
void ScriptEditorDebugger::debug_next() {
- ERR_FAIL_COND(!breaked);
+ ERR_FAIL_COND(!is_breaked());
- _put_msg("next", Array());
+ _put_msg("next", Array(), debugging_thread_id);
_clear_execution();
}
void ScriptEditorDebugger::debug_step() {
- ERR_FAIL_COND(!breaked);
+ ERR_FAIL_COND(!is_breaked());
- _put_msg("step", Array());
+ _put_msg("step", Array(), debugging_thread_id);
_clear_execution();
}
void ScriptEditorDebugger::debug_break() {
- ERR_FAIL_COND(breaked);
+ ERR_FAIL_COND(is_breaked());
_put_msg("break", Array());
}
void ScriptEditorDebugger::debug_continue() {
- ERR_FAIL_COND(!breaked);
+ ERR_FAIL_COND(!is_breaked());
// Allow focus stealing only if we actually run this client for security.
if (remote_pid && EditorNode::get_singleton()->has_child_process(remote_pid)) {
@@ -130,7 +132,7 @@ void ScriptEditorDebugger::debug_continue() {
}
_clear_execution();
- _put_msg("continue", Array());
+ _put_msg("continue", Array(), debugging_thread_id);
_put_msg("servers:foreground", Array());
}
@@ -299,43 +301,89 @@ Size2 ScriptEditorDebugger::get_minimum_size() const {
return ms;
}
-void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
+void ScriptEditorDebugger::_thread_debug_enter(uint64_t p_thread_id) {
+ ERR_FAIL_COND(!threads_debugged.has(p_thread_id));
+ ThreadDebugged &td = threads_debugged[p_thread_id];
+ _set_reason_text(td.error, MESSAGE_ERROR);
+ emit_signal(SNAME("breaked"), true, td.can_debug, td.error, td.has_stackdump);
+ if (!td.error.is_empty()) {
+ tabs->set_current_tab(0);
+ }
+ inspector->clear_cache(); // Take a chance to force remote objects update.
+ _put_msg("get_stack_dump", Array(), p_thread_id);
+}
+
+void ScriptEditorDebugger::_select_thread(int p_index) {
+ debugging_thread_id = threads->get_item_metadata(threads->get_selected());
+ _thread_debug_enter(debugging_thread_id);
+}
+
+void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread_id, const Array &p_data) {
emit_signal(SNAME("debug_data"), p_msg, p_data);
if (p_msg == "debug_enter") {
- _put_msg("get_stack_dump", Array());
-
- ERR_FAIL_COND(p_data.size() != 3);
- bool can_continue = p_data[0];
- String error = p_data[1];
- bool has_stackdump = p_data[2];
- breaked = true;
- can_request_idle_draw = true;
- can_debug = can_continue;
- _update_buttons_state();
- _set_reason_text(error, MESSAGE_ERROR);
- emit_signal(SNAME("breaked"), true, can_continue, error, has_stackdump);
- if (is_move_to_foreground()) {
- DisplayServer::get_singleton()->window_move_to_foreground();
- }
- if (!error.is_empty()) {
- tabs->set_current_tab(0);
+ ERR_FAIL_COND(p_data.size() != 4);
+
+ ThreadDebugged td;
+ td.name = p_data[3];
+ td.error = p_data[1];
+ td.can_debug = p_data[0];
+ td.has_stackdump = p_data[2];
+ td.thread_id = p_thread_id;
+ static uint32_t order_inc = 0;
+ td.debug_order = order_inc++;
+
+ threads_debugged.insert(p_thread_id, td);
+
+ if (threads_debugged.size() == 1) {
+ // First thread that requests debug
+ debugging_thread_id = p_thread_id;
+ _thread_debug_enter(p_thread_id);
+ can_request_idle_draw = true;
+ if (is_move_to_foreground()) {
+ DisplayServer::get_singleton()->window_move_to_foreground();
+ }
+ profiler->set_enabled(false, false);
+ visual_profiler->set_enabled(false);
}
- profiler->set_enabled(false, false);
- visual_profiler->set_enabled(false);
- inspector->clear_cache(); // Take a chance to force remote objects update.
+ _update_buttons_state();
} else if (p_msg == "debug_exit") {
- breaked = false;
- can_debug = false;
- _clear_execution();
- _update_buttons_state();
- _set_reason_text(TTR("Execution resumed."), MESSAGE_SUCCESS);
- emit_signal(SNAME("breaked"), false, false, "", false);
+ threads_debugged.erase(p_thread_id);
+ if (p_thread_id == debugging_thread_id) {
+ _clear_execution();
+ if (threads_debugged.size() == 0) {
+ debugging_thread_id = Thread::UNASSIGNED_ID;
+ } else {
+ // Find next thread to debug.
+ uint32_t min_order = 0xFFFFFFFF;
+ uint64_t next_thread = Thread::UNASSIGNED_ID;
+ for (KeyValue<uint64_t, ThreadDebugged> T : threads_debugged) {
+ if (T.value.debug_order < min_order) {
+ min_order = T.value.debug_order;
+ next_thread = T.key;
+ }
+ }
+
+ debugging_thread_id = next_thread;
+ }
- profiler->set_enabled(true, false);
- profiler->disable_seeking();
+ if (debugging_thread_id == Thread::UNASSIGNED_ID) {
+ // Nothing else to debug.
+ profiler->set_enabled(true, false);
+ profiler->disable_seeking();
- visual_profiler->set_enabled(true);
+ visual_profiler->set_enabled(true);
+
+ _set_reason_text(TTR("Execution resumed."), MESSAGE_SUCCESS);
+ emit_signal(SNAME("breaked"), false, false, "", false);
+
+ _update_buttons_state();
+ } else {
+ _thread_debug_enter(debugging_thread_id);
+ }
+ } else {
+ _update_buttons_state();
+ }
} else if (p_msg == "set_pid") {
ERR_FAIL_COND(p_data.size() < 1);
@@ -379,7 +427,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
vmem_total->set_tooltip_text(TTR("Bytes:") + " " + itos(total));
vmem_total->set_text(String::humanize_size(total));
-
} else if (p_msg == "servers:drawn") {
can_request_idle_draw = true;
} else if (p_msg == "stack_dump") {
@@ -414,11 +461,9 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
inspector->clear_stack_variables();
ERR_FAIL_COND(p_data.size() != 1);
emit_signal(SNAME("stack_frame_vars"), p_data[0]);
-
} else if (p_msg == "stack_frame_var") {
inspector->add_stack_variable(p_data);
emit_signal(SNAME("stack_frame_var"), p_data);
-
} else if (p_msg == "output") {
ERR_FAIL_COND(p_data.size() != 2);
@@ -458,7 +503,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
frame_data.write[i] = p_data[i];
}
performance_profiler->add_profile_frame(frame_data);
-
} else if (p_msg == "visual:profile_frame") {
ServersDebugger::VisualProfilerFrame frame;
frame.deserialize(p_data);
@@ -477,7 +521,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
}
}
visual_profiler->add_frame_metric(metric);
-
} else if (p_msg == "error") {
DebuggerMarshalls::OutputError oe;
ERR_FAIL_COND_MSG(oe.deserialize(p_data) == false, "Failed to deserialize error message");
@@ -625,13 +668,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
} else {
error_count++;
}
-
} else if (p_msg == "servers:function_signature") {
// Cache a profiler signature.
ServersDebugger::ScriptFunctionSignature sig;
sig.deserialize(p_data);
profiler_signature[sig.id] = sig.name;
-
} else if (p_msg == "servers:profile_frame" || p_msg == "servers:profile_total") {
EditorProfiler::Metric metric;
ServersDebugger::ServersProfilerFrame frame;
@@ -744,11 +785,9 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
} else {
profiler->add_frame_metric(metric, true);
}
-
} else if (p_msg == "request_quit") {
emit_signal(SNAME("stop_requested"));
_stop_and_notify();
-
} else if (p_msg == "performance:profile_names") {
Vector<StringName> monitors;
monitors.resize(p_data.size());
@@ -757,13 +796,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
monitors.set(i, p_data[i]);
}
performance_profiler->update_monitors(monitors);
-
} else if (p_msg == "filesystem:update_file") {
ERR_FAIL_COND(p_data.size() < 1);
if (EditorFileSystem::get_singleton()) {
EditorFileSystem::get_singleton()->update_file(p_data[0]);
}
-
} else {
int colon_index = p_msg.find_char(':');
ERR_FAIL_COND_MSG(colon_index < 1, "Invalid message received");
@@ -878,7 +915,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
msg.push_back(cam->get_far());
_put_msg("scene:override_camera_3D:transform", msg);
}
- if (breaked && can_request_idle_draw) {
+ if (is_breaked() && can_request_idle_draw) {
_put_msg("servers:draw", Array());
can_request_idle_draw = false;
}
@@ -888,11 +925,12 @@ void ScriptEditorDebugger::_notification(int p_what) {
while (peer.is_valid() && peer->has_message()) {
Array arr = peer->get_message();
- if (arr.size() != 2 || arr[0].get_type() != Variant::STRING || arr[1].get_type() != Variant::ARRAY) {
+ if (arr.size() != 3 || arr[0].get_type() != Variant::STRING || arr[1].get_type() != Variant::INT || arr[2].get_type() != Variant::ARRAY) {
_stop_and_notify();
ERR_FAIL_MSG("Invalid message format received from peer");
}
- _parse_message(arr[0], arr[1]);
+
+ _parse_message(arr[0], arr[1], arr[2]);
if (OS::get_singleton()->get_ticks_msec() > until) {
break;
@@ -959,8 +997,6 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
performance_profiler->reset();
set_process(true);
- breaked = false;
- can_debug = true;
camera_override = CameraOverride::OVERRIDE_NONE;
tabs->set_current_tab(0);
@@ -973,13 +1009,35 @@ void ScriptEditorDebugger::_update_buttons_state() {
const bool active = is_session_active();
const bool has_editor_tree = active && editor_remote_tree && editor_remote_tree->get_selected();
vmem_refresh->set_disabled(!active);
- step->set_disabled(!active || !breaked || !can_debug);
- next->set_disabled(!active || !breaked || !can_debug);
- copy->set_disabled(!active || !breaked);
- docontinue->set_disabled(!active || !breaked);
- dobreak->set_disabled(!active || breaked);
+ step->set_disabled(!active || !is_breaked() || !is_debuggable());
+ next->set_disabled(!active || !is_breaked() || !is_debuggable());
+ copy->set_disabled(!active || !is_breaked());
+ docontinue->set_disabled(!active || !is_breaked());
+ dobreak->set_disabled(!active || is_breaked());
le_clear->set_disabled(!active);
le_set->set_disabled(!has_editor_tree);
+
+ thread_list_updating = true;
+ LocalVector<ThreadDebugged *> threadss;
+ for (KeyValue<uint64_t, ThreadDebugged> &I : threads_debugged) {
+ threadss.push_back(&I.value);
+ }
+
+ threadss.sort_custom<ThreadSort>();
+ threads->clear();
+ int32_t selected_index = -1;
+ for (uint32_t i = 0; i < threadss.size(); i++) {
+ if (debugging_thread_id == threadss[i]->thread_id) {
+ selected_index = i;
+ }
+ threads->add_item(threadss[i]->name);
+ threads->set_item_metadata(threads->get_item_count() - 1, threadss[i]->thread_id);
+ }
+ if (selected_index != -1) {
+ threads->select(selected_index);
+ }
+
+ thread_list_updating = false;
}
void ScriptEditorDebugger::_stop_and_notify() {
@@ -990,8 +1048,8 @@ void ScriptEditorDebugger::_stop_and_notify() {
void ScriptEditorDebugger::stop() {
set_process(false);
- breaked = false;
- can_debug = false;
+ threads_debugged.clear();
+ debugging_thread_id = Thread::UNASSIGNED_ID;
remote_pid = 0;
_clear_execution();
@@ -1043,7 +1101,7 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable, int p_type) {
}
void ScriptEditorDebugger::_profiler_seeked() {
- if (breaked) {
+ if (is_breaked()) {
return;
}
debug_break();
@@ -1067,7 +1125,7 @@ void ScriptEditorDebugger::_export_csv() {
}
String ScriptEditorDebugger::get_var_value(const String &p_var) const {
- if (!breaked) {
+ if (!is_breaked()) {
return String();
}
return inspector->get_stack_variable(p_var);
@@ -1255,7 +1313,7 @@ bool ScriptEditorDebugger::request_stack_dump(const int &p_frame) {
Array msg;
msg.push_back(p_frame);
- _put_msg("get_stack_frame_vars", msg);
+ _put_msg("get_stack_frame_vars", msg, debugging_thread_id);
return true;
}
@@ -1407,7 +1465,7 @@ void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool
msg.push_back(p_path);
msg.push_back(p_line);
msg.push_back(p_enabled);
- _put_msg("breakpoint", msg);
+ _put_msg("breakpoint", msg, debugging_thread_id != Thread::UNASSIGNED_ID ? debugging_thread_id : Thread::MAIN_ID);
TreeItem *path_item = breakpoints_tree->search_item_text(p_path);
if (path_item == nullptr) {
@@ -1450,7 +1508,7 @@ void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool
}
void ScriptEditorDebugger::reload_scripts() {
- _put_msg("reload_scripts", Array());
+ _put_msg("reload_scripts", Array(), debugging_thread_id != Thread::UNASSIGNED_ID ? debugging_thread_id : Thread::MAIN_ID);
}
bool ScriptEditorDebugger::is_skip_breakpoints() {
@@ -1804,15 +1862,26 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
sc->set_h_size_flags(SIZE_EXPAND_FILL);
parent_sc->add_child(sc);
+ VBoxContainer *stack_vb = memnew(VBoxContainer);
+ stack_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ sc->add_child(stack_vb);
+ HBoxContainer *thread_hb = memnew(HBoxContainer);
+ stack_vb->add_child(thread_hb);
+ thread_hb->add_child(memnew(Label(TTR("Thread:"))));
+ threads = memnew(OptionButton);
+ thread_hb->add_child(threads);
+ threads->set_h_size_flags(SIZE_EXPAND_FILL);
+ threads->connect("item_selected", callable_mp(this, &ScriptEditorDebugger::_select_thread));
+
stack_dump = memnew(Tree);
stack_dump->set_allow_reselect(true);
stack_dump->set_columns(1);
stack_dump->set_column_titles_visible(true);
stack_dump->set_column_title(0, TTR("Stack Frames"));
- stack_dump->set_h_size_flags(SIZE_EXPAND_FILL);
stack_dump->set_hide_root(true);
+ stack_dump->set_v_size_flags(SIZE_EXPAND_FILL);
stack_dump->connect("cell_selected", callable_mp(this, &ScriptEditorDebugger::_stack_dump_frame_selected));
- sc->add_child(stack_dump);
+ stack_vb->add_child(stack_dump);
VBoxContainer *inspector_vbox = memnew(VBoxContainer);
inspector_vbox->set_h_size_flags(SIZE_EXPAND_FILL);