2011-05-30 Pedro Alves <pedro@codesourcery.com>

gdb/
	* 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.
This commit is contained in:
Pedro Alves 2011-05-30 18:04:32 +00:00
parent c2949be03b
commit fa4cd53f7d
9 changed files with 177 additions and 99 deletions

View File

@ -1,3 +1,44 @@
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.

View File

@ -9508,7 +9508,7 @@ struct until_break_command_continuation_args
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;

View File

@ -51,14 +51,14 @@ make_continuation (struct continuation **pmy_chain,
}
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);
@ -66,7 +66,7 @@ do_my_continuations_1 (struct continuation **pmy_chain)
}
static void
do_my_continuations (struct continuation **list)
do_my_continuations (struct continuation **list, int err)
{
struct continuation *continuations;
@ -82,7 +82,7 @@ do_my_continuations (struct continuation **list)
*list = NULL;
/* Work now on the list we have set aside. */
do_my_continuations_1 (&continuations);
do_my_continuations_1 (&continuations, err);
}
static void
@ -123,10 +123,10 @@ add_inferior_continuation (continuation_ftype *hook, void *args,
/* 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. */
@ -167,7 +167,8 @@ restore_thread_cleanup (void *arg)
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;
@ -191,7 +192,7 @@ do_all_continuations_ptid (ptid_t ptid,
/* 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);
}
@ -201,24 +202,25 @@ do_all_continuations_ptid (ptid_t ptid,
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. */
@ -274,26 +276,28 @@ static int
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. */

View File

@ -30,8 +30,16 @@ struct inferior;
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
@ -43,16 +51,16 @@ typedef void (continuation_free_arg_ftype) (void *);
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 *);
@ -61,7 +69,7 @@ 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

View File

@ -63,13 +63,12 @@ inferior_event_handler (enum inferior_event_type event_type,
/* 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);
}
@ -95,7 +94,7 @@ inferior_event_handler (enum inferior_event_type event_type,
/* 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
@ -107,9 +106,9 @@ inferior_event_handler (enum inferior_event_type event_type,
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.
@ -118,9 +117,9 @@ inferior_event_handler (enum inferior_event_type event_type,
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
@ -147,9 +146,9 @@ inferior_event_handler (enum inferior_event_type event_type,
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:

View File

@ -940,7 +940,7 @@ struct step_1_continuation_args
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;
@ -949,7 +949,8 @@ step_1_continuation (void *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. */
@ -960,8 +961,9 @@ step_1_continuation (void *args)
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);
}
@ -1246,14 +1248,22 @@ signal_command (char *signum_exp, int from_tty)
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
@ -1316,8 +1326,13 @@ until_next_command (int from_tty)
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);
@ -1458,62 +1473,69 @@ print_return_value (struct type *func_type, struct type *value_type)
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))
if (!err)
{
tp = inferior_thread ();
bs = tp->control.stop_bpstat;
}
struct thread_info *tp = NULL;
bpstat bs = NULL;
if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
&& a->function != NULL)
{
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"));
if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
if (!ptid_equal (inferior_ptid, null_ptid)
&& target_has_execution
&& is_stopped (inferior_ptid))
{
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);
tp = inferior_thread ();
bs = tp->control.stop_bpstat;
}
if (bpstat_find_breakpoint (bs, a->breakpoint) != NULL
&& a->function != NULL)
{
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"));
if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
{
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);
}
}
/* 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
@ -1604,6 +1626,7 @@ finish_forward (struct symbol *function, struct frame_info *frame)
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,
@ -1612,7 +1635,7 @@ finish_forward (struct symbol *function, struct frame_info *frame)
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
@ -2405,10 +2428,13 @@ struct attach_command_continuation_args
};
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);
}

View File

@ -2393,12 +2393,10 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
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);

View File

@ -150,7 +150,7 @@ interp_set (struct interp *interp, int top_level)
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->

View File

@ -125,8 +125,8 @@ clear_thread_inferior_resources (struct thread_info *tp)
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);
}
@ -134,8 +134,6 @@ clear_thread_inferior_resources (struct thread_info *tp)
static void
free_thread (struct thread_info *tp)
{
clear_thread_inferior_resources (tp);
if (tp->private)
{
if (tp->private_dtor)
@ -297,15 +295,19 @@ delete_thread_1 (ptid_t ptid, int silent)
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);
}