From fa4cd53f7d2a4d6981bc4e09d5233f0df2c7f1cd Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 30 May 2011 18:04:32 +0000 Subject: [PATCH] 2011-05-30 Pedro Alves 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. --- gdb/ChangeLog | 41 ++++++++++++++++ gdb/breakpoint.c | 2 +- gdb/continuations.c | 40 +++++++++------- gdb/continuations.h | 22 ++++++--- gdb/inf-loop.c | 21 ++++---- gdb/infcmd.c | 114 +++++++++++++++++++++++++++----------------- gdb/infrun.c | 8 ++-- gdb/interps.c | 2 +- gdb/thread.c | 18 +++---- 9 files changed, 173 insertions(+), 95 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7a60b8e3cf5..17db1752743 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,44 @@ +2011-05-30 Pedro Alves + + * 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 * infcall.c (call_function_by_hand): Rephrase error message. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index d26a347ba1a..fe797dd3140 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -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; diff --git a/gdb/continuations.c b/gdb/continuations.c index c6f45a23e8f..0ad3184702b 100644 --- a/gdb/continuations.c +++ b/gdb/continuations.c @@ -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. */ diff --git a/gdb/continuations.h b/gdb/continuations.h index aaba362f0b9..bf3b516af7a 100644 --- a/gdb/continuations.h +++ b/gdb/continuations.h @@ -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 diff --git a/gdb/inf-loop.c b/gdb/inf-loop.c index 1645c38b6e1..0ab372c784d 100644 --- a/gdb/inf-loop.c +++ b/gdb/inf-loop.c @@ -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: diff --git a/gdb/infcmd.c b/gdb/infcmd.c index f499e3e64bf..aa3646b483c 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -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)) - { - 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 @@ -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); } diff --git a/gdb/infrun.c b/gdb/infrun.c index efc35f96f8a..e0d808ae255 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -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); diff --git a/gdb/interps.c b/gdb/interps.c index bd9a352ce2c..2fbd855c81d 100644 --- a/gdb/interps.c +++ b/gdb/interps.c @@ -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-> diff --git a/gdb/thread.c b/gdb/thread.c index 3090b692556..5a78ad17025 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -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); } -- 2.30.2