+2011-05-30 Pedro Alves <pedro@codesourcery.com>
+
+ * continuations.h (continuation_ftype): Add `err' parameter.
+ Document parameters.
+ (do_all_continuations, do_all_continuations_thread)
+ (do_all_intermediate_continuations)
+ (do_all_intermediate_continuations_thread)
+ (do_all_inferior_continuations): Add `err' parameter.
+ * continuations.c (do_my_continuations_1, do_my_continuations)
+ (do_all_inferior_continuations, do_all_continuations_ptid)
+ (do_all_continuations_thread_callback)
+ (do_all_continuations_thread, do_all_continuations)
+ (do_all_intermediate_continuations_thread_callback)
+ (do_all_intermediate_continuations_thread)
+ (do_all_intermediate_continuations): Add `err' parameter, and pass
+ it down all the way to the continuations proper.
+ * inf-loop.c (inferior_event_handler): If fetching an inferior
+ event throws an error, don't pop the target, and still call the
+ continuations, but with `err' set. Adjust all other continuation
+ calls.
+ * breakpoint.c (until_break_command_continuation): Add `err'
+ parameter.
+ * infcmd.c (step_1_continuation): Add `err' parameter. Don't
+ issue another step if `err' is set.
+ (struct until_next_continuation_args): New.
+ (until_next_continuation): Add `err' parameter. Adjust.
+ (until_next_command): Adjust.
+ (struct finish_command_continuation_args): Add `thread' field.
+ (finish_command_continuation): Add `err' parameter. Handle it.
+ (finish_forward): Adjust.
+ (attach_command_continuation): Add `err' parameter. Handle it.
+ * infrun.c (infrun_thread_stop_requested_callback): Adjust to
+ cancel the continuations.
+ * interps.c (interp_set): Adjust to cancel the continuations.
+ * thread.c (clear_thread_inferior_resources): Adjust to cancel the
+ continuations rather than discarding.
+ (free_thread): Don't clear thread inferior resources here.
+ (delete_thread_1): Do it here instead. And do it before removing
+ the thread from the threads list. Tag the thread as exited before
+ clearing thread inferior resources.
+
2011-05-30 Joel Brobecker <brobecker@adacore.com>
* infcall.c (call_function_by_hand): Rephrase error message.
care of cleaning up the temporary breakpoints set up by the until
command. */
static void
-until_break_command_continuation (void *arg)
+until_break_command_continuation (void *arg, int err)
{
struct until_break_command_continuation_args *a = arg;
}
static void
-do_my_continuations_1 (struct continuation **pmy_chain)
+do_my_continuations_1 (struct continuation **pmy_chain, int err)
{
struct continuation *ptr;
while ((ptr = *pmy_chain) != NULL)
{
*pmy_chain = ptr->next; /* Do this first in case of recursion. */
- (*ptr->function) (ptr->arg);
+ (*ptr->function) (ptr->arg, err);
if (ptr->free_arg)
(*ptr->free_arg) (ptr->arg);
xfree (ptr);
}
static void
-do_my_continuations (struct continuation **list)
+do_my_continuations (struct continuation **list, int err)
{
struct continuation *continuations;
*list = NULL;
/* Work now on the list we have set aside. */
- do_my_continuations_1 (&continuations);
+ do_my_continuations_1 (&continuations, err);
}
static void
/* Do all continuations of the current inferior. */
void
-do_all_inferior_continuations (void)
+do_all_inferior_continuations (int err)
{
struct inferior *inf = current_inferior ();
- do_my_continuations (&inf->continuations);
+ do_my_continuations (&inf->continuations, err);
}
/* Get rid of all the inferior-wide continuations of INF. */
static void
do_all_continuations_ptid (ptid_t ptid,
- struct continuation **continuations_p)
+ struct continuation **continuations_p,
+ int err)
{
struct cleanup *old_chain;
ptid_t current_thread;
/* Let the continuation see this thread as selected. */
switch_to_thread (ptid);
- do_my_continuations (continuations_p);
+ do_my_continuations (continuations_p, err);
do_cleanups (old_chain);
}
static int
do_all_continuations_thread_callback (struct thread_info *thread, void *data)
{
- do_all_continuations_ptid (thread->ptid, &thread->continuations);
+ int err = * (int *) data;
+ do_all_continuations_ptid (thread->ptid, &thread->continuations, err);
return 0;
}
/* Do all continuations of thread THREAD. */
void
-do_all_continuations_thread (struct thread_info *thread)
+do_all_continuations_thread (struct thread_info *thread, int err)
{
- do_all_continuations_thread_callback (thread, NULL);
+ do_all_continuations_thread_callback (thread, &err);
}
/* Do all continuations of all threads. */
void
-do_all_continuations (void)
+do_all_continuations (int err)
{
- iterate_over_threads (do_all_continuations_thread_callback, NULL);
+ iterate_over_threads (do_all_continuations_thread_callback, &err);
}
/* Callback for iterate over threads. */
do_all_intermediate_continuations_thread_callback (struct thread_info *thread,
void *data)
{
+ int err = * (int *) data;
+
do_all_continuations_ptid (thread->ptid,
- &thread->intermediate_continuations);
+ &thread->intermediate_continuations, err);
return 0;
}
/* Do all intermediate continuations of thread THREAD. */
void
-do_all_intermediate_continuations_thread (struct thread_info *thread)
+do_all_intermediate_continuations_thread (struct thread_info *thread, int err)
{
- do_all_intermediate_continuations_thread_callback (thread, NULL);
+ do_all_intermediate_continuations_thread_callback (thread, &err);
}
/* Do all intermediate continuations of all threads. */
void
-do_all_intermediate_continuations (void)
+do_all_intermediate_continuations (int err)
{
iterate_over_threads (do_all_intermediate_continuations_thread_callback,
- NULL);
+ &err);
}
/* Callback for iterate over threads. */
used by the finish and until commands, and in the remote protocol
when opening an extended-remote connection. */
-/* Prototype of the continuation callback functions. */
-typedef void (continuation_ftype) (void *);
+/* Prototype of the continuation callback functions. ARG is the
+ continuation argument registered in the corresponding
+ add_*_continuation call. ERR is true when the command should be
+ cancelled instead of finished normally. In that case, the
+ continuation should clean up whatever state had been set up for the
+ command in question (e.g., remove momentary breakpoints). This
+ happens e.g., when an error was thrown while handling a target
+ event, or when the inferior thread the command was being executed
+ on exits. */
+typedef void (continuation_ftype) (void *arg, int err);
/* Prototype of the function responsible for releasing the argument
passed to the continuation callback functions, either when the
extern void add_continuation (struct thread_info *,
continuation_ftype *, void *,
continuation_free_arg_ftype *);
-extern void do_all_continuations (void);
-extern void do_all_continuations_thread (struct thread_info *);
+extern void do_all_continuations (int err);
+extern void do_all_continuations_thread (struct thread_info *, int err);
extern void discard_all_continuations (void);
extern void discard_all_continuations_thread (struct thread_info *);
extern void add_intermediate_continuation (struct thread_info *,
continuation_ftype *, void *,
continuation_free_arg_ftype *);
-extern void do_all_intermediate_continuations (void);
-extern void do_all_intermediate_continuations_thread (struct thread_info *);
+extern void do_all_intermediate_continuations (int err);
+extern void do_all_intermediate_continuations_thread (struct thread_info *, int err);
extern void discard_all_intermediate_continuations (void);
extern void discard_all_intermediate_continuations_thread (struct thread_info *);
extern void add_inferior_continuation (continuation_ftype *,
void *,
continuation_free_arg_ftype *);
-extern void do_all_inferior_continuations (void);
+extern void do_all_inferior_continuations (int err);
extern void discard_all_inferior_continuations (struct inferior *inf);
#endif
/* Use catch errors for now, until the inner layers of
fetch_inferior_event (i.e. readchar) can return meaningful
error status. If an error occurs while getting an event from
- the target, just get rid of the target. */
+ the target, just cancel the current command. */
if (!catch_errors (fetch_inferior_event_wrapper,
client_data, "", RETURN_MASK_ALL))
{
- pop_all_targets_above (file_stratum, 0);
- discard_all_intermediate_continuations ();
- discard_all_continuations ();
+ do_all_intermediate_continuations (1);
+ do_all_continuations (1);
async_enable_stdin ();
display_gdb_prompt (0);
}
/* Do all continuations associated with the whole inferior (not
a particular thread). */
if (!ptid_equal (inferior_ptid, null_ptid))
- do_all_inferior_continuations ();
+ do_all_inferior_continuations (0);
/* If we were doing a multi-step (eg: step n, next n), but it
got interrupted by a breakpoint, still do the pending
if (non_stop
&& target_has_execution
&& !ptid_equal (inferior_ptid, null_ptid))
- do_all_intermediate_continuations_thread (inferior_thread ());
+ do_all_intermediate_continuations_thread (inferior_thread (), 0);
else
- do_all_intermediate_continuations ();
+ do_all_intermediate_continuations (0);
/* Always finish the previous command before running any
breakpoint commands. Any stop cancels the previous command.
if (non_stop
&& target_has_execution
&& !ptid_equal (inferior_ptid, null_ptid))
- do_all_continuations_thread (inferior_thread ());
+ do_all_continuations_thread (inferior_thread (), 0);
else
- do_all_continuations ();
+ do_all_continuations (0);
if (info_verbose
&& current_language != expected_language
complete? */
if (non_stop)
- do_all_intermediate_continuations_thread (inferior_thread ());
+ do_all_intermediate_continuations_thread (inferior_thread (), 0);
else
- do_all_intermediate_continuations ();
+ do_all_intermediate_continuations (0);
break;
case INF_QUIT_REQ:
proceed(), via step_once(). Basically it is like step_once and
step_1_continuation are co-recursive. */
static void
-step_1_continuation (void *args)
+step_1_continuation (void *args, int err)
{
struct step_1_continuation_args *a = args;
struct thread_info *tp;
tp = inferior_thread ();
- if (tp->step_multi && tp->control.stop_step)
+ if (!err
+ && tp->step_multi && tp->control.stop_step)
{
/* There are more steps to make, and we did stop due to
ending a stepping range. Do another step. */
tp->step_multi = 0;
}
- /* We either stopped for some reason that is not stepping, or there
- are no further steps to make. Cleanup. */
+ /* We either hit an error, or stopped for some reason that is
+ not stepping, or there are no further steps to make.
+ Cleanup. */
if (!a->single_inst || a->skip_subroutines)
delete_longjmp_breakpoint (a->thread);
}
proceed ((CORE_ADDR) -1, oursig, 0);
}
+/* Continuation args to be passed to the "until" command
+ continuation. */
+struct until_next_continuation_args
+{
+ /* The thread that was current when the command was executed. */
+ int thread;
+};
+
/* A continuation callback for until_next_command. */
static void
-until_next_continuation (void *arg)
+until_next_continuation (void *arg, int err)
{
- struct thread_info *tp = arg;
+ struct until_next_continuation_args *a = arg;
- delete_longjmp_breakpoint (tp->num);
+ delete_longjmp_breakpoint (a->thread);
}
/* Proceed until we reach a different source line with pc greater than
if (target_can_async_p () && is_running (inferior_ptid))
{
+ struct until_next_continuation_args *cont_args;
+
discard_cleanups (old_chain);
- add_continuation (tp, until_next_continuation, tp, NULL);
+ cont_args = XNEW (struct until_next_continuation_args);
+ cont_args->thread = inferior_thread ()->num;
+
+ add_continuation (tp, until_next_continuation, cont_args, xfree);
}
else
do_cleanups (old_chain);
impossible to do all the stuff as part of the finish_command
function itself. The only chance we have to complete this command
is in fetch_inferior_event, which is called by the event loop as
- soon as it detects that the target has stopped. This function is
- called via the cmd_continuation pointer. */
+ soon as it detects that the target has stopped. */
struct finish_command_continuation_args
{
+ /* The thread that as current when the command was executed. */
+ int thread;
struct breakpoint *breakpoint;
struct symbol *function;
};
static void
-finish_command_continuation (void *arg)
+finish_command_continuation (void *arg, int err)
{
struct finish_command_continuation_args *a = arg;
- struct thread_info *tp = NULL;
- bpstat bs = NULL;
-
- if (!ptid_equal (inferior_ptid, null_ptid)
- && target_has_execution
- && is_stopped (inferior_ptid))
- {
- tp = inferior_thread ();
- bs = tp->control.stop_bpstat;
- }
- if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
- && a->function != NULL)
+ if (!err)
{
- struct type *value_type;
+ struct thread_info *tp = NULL;
+ bpstat bs = NULL;
- value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function));
- if (!value_type)
- internal_error (__FILE__, __LINE__,
- _("finish_command: function has no target type"));
+ if (!ptid_equal (inferior_ptid, null_ptid)
+ && target_has_execution
+ && is_stopped (inferior_ptid))
+ {
+ tp = inferior_thread ();
+ bs = tp->control.stop_bpstat;
+ }
- if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
+ if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
+ && a->function != NULL)
{
- volatile struct gdb_exception ex;
+ struct type *value_type;
+
+ value_type = TYPE_TARGET_TYPE (SYMBOL_TYPE (a->function));
+ if (!value_type)
+ internal_error (__FILE__, __LINE__,
+ _("finish_command: function has no target type"));
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
{
- /* print_return_value can throw an exception in some
- circumstances. We need to catch this so that we still
- delete the breakpoint. */
- print_return_value (SYMBOL_TYPE (a->function), value_type);
+ volatile struct gdb_exception ex;
+
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ /* print_return_value can throw an exception in some
+ circumstances. We need to catch this so that we still
+ delete the breakpoint. */
+ print_return_value (SYMBOL_TYPE (a->function), value_type);
+ }
+ if (ex.reason < 0)
+ exception_print (gdb_stdout, ex);
}
- if (ex.reason < 0)
- exception_print (gdb_stdout, ex);
}
+
+ /* We suppress normal call of normal_stop observer and do it
+ here so that the *stopped notification includes the return
+ value. */
+ if (bs != NULL && tp->control.proceed_to_finish)
+ observer_notify_normal_stop (bs, 1 /* print frame */);
}
- /* We suppress normal call of normal_stop observer and do it here so
- that the *stopped notification includes the return value. */
- if (bs != NULL && tp->control.proceed_to_finish)
- observer_notify_normal_stop (bs, 1 /* print frame */);
delete_breakpoint (a->breakpoint);
- delete_longjmp_breakpoint (inferior_thread ()->num);
+ delete_longjmp_breakpoint (a->thread);
}
static void
tp->control.proceed_to_finish = 1;
cargs = xmalloc (sizeof (*cargs));
+ cargs->thread = thread;
cargs->breakpoint = breakpoint;
cargs->function = function;
add_continuation (tp, finish_command_continuation, cargs,
discard_cleanups (old_chain);
if (!target_can_async_p ())
- do_all_continuations ();
+ do_all_continuations (0);
}
/* "finish": Set a temporary breakpoint at the place the selected
};
static void
-attach_command_continuation (void *args)
+attach_command_continuation (void *args, int err)
{
struct attach_command_continuation_args *a = args;
+ if (err)
+ return;
+
attach_command_post_wait (a->args, a->from_tty, a->async_exec);
}
normal_stop ();
- /* Finish off the continuations. The continations
- themselves are responsible for realising the thread
- didn't finish what it was supposed to do. */
+ /* Finish off the continuations. */
tp = inferior_thread ();
- do_all_intermediate_continuations_thread (tp);
- do_all_continuations_thread (tp);
+ do_all_intermediate_continuations_thread (tp, 1);
+ do_all_continuations_thread (tp, 1);
}
do_cleanups (old_chain);
if (current_interpreter != NULL)
{
- do_all_continuations ();
+ do_all_continuations (1);
ui_out_flush (uiout);
if (current_interpreter->procs->suspend_proc
&& !current_interpreter->procs->suspend_proc (current_interpreter->
bpstat_clear (&tp->control.stop_bpstat);
- discard_all_intermediate_continuations_thread (tp);
- discard_all_continuations_thread (tp);
+ do_all_intermediate_continuations_thread (tp, 1);
+ do_all_continuations_thread (tp, 1);
delete_longjmp_breakpoint (tp->num);
}
static void
free_thread (struct thread_info *tp)
{
- clear_thread_inferior_resources (tp);
-
if (tp->private)
{
if (tp->private_dtor)
return;
}
+ /* Notify thread exit, but only if we haven't already. */
+ if (tp->state_ != THREAD_EXITED)
+ observer_notify_thread_exit (tp, silent);
+
+ /* Tag it as exited. */
+ tp->state_ = THREAD_EXITED;
+ clear_thread_inferior_resources (tp);
+
if (tpprev)
tpprev->next = tp->next;
else
thread_list = tp->next;
- /* Notify thread exit, but only if we haven't already. */
- if (tp->state_ != THREAD_EXITED)
- observer_notify_thread_exit (tp, silent);
-
free_thread (tp);
}