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]

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.


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