This is the mail archive of the gdb-patches@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: Multiexec MI


On Monday 08 February 2010 22:28:52 you wrote:

> BTW,
> 
> >qr
> Warning: trailing whitespace in lines 21731,22187,22232,26738 of gdb/doc/gdb.texinfo
> Warning: trailing whitespace in lines 217,218,244,246,261,390,404,439,603,1623,1630,1633,1652 of gdb/mi/mi-main.c
> Warning: trailing whitespace in line 751 of gdb/inferior.c
> Warning: trailing whitespace in lines 304,323,333,344,355,365,533,534,535,538,539,540,553,554,555,558,559,560,575 of gdb/mi/mi-interp.c
> Refreshed patch multiexec-mi.diff

Oh, almost forgot about this one. I've installed some pile of
shell magic that is supposed to automatically remove trailing whitespace in
modified lines after 'git commit', and it seems to work. Here's the
result.


Thanks,

-- 
Vladimir Prus
CodeSourcery
vladimir@codesourcery.com
(650) 331-3385 x722
commit 1dfcc1e4f43a726104311cbfc397becb4ad892fd
Author: Vladimir Prus <vladimir@codesourcery.com>
Date:   Fri Feb 19 23:12:28 2010 +0300

    	Multiexec MI
    
            gdb/
            * breakpoint.c (clear_syscall_counts): Take struct inferior*.
    
            gdb/doc/
            * gdb.texinfo (GDB/MI Command Syntax): Document notification
            changes.
            (GDB/MI Program Execution): Document current behaviour of
            --all and --thread-group.
            (GDB/MI Miscellaneous Commands): Document -add-inferior and
            -remove-inferior.
            * observer.texi (inferior_added, inferior_removed): New
            observers.
    
            * inferior.c (add_inferior_silent): Notify inferior_added
            observer.
            (delete_inferior_1): Notify inferior_removed observer.
            (exit_inferior_1): Pass inferior, not pid, to observer.
            (inferior_appeared): Likewise.
            (add_inferior_with_spaces): New.
            (add_inferior_command): Use the above.
            * inferior.h (delete_inferior_1, add_inferior_with_spaces):
            Declare.
    
            * inflow.c (inflow_inferior_exit): Likewise.
            * jit.c (jit_inferior_exit_hook): Likewise.
    
            * mi/mi-cmds.c (mi_cmds): Register add-inferior and
            remove-inferior.
            * mi/mi-cmds.h (mi_cmd_add_inferior, mi_cmd_remove_inferior): New.
            * mi/mi-interp.c (mi_inferior_added, mi_inferior_removed): New.
            (report_initial_inferior): New.
            (mi_inferior_removed): Register the above. Make sure
            inferior_added observer is called on the first inferior.
            (mi_new_thread, mi_thread_exit): Thread group is now identified by
            inferior number, not pid.
            (mi_solib_loaded, mi_solib_unloaded): Report which inferiors are
            affected.
            * mi/mi-main.c (current_context): New.
            (proceed_thread_callback): Use typed closure.
            Proceed everything if pid is 0. Most implementation split into
    	(proceed_thread): ... this.
            (run_one_inferior): New.
            (mi_cmd_exec_continue, mi_cmd_exec_interrupt, mi_cmd_exec_run):
            Adjust for multiexec behaviour.
            (mi_cmd_add_inferior, mi_cmd_remove_inferior): New.
            (mi_cmd_execute): Handle the 'thread-group' option here.
            Do some extra checks.
            * mi-parse.c (mi_parse): Handle the --all and --thread-group
            options.
            * mi-parse.h (struct mi_parse): New fields all and thread_group.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8c97949..45ee622 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -10240,10 +10240,8 @@ add_catch_command (char *name, char *docstring,
 }
 
 static void
-clear_syscall_counts (int pid)
+clear_syscall_counts (struct inferior *inf)
 {
-  struct inferior *inf = find_inferior_pid (pid);
-
   inf->total_syscalls_count = 0;
   inf->any_syscall_count = 0;
   VEC_free (int, inf->syscalls_counts);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0e3e093..183918e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -21736,6 +21736,11 @@ groups can be obtained using @samp{-list-thread-groups --available}.
 In general, the content of a thread group may be only retrieved only
 after attaching to that thread group.
 
+Thread groups are related to inferiors (@pxref{Inferiors and
+Programs}).  Each inferior corresponds to a thread group of a special
+type @samp{process}, and some additional operations are permitted on
+such thread groups.
+
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Command Syntax
 @section @sc{gdb/mi} Command Syntax
@@ -22180,9 +22185,24 @@ several threads in the list.  The @var{core} field reports the
 processor core on which the stop event has happened.  This field may be absent
 if such information is not available.
 
-@item =thread-group-created,id="@var{id}"
+@item =thread-group-added,id="@var{id}"
+@itemx =thread-group-removed,id="@var{id}"
+A thread group was either added or removed.  The @var{id} field
+contains the @value{GDBN} identifier of the thread group.  When a thread
+group is added, it generally might not be associated with a running
+process.  When a thread group is removed, its id becomes invalid and
+cannot be used in any way.
+
+@item =thread-group-started,id="@var{id}",pid="@var{pid}"
+A thread group became associated with a running program,
+either because the program was just started or the thread group
+was attached to a program.  The @var{id} field contains the
+@value{GDBN} identifier of the thread group.  The @var{pid} field
+contains process identifier, specific to the operating system.
+
 @itemx =thread-group-exited,id="@var{id}"
-A thread thread group either was attached to, or has exited/detached
+A thread group is no longer associated with a running program,
+either because the program has exited, or because it was detached
 from.  The @var{id} field contains the @value{GDBN} identifier of the
 thread group.
 
@@ -22213,12 +22233,19 @@ opaque identifier of the library.  For remote debugging case,
 library file on the target, and on the host respectively.  For native
 debugging, both those fields have the same value.  The
 @var{symbols-loaded} field reports if the debug symbols for this
-library are loaded.
+library are loaded.  The @var{thread-group} field, if present,
+specifies the id of the thread group in whose context the library was loaded.
+If the field is absent, it means the library was loaded in the context
+of all present thread groups.
 
 @item =library-unloaded,...
 Reports that a library was unloaded by the program.  This notification
 has 3 fields---@var{id}, @var{target-name} and @var{host-name} with
-the same meaning as for the @code{=library-loaded} notification
+the same meaning as for the @code{=library-loaded} notification.
+The @var{thread-group} field, if present, specifies the id of the
+thread group in whose context the library was unloaded.  If the field is
+absent, it means the library was unloaded in the context of all present
+thread groups.
 
 @end table
 
@@ -23337,7 +23364,7 @@ the end or beginning of a replay log if one is being used.
 In all-stop mode (@pxref{All-Stop
 Mode}), may resume only one thread, or all threads, depending on the
 value of the @samp{scheduler-locking} variable.  If @samp{--all} is
-specified, all threads will be resumed.  The @samp{--all} option is
+specified, all threads (in all inferiors) will be resumed.  The @samp{--all} option is
 ignored in all-stop mode.  If the @samp{--thread-group} options is
 specified, then all threads in that thread group are resumed.
 
@@ -23429,9 +23456,9 @@ asynchronous just like other execution commands.  That is, first the
 reported after that using the @samp{*stopped} notification.
 
 In non-stop mode, only the context thread is interrupted by default.
-All threads will be interrupted if the @samp{--all} option is
-specified.  If the @samp{--thread-group} option is specified, all
-threads in that group will be interrupted.
+All threads (in all inferiors) will be interrupted if the
+@samp{--all}  option is specified.  If the @samp{--thread-group}
+option is specified, all threads in that group will be interrupted.
 
 @subsubheading @value{GDBN} Command
 
@@ -23608,7 +23635,7 @@ fullname="/home/foo/bar/devo/gdb/testsuite/gdb.mi/basics.c",line="18"@}
 @subsubheading Synopsis
 
 @smallexample
- -exec-run
+ -exec-run [--all | --thread-group N ]
 @end smallexample
 
 Starts execution of the inferior from the beginning.  The inferior
@@ -23616,6 +23643,11 @@ executes until either a breakpoint is encountered or the program
 exits.  In the latter case the output will include an exit code, if
 the program has exited exceptionally.
 
+When no option is specified, the current inferior is started.  If the
+@samp{--thread-group} option is specified, it should refer to a thread
+group of type @samp{process}, and that thread group will be started.
+If the @samp{--all} option is specified, then all inferiors will be started.
+
 @subsubheading @value{GDBN} Command
 
 The corresponding @value{GDBN} command is @samp{run}.
@@ -26678,6 +26710,8 @@ have the following fields:
 @table @code
 @item id
 Identifier of the thread group.  This field is always present.
+The identifier is an opaque string; frontends should not try to
+convert it to an integer, even though it might look like one.
 
 @item type
 The type of the thread group.  At present, only @samp{process} is a
@@ -26685,7 +26719,7 @@ valid type.
 
 @item pid
 The target-specific process identifier.  This field is only present
-for thread groups of type @samp{process}.
+for thread groups of type @samp{process} and only if the process exists.
 
 @item num_children
 The number of children this thread group has.  This field may be
@@ -26701,6 +26735,11 @@ This field is a list of integers, each identifying a core that one
 thread of the group is running on.  This field may be absent if
 such information is not available.
 
+@item executable
+The name of the executable file that corresponds to this thread group.
+The field is only present for thread groups of type @samp{process},
+and only if there is a corresponding executable file.
+
 @end table
 
 @subheading Example
@@ -26727,6 +26766,31 @@ such information is not available.
                         @{id="2",target-id="Thread 0xb7e14b90",cores=[2]@}]@},...]
 @end smallexample
 
+
+@subheading The @code{-add-inferior} Command
+@findex -add-inferior
+
+@subheading Synopsis
+
+@smallexample
+-add-inferior
+@end smallexample
+
+Creates a new inferior (@pxref{Inferiors and Programs}).  The created
+inferior is not associated with any executable.  Such association may
+be established with the @samp{-file-exec-and-symbols} command
+(@pxref{GDB/MI File Commands}).  The command response has a single
+field, @samp{thread-group}, whose value is the identifier of the
+thread group corresponding to the new inferior.
+
+@subheading Example
+
+@smallexample
+@value{GDBP}
+-add-inferior
+^done,thread-group="i3"
+@end smallexample
+
 @subheading The @code{-interpreter-exec} Command
 @findex -interpreter-exec
 
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index db3d114..c4cfe27 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -199,13 +199,23 @@ The thread's ptid has changed.  The @var{old_ptid} parameter specifies
 the old value, and @var{new_ptid} specifies the new value.
 @end deftypefun
 
-@deftypefun void inferior_appeared (int @var{pid})
-@value{GDBN} has attached to a new inferior identified by @var{pid}.
+@deftypefun void inferior_added (struct inferior *@var{inf})
+The inferior @var{inf} has been added to the list of inferior.  At
+this point, it might not be associated with any process.
 @end deftypefun
 
-@deftypefun void inferior_exit (int @var{pid})
-Either @value{GDBN} detached from the inferior, or the inferior
-exited.  The argument @var{pid} identifies the inferior.
+@deftypefun void inferior_appeared (struct inferior *@var{inf})
+The inferior identified by @var{inf} has been attached to a process.
+@end deftypefun
+
+@deftypefun void inferior_exit (struct inferior *@var{inf})
+Either the inferior associated with @var{inf} has been detached from the
+process, or the process has exited.
+@end deftypefun
+
+@deftypefun void inferior_removed (struct inferior *@var{inf})
+The inferior @var{inf} has been removed from the list of inferiors.
+This method is called immediate before freeing @var{inf}.
 @end deftypefun
 
 @deftypefun void memory_changed (CORE_ADDR @var{addr}, int @var{len}, const bfd_byte *@var{data})
@@ -213,8 +223,8 @@ Bytes from @var{data} to @var{data} + @var{len} have been written
 to the current inferior at @var{addr}.
 @end deftypefun
 
- @deftypefun void test_notification (int @var{somearg})
+@deftypefun void test_notification (int @var{somearg})
 This observer is used for internal testing.  Do not use.  
 See testsuite/gdb.gdb/observer.exp.
- @end deftypefun
+@end deftypefun
 
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 0667bfa..f1991c9 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -133,6 +133,8 @@ add_inferior_silent (int pid)
 
   inferior_alloc_data (inf);
 
+  observer_notify_inferior_added (inf);
+
   if (pid != 0)
     inferior_appeared (inf, pid);
 
@@ -194,7 +196,7 @@ delete_threads_of_inferior (int pid)
 /* If SILENT then be quiet -- don't announce a inferior death, or the
    exit of its threads.  */
 
-static void
+void
 delete_inferior_1 (struct inferior *todel, int silent)
 {
   struct inferior *inf, *infprev;
@@ -219,6 +221,8 @@ delete_inferior_1 (struct inferior *todel, int silent)
   else
     inferior_list = inf->next;
 
+  observer_notify_inferior_removed (inf);
+
   free_inferior (inf);
 }
 
@@ -265,7 +269,7 @@ exit_inferior_1 (struct inferior *inftoex, int silent)
 
   /* Notify the observers before removing the inferior from the list,
      so that the observers have a chance to look it up.  */
-  observer_notify_inferior_exit (inf->pid);
+  observer_notify_inferior_exit (inf);
 
   inf->pid = 0;
   if (inf->vfork_parent != NULL)
@@ -315,7 +319,7 @@ inferior_appeared (struct inferior *inf, int pid)
 {
   inf->pid = pid;
 
-  observer_notify_inferior_appeared (pid);
+  observer_notify_inferior_appeared (inf);
 }
 
 void
@@ -738,6 +742,24 @@ remove_inferior_command (char *args, int from_tty)
   delete_inferior_1 (inf, 1);
 }
 
+struct inferior *
+add_inferior_with_spaces (void)
+{
+  struct address_space *aspace;
+  struct program_space *pspace;
+  struct inferior *inf;
+
+  /* If all inferiors share an address space on this system, this
+     doesn't really return a new address space; otherwise, it
+     really does.  */
+  aspace = maybe_new_address_space ();
+  pspace = add_program_space (aspace);
+  inf = add_inferior (0);
+  inf->pspace = pspace;
+  inf->aspace = pspace->aspace;
+
+  return inf;
+}
 
 /* add-inferior [-copies N] [-exec FILENAME]  */
 
@@ -782,18 +804,7 @@ add_inferior_command (char *args, int from_tty)
 
   for (i = 0; i < copies; ++i)
     {
-      struct address_space *aspace;
-      struct program_space *pspace;
-      struct inferior *inf;
-
-      /* If all inferiors share an address space on this system, this
-	 doesn't really return a new address space; otherwise, it
-	 really does.  */
-      aspace = maybe_new_address_space ();
-      pspace = add_program_space (aspace);
-      inf = add_inferior (0);
-      inf->pspace = pspace;
-      inf->aspace = pspace->aspace;
+      struct inferior *inf = add_inferior_with_spaces ();
 
       printf_filtered (_("Added inferior %d\n"), inf->num);
 
@@ -801,7 +812,7 @@ add_inferior_command (char *args, int from_tty)
 	{
 	  /* Switch over temporarily, while reading executable and
 	     symbols.q  */
-	  set_current_program_space (pspace);
+	  set_current_program_space (inf->pspace);
 	  set_current_inferior (inf);
 	  switch_to_thread (null_ptid);
 
diff --git a/gdb/inferior.h b/gdb/inferior.h
index e557d6c..4571893 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -523,6 +523,8 @@ extern struct inferior *add_inferior_silent (int pid);
 /* Delete an existing inferior list entry, due to inferior exit.  */
 extern void delete_inferior (int pid);
 
+extern void delete_inferior_1 (struct inferior *todel, int silent);
+
 /* Same as delete_inferior, but don't print new inferior notifications
    to the CLI.  */
 extern void delete_inferior_silent (int pid);
@@ -609,4 +611,6 @@ extern void prune_inferiors (void);
 
 extern int number_of_inferiors (void);
 
+extern struct inferior *add_inferior_with_spaces (void);
+
 #endif /* !defined (INFERIOR_H) */
diff --git a/gdb/inflow.c b/gdb/inflow.c
index cef36ea..8de68e1 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -500,9 +500,8 @@ get_inflow_inferior_data (struct inferior *inf)
    list.  */
 
 static void
-inflow_inferior_exit (int pid)
+inflow_inferior_exit (struct inferior *inf)
 {
-  struct inferior *inf = find_inferior_pid (pid);
   struct terminal_info *info;
 
   info = inferior_data (inf, inflow_inferior_data);
diff --git a/gdb/jit.c b/gdb/jit.c
index 433746a..e17f0ab 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -397,7 +397,7 @@ jit_inferior_created_observer (struct target_ops *objfile, int from_tty)
    for example when it crashes.  */
 
 static void
-jit_inferior_exit_hook (int pid)
+jit_inferior_exit_hook (struct inferior *inf)
 {
   struct objfile *objf;
   struct objfile *temp;
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 729cc5f..013b2c1 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -33,6 +33,7 @@ static void build_table (struct mi_cmd *commands);
 
 struct mi_cmd mi_cmds[] =
 {
+  { "add-inferior", { NULL, 0 }, mi_cmd_add_inferior },
   { "break-after", { "ignore", 1 }, NULL },
   { "break-condition", { "cond", 1 }, NULL },
   { "break-commands", { NULL, 0 }, mi_cmd_break_commands },
@@ -84,6 +85,7 @@ struct mi_cmd mi_cmds[] =
   { "list-features", { NULL, 0 }, mi_cmd_list_features},
   { "list-target-features", { NULL, 0 }, mi_cmd_list_target_features},
   { "list-thread-groups", { NULL, 0 }, mi_cmd_list_thread_groups },  
+  { "remove-inferior", { NULL, 0 }, mi_cmd_remove_inferior },
   { "stack-info-depth", { NULL, 0 }, mi_cmd_stack_info_depth},
   { "stack-info-frame", { NULL, 0 }, mi_cmd_stack_info_frame},
   { "stack-list-arguments", { NULL, 0 }, mi_cmd_stack_list_args},
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 7e1c819..d840104 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -36,6 +36,7 @@ extern const char mi_all_values[];
 typedef void (mi_cmd_argv_ftype) (char *command, char **argv, int argc);
 
 /* Function implementing each command */
+extern mi_cmd_argv_ftype mi_cmd_add_inferior;
 extern mi_cmd_argv_ftype mi_cmd_break_insert;
 extern mi_cmd_argv_ftype mi_cmd_break_commands;
 extern mi_cmd_argv_ftype mi_cmd_break_watch;
@@ -72,6 +73,7 @@ extern mi_cmd_argv_ftype mi_cmd_interpreter_exec;
 extern mi_cmd_argv_ftype mi_cmd_list_features;
 extern mi_cmd_argv_ftype mi_cmd_list_target_features;
 extern mi_cmd_argv_ftype mi_cmd_list_thread_groups;
+extern mi_cmd_argv_ftype mi_cmd_remove_inferior;
 extern mi_cmd_argv_ftype mi_cmd_stack_info_depth;
 extern mi_cmd_argv_ftype mi_cmd_stack_info_frame;
 extern mi_cmd_argv_ftype mi_cmd_stack_list_args;
diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c
index 41388bb..af225e7 100644
--- a/gdb/mi/mi-interp.c
+++ b/gdb/mi/mi-interp.c
@@ -56,13 +56,17 @@ static void mi_on_normal_stop (struct bpstats *bs, int print_frame);
 
 static void mi_new_thread (struct thread_info *t);
 static void mi_thread_exit (struct thread_info *t, int silent);
-static void mi_inferior_appeared (int pid);
-static void mi_inferior_exit (int pid);
+static void mi_inferior_added (struct inferior *inf);
+static void mi_inferior_appeared (struct inferior *inf);
+static void mi_inferior_exit (struct inferior *inf);
+static void mi_inferior_removed (struct inferior *inf);
 static void mi_on_resume (ptid_t ptid);
 static void mi_solib_loaded (struct so_list *solib);
 static void mi_solib_unloaded (struct so_list *solib);
 static void mi_about_to_proceed (void);
 
+static int report_initial_inferior (struct inferior *inf, void *closure);
+
 static void *
 mi_interpreter_init (int top_level)
 {
@@ -86,13 +90,20 @@ mi_interpreter_init (int top_level)
     {
       observer_attach_new_thread (mi_new_thread);
       observer_attach_thread_exit (mi_thread_exit);
+      observer_attach_inferior_added (mi_inferior_added);
       observer_attach_inferior_appeared (mi_inferior_appeared);
       observer_attach_inferior_exit (mi_inferior_exit);
+      observer_attach_inferior_removed (mi_inferior_removed);
       observer_attach_normal_stop (mi_on_normal_stop);
       observer_attach_target_resumed (mi_on_resume);
       observer_attach_solib_loaded (mi_solib_loaded);
       observer_attach_solib_unloaded (mi_solib_unloaded);
       observer_attach_about_to_proceed (mi_about_to_proceed);
+
+      /* The initial inferior is created before this function is called, so we
+	 need to report it explicitly.  Use iteration in case future version
+	 of GDB creates more than one inferior up-front.  */
+      iterate_over_inferiors (report_initial_inferior, mi);
     }
 
   return mi;
@@ -285,10 +296,13 @@ static void
 mi_new_thread (struct thread_info *t)
 {
   struct mi_interp *mi = top_level_interpreter_data ();
+  struct inferior *inf = find_inferior_pid (ptid_get_pid (t->ptid));
+
+  gdb_assert (inf);
 
   fprintf_unfiltered (mi->event_channel, 
-		      "thread-created,id=\"%d\",group-id=\"%d\"", 
-		      t->num, t->ptid.pid);
+		      "thread-created,id=\"%d\",group-id=\"i%d\"",
+		      t->num, inf->num);
   gdb_flush (mi->event_channel);
 }
 
@@ -296,39 +310,65 @@ static void
 mi_thread_exit (struct thread_info *t, int silent)
 {
   struct mi_interp *mi;
+  struct inferior *inf;
 
   if (silent)
     return;
 
+  inf = find_inferior_pid (ptid_get_pid (t->ptid));
+
   mi = top_level_interpreter_data ();
   target_terminal_ours ();
   fprintf_unfiltered (mi->event_channel, 
-		      "thread-exited,id=\"%d\",group-id=\"%d\"", 
-		      t->num,t->ptid.pid);
+		      "thread-exited,id=\"%d\",group-id=\"i%d\"",
+		      t->num, inf->num);
   gdb_flush (mi->event_channel);
 }
 
-void
-mi_inferior_appeared (int pid)
+static void
+mi_inferior_added (struct inferior *inf)
+{
+  struct mi_interp *mi = top_level_interpreter_data ();
+  target_terminal_ours ();
+  fprintf_unfiltered (mi->event_channel,
+		      "thread-group-added,id=\"i%d\"",
+		      inf->num);
+  gdb_flush (mi->event_channel);
+}
+
+static void
+mi_inferior_appeared (struct inferior *inf)
 {
   struct mi_interp *mi = top_level_interpreter_data ();
   target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel, "thread-group-created,id=\"%d\"",
-		      pid);
+  fprintf_unfiltered (mi->event_channel,
+		      "thread-group-started,id=\"i%d\",pid=\"%d\"",
+		      inf->num, inf->pid);
   gdb_flush (mi->event_channel);
 }
 
 static void
-mi_inferior_exit (int pid)
+mi_inferior_exit (struct inferior *inf)
 {
   struct mi_interp *mi = top_level_interpreter_data ();
   target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel, "thread-group-exited,id=\"%d\"", 
-		      pid);
+  fprintf_unfiltered (mi->event_channel, "thread-group-exited,id=\"i%d\"",
+		      inf->num);
   gdb_flush (mi->event_channel);  
 }
 
 static void
+mi_inferior_removed (struct inferior *inf)
+{
+  struct mi_interp *mi = top_level_interpreter_data ();
+  target_terminal_ours ();
+  fprintf_unfiltered (mi->event_channel,
+		      "thread-group-removed,id=\"i%d\"",
+		      inf->num);
+  gdb_flush (mi->event_channel);
+}
+
+static void
 mi_on_normal_stop (struct bpstats *bs, int print_frame)
 {
   /* Since this can be called when CLI command is executing,
@@ -489,10 +529,21 @@ mi_solib_loaded (struct so_list *solib)
 {
   struct mi_interp *mi = top_level_interpreter_data ();
   target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel, 
-		      "library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded=\"%d\"", 
-		      solib->so_original_name, solib->so_original_name, 
-		      solib->so_name, solib->symbols_loaded);
+  if (gdbarch_has_global_solist (target_gdbarch))
+    fprintf_unfiltered (mi->event_channel,
+			"library-loaded,id=\"%s\",target-name=\"%s\","
+			"host-name=\"%s\",symbols-loaded=\"%d\"",
+			solib->so_original_name, solib->so_original_name,
+			solib->so_name, solib->symbols_loaded);
+  else
+    fprintf_unfiltered (mi->event_channel,
+			"library-loaded,id=\"%s\",target-name=\"%s\","
+			"host-name=\"%s\",symbols-loaded=\"%d\","
+			"thread-group=\"i%d\"",
+			solib->so_original_name, solib->so_original_name,
+			solib->so_name, solib->symbols_loaded,
+			current_inferior ()->num);
+
   gdb_flush (mi->event_channel);
 }
 
@@ -501,13 +552,37 @@ mi_solib_unloaded (struct so_list *solib)
 {
   struct mi_interp *mi = top_level_interpreter_data ();
   target_terminal_ours ();
-  fprintf_unfiltered (mi->event_channel, 
-		      "library-unloaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\"", 
-		      solib->so_original_name, solib->so_original_name, 
-		      solib->so_name);
+  if (gdbarch_has_global_solist (target_gdbarch))
+    fprintf_unfiltered (mi->event_channel,
+			"library-unloaded,id=\"%s\",target-name=\"%s\","
+			"host-name=\"%s\"",
+			solib->so_original_name, solib->so_original_name,
+			solib->so_name);
+  else
+    fprintf_unfiltered (mi->event_channel,
+			"library-unloaded,id=\"%s\",target-name=\"%s\","
+			"host-name=\"%s\",thread-group=\"i%d\"",
+			solib->so_original_name, solib->so_original_name,
+			solib->so_name, current_inferior ()->num);
+
   gdb_flush (mi->event_channel);
 }
 
+static int
+report_initial_inferior (struct inferior *inf, void *closure)
+{
+  /* This function is called from mi_intepreter_init, and since
+     mi_inferior_added assumes that inferior is fully initialized
+     and top_level_interpreter_data is set, we cannot call
+     it here.  */
+  struct mi_interp *mi = closure;
+  target_terminal_ours ();
+  fprintf_unfiltered (mi->event_channel,
+		      "thread-group-added,id=\"i%d\"",
+		      inf->num);
+  gdb_flush (mi->event_channel);
+  return 0;
+}
 
 extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-prototypes */
 
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index db3c7d2..9243fd2 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -78,6 +78,11 @@ static struct mi_timestamp *current_command_ts;
 static int do_timings = 0;
 
 char *current_token;
+/* Few commands would like to know if options like --thread-group
+   were explicitly specified.  This variable keeps the current
+   parsed command including all option, and make it possible.  */
+static struct mi_parse *current_context;
+
 int running_result_record_printed = 1;
 
 /* Flag indicating that the target has proceeded since the last
@@ -193,55 +198,79 @@ mi_cmd_exec_jump (char *args, char **argv, int argc)
   mi_execute_async_cli_command ("jump", argv, argc);
 }
  
-static int
-proceed_thread_callback (struct thread_info *thread, void *arg)
+static void
+proceed_thread (struct thread_info *thread, int pid)
 {
-  int pid = *(int *)arg;
-
   if (!is_stopped (thread->ptid))
-    return 0;
+    return;
 
-  if (PIDGET (thread->ptid) != pid)
-    return 0;
+  if (pid != 0 && PIDGET (thread->ptid) != pid)
+    return;
 
   switch_to_thread (thread->ptid);
   clear_proceed_status ();
   proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+}
+
+
+static int
+proceed_thread_callback (struct thread_info *thread, void *arg)
+{
+  int pid = *(int *)arg;
+  proceed_thread (thread, pid);
   return 0;
 }
 
 static void
 exec_continue (char **argv, int argc)
 {
-  if (argc == 0)
-    continue_1 (0);
-  else if (argc == 1 && strcmp (argv[0], "--all") == 0)
-    continue_1 (1);
-  else if (argc == 2 && strcmp (argv[0], "--thread-group") == 0)
+  if (non_stop)
     {
-      struct cleanup *old_chain;
-      int pid;
-      if (argv[1] == NULL || argv[1] == '\0')
-	error ("Thread group id not specified");
-      pid = atoi (argv[1]);
-      if (!in_inferior_list (pid))
-	error ("Invalid thread group id '%s'", argv[1]);
+      /* In non-stop mode, 'resume' always resumes a single thread.  Therefore,
+	 to resume all threads of the current inferior, or all threads in all
+	 inferiors, we need to iterate over threads.
+
+	 See comment on infcmd.c:proceed_thread_callback for rationale.  */
+      if (current_context->all || current_context->thread_group != -1)
+	{
+	  int pid = 0;
+	  struct cleanup *back_to = make_cleanup_restore_current_thread ();
 
-      old_chain = make_cleanup_restore_current_thread ();
-      iterate_over_threads (proceed_thread_callback, &pid);
-      do_cleanups (old_chain);            
+	  if (!current_context->all)
+	    {
+	      struct inferior *inf = find_inferior_id (current_context->thread_group);
+	      pid = inf->pid;
+	    }
+	  iterate_over_threads (proceed_thread_callback, &pid);
+	  do_cleanups (back_to);
+	}
+      else
+	{
+	  continue_1 (0);
+	}
     }
   else
-    error ("Usage: -exec-continue [--reverse] [--all|--thread-group id]");
+    {
+      struct cleanup *back_to = make_cleanup_restore_integer (&sched_multi);
+      if (current_context->all)
+	{
+	  sched_multi = 1;
+	  continue_1 (0);
+	}
+      else
+	{
+	  /* In all-stop mode, -exec-continue traditionally resumed either
+	     all threads, or one thread, depending on the 'scheduler-locking'
+	     variable.  Let's continue to do the same.  */
+	  continue_1 (1);
+	}
+      do_cleanups (back_to);
+    }
 }
 
-/* continue in reverse direction:
-   XXX: code duplicated from reverse.c */
-
 static void
-exec_direction_default (void *notused)
+exec_direction_forward (void *notused)
 {
-  /* Return execution direction to default state.  */
   execution_direction = EXEC_FORWARD;
 }
 
@@ -260,7 +289,7 @@ exec_reverse_continue (char **argv, int argc)
   if (!target_can_execute_reverse)
     error (_("Target %s does not support this command."), target_shortname);
 
-  old_chain = make_cleanup (exec_direction_default, NULL);
+  old_chain = make_cleanup (exec_direction_forward, NULL);
   execution_direction = EXEC_REVERSE;
   exec_continue (argv, argc);
   do_cleanups (old_chain);
@@ -269,7 +298,7 @@ exec_reverse_continue (char **argv, int argc)
 void
 mi_cmd_exec_continue (char *command, char **argv, int argc)
 {
-  if (argc > 0 && strcmp(argv[0], "--reverse") == 0)
+  if (argc > 0 && strcmp (argv[0], "--reverse") == 0)
     exec_reverse_continue (argv + 1, argc - 1);
   else
     exec_continue (argv, argc);
@@ -298,36 +327,31 @@ interrupt_thread_callback (struct thread_info *thread, void *arg)
 void
 mi_cmd_exec_interrupt (char *command, char **argv, int argc)
 {
-  if (argc == 0)
+  /* In all-stop mode, everything stops, so we don't need to try
+     anything specific.  */
+  if (!non_stop)
     {
-      if (!is_running (inferior_ptid))
-	error ("Current thread is not running.");
-
       interrupt_target_1 (0);
+      return;
     }
-  else if (argc == 1 && strcmp (argv[0], "--all") == 0)
+
+  if (current_context->all)
     {
-      if (!any_running ())
-	error ("Inferior not running.");
-      
+      /* This will interrupt all threads in all inferiors.  */
       interrupt_target_1 (1);
     }
-  else if (argc == 2 && strcmp (argv[0], "--thread-group") == 0)
+  else if (current_context->thread_group != -1)
     {
-      struct cleanup *old_chain;
-      int pid;
-      if (argv[1] == NULL || argv[1] == '\0')
-	error ("Thread group id not specified");
-      pid = atoi (argv[1]);
-      if (!in_inferior_list (pid))
-	error ("Invalid thread group id '%s'", argv[1]);
-
-      old_chain = make_cleanup_restore_current_thread ();
-      iterate_over_threads (interrupt_thread_callback, &pid);
-      do_cleanups (old_chain);
+      struct inferior *inf = find_inferior_id (current_context->thread_group);
+      iterate_over_threads (interrupt_thread_callback, &(inf->pid));
     }
   else
-    error ("Usage: -exec-interrupt [--all|--thread-group id]");
+    {
+      /* Interrupt just the current thread -- either explicitly
+	 specified via --thread or whatever was current before
+	 MI command was sent.  */
+      interrupt_target_1 (0);
+    }
 }
 
 /* Given MI command arguments, recompose then back into a single string
@@ -404,6 +428,35 @@ mi_cmd_exec_until (char *command, char **argv, int argc)
   do_cleanups (back_to);
 }
 
+static int
+run_one_inferior (struct inferior *inf, void *arg)
+{
+  struct thread_info *tp = 0;
+
+  if (inf->pid != 0)
+    {
+      if (inf->pid != ptid_get_pid (inferior_ptid))
+	{
+	  struct thread_info *tp;
+
+	  tp = any_thread_of_process (inf->pid);
+	  if (!tp)
+	    error (_("Inferior has no threads."));
+
+	  switch_to_thread (tp->ptid);
+	}
+    }
+  else
+    {
+      set_current_inferior (inf);
+      switch_to_thread (null_ptid);
+      set_current_program_space (inf->pspace);
+    }
+  mi_execute_cli_command ("run", target_can_async_p (),
+			  target_can_async_p () ? "&" : NULL);
+  return 0;
+}
+
 void
 mi_cmd_exec_run (char *command, char **argv, int argc)
 {
@@ -426,14 +479,26 @@ mi_cmd_exec_run (char *command, char **argv, int argc)
 
   if (argc == 0)
     {
-      mi_execute_cli_command ("run", target_can_async_p (), 
-			      target_can_async_p () ? "&" : NULL);
+      if (current_context->all)
+	{
+	  struct cleanup *back_to = save_current_space_and_thread ();
+	  iterate_over_inferiors (run_one_inferior, NULL);
+	  do_cleanups (back_to);
+	}
+      else
+	{
+	  mi_execute_cli_command ("run", target_can_async_p (),
+				  target_can_async_p () ? "&" : NULL);
+	}
     }
   else
     {
       struct cleanup *back_to;
       char *r = recompose_args (argv, argc, target_can_async_p ());
       back_to = make_cleanup (xfree, r);
+
+      if (current_context->all)
+	error (_("Can not use --all with explicit arguments"));
       
       mi_execute_cli_command ("run", 1, r);
 
@@ -579,13 +644,23 @@ print_one_inferior (struct inferior *inferior, void *xdata)
       struct cleanup *back_to
 	= make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
 
-      ui_out_field_fmt (uiout, "id", "%d", inferior->pid);
+      ui_out_field_fmt (uiout, "id", "i%d", inferior->num);
       ui_out_field_string (uiout, "type", "process");
-      ui_out_field_int (uiout, "pid", inferior->pid);
+      if (inferior->pid != 0)
+	ui_out_field_int (uiout, "pid", inferior->pid);
+
+      if (inferior->pspace->ebfd)
+	{
+	  ui_out_field_string (uiout, "executable",
+			       bfd_get_filename (inferior->pspace->ebfd));
+	}
 
-      data.pid = inferior->pid;
       data.cores = 0;
-      iterate_over_threads (collect_cores, &data);
+      if (inferior->pid != 0)
+	{
+	  data.pid = inferior->pid;
+	  iterate_over_threads (collect_cores, &data);
+	}
 
       if (!VEC_empty (int, data.cores))
 	{
@@ -1596,6 +1671,40 @@ mi_cmd_list_target_features (char *command, char **argv, int argc)
   error ("-list-target-features should be passed no arguments");
 }
 
+void
+mi_cmd_add_inferior (char *command, char **argv, int argc)
+{
+  struct inferior *inf;
+
+  if (argc != 0)
+    error (_("-add-inferior should be passed no arguments"));
+
+  inf = add_inferior_with_spaces ();
+
+  ui_out_field_fmt (uiout, "inferior", "i%d", inf->num);
+}
+
+void
+mi_cmd_remove_inferior (char *command, char **argv, int argc)
+{
+  int id;
+  struct inferior *inf;
+
+  if (argc != 1)
+    error ("-remove-inferior should be passed a single argument");
+
+  if (sscanf (argv[1], "i%d", &id) != 1)
+    error ("the thread group id is syntactically invalid");
+
+  inf = find_inferior_id (id);
+  if (!inf)
+    error ("the specified thread group does not exist");
+
+  delete_inferior_1 (inf, 1 /* silent */);
+}
+
+
+
 /* Execute a command within a safe environment.
    Return <0 for error; >=0 for ok.
 
@@ -1797,9 +1906,37 @@ mi_cmd_execute (struct mi_parse *parse)
 
   cleanup = make_cleanup (null_cleanup, NULL);
 
+  if (parse->all && parse->thread_group != -1)
+    error (_("Cannot specify --thread-group together with --all"));
+
+  if (parse->all && parse->thread != -1)
+    error (_("Cannot specify --thread together with --all"));
+
+  if (parse->thread_group != -1 && parse->thread != -1)
+    error (_("Cannot specify --thread together with --thread-group"));
+
   if (parse->frame != -1 && parse->thread == -1)
     error (_("Cannot specify --frame without --thread"));
 
+  if (parse->thread_group != -1)
+    {
+      struct inferior *inf = find_inferior_id (parse->thread_group);
+      struct thread_info *tp = 0;
+
+      if (!inf)
+	error (_("Invalid thread group for the --tread-group option"));
+
+      set_current_inferior (inf);
+      /* This behaviour means that if --thread-group option identifies
+	 an inferior with multiple threads, then a random one will be picked.
+	 This is not a problem -- frontend should always provide --thread if
+	 it wishes to operate on a specific thread.  */
+      if (inf->pid != 0)
+	tp = any_thread_of_process (inf->pid);
+      switch_to_thread (tp ? tp->ptid : null_ptid);
+      set_current_program_space (inf->pspace);
+    }
+
   if (parse->thread != -1)
     {
       struct thread_info *tp = find_thread_id (parse->thread);
@@ -1824,6 +1961,8 @@ mi_cmd_execute (struct mi_parse *parse)
 	error (_("Invalid frame id: %d"), frame);
     }
 
+  current_context = parse;
+
   if (parse->cmd->argv_func != NULL)
     parse->cmd->argv_func (parse->command, parse->argv, parse->argc);
   else if (parse->cmd->cli.cmd != 0)
diff --git a/gdb/mi/mi-parse.c b/gdb/mi/mi-parse.c
index 4ff70ef..0cb2c68 100644
--- a/gdb/mi/mi-parse.c
+++ b/gdb/mi/mi-parse.c
@@ -151,6 +151,8 @@ mi_parse (char *cmd)
   char *chp;
   struct mi_parse *parse = XMALLOC (struct mi_parse);
   memset (parse, 0, sizeof (*parse));
+  parse->all = 0;
+  parse->thread_group = -1;
   parse->thread = -1;
   parse->frame = -1;
 
@@ -210,19 +212,43 @@ mi_parse (char *cmd)
   for (;;)
     {
       char *start = chp;
+      size_t as = sizeof ("--all ") - 1;
+      size_t tgs = sizeof ("--thread-group ") - 1;
       size_t ts = sizeof ("--thread ") - 1;
       size_t fs = sizeof ("--frame ") - 1;
+      if (strncmp (chp, "--all ", as) == 0)
+	{
+	  parse->all = 1;
+	  chp += as;
+	}
+      /* See if this --all as the last token in the input.
+	 Both the string and count are smaller by 1.  */
+      if (strncmp (chp, "--all", as - 1) == 0)
+	{
+	  parse->all = 1;
+	  chp += (as - 1);
+	}
+      if (strncmp (chp, "--thread-group ", tgs) == 0)
+	{
+	  if (parse->thread_group != -1)
+	    error (_("Duplicate '--thread-group' option"));
+	  chp += tgs;
+	  if (*chp != 'i')
+	    error (_("Invalid thread group id"));
+	  chp += 1;
+	  parse->thread_group = strtol (chp, &chp, 10);
+	}
       if (strncmp (chp, "--thread ", ts) == 0)
 	{
 	  if (parse->thread != -1)
-	    error ("Duplicate '--thread' option");
+	    error (_("Duplicate '--thread' option"));
 	  chp += ts;
 	  parse->thread = strtol (chp, &chp, 10);
 	}
       else if (strncmp (chp, "--frame ", fs) == 0)
 	{
 	  if (parse->frame != -1)
-	    error ("Duplicate '--frame' option");
+	    error (_("Duplicate '--frame' option"));
 	  chp += fs;
 	  parse->frame = strtol (chp, &chp, 10);
 	}
@@ -230,7 +256,7 @@ mi_parse (char *cmd)
 	break;
 
       if (*chp != '\0' && !isspace (*chp))
-	error ("Invalid value for the '%s' option",
+	error (_("Invalid value for the '%s' option"),
 	       start[2] == 't' ? "--thread" : "--frame");
       while (isspace (*chp))
 	chp++;
diff --git a/gdb/mi/mi-parse.h b/gdb/mi/mi-parse.h
index a63ee8e..3c6cd9a 100644
--- a/gdb/mi/mi-parse.h
+++ b/gdb/mi/mi-parse.h
@@ -46,6 +46,8 @@ struct mi_parse
     char *args;
     char **argv;
     int argc;
+    int all;
+    int thread_group; /* At present, the same as inferior number.  */
     int thread;
     int frame;
   };
diff --git a/gdb/testsuite/gdb.mi/mi-nonstop.exp b/gdb/testsuite/gdb.mi/mi-nonstop.exp
index f83eed7..278fe2a 100644
--- a/gdb/testsuite/gdb.mi/mi-nonstop.exp
+++ b/gdb/testsuite/gdb.mi/mi-nonstop.exp
@@ -160,7 +160,7 @@ if { [is_remote target] } {
     unsupported $test
 } else {
     gdb_expect {
-	-re ".*=thread-exited,id=\"2\",group-id=\"\[0-9\]+\"\r\n$" {
+	-re ".*=thread-exited,id=\"2\",group-id=\"i\[0-9\]+\"\r\n$" {
 	    pass $test
 	}
 	timeout {

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