Index: tools/lldb-mi/Driver.h =================================================================== --- tools/lldb-mi/Driver.h +++ tools/lldb-mi/Driver.h @@ -64,6 +64,7 @@ virtual bool SetDriverParent(const CMIDriverBase &vrOtherDriver); virtual const CMIUtilString &GetDriverName(void) const; virtual const CMIUtilString &GetDriverId(void) const; + virtual void DeliverSignal(int signal) {} // Original code: public: Index: tools/lldb-mi/MICmnStreamStdin.h =================================================================== --- tools/lldb-mi/MICmnStreamStdin.h +++ tools/lldb-mi/MICmnStreamStdin.h @@ -84,6 +84,7 @@ bool SetVisitor(IStreamStdin &vrVisitor); bool SetOSStdinHandler(IOSStdinHandler &vrHandler); void OnExitHandler(void); + const MIchar *ReadLine(CMIUtilString &vwErrMsg); // Overridden: public: @@ -104,7 +105,6 @@ void operator=(const CMICmnStreamStdin &); bool MonitorStdin(bool &vrwbYesExit); - const MIchar *ReadLine(CMIUtilString &vwErrMsg); bool InputAvailable(bool &vbAvail); // Bytes are available on stdin @@ -122,4 +122,6 @@ bool m_bShowPrompt; // True = Yes prompt is shown/output to the user (stdout), false = no prompt bool m_bRedrawPrompt; // True = Prompt needs to be redrawn IOSStdinHandler *m_pStdinReadHandler; + static const int m_constBufferSize = 2048; + char m_cmdBuffer[m_constBufferSize]; }; Index: tools/lldb-mi/MICmnStreamStdin.cpp =================================================================== --- tools/lldb-mi/MICmnStreamStdin.cpp +++ tools/lldb-mi/MICmnStreamStdin.cpp @@ -33,6 +33,7 @@ #else #include "MICmnStreamStdinLinux.h" #endif // defined( _MSC_VER ) +#include // For std::strerror() //++ ------------------------------------------------------------------------------------ // Details: CMICmnStreamStdin constructor. @@ -355,7 +356,28 @@ const MIchar * CMICmnStreamStdin::ReadLine(CMIUtilString &vwErrMsg) { - return m_pStdinReadHandler->ReadLine(vwErrMsg); + vwErrMsg.clear(); + + // Read user input + const MIchar *pText = ::fgets(&m_cmdBuffer[0], m_constBufferSize, stdin); + if (pText == nullptr) + { + if (::ferror(stdin) != 0) + vwErrMsg = ::strerror(errno); + return nullptr; + } + + // Strip off new line characters + for (MIchar *pI = m_cmdBuffer; *pI != '\0'; pI++) + { + if ((*pI == '\n') || (*pI == '\r')) + { + *pI = '\0'; + break; + } + } + + return pText; } //++ ------------------------------------------------------------------------------------ Index: tools/lldb-mi/MIDriver.h =================================================================== --- tools/lldb-mi/MIDriver.h +++ tools/lldb-mi/MIDriver.h @@ -51,7 +51,6 @@ class CMIDriver : public CMICmnBase, public CMIDriverMgr::IDriver, public CMIDriverBase, - public CMICmnStreamStdin::IStreamStdin, public MI::ISingleton { friend class MI::ISingleton; @@ -101,7 +100,6 @@ bool WriteMessageToLog(const CMIUtilString &vMessage); bool SetEnableFallThru(const bool vbYes); bool GetEnableFallThru(void) const; - bool InjectMICommand(const CMIUtilString &vMICmd); bool HaveExecutableFileNamePathOnCmdLine(void) const; const CMIUtilString &GetExecutableFileNamePathOnCmdLine(void) const; @@ -128,8 +126,7 @@ virtual FILE *GetStderr(void) const; virtual const CMIUtilString &GetDriverName(void) const; virtual const CMIUtilString &GetDriverId(void) const; - // From CMICmnStreamStdin - virtual bool ReadLine(const CMIUtilString &vStdInBuffer, bool &vrbYesExit); + virtual void DeliverSignal(int signal); // Typedefs: private: @@ -142,7 +139,6 @@ void operator=(const CMIDriver &); lldb::SBError ParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &vwbExiting); - bool ReadStdinLineQueue(void); bool DoAppQuit(void); bool InterpretCommand(const CMIUtilString &vTextLine); bool InterpretCommandThisDriver(const CMIUtilString &vTextLine, bool &vwbCmdYesValid); @@ -152,7 +148,6 @@ bool StopWorkerThreads(void); bool InitClientIDEToMIDriver(void) const; bool InitClientIDEEclipse(void) const; - bool QueueMICommand(const CMIUtilString &vMICmd); bool LocalDebugSessionStartupInjectCommands(void); // Overridden: @@ -168,7 +163,6 @@ // bool m_bFallThruToOtherDriverEnabled; // True = yes fall through, false = do not pass on command CMIUtilThreadMutex m_threadMutex; - QueueStdinLine_t m_queueStdinLine; // Producer = stdin monitor, consumer = *this driver bool m_bDriverIsExiting; // True = yes, driver told to quit, false = continue working void *m_handleMainThread; // *this driver is run by the main thread CMICmnStreamStdin &m_rStdin; Index: tools/lldb-mi/MIDriver.cpp =================================================================== --- tools/lldb-mi/MIDriver.cpp +++ tools/lldb-mi/MIDriver.cpp @@ -500,42 +500,6 @@ } //++ ------------------------------------------------------------------------------------ -// Details: Callback function for monitoring stream stdin object. Part of the visitor -// pattern. -// This function is called by the CMICmnStreamStdin::CThreadStdin -// "stdin monitor" thread (ID). -// Type: Overridden. -// Args: vStdInBuffer - (R) Copy of the current stdin line data. -// vrbYesExit - (RW) True = yes exit stdin monitoring, false = continue monitor. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -CMIDriver::ReadLine(const CMIUtilString &vStdInBuffer, bool &vrwbYesExit) -{ - // For debugging. Update prompt show stdin is working - // printf( "%s\n", vStdInBuffer.c_str() ); - // fflush( stdout ); - - // Special case look for the quit command here so stop monitoring stdin stream - // So we do not go back to fgetc() and wait and hang thread on exit - if (vStdInBuffer == "quit") - vrwbYesExit = true; - - // 1. Put new line in the queue container by stdin monitor thread - // 2. Then *this driver calls ReadStdinLineQueue() when ready to read the queue in its - // own thread - const bool bOk = QueueMICommand(vStdInBuffer); - - // Check to see if the *this driver is shutting down (exit application) - if (!vrwbYesExit) - vrwbYesExit = m_bDriverIsExiting; - - return bOk; -} - -//++ ------------------------------------------------------------------------------------ // Details: Start worker threads for the driver. // Type: Method. // Args: None. @@ -551,16 +515,6 @@ // Grab the thread manager CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance(); - // Start the stdin thread - bOk &= m_rStdin.SetVisitor(*this); - if (bOk && !rThreadMgr.ThreadStart(m_rStdin)) - { - const CMIUtilString errMsg = CMIUtilString::Format(MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE), - CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str()); - SetErrorDescriptionn(errMsg); - return MIstatus::failure; - } - // Start the event polling thread if (bOk && !rThreadMgr.ThreadStart(m_rLldbDebugger)) { @@ -627,11 +581,31 @@ // While the app is active while (!m_bExitApp) { - // Poll stdin queue and dispatch - if (!ReadStdinLineQueue()) + CMIUtilString errorText; + const MIchar *pCmd = m_rStdin.ReadLine (errorText); + if (pCmd != nullptr) { - // Something went wrong - break; + CMIUtilString lineText(pCmd); + if (!lineText.empty ()) + { + if (lineText == "quit") + { + // We want to be exiting when receiving a quit command + m_bExitApp = true; + break; + } + + bool bOk = false; + { + // Lock Mutex before processing commands so that we don't disturb an event + // being processed + CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex()); + bOk = InterpretCommand(lineText); + } + // Draw prompt if desired + if (bOk && m_rStdin.GetEnablePrompt()) + m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); + } } } @@ -648,72 +622,6 @@ } //++ ------------------------------------------------------------------------------------ -// Details: *this driver sits and waits for input to the stdin line queue shared by *this -// driver and the stdin monitor thread, it queues, *this reads, interprets and -// reacts. -// This function is used by the application's main thread. -// Type: Method. -// Args: None. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -CMIDriver::ReadStdinLineQueue(void) -{ - // True when queue contains input - bool bHaveInput = false; - - // Stores the current input line - CMIUtilString lineText; - { - // Lock while we access the queue - CMIUtilThreadLock lock(m_threadMutex); - if (!m_queueStdinLine.empty()) - { - lineText = m_queueStdinLine.front(); - m_queueStdinLine.pop(); - bHaveInput = !lineText.empty(); - } - } - - // Process while we have input - if (bHaveInput) - { - if (lineText == "quit") - { - // We want to be exiting when receiving a quit command - m_bExitApp = true; - return MIstatus::success; - } - - // Process the command - bool bOk = false; - { - // Lock Mutex before processing commands so that we don't disturb an event - // that is being processed. - CMIUtilThreadLock lock(CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex()); - bOk = InterpretCommand(lineText); - } - - // Draw prompt if desired - if (bOk && m_rStdin.GetEnablePrompt()) - m_rStdOut.WriteMIResponse(m_rStdin.GetPrompt()); - - // Input has been processed - bHaveInput = false; - } - else - { - // Give resources back to the OS - const std::chrono::milliseconds time(1); - std::this_thread::sleep_for(time); - } - - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ // Details: Set things in motion, set state etc that brings *this driver (and the // application) to a tidy shutdown. // This function is used by the application's main thread. @@ -926,42 +834,6 @@ } //++ ------------------------------------------------------------------------------------ -// Details: Inject a command into the command processing system to be interpreted as a -// command read from stdin. The text representing the command is also written -// out to stdout as the command did not come from via stdin. -// Type: Method. -// Args: vMICmd - (R) Text data representing a possible command. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -CMIDriver::InjectMICommand(const CMIUtilString &vMICmd) -{ - const bool bOk = m_rStdOut.WriteMIResponse(vMICmd); - - return bOk && QueueMICommand(vMICmd); -} - -//++ ------------------------------------------------------------------------------------ -// Details: Add a new command candidate to the command queue to be processed by the -// command system. -// Type: Method. -// Args: vMICmd - (R) Text data representing a possible command. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -CMIDriver::QueueMICommand(const CMIUtilString &vMICmd) -{ - CMIUtilThreadLock lock(m_threadMutex); - m_queueStdinLine.push(vMICmd); - - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ // Details: Interpret the text data and match against current commands to see if there // is a match. If a match then the command is issued and actioned on. The // text data if not understood by *this driver is past on to the Fall Thru @@ -1093,7 +965,7 @@ // but halt the inferior program being debugged instead if (m_eCurrentDriverState == eDriverState_RunningDebugging) { - InjectMICommand("-exec-interrupt"); + InterpretCommand("-exec-interrupt"); return; } @@ -1302,9 +1174,9 @@ bool CMIDriver::LocalDebugSessionStartupInjectCommands(void) { - const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols %s", m_strCmdLineArgExecuteableFileNamePath.c_str())); + const CMIUtilString strCmd(CMIUtilString::Format("-file-exec-and-symbols \"%s\"", m_strCmdLineArgExecuteableFileNamePath.c_str())); - return InjectMICommand(strCmd); + return InterpretCommand(strCmd); } //++ ------------------------------------------------------------------------------------ @@ -1335,3 +1207,18 @@ { return m_bDriverDebuggingArgExecutable; } + +//++ ------------------------------------------------------------------------------------ +// Details: Gets called when lldb-mi gets a signal. Stops the process if it was SIGINT. +// +// Type: Method. +// Args: signal that was delivered +// Return: None. +// Throws: None. +//-- +void +CMIDriver::DeliverSignal(int signal) +{ + if (signal == SIGINT && (m_eCurrentDriverState == eDriverState_RunningDebugging)) + InterpretCommand("-exec-interrupt"); +} Index: tools/lldb-mi/MIDriverMain.cpp =================================================================== --- tools/lldb-mi/MIDriverMain.cpp +++ tools/lldb-mi/MIDriverMain.cpp @@ -132,9 +132,8 @@ CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGINT", vSigno)); - // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM - // Signal MI to shutdown or halt a running debug session - CMICmnStreamStdin::Instance().SetCtrlCHit(); + // Send signal to driver so that it can take suitable action + rDriverMgr.DeliverSignal (vSigno); } // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent @@ -165,8 +164,8 @@ CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGTSTP", vSigno)); - // Signal MI to shutdown - CMICmnStreamStdin::Instance().SetCtrlCHit(); + // Send signal to driver so that it can take suitable action + rDriverMgr.DeliverSignal (vSigno); } // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent @@ -196,8 +195,8 @@ CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGCONT", vSigno)); - // Signal MI to shutdown - CMICmnStreamStdin::Instance().SetCtrlCHit(); + // Send signal to driver so that it can take suitable action + rDriverMgr.DeliverSignal (vSigno); } //++ ------------------------------------------------------------------------------------ Index: tools/lldb-mi/MIDriverMgr.h =================================================================== --- tools/lldb-mi/MIDriverMgr.h +++ tools/lldb-mi/MIDriverMgr.h @@ -79,6 +79,7 @@ virtual bool GetDriverIsGDBMICompatibleDriver(void) const = 0; virtual bool SetId(const CMIUtilString &vId) = 0; virtual const CMIUtilString &GetId(void) const = 0; + virtual void DeliverSignal(int signal) = 0; // Not part of the interface, ignore /* dtor */ virtual ~IDriver(void) {} @@ -106,6 +107,7 @@ CMIUtilString DriverGetError(void) const; CMIUtilString DriverGetName(void) const; lldb::SBDebugger *DriverGetTheDebugger(void); + void DeliverSignal(int signal); // Typedef: private: Index: tools/lldb-mi/MIDriverMgr.cpp =================================================================== --- tools/lldb-mi/MIDriverMgr.cpp +++ tools/lldb-mi/MIDriverMgr.cpp @@ -778,3 +778,19 @@ return pDriver; } + + +//++ ------------------------------------------------------------------------------------ +// Details: Gets called when lldb-mi gets a signal. Passed signal to current driver. +// +// Type: Method. +// Args: signal that was delivered +// Return: None. +// Throws: None. +//-- +void +CMIDriverMgr::DeliverSignal(int signal) +{ + if (m_pDriverCurrent != nullptr) + m_pDriverCurrent->DeliverSignal(signal); +}