This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: MI non-stop mode spec


Thanks Vladimir,
My comments below.


Vladimir Prus wrote:
Pawel Piech wrote:

Hi Vladimir,
Thank you very much for the reply and for considering my input.  Below
are my replies:

Vladimir Prus wrote:
On Friday 21 March 2008 21:12:34 Pawel Piech wrote:
Hi Vladimir,
Thank you for putting together this proposal for extending the MI
protocol to allow non-stop debugging.  In general I think the changes
you are proposing are positive I just have two criticisms when looking
at this proposal from the client's point of view.  BTW, I work with Marc
on the Eclipse DSF-GDB integration.  One disclaimer I should make is
that I'm not familiar with any of the GDB internals so I don't know what
is easier/more difficult.  I'm only speaking from a client's point of view.

1) Changing the protocol to be (partially) stateless by adding -thread
and -global options to multitude of commands is not backwards compatible.
Note that --global option is not longer proposed.
I saw this in the prior discussions, although I didn't see what was the
the proposed replacement. For a UI, it is still very useful to be able
to resume or suspend all threads with a single command.

This is supposed to be done by -exec-continue or -exec-interrupt without --thread option.

 From the clients point of view, keeping the protocol backward
compatible is a great benefit.  I'm not a big fan of -thread-select, but
it's there and trying to remove it now I think will cause more problems
than it solves.

You mentioned that when switching to non-stop mode there is an inherent
race condition in using -thread-select because GDB may switch current
threads due to an async stopped event. A less jarring change to the
protocol than adding -thread/-global to all the commands would be to
change the behavior of *stopped not to switch the current thread. To
remain backward compatible with older GDB versions, i.e. to work with
old *stopped event behavior, MI clients can make the assumption that
after a stopped event the current thread is not known and send a
-thread-select before sending new commands. One objection to this
change may be that it's not forward compatible and older clients will
not work with the new MI protocol version, but I think older clients
will not work with GDB in non-stop mode anyhow with the protocol changes
that you propose, so that point should make no difference in your decision.
So, we have establishes that current GDB behaviour just is not suitable
for non-stop mode. It can be changed in two ways:

- Making GDB never change the current thread on its own
- Adding --thread option

<snip>
My conclusion is that the effect on compatibility and the implementation
effort on the frontend side are basically the same, so we can judge the
alternatives based on how good they are from the protocol standpoint.

I have to disagree with you on this point. There is different impact on
compatibility for the client between these two options. The first
change in protocol would allow the client to more easily remain backward
compatible with old versions of GDB as I described above. Adding the
-thread option would force clients to query the GDB version explicitly
and in order to know to use different a format of commands that now
require the -thread parameter. Just as you worry that the new version
of GDB should work with older clients. Clients worry that they won't
work with old versions of GDB. So if you would like quicker adoption of
this new non-stop debugging feature by clients, I urge you not to
introduce the -thread parameter.

I'm afraid I still don't see where the complexity lieth. There's exactly one command that a frontend has to emit at startup in order to query
gdb functionality. Then, it's just a matter of single "if" statement
to send --thread.


Definitely, this can be done in KDevelop fairly easily. BTW, this is
not different from other new MI features. For example, I've recently
added support for pending breakpoints via MI -- which is the -f option
to -break-insert. KDevelop was also modified to query for presence of
this features, and use -break-insert -f if available, and fallback to
emulation otherwise. This works fine, and not particularly complex.


Perhaps complexity is in the eye of the beholder :-) In DSF-GDB, the implementation is divided into services along the lines of the functionality such as run control, stack, variables, breakpoints, etc. Depending on GDB version or variant, different services or extensions to those services can be put together to support a given debugger back end. BTW, the goal of DSF-GDB is not just to support GDB, it's to create a set of components that can be re-used to integrate with Eclipse any debugger that uses the MI protocol.


If a new feature is added to a particular command, such as the deferred breakpoints, that single service can be replaced, updated, or extended as needed. While adding an option across all commands forces changes in all services. There is a command factory mechanism in CDI-GDB to abstract some protocol changes which deals with small changes to individual commands based on the protocol version, which DSF-GDB is probably going to have to adopt as well. But this mechanism wouldn't be necessary if the evolution in the protocol was more concerned with backward compatibility, especially in a case like this where the protocol change is not really necessary.

I'm not going to argue this point any further though. It seems that you've made up your mind on this point and I stated my case clearly enough. I'm not a GDB committer so it's up to you to make a decision.

I think I still prefer --thread, as it allows the frontend to eventually
get rid of all the change-thread-do-operation-restore-thread logic.

Getting rid of -thread-select is not going to make the MI protocol
stateless, as there is still a current stack frame.

Note that when using variable objects, which is the recommended way to get at variables and registers, you can already request specific frame.


So the state handling logic would have to remain... at least in the Eclipse
implementation. Besides, every client that works with GDB already has
this logic working and and time-tested, so besides pursuing an
ideological goal I don't think you're doing the clients any favors by
getting rid of -thread-select.

You might not want to remove that logic in a existing frontend right away, especially if you want to support older GDB for a while. But for newer frontends, and for the times when a frontend is being rearchitected, I think it will be a help.

The
other alternative is less clean -- it means that there will be actually
three "current threads". One is the current thread from the frontend POV.
Another is the current thread variable that is implicitly used by most
of gdb codebase (which necessary changes as gdb works). The last is
the "current thread" for MI commands. Having those 3 current threads
and keeping those in sync sounds nasty.
Eclipse integrations with GDB already track the first two current
threads efficiently. I would even say that the logic to track it in
DSF-GDB is rather elegant :-)

Well, have a pointer to source code? (Names of files will do, I have
DSF-GDB source here).
The current context in the UI is not MI-debugger specific. And it's implementation is rather flexible allowing for different simultaneous current contexts in current windows. The handling of this context is mostly implemented in the org.eclipse.debug.internal.ui.context package of the org.eclipse.debug.ui plugin.

The AbstractMIControl module in org.eclipse.dd.mi plugin handles tracking of the MI protocol state. It determines when to send -thread-select or -stack-frame-select based on the context contained within each command. It's simple, contained, and reliable.
I can't speak for the GDB internal "current thread", but I assumed that it was the same as the MI protocol
current thread. Maybe I didn't make myself clear, but my suggestion was
to keep the CLI current thread and MI current thread in sync, and avoid
switching the current thread in the CLI interface upon suspended event
also. This actually makes a lot of sense even when the command line
interface is used without a UI while in non-stop debug mode, because as
a user I wouldn't want an asynchronous event to switch the current
thread from under me as I'm entering a new command.

That's an interesting issue. I feel like thread switches might not be as
big issue for CLI user, but probably not switching the thread is indeed
better. It still seems like unknown amount of work. As I mention, gdb
currently has one notion of current thread, which it switches often to perform
its operations. We can introduce 'user-level current thread', and then
set gdb's current thread to user's current thread before executing any CLI
operation. However, I suspect this might break things badly, if user types new command when gdb is busy doing some run operation.

Thanks for agreeing :-) Like I said, I have no idea of the complexity of such a change. However, it seems to me that you should be able to implement a simple protcol-state-tracking logic for both CLI and MI protocols, and simply simulate the --thread option for commands that don't supply one. This way you could have both the backward compatible stateful protocol, and have the -thread option to override it on the individual commands.


I don't fully understand why disabling CLI commands is desired, but I'm
guessing it's because the CLI commands would still rely on the current
thread. If so, then keeping the MI protocol stateful would hopefully
address that concern and not force you to disable the CLI interface,
which would be unfortunate.
The reason I've proposed postponing CLI support is purely practical. Right now,
GDB explicitly decides which commands are allowed while the target is running.
In order to enable each specific command, one should:

  - decide what restrictions, if any, that command should have
  - actually try that command, and make sure GDB works fine, that is does
  not try to access frames in running threads, and so on.

This takes time.

The problem of implicit thread switch is not so bad, because user typing
commands in GDB console probably waits for result of each one before
typing next.

I guess I probably can enable the -interpreter-exec command for MI,
with the big warning that any given CLI command might not work.
I think that's a fair compromise.

OK, I have updated the spec. Does DSF-GDB actually use -interpreter-exec, as opposed to sending the raw CLI command?


Yes, both CDI and DSF integrations with GDB use the -interpreter-exec command to execute CLI commands.


2) The proposal does not address multi-process debugging in any way.  I
understand that multi-process (or multi-core) debugging is not part of
this proposal, but I think keeping that use case in mind when making
this change would make it less painful for the clients when we actually
get to that point.  In context of multi-process debugging, options such
as -global and fields such as "all" are rather ambigeous.  Instead, I
have the following suggestion:

Assign an ID to a process in the same name space as threads. Until
multi-process debugging is implemented you could just reserve a thread
id, such as "0" to be the process thread ID. For completeness this ID
would be returned already in the thread-id field of the response to
-target-select command In order to operate on a whole process context
use a -thread-select command with the process context id (followed by
the command). -thread-list-ids would list threads within that process,
normally starting with "1". In reporting stopped events, (in non-stop
debugging mode) if a thread has suspended, use the thread-id field to
indicate which thread has triggered the stop. Use a separate field:
container-id, to indicate whether the whole process stopped, assuming
that some events still cause all threads to stop.
Can we rename 'container-id' to 'process-id', as that is what it is?
I would guess is that there are more GDB extensions out there that
connect to multiple cores rather than multiple processes. But of course
it's OK to change it, it's just a name.

OK.


I actually thought that the path forward for multi-process debugging
would be to add the --process option.
I had an feeling you would say that :-) The "-process" option would
have to be added to just about every MI command, and just as -thread it
would not be a backward compatible change. I.e. more work for clients =
slower adoption.

Again, it would seem to be like making the GDB announce the present of --process, and having frontend only send it if supported should be a fairly trivial change.

In all-stop mode, the
container-id field would always be present in the stopped event. I
think that making this change would allow clients to still work with
older versions of GDB in all-stop mode, since thread 0 in all-stop mode
would act like a container thread anyway, resuming and suspending all
threads.
I'm afraid I don't understand the last sentence. Can you clarify?

I was trying to explain the mechanics of how clients could remain
backward compatible with older GDB versions with my proposed protocol
changes. It boils down to the following assumptions (for the client):
1) After a stopped event, the current selected thread is unknown.
2) If multi-container awareness is not yet implemented, container-id="0"
3) If a running/stopped event does not contain a container-id field,
then container-id="0" is implied in the event.

What is the benefit of container-id="0" if it's already implied? BTW, how does one select thread N in process M in your scheme?


In the newer version of the protocol, the container-id field in events should be explicit. If debugging multiple processes/cores, the container-id field would indicate whether the whole process/core changed state, or whether only a given thread suspended. Although, I think I got ahead of myself a little bit. In the Wind River debugger, the container-id field actually contains an array container-ids="[...]", and the same is true for threads, because there are cases where multiple, but not all threads may suspend with a given event. In order to indicate that only a thread and not a container changed state, we use the container-ids field with an empty array.


Each thread id is unique, even across multiple processes. To switch to a thread in a different process, only a thread-select is needed.

One thing that was not clear to me from your proposal is how GDB would
support all-stop targets with the new version of the protocol (such as
on chip debugging). If the answer is, by using the old protocol
version, I must I admit I'll be rather disappointed. For a clients, to
support multiple versions of a protocol indefinitely into the future is
going to be rather expensive. I would imagine the same is true for GDB...

A frontend that is capable of new MI, will use it both for all-stop and non-stop targets. A frontend that is capable of only new MI presumably won't be able to send the command that enables non-stop mode.


- Volodya
Thank you for your time. I hope we can keep this conversation going so
we can reach a conclusion that makes us all happy. We have mostly the
same goals, the only difference being whether the GDB or the clients
will have to do more work to support these new features. But I hope
that it's also in GDB's interest to make it easy for clients to adopt
this new functionality and reach a wider user base quickly.

FWIW, I'm looking at MI not only as GDB developer, but also as a frontend developer :-)

- Volodya
Thanks good, hopefully it will help you understand my concerns. Thank you for your time.
Pawel



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]