You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-09 12:50:35 +00:00
Support threads in the script debugger
* 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.
This commit is contained in:
@@ -364,12 +364,26 @@ class GDScriptLanguage : public ScriptLanguage {
|
||||
int *line = nullptr;
|
||||
};
|
||||
|
||||
int _debug_parse_err_line;
|
||||
String _debug_parse_err_file;
|
||||
String _debug_error;
|
||||
int _debug_call_stack_pos;
|
||||
int _debug_max_call_stack;
|
||||
CallLevel *_call_stack = nullptr;
|
||||
static thread_local int _debug_parse_err_line;
|
||||
static thread_local String _debug_parse_err_file;
|
||||
static thread_local String _debug_error;
|
||||
struct CallStack {
|
||||
CallLevel *levels = nullptr;
|
||||
int stack_pos = 0;
|
||||
|
||||
void free() {
|
||||
if (levels) {
|
||||
memdelete(levels);
|
||||
levels = nullptr;
|
||||
}
|
||||
}
|
||||
~CallStack() {
|
||||
free();
|
||||
}
|
||||
};
|
||||
|
||||
static thread_local CallStack _call_stack;
|
||||
int _debug_max_call_stack = 0;
|
||||
|
||||
void _add_global(const StringName &p_name, const Variant &p_value);
|
||||
|
||||
@@ -395,59 +409,51 @@ public:
|
||||
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
|
||||
|
||||
_FORCE_INLINE_ void enter_function(GDScriptInstance *p_instance, GDScriptFunction *p_function, Variant *p_stack, int *p_ip, int *p_line) {
|
||||
if (Thread::get_main_id() != Thread::get_caller_id()) {
|
||||
return; //no support for other threads than main for now
|
||||
if (unlikely(_call_stack.levels == nullptr)) {
|
||||
_call_stack.levels = memnew_arr(CallLevel, _debug_max_call_stack + 1);
|
||||
}
|
||||
|
||||
if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
|
||||
EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() + 1);
|
||||
}
|
||||
|
||||
if (_debug_call_stack_pos >= _debug_max_call_stack) {
|
||||
if (_call_stack.stack_pos >= _debug_max_call_stack) {
|
||||
//stack overflow
|
||||
_debug_error = vformat("Stack overflow (stack size: %s). Check for infinite recursion in your script.", _debug_max_call_stack);
|
||||
EngineDebugger::get_script_debugger()->debug(this);
|
||||
return;
|
||||
}
|
||||
|
||||
_call_stack[_debug_call_stack_pos].stack = p_stack;
|
||||
_call_stack[_debug_call_stack_pos].instance = p_instance;
|
||||
_call_stack[_debug_call_stack_pos].function = p_function;
|
||||
_call_stack[_debug_call_stack_pos].ip = p_ip;
|
||||
_call_stack[_debug_call_stack_pos].line = p_line;
|
||||
_debug_call_stack_pos++;
|
||||
_call_stack.levels[_call_stack.stack_pos].stack = p_stack;
|
||||
_call_stack.levels[_call_stack.stack_pos].instance = p_instance;
|
||||
_call_stack.levels[_call_stack.stack_pos].function = p_function;
|
||||
_call_stack.levels[_call_stack.stack_pos].ip = p_ip;
|
||||
_call_stack.levels[_call_stack.stack_pos].line = p_line;
|
||||
_call_stack.stack_pos++;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void exit_function() {
|
||||
if (Thread::get_main_id() != Thread::get_caller_id()) {
|
||||
return; //no support for other threads than main for now
|
||||
}
|
||||
|
||||
if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
|
||||
EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() - 1);
|
||||
}
|
||||
|
||||
if (_debug_call_stack_pos == 0) {
|
||||
if (_call_stack.stack_pos == 0) {
|
||||
_debug_error = "Stack Underflow (Engine Bug)";
|
||||
EngineDebugger::get_script_debugger()->debug(this);
|
||||
return;
|
||||
}
|
||||
|
||||
_debug_call_stack_pos--;
|
||||
_call_stack.stack_pos--;
|
||||
}
|
||||
|
||||
virtual Vector<StackInfo> debug_get_current_stack_info() override {
|
||||
if (Thread::get_main_id() != Thread::get_caller_id()) {
|
||||
return Vector<StackInfo>();
|
||||
}
|
||||
|
||||
Vector<StackInfo> csi;
|
||||
csi.resize(_debug_call_stack_pos);
|
||||
for (int i = 0; i < _debug_call_stack_pos; i++) {
|
||||
csi.write[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0;
|
||||
if (_call_stack[i].function) {
|
||||
csi.write[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name();
|
||||
csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_script_path();
|
||||
csi.resize(_call_stack.stack_pos);
|
||||
for (int i = 0; i < _call_stack.stack_pos; i++) {
|
||||
csi.write[_call_stack.stack_pos - i - 1].line = _call_stack.levels[i].line ? *_call_stack.levels[i].line : 0;
|
||||
if (_call_stack.levels[i].function) {
|
||||
csi.write[_call_stack.stack_pos - i - 1].func = _call_stack.levels[i].function->get_name();
|
||||
csi.write[_call_stack.stack_pos - i - 1].file = _call_stack.levels[i].function->get_script()->get_script_path();
|
||||
}
|
||||
}
|
||||
return csi;
|
||||
|
||||
Reference in New Issue
Block a user