+2008-11-05 Pedro Alves <pedro@codesourcery.com>
+
+ * defs.h (add_inferior_continuation)
+ (do_all_inferior_continuations)
+ (discard_all_inferior_continuations): Declare.
+ * utils.c (add_inferior_continuation)
+ (do_all_inferior_continuations)
+ (discard_all_inferior_continuations): New.
+ * inferior.h (struct inferior) <continuations>: New field.
+ * inferior.c (free_inferior): Discard all the inferior
+ continuations.
+ * inf-loop.c (inferior_event_handler): Do all current inferior
+ continuations.
+ * infcmd.c (attach_command): Register an inferior continuation
+ instead of a thread continuation.
+ * infrun.c (handle_inferior_event): If stop_soon is
+ STOP_QUIETLY_NO_SIGSTOP, also expect a TARGET_SIGNAL_0.
+
2008-11-04 Pedro Alves <pedro@codesourcery.com>
* inf-loop.c (inferior_event_handler): On INF_ERROR and
struct continuation;
struct thread_info;
+struct inferior;
/* From utils.c */
+
+/* Thread specific continuations. */
+
extern void add_continuation (struct thread_info *,
void (*)(void *), void *,
void (*)(void *));
extern void discard_all_intermediate_continuations (void);
extern void discard_all_intermediate_continuations_thread (struct thread_info *);
+/* Inferior specific (any thread) continuations. */
+
+extern void add_inferior_continuation (void (*) (void *),
+ void *,
+ void (*) (void *));
+extern void do_all_inferior_continuations (void);
+extern void discard_all_inferior_continuations (struct inferior *inf);
+
/* String containing the current directory (what getwd would return). */
extern char *current_directory;
was_sync = sync_execution;
async_enable_stdin ();
+ /* Do all continuations associated with the whole inferior (not
+ a particular thread). */
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ do_all_inferior_continuations ();
+
/* If we were doing a multi-step (eg: step n, next n), but it
got interrupted by a breakpoint, still do the pending
continuations. The continuation itself is responsible for
a->args = xstrdup (args);
a->from_tty = from_tty;
a->async_exec = async_exec;
- add_continuation (inferior_thread (),
- attach_command_continuation, a,
- attach_command_continuation_free_args);
+ add_inferior_continuation (attach_command_continuation, a,
+ attach_command_continuation_free_args);
discard_cleanups (back_to);
return;
}
static void
free_inferior (struct inferior *inf)
{
+ discard_all_inferior_continuations (inf);
xfree (inf->private);
xfree (inf);
}
forked. */
int attach_flag;
+ /* What is left to do for an execution command after any thread of
+ this inferior stops. For continuations associated with a
+ specific thread, see `struct thread_info'. */
+ struct continuation *continuations;
+
/* Private data used by the target vector implementation. */
struct private_inferior *private;
};
SIGTRAP. Some systems (e.g. Windows), and stubs supporting
target extended-remote report it instead of a SIGSTOP
(e.g. gdbserver). We already rely on SIGTRAP being our
- signal, so this is no exception. */
+ signal, so this is no exception.
+
+ Also consider that the attach is complete when we see a
+ TARGET_SIGNAL_0. In non-stop mode, GDB will explicitly tell
+ the target to stop all threads of the inferior, in case the
+ low level attach operation doesn't stop them implicitly. If
+ they weren't stopped implicitly, then the stub will report a
+ TARGET_SIGNAL_0, meaning: stopped for no particular reason
+ other than GDB's request. */
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
&& (ecs->event_thread->stop_signal == TARGET_SIGNAL_STOP
- || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP))
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+ || ecs->event_thread->stop_signal == TARGET_SIGNAL_0))
{
stop_stepping (ecs);
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
thread->continuations = (struct continuation *) as_cleanup;
}
+/* Add a continuation to the continuation list of INFERIOR. The new
+ continuation will be added at the front. */
+
+void
+add_inferior_continuation (void (*continuation_hook) (void *), void *args,
+ void (*continuation_free_args) (void *))
+{
+ struct inferior *inf = current_inferior ();
+ struct cleanup *as_cleanup = &inf->continuations->base;
+ make_cleanup_ftype *continuation_hook_fn = continuation_hook;
+
+ make_my_cleanup2 (&as_cleanup,
+ continuation_hook_fn,
+ args,
+ continuation_free_args);
+
+ inf->continuations = (struct continuation *) as_cleanup;
+}
+
+/* Do all continuations of the current inferior. */
+
+void
+do_all_inferior_continuations (void)
+{
+ struct cleanup *old_chain;
+ struct cleanup *as_cleanup;
+ struct inferior *inf = current_inferior ();
+
+ if (inf->continuations == NULL)
+ return;
+
+ /* Copy the list header into another pointer, and set the global
+ list header to null, so that the global list can change as a side
+ effect of invoking the continuations and the processing of the
+ preexisting continuations will not be affected. */
+
+ as_cleanup = &inf->continuations->base;
+ inf->continuations = NULL;
+
+ /* Work now on the list we have set aside. */
+ do_my_cleanups (&as_cleanup, NULL);
+}
+
+/* Get rid of all the inferior-wide continuations of INF. */
+
+void
+discard_all_inferior_continuations (struct inferior *inf)
+{
+ struct cleanup *continuation_ptr = &inf->continuations->base;
+ discard_my_cleanups (&continuation_ptr, NULL);
+ inf->continuations = NULL;
+}
+
static void
restore_thread_cleanup (void *arg)
{