This is the mail archive of the
gdb@sourceware.org
mailing list for the GDB project.
MI non-stop mode spec
- From: Vladimir Prus <vladimir at codesourcery dot com>
- To: gdb at sources dot redhat dot com
- Date: Wed, 19 Mar 2008 00:16:01 +0300
- Subject: MI non-stop mode spec
Making good used of GDB in async mode, and especially in async non-stop
mode demands some changes in MI -- both general clarifications, and actual
work to allow most MI commands while the target is running and define
their behaviour.
I propose the changes as below. Please view this document as spec
of how MI should ideally operate. In the cases where MI currently
operates differently, there may be various transition plans, including
deciding that current frontends won't be affected by change anyway,
allowing earlier behaviour with a big warning in MI docs, or bumping
MI version and implementing new behaviour only for MI3. This spec does
not deal with such compatibility issues -- only with ideal MI
behaviour.
MI command details
==================
Legend:
(*) Changes from current MI behaviour.
(**) Changes from original non-stop mode proposal in
http://sourceware.org/ml/gdb/2007-11/msg00198.html
-> Todo items
General clarifications
----------------------
When operating in MI mode, gdb prints a prompt if and only if it is ready to
immediately read and process the next command. Of course, a frontend can
send a command without waiting for the prompt, and it will be eventually
processed. However, if gdb has not printed a prompt after the previous
command yet, it means that it might take a lot time until the next command
will be executed. The frontend may use the lack of prompt to disable
some commands, or to show "waiting for previous command to finish"
indicator.
(*) Current MI syntax says that any result record must be followed by a
prompt. For sync targets, this is wrong -- when gdb prints ^running
and resumes the target, it does not check for input, so (gdb) is misleading.
When the target stops, the *stopped message, followed by the prompt is
printed -- and it's at this point that gdb starts to accept the input
again. So, I propose to remove the prompt right after ^running for the
sync targets.
Each MI command results in either ^done, ^error, ^connected or ^running
response. The ^connected response is basically identical to ^done,
and the naming is different for historic reasons. All of those
except for ^running are immediately followed by prompt. The ^running
response means that the target has started running. Further events
from the target will be reported using async notifications.
The async notifications are for various interesting events that cannot
generally be reported as result of a command. For example,
=thread-created
is emitted whenever a new thread appears, and *stopped is emitted whenever
target stops for any reason (generally, a stop in the target is not
100% related to the execution command we were last doing, for example
-exec-next can cause a breakpoint to be hit in unrelated thread).
Because async notifications are not related to any given command,
they don't, generally speaking, include the token of any previous
MI command.
(*) Currently, the *stopped output does include the token of
the last command. However, it's implemented in limited way --
if we allow any command except for -exec-interrupt in async
mode, the token printed for *stopped will be wrong. In non-stop
mode, associating *stopped with a command is just impossible.
Presently, MI spec says a command can output ^running just once.
However, it the presense of breakpoint commands, it's quite possible
that we resume one thread, hit a breakpoint, and breakpoint commands
resume all threads, or some other thread.
To handle this case we need a new async output for this case:
*running,thread-id="xxx"
which is emitted whenever a previously stopped thread is resumed.
In case all threads are resumed, "xxx" will be "all".
Async/non-stop mode notes
-------------------------
The async mode basically means that gdb can process commands even while
the target is running. This mode is enabled whenever the target is
async-capable.
In async mode, there are two further distinctions:
- Should we allow an exec command while some other exec command
is already in progress?
- Should we stop all threads whenever an event is detected in one thread?
Those issues seem independent initially, so we might try to allow
two -exec-next at one time, and then stop all threads when any -exec-next
is finished. However, that will require user to explicitly resume the
-exec-next that is not yet finished, which does not seem very helpful --
it's not much better than sending two -exec-next sequentally.
Therefore, for now we shall have only two modes:
- "all-stop", when all threads are stopped if any thread stops,
and when only one exec command is allowed to be active at any given time,
- "non-stop", where individual threads are stopped, and several
exec commands can be active.
Except for what is said above "all-stop" and "non-stop" async modes are
identical.
Generally, most MI commands are allowed while a target is running, with the
following exceptions:
- An execution command that logically applies to a single thread
cannot be used if the thread is already running. Global -exec-continue is
OK, and will resume all threads that are not presently running. In all-stop
mode an execution command cannot be started if any thread is running.
- Many commands in current MI operate on current thread. In non-stop
mode, this creates a potential for race condition -- between the
frontend sending a command to gdb and gdb reading that command,
gdb can detect a breakpoint and change the current thread. Furthermore, in
case when a frontend sends a series of commands and gdb detects a thread
stop in between, it's plain impossible to figure if the second command
should be executed in the originally current thread, or in the thread
were stop was detected. For that reason, in non-stop mode all MI commands
that require a thread will require the frontend to specify the thread
explicitly.
Note: stateless protocol will not only be more robust in
non-stop mode, but actually simplify frontends. Say, in CDT
there are several places were we switch a thread, do some operation,
and then switch back to the original thread. Say,
Thread.getStackFrameCount or Target.evaluateExpressionToString.
- Some data access commands are also implicitly using a specific thread --
because they are using registers, or variables in specific thread/frame,
or because they have to call a function in the inferior. Such data access
commands are not allowed when the necessary thread is running. Wholesale
update operations like -var-update will plain ignore variable objects
that need now-running threads.
- The commands that grab global state of the target are allowed when
some threads are running. It should be understood that the result may
be inaccurate -- in particular, the memory content can change while
we read it, and the list of threads might not be updated until some
event from the target arrives. In addition, some targets might not
even allow reading memory while all threads are running -- so memory
access commands on such targets will require that at least one thread
is stopped.
To simplify things, if GDB is started in MI mode, no CLI command is allowed
while the target is running, and -interpreter-exec is not allowed either.
Note: in cases when to implement a command, GDB requires that at least
one (or all) threads are stopped, and the command is issued when this
condition is not met, we have two choices -- issue an error, or briefly
stop the target, perform the operation, and resume. Clearly, doing
that in GDB (or even in the target) will be less intrusive then doing
that in frontend. However, it might be still too intrusive. For now,
we'll just emit error, should a real need arise, we can always implement
automatic interruption of the target.
MI commands changes
-------------------
(**) There are two new options that a number of MI commands may take:
--thread <id>
option specifies the id of the thread the command should operate on.
--global
specifies that the command should operate on no thread, but on
global data. This option is necessary to distinguish the case where
the frontend has forgot to specify --thread, assuming that the current
thread will be used, from the case when frontend explicitly wants
to execute a command in global scope. This clarify of intention
is particularly important when the "current thread" is running.
- Break commands. All breakpoints commands are allowed at any time
and the changes are applied to the program immediately.
The output of -break-list and -break-info in general should be considered
invalid as soon as a stop in any thread is reported. The break commands
generally don't care about current thread and frame.
If -break-insert command specifies only line number, then it implicitly
depends on the filename of the current thread/frame. In non-stop mode,
the frontend is required to specify thread and frame explicitly.
- Program context commands. Those are not allowed after the program
has started execution.
- Thread commands. The -thread-info command should be implemented (a
patch is already posted).
(**) The -thread-list-all-threads is not necessary with the current
behaviour of -thread-info.
(**) The -thread-select command is only allowed on the that that is
currently stopped. This command should not generally be used in
non-stop mode.
- Program execution. The -exec-next, -exec-step, -exec-finish,
-exec-until, -exec-return, -exec-step-instruction and
-exec-next-instruction command require --thread parameter. Also,
those commands resume strictly the thread that is being stepped,
equivalent to "scheduler-locking on".
The -exec-continue command with the --thread parameter will resume
just one thread, whereas -exec-continue without a --thread parameter
will resume all threads that are not presently running.
- Stack commands. All are allowed. All require a thread parameter in
non-stop mode.
- Variable objects. The -var-create command requires either the
--thread or --global option. If --thread is specified, then the
referred thread must be stopped. With --global,
varobj's expression is evaluated in the global scope.
If a variable object makes use of any local variable, the object
becomes bound to the
thread where it was created. An attempt to manipulate an
individual variable obect when the thread it is bound to is not
stopped results in an error. As a special exception, -var-update will
ignore any variable object whose bound thread is not stopped.
A variable object's expression might involve a function call. If a
variable object is not bound to any thread, the function call will be
executed in any currently stopped thread.
Note: this does allow creating a global varobj while all threads
are running. If the target does not allow accessing memory when
all threads are running, such a varobj will only get any value
at a later time.
-> Should @ varobjs be bound to only thread, or to nothing at all.
- Data manipulation. All commands are supported, except for
data-list-changed-registers, which is presently thread-unaware and seems
inferior to using variable objects anyway.
The -data-evaluate-expression and -data-list-register-values requires
that either the --thread or the --global option be provided.
- Symbol query commands. All are supported.
- File commands. The -file-exec-and-symbols and -file-exec-file cannot
be used when any thread is running. The -file-list-shared-libraries
can be used while inferior is running, but the results might be
invalidated immediately. Same for -file-list-symbol-files. Others
can be used without limitations.
On some targets it might not be possible to get the list of shared
libraries from the target while it is running. In such cases, GDB will
report an error.
- Target manipulation. The -target-disconnect can be used while threads
are running. Other (currently implemented) commands can only
be used before we have an executable.
- File transfer. Can be always used.
- Misc. Case-by-case, nothing interesting.