[gem5-dev] Change in gem5/gem5[develop]: base: handle initial communication with GDB in `attach()`

2021-08-05 Thread Jan Vrany (Gerrit) via gem5-dev
Jan Vrany has submitted this change. (  
https://gem5-review.googlesource.com/c/public/gem5/+/48182 )


Change subject: base: handle initial communication with GDB in `attach()`
..

base: handle initial communication with GDB in `attach()`

When remote GDB attaches to gem5, handle the initial communication
(`qSupported` and alike) right away instead of scheduling a `DataEvent`
and firing the simulation loop in hope that GDB will be quick enough to
send initial packets before instructions are dispatched.

This requires attach() to be always called at instruction boundary
to make it safe to interact with the rest of gem5.

When `--wait-gdb` is used, connect() is called from workflow startup,
therefore on an instruction boundary and therefore needs not special
handling.

To handle case the GDB connects while simulation is already running,
we arrange (new) assynchronous IncommingConnectionEvent on listening
socket that, when there's a new connection being made, *only* schedules
*synchronous* ConnectEvent that handles the rest, *including* calling
an accept() on listening socket. This way it is safe to process commands
in attach().

In order to make the code more systematic and easier to understands,
detach() is also made to be called only synchronously (that is, at
intruction boundary). Asynchronous events and event handlers are
prefixed with "incoming".

This seems to fix the race described in 44612 [1]

[1]: https://gem5-review.googlesource.com/c/public/gem5/+/44612

Change-Id: I33b2922ba017205acabd51b6a8be3e6fb2d6409a
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/48182
Reviewed-by: Boris Shingarov 
Maintainer: Boris Shingarov 
Tested-by: kokoro 
---
M src/base/remote_gdb.cc
M src/base/remote_gdb.hh
2 files changed, 79 insertions(+), 33 deletions(-)

Approvals:
  Boris Shingarov: Looks good to me, approved; Looks good to me, approved
  kokoro: Regressions pass



diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
index b53cbc0..1437b75 100644
--- a/src/base/remote_gdb.cc
+++ b/src/base/remote_gdb.cc
@@ -356,14 +356,16 @@
 }

 BaseRemoteGDB::BaseRemoteGDB(System *_system, int _port) :
-connectEvent(nullptr), dataEvent(nullptr), _port(_port), fd(-1),
-sys(_system), trapEvent(this), singleStepEvent(*this)
+incomingConnectionEvent(nullptr), incomingDataEvent(nullptr),
+_port(_port), fd(-1), sys(_system),
+connectEvent(this), disconnectEvent(this), trapEvent(this),
+singleStepEvent(*this)
 {}

 BaseRemoteGDB::~BaseRemoteGDB()
 {
-delete connectEvent;
-delete dataEvent;
+delete incomingConnectionEvent;
+delete incomingDataEvent;
 }

 std::string
@@ -385,8 +387,9 @@
 _port++;
 }

-connectEvent = new ConnectEvent(this, listener.getfd(), POLLIN);
-pollQueue.schedule(connectEvent);
+incomingConnectionEvent =
+new IncomingConnectionEvent(this, listener.getfd(), POLLIN);
+pollQueue.schedule(incomingConnectionEvent);

 ccprintf(std::cerr, "%d: %s: listening for remote gdb on port %d\n",
  curTick(), name(), _port);
@@ -398,6 +401,8 @@
 panic_if(!listener.islistening(),
  "Can't accept GDB connections without any threads!");

+pollQueue.remove(incomingConnectionEvent);
+
 int sfd = listener.accept(true);

 if (sfd != -1) {
@@ -421,23 +426,48 @@
 {
 fd = f;

-dataEvent = new DataEvent(this, fd, POLLIN);
-pollQueue.schedule(dataEvent);
-
 attached = true;
 DPRINTFN("remote gdb attached\n");
+
+processCommands();
+
+if (isAttached()) {
+// At this point an initial communication with GDB is handled
+// and we're ready to continue. Here we arrange IncomingDataEvent
+// to get notified when GDB breaks in.
+//
+// However, GDB can decide to disconnect during that initial
+// communication. In that case, we cannot arrange data event  
because
+// the socket is already closed (not that it makes any sense,  
anyways).

+//
+// Hence the check above.
+incomingDataEvent = new IncomingDataEvent(this, fd, POLLIN);
+pollQueue.schedule(incomingDataEvent);
+}
 }

 void
 BaseRemoteGDB::detach()
 {
 attached = false;
-active = false;
 clearSingleStep();
 close(fd);
 fd = -1;

-pollQueue.remove(dataEvent);
+if (incomingDataEvent) {
+// incomingDataEvent gets scheduled in attach() after
+// initial communication with GDB is handled and GDB tells
+// gem5 to continue.
+//
+// GDB can disconnect before that in which case `incomingDataEvent`
+// is NULL.
+//
+// Hence the check above.
+
+pollQueue.remove(incomingDataEvent);
+incomingDataEvent = nullptr;
+}
+pollQueue.schedule(incomingConnectionEvent);
 DPRINTFN("remote gdb detached\n");
 }

@@ -498,19 +528,7 @@

 c

[gem5-dev] Change in gem5/gem5[develop]: base: handle initial communication with GDB in `attach()`

2021-07-15 Thread Jan Vrany (Gerrit) via gem5-dev
Jan Vrany has uploaded this change for review. (  
https://gem5-review.googlesource.com/c/public/gem5/+/48182 )



Change subject: base: handle initial communication with GDB in `attach()`
..

base: handle initial communication with GDB in `attach()`

When remote GDB attaches to gem5, handle the initial communication
(`qSupported` and alike) right away instead of scheduling a `DataEvent`
and firing the simulation loop in hope that GDB will be quick enough to
send initial packets before instructions are dispatched.

This seems to fix the race described in 44612 [1]

[1]: https://gem5-review.googlesource.com/c/public/gem5/+/44612

Change-Id: I33b2922ba017205acabd51b6a8be3e6fb2d6409a
---
M src/base/remote_gdb.cc
M src/base/remote_gdb.hh
2 files changed, 6 insertions(+), 18 deletions(-)



diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
index 26aff5c..a6c569e 100644
--- a/src/base/remote_gdb.cc
+++ b/src/base/remote_gdb.cc
@@ -419,18 +419,19 @@
 {
 fd = f;

-dataEvent = new DataEvent(this, fd, POLLIN);
-pollQueue.schedule(dataEvent);
-
 attached = true;
 DPRINTFN("remote gdb attached\n");
+
+processCommands();
+
+dataEvent = new DataEvent(this, fd, POLLIN);
+pollQueue.schedule(dataEvent);
 }

 void
 BaseRemoteGDB::detach()
 {
 attached = false;
-active = false;
 clearSingleStep();
 close(fd);
 fd = -1;
@@ -496,19 +497,7 @@

 clearSingleStep();

-/*
- * The first entry to this function is normally through
- * a breakpoint trap in kgdb_connect(), in which case we
- * must advance past the breakpoint because gdb will not.
- *
- * On the first entry here, we expect that gdb is not yet
- * listening to us, so just enter the interaction loop.
- * After the debugger is "active" (connected) it will be
- * waiting for a "signaled" message from us.
- */
-if (!active) {
-active = true;
-} else if (threadSwitching) {
+if (threadSwitching) {
 threadSwitching = false;
 // Tell GDB the thread switch has completed.
 send("OK");
diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh
index 6f57ae0..dbf3774 100644
--- a/src/base/remote_gdb.hh
+++ b/src/base/remote_gdb.hh
@@ -248,7 +248,6 @@
 /*
  * Simulator side debugger state.
  */
-bool active = false;
 bool attached = false;
 bool threadSwitching = false;


--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/48182
To unsubscribe, or for help writing mail filters, visit  
https://gem5-review.googlesource.com/settings


Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I33b2922ba017205acabd51b6a8be3e6fb2d6409a
Gerrit-Change-Number: 48182
Gerrit-PatchSet: 1
Gerrit-Owner: Jan Vrany 
Gerrit-MessageType: newchange
___
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s