From 17a078d5bb5017a8c50c4557a63f75fb03b4e284 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Thu, 14 May 2009 16:00:52 +0200 Subject: [PATCH] debugger: work on tcf communication --- src/plugins/debugger/tcfengine.cpp | 184 ++++++++++++++++++++++------- src/plugins/debugger/tcfengine.h | 30 ++++- 2 files changed, 165 insertions(+), 49 deletions(-) diff --git a/src/plugins/debugger/tcfengine.cpp b/src/plugins/debugger/tcfengine.cpp index f3bb0468817..7cec45bb592 100644 --- a/src/plugins/debugger/tcfengine.cpp +++ b/src/plugins/debugger/tcfengine.cpp @@ -76,6 +76,8 @@ using namespace Debugger::Constants; #define CB(callback) &TcfEngine::callback, STRINGIFY(callback) +//#define USE_CONGESTION_CONTROL + /////////////////////////////////////////////////////////////////////// // // TcfData @@ -86,7 +88,19 @@ using namespace Debugger::Constants; TcfData::TcfData(const QByteArray &data) { fromString(data); - qDebug() << "TCF RESPONSE: " << data << " -> " << toString(); +} + + +/////////////////////////////////////////////////////////////////////// +// +// TcfCommand +// +/////////////////////////////////////////////////////////////////////// + + +QString TcfEngine::TcfCommand::toString() const +{ + return quoteUnprintableLatin1(command); } @@ -100,6 +114,14 @@ TcfEngine::TcfEngine(DebuggerManager *parent) { q = parent; qq = parent->engineInterface(); + + m_congestion = 0; + m_inAir = 0; + + m_sendTimer.setSingleShot(true); + m_sendTimer.setInterval(100); // ms + connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer())); + m_socket = new QTcpSocket(this); connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected())); connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); @@ -175,6 +197,9 @@ void TcfEngine::executeDebuggerCommand(const QString &command) void TcfEngine::shutdown() { + m_congestion = 0; + m_inAir = 0; + m_services.clear(); exitDebugger(); } @@ -298,87 +323,104 @@ void TcfEngine::handleResponse(const QByteArray &response) //emit tcfOutputAvailable(_(" "), currentTime()); QList<QByteArray> parts = response.split('\0'); if (parts.size() < 2 || !parts.last().isEmpty()) { - qDebug() << "Wrong response packet layout" - << quoteUnprintableLatin1(response); + SDEBUG("WRONG RESPONSE PACKET LAYOUT" << parts); return; } parts.removeLast(); // always empty QByteArray tag = parts.at(0); int n = parts.size(); - if (n == 1 && tag == "N") { // unidentified command - qDebug() << "Command not recognized."; - } else if (n == 2 && tag == "N") { // flow control - int congestion = parts.at(1).toInt(); - qDebug() << "Congestion: " << congestion; + if (n == 2 && tag == "N") { // unidentified command + int token = parts.at(1).toInt(); + TcfCommand tcf = m_cookieForToken[token]; + SDEBUG("COMMAND NOT RECOGNIZED FOR TOKEN" << token << tcf.toString()); + emit tcfOutputAvailable("", QString::number(token) + "^" + + "NOT RECOQNIZED: " + quoteUnprintableLatin1(response)); + acknowledgeResult(); + } else if (n == 2 && tag == "F") { // flow control + m_congestion = parts.at(1).toInt(); + SDEBUG("CONGESTION: " << m_congestion); } else if (n == 4 && tag == "R") { // result data + acknowledgeResult(); int token = parts.at(1).toInt(); QByteArray message = parts.at(2); TcfData data(parts.at(3)); - emit tcfOutputAvailable(_("\ntcf R:"), quoteUnprintableLatin1(response)); + emit tcfOutputAvailable("", QString::number(token) + "^" + + quoteUnprintableLatin1(response) + data.toString()); TcfCommand tcf = m_cookieForToken[token]; TcfData result(data); - //qDebug() << "Good response: " << quoteUnprintableLatin1(response); + SDEBUG("GOOD RESPONSE: " << quoteUnprintableLatin1(response)); if (tcf.callback) (this->*(tcf.callback))(result, tcf.cookie); } else if (n == 3 && tag == "P") { // progress data (partial result) //int token = parts.at(1).toInt(); QByteArray data = parts.at(2); - emit tcfOutputAvailable(_("\ntcf P:"), quoteUnprintableLatin1(response)); + SDEBUG(_("\nTCF PARTIAL:") << quoteUnprintableLatin1(response)); } else if (n == 4 && tag == "E") { // an event QByteArray service = parts.at(1); QByteArray eventName = parts.at(2); TcfData data(parts.at(3)); if (eventName != "peerHeartBeat") - emit tcfOutputAvailable(_("\ntcf E:"), quoteUnprintableLatin1(response)); + SDEBUG(_("\nTCF EVENT:") << quoteUnprintableLatin1(response) + << data.toString()); if (service == "Locator" && eventName == "Hello") { m_services.clear(); - foreach (const GdbMi &service, data.children()) { - qDebug() << "Found service: " << service.data(); + foreach (const GdbMi &service, data.children()) m_services.append(service.data()); - } QTimer::singleShot(0, this, SLOT(startDebugging())); } } else { - qDebug() << "Unknown response packet" - << quoteUnprintableLatin1(response) << parts; + SDEBUG("UNKNOWN RESPONSE PACKET:" + << quoteUnprintableLatin1(response) << parts); } } void TcfEngine::startDebugging() { - //postCommand('C', CB(handleRunControlSuspend), - // "RunControl", "suspend", "\"Thread1\""); - //postCommand('C', CB(handleRunControlSuspend), - // "RunControl", "getContext", "\"P12318\""); - postCommand('C', CB(handleRunControlGetChildren), - "RunControl", "getChildren", "\"\""); + foreach (const QByteArray &service, m_services) { + postCommand(CB(handleRunControlGetChildren), + service, "getChildren", "\"\""); + } + + postCommand(CB(handleRunControlGetChildren), "Diagnostics", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Streams", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Expressions", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "SysMonitor", "getChildren"); + //postCommand(CB(handleRunControlGetChildren), "FileSystem", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Processes", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "LineNumbers", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Symbols", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "StackTrace", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Registers", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Memory", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Breakpoints", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "RunControl", "getChildren"); + postCommand(CB(handleRunControlGetChildren), "Locator", "getChildren"); - postCommand('C', CB(handleSysMonitorGetChildren), - "SysMonitor", "getChildren", "\"\""); - //postCommand('F', "0", "", ""); - //postCommand('E', "Locator", "Hello", ""); - //postCommand('C', "Locator", "sync", ""); - //postCommand("Locator", "redirect", "ID"); + //postCommand(CB(handleRunControlSuspend), + // "RunControl", "suspend", "\"Thread1\""); + //postCommand(CB(handleRunControlSuspend), + // "RunControl", "getContext", "\"P12318\""); + + //postCommand("Locator", "sync", ""); + //postCommand("Locator", "redirect", "ID"); } -void TcfEngine::postCommand(char tag, - TcfCommandCallback callback, +void TcfEngine::postCommand(TcfCommandCallback callback, const char *callbackName, const QByteArray &service, const QByteArray &cmd, const QByteArray &args) { - static int token = 50; + static int token = 20; ++token; const char delim = 0; - const char marker_eom = -1; - const char marker_eos = -2; - const char marker_null = -3; + //const char marker_eom = -1; + //const char marker_eos = -2; + //const char marker_null = -3; - QByteArray ba; - ba.append(tag); + QByteArray ba = "C"; ba.append(delim); ba.append(QByteArray::number(token)); ba.append(delim); @@ -394,28 +436,84 @@ void TcfEngine::postCommand(char tag, TcfCommand tcf; tcf.command = ba; tcf.callback = callback; + tcf.callbackName = callbackName; + tcf.token = token; m_cookieForToken[token] = tcf; - emit tcfInputAvailable("send", quoteUnprintableLatin1(ba)); - int result = m_socket->write(tcf.command); + enqueueCommand(tcf); // congestion based +} + +// Congestion control does not seem to work that way. Basically it's +// already too late when we get a flow control packet +void TcfEngine::enqueueCommand(const TcfCommand &cmd) +{ +#ifdef USE_CONGESTION_CONTROL + // congestion controled + if (m_congestion <= 0 && m_sendQueue.isEmpty()) { + //SDEBUG("DIRECT SEND" << cmd.toString()); + sendCommandNow(cmd); + } else { + SDEBUG("QUEUE " << cmd.toString()); + m_sendQueue.enqueue(cmd); + m_sendTimer.start(); + } +#else + // synchrounously + if (m_inAir == 0) + sendCommandNow(cmd); + else + m_sendQueue.enqueue(cmd); +#endif +} + +void TcfEngine::handleSendTimer() +{ + QTC_ASSERT(!m_sendQueue.isEmpty(), return); + + if (m_congestion > 0) { + // not ready... + SDEBUG("WAITING FOR CONGESTION TO GO DOWN..."); + m_sendTimer.start(); + } else { + // go! + sendCommandNow(m_sendQueue.dequeue()); + } +} + +void TcfEngine::sendCommandNow(const TcfCommand &cmd) +{ + ++m_inAir; + int result = m_socket->write(cmd.command); m_socket->flush(); - emit tcfInputAvailable("send", QString::number(result)); + emit tcfInputAvailable("send", QString::number(cmd.token) + + " " + cmd.toString() + " " + QString::number(result)); + SDEBUG("SEND " << cmd.toString() << " " << QString::number(result)); +} + +void TcfEngine::acknowledgeResult() +{ +#if !defined(USE_CONGESTION_CONTROL) + QTC_ASSERT(m_inAir == 1, /**/); + m_inAir = 0; + if (!m_sendQueue.isEmpty()) + sendCommandNow(m_sendQueue.dequeue()); +#endif } void TcfEngine::handleRunControlSuspend(const TcfData &data, const QVariant &) { - qDebug() << "HANDLE RESULT"; + SDEBUG("HANDLE RESULT"); } void TcfEngine::handleRunControlGetChildren(const TcfData &data, const QVariant &) { - qDebug() << "HANDLE RUN CONTROL GET CHILDREN" << data.toString(); + SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString()); } void TcfEngine::handleSysMonitorGetChildren(const TcfData &data, const QVariant &) { - qDebug() << "HANDLE RUN CONTROL GET CHILDREN" << data.toString(); + SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString()); } diff --git a/src/plugins/debugger/tcfengine.h b/src/plugins/debugger/tcfengine.h index d0699894272..23dda9d56b5 100644 --- a/src/plugins/debugger/tcfengine.h +++ b/src/plugins/debugger/tcfengine.h @@ -34,9 +34,11 @@ #include <QtCore/QHash> #include <QtCore/QMap> #include <QtCore/QObject> -#include <QtCore/QProcess> #include <QtCore/QPoint> +#include <QtCore/QProcess> +#include <QtCore/QQueue> #include <QtCore/QSet> +#include <QtCore/QTimer> #include <QtCore/QVariant> #include <QtNetwork/QAbstractSocket> @@ -138,28 +140,44 @@ private: struct TcfCommand { - TcfCommand() : flags(0), callback(0), callbackName(0) {} + TcfCommand() : flags(0), token(-1), callback(0), callbackName(0) {} + + QString toString() const; int flags; + int token; TcfCommandCallback callback; const char *callbackName; QByteArray command; QVariant cookie; }; - void postCommand(char tag, - TcfCommandCallback callback, + void postCommand(TcfCommandCallback callback, const char *callbackName, const QByteArray &service, - const QByteArray &cmd, const QByteArray &args); + const QByteArray &cmd, + const QByteArray &args = "\"\""); + void sendCommandNow(const TcfCommand &command); QHash<int, TcfCommand> m_cookieForToken; + QQueue<TcfCommand> m_sendQueue; + + // timer based congestion control. does not seem to work well. + void enqueueCommand(const TcfCommand &command); + Q_SLOT void handleSendTimer(); + int m_congestion; + QTimer m_sendTimer; + + // synchrounous communication + void acknowledgeResult(); + int m_inAir; + DebuggerManager *q; IDebuggerManagerAccessForEngines *qq; QTcpSocket *m_socket; QByteArray m_inbuffer; - QStringList m_services; + QList<QByteArray> m_services; }; } // namespace Internal -- GitLab