Comments (3)
I found some time to sketch out a rough implementation of what this API might look like in the async-interrupt
branch.
While the user-facing bits of the API are pretty clean, the internal implementation is an absolute mess. Check out the code in the vCont hander in gdbstub_impl
- yikes! As expected, getting this feature in will require some breaking API changes, but that's to be expected.
One fundamental issue I encountered while working on this implementation is that I'd still want to support running gdbstub
over non-async interfaces (such as std::net::TcpStream
, or UARTs), while avoiding adding a whole new AsyncConnection
trait. The current implementation in the async-interrupt
does fulfill this design requirement through the use of (you guessed it) some Connection
IDETs, but this has the side-effect of requiring some very gnarly code in the vCont handler. As for code bloat - the size of the no_std
example went up by 300 bytes, which isn't too bad given the extent of the changes.
Long story short - while I'm not ready to merge any code to master just yet, I do have a fairly concrete idea of how to implement this API, and hope to find some more time and energy to work on it at some point down the line.
from gdbstub.
I just merged a new top-level state-machine based API to gdbstub
into the dev/0.6
branch. While the state-machine API was initially conceived as a way to enable using gdbstub
at the bare-metal (see #56), it ended up inadvertently solving a lot of lingering API design questions I've had in the back of my mind for a while now - including the one!
To quote the new GdbStub::run
docs:
Using the more advanced
GdbStubStateMachine
API (alongside deferred
stop reasons) makes it possible to lift the responsibility of checking
for GDB Ctrl-C interrupts out of the target'sresume
implementation
(i.e: polling the callback function), and into the top-levelgdbstub
event loop.A key consequence of lifting this responsibility up the call-stack is
that thegdbstub
event loop knows the concreteConnection
type
being used, enabling implementations to leverage whatever
transport-specific efficient waiting mechanism it exposes. Compare this
with polling for interrupts in the target'sresume
implementation,
where the method doesn't have access to the the concreteConnection
type being used.
As such, once release 0.6
is published to crates.io, I'll be closing this issue.
from gdbstub.
Yeah, this is something I've been thinking about as well.
More generally, this would fall under the Roadmap item "Exposing an async/await interface", which isn't necessarily select()
or poll()
specific (as those aren't available on all platforms / on no_std
). I'll go ahead and change the issue title accordingly.
I haven't put too much thought into the implementation, but one simple approach might be to simply plumb-through the underlying Connection
object via the check_gdb_interrupt
type. e.g: if the Connection
is a TcpStream
, then check_gdb_interrupt
could be modified to have a .as_conn(&mut) -> &mut C
method. This would allow you to use whatever non-blocking wait mechanism the transport provides, including select()/poll()
, and then call the .check()
method once new data is available.
The tricky thing is how exactly that C
type parameter should be plumbed-through into the Target. At the moment, the Target
trait it completely independent of the Connection
trait, which is important, as it allows a Target to work transparently with any connection. Adding an .as_conn
method would have the domino-effect of requiring Target implementations to be connection-specific, which isn't the end of the world, but it's not something I'm particularly excited about.
The approach that I'm leaning towards would be to modify the Connection
trait to implement Future<Output = u8>
, and re-write the check_gdb_interrupt
as a Future<Output = ()>
. This is nice, as it doesn't leak any Connection
specific details through the Target
.
Individual Connection
implementations could then decide how exactly they should implement the Future::poll
method. Simple implementations might just use the transport's non-blocking peek()
method to return Poll::Pending/Poll::Ready
(i.e: what the current system does). More advanced implementation could use something like select()
or poll()
to block the thread, waiting for new messages to arrive.
The annoying part with both of these approaches is that I foolishly leaked the implementation details of check_gdb_interrupt
into the Target
interface by explicitly specifying that it's a &mut dyn FnMut() -> bool
. I should have used an opaque wrapper type instead (e.g: CheckGdbInterrupt(&mut dyn FnMut() -> bool)
with a .check()
method), similar to what I ded in fec620c. Because of this, adding any sort of non-blocking check will require making a breaking API change, which isn't the end of the world, but nonetheless quite unfortunate. Ah well...
I'm not entirely sure when I'll have time to play around with these changes, but hopefully I've given you some idea of how you might tackle the problem.
The first approach is pretty quick-and-dirty, but if you're just looking to get something up and running locally, it might be the way to go. Alternatively, if you've got some time to spare and are willing to keep working on gdbstub
, I'd love it if you could take a shot at implementing the second approach!
from gdbstub.
Related Issues (20)
- Allow `read_addrs()` to send fewer bytes than requested HOT 2
- Improved Error Type (more specificity, fewer semver hazards, etc...) HOT 1
- Clippy warnings in library code HOT 3
- Allow passing a custom initial stop reason
- [mips] "unexpected packet" packet on single step HOT 10
- Not getting any events when breakpoint is set HOT 1
- All registers are byteswapped when using lldb HOT 14
- Switch `enum Signal` to `struct Signal(pub u8)` with associated constants
- NoActiveThreads error when there are no active thread HOT 9
- Misleading comment in `state_machine`? HOT 2
- Multiprocess debugging HOT 8
- [riscv32] `PacketUnexpected` when issuing `stepi` HOT 3
- vAttach: invalid response causes command to not work HOT 6
- Remove `NoActiveThread` Error
- example_no_std doesn't build on Windows HOT 1
- Remove `SingleStepBehavior` guard rail HOT 1
- Make `QStartNoAckMode` optional HOT 1
- Options for flow control? HOT 3
- Support "ack/nack" packets for unreliable transports HOT 6
- Fails to compile for atmega328p (Arduino Uno) HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gdbstub.