From bf1b0a4bb837db535ea4233d663b82a43cf35d68 Mon Sep 17 00:00:00 2001 From: micio Date: Thu, 20 Feb 2014 13:00:22 +0000 Subject: [PATCH] Ide/Debuggers/Gdb_MI2 : added asynchronous break command - only posix by now git-svn-id: svn://ultimatepp.org/upp/trunk@6939 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/ide/Debuggers/Gdb_MI2.cpp | 94 ++++++++++++++++++++++++++------ uppsrc/ide/Debuggers/Gdb_MI2.h | 23 ++++++++ 2 files changed, 99 insertions(+), 18 deletions(-) diff --git a/uppsrc/ide/Debuggers/Gdb_MI2.cpp b/uppsrc/ide/Debuggers/Gdb_MI2.cpp index 9fae35f73..984aa4d5d 100644 --- a/uppsrc/ide/Debuggers/Gdb_MI2.cpp +++ b/uppsrc/ide/Debuggers/Gdb_MI2.cpp @@ -40,8 +40,9 @@ void Gdb_MI2::DebugBar(Bar& bar) { bar.Add("Stop debugging", DbgImg::StopDebug(), THISBACK(Stop)).Key(K_SHIFT_F5); bar.Separator(); -// see note on Run() function -- crashes X on my machine, so removed by now -// bar.Add(!stopped, "Asynchronous break", THISBACK(AsyncBrk)); +#ifdef PLATFORM_POSIX + bar.Add(!stopped, "Asynchronous break", THISBACK(AsyncBrk)); +#endif bool b = !IdeIsDebugLock(); bar.Add(b, "Step into", DbgImg::StepInto(), THISBACK1(Step, disas.HasFocus() ? "exec-step-instruction" : "exec-step")).Key(K_F11); bar.Add(b, "Step over", DbgImg::StepOver(), THISBACK1(Step, disas.HasFocus() ? "exec-next-instruction" : "exec-next")).Key(K_F10); @@ -160,27 +161,39 @@ void Gdb_MI2::Run() IdeActivateBottom(); } +#ifdef PLATFORM_POSIX +// sends a ctrl-c to debugger, returns true on success, false otherwise +bool Gdb_MI2::InterruptDebugger(void) +{ + int killed = 0; + for(int iProc = 0; iProc < processes.GetCount(); iProc++) + if(kill(processes[iProc], SIGINT) == 0) + killed++; + return killed; +} +#endif + +#ifdef PLATFORM_POSIX void Gdb_MI2::AsyncBrk() { - // send an interrupt command to all running threads - StopAllThreads(); - + // data must be refreshed dataSynced = false; - - // gdb usually returns to command prompt instantly, BEFORE - // giving out stop reason, which we need. So, we wait some - // milliseconds and re-read (non blocking) GDB output to get it -/* - for(int i = 0; i < 20 && !stopped; i++) - { - Sleep(100); - ReadGdb(false); - } -*/ - // if target is correctly stopped, 'stopped' flag should be already set - // so we don't care here. If not set, target can't be stopped. + // send interrupt command to debugger + if(!InterruptDebugger()) + return; + + // if successful, wait for some time for 'stopped' flag to become true + for(int iMsec = 0; iMsec < 1000; iMsec += 20) + { + ReadGdb(false); + Sleep(20); + Ctrl::ProcessEvents(); + if(stopped) + break; + } } +#endif void Gdb_MI2::Stop() { @@ -343,6 +356,13 @@ Gdb_MI2::Gdb_MI2() periodic.Set(-50, THISBACK(Periodic)); dataSynced = false; + +#ifdef flagMT + // no running debug threads + runningThreads = 0; + stopThreads = false; +#endif + } Gdb_MI2::~Gdb_MI2() @@ -460,6 +480,40 @@ MIValue Gdb_MI2::ParseGdb(String const &output, bool wait) continue; } + // catch process start/stop and store/remove pids + else if(s.StartsWith("=thread-group-started,id=")) + { + String id, pid; + int i = s.Find("id="); + if(i < 0) + continue; + i += 4; + while(s[i] && s[i] != '"') + id.Cat(s[i++]); + i = s.Find("pid="); + if(i < 0) + continue; + i += 5; + while(s[i] && s[i] != '"') + pid.Cat(s[i++]); + + processes.Add(id, atoi(pid)); + } + + else if(s.StartsWith("=thread-group-exited,id=")) + { + String id; + int i = s.Find("id="); + if(i < 0) + continue; + i += 4; + while(s[i] && s[i] != '"') + id.Cat(s[i++]); + i = processes.Find(id); + if(i >= 0) + processes.Remove(i); + } + // skip asynchronous responses // in future, we could be gather/use them if(s[0] == '*'|| s[0] == '=') @@ -805,6 +859,7 @@ void Gdb_MI2::LogFrame(String const &msg, MIValue &frame) PutConsole(Format(msg + " at %s, function '%s', file '%s', line %s", addr, function, file, line)); } +/* // stop all running threads and re-select previous current thread void Gdb_MI2::StopAllThreads(void) { @@ -838,6 +893,7 @@ void Gdb_MI2::StopAllThreads(void) if(current != "") MICmd("thread-select " + current); } +*/ // check for stop reason void Gdb_MI2::CheckStopReason(void) @@ -856,12 +912,14 @@ void Gdb_MI2::CheckStopReason(void) else reason = stReason["reason"]; +/* // as we are in non-stop mode, to allow async break to work // we shall stop ALL running threads here, otherwise we'll have // problems when single stepping a gui MT app // single step will be done so for a single thread, while other // are idle. Maybe we could make this behaviour optional StopAllThreads(); +*/ if(reason == "exited-normally") { diff --git a/uppsrc/ide/Debuggers/Gdb_MI2.h b/uppsrc/ide/Debuggers/Gdb_MI2.h index abac826ea..c4309958c 100644 --- a/uppsrc/ide/Debuggers/Gdb_MI2.h +++ b/uppsrc/ide/Debuggers/Gdb_MI2.h @@ -15,6 +15,29 @@ class Gdb_MI2 : public Debugger, public ParentCtrl { private: + // list of processes (and connected thread groups) + // used to stop them + VectorMap processes; + + // multithread support +#ifdef flagMT + // numbr of running debug threads + int runningThreads; + + // flag to signal threads to stop + bool stopThreads; + + // mutex and thead object + Mutex mutex; + Thread debugThread; + +#endif + + // debug break support -- ONLY POSIX, by now +#ifdef PLATFORM_POSIX + bool InterruptDebugger(void); +#endif + // used to post and kill timed callbacks TimeCallback timeCallback;