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]

Properly cancel continuations on error. Don't throw away the target on error thrown while handling a target event.


Currently, in async mode, if any error thrown while handling an
event (within fetch_inferior_event, handle_inferior_event, target_wait,
etc.), the target is simply forcibly removed off target stack (!).

inf-loop.c:inferior_event_handler:
...
    case INF_REG_EVENT:
      /* 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.  */
      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 ();
	  async_enable_stdin ();


This happens, e.g., if something in the unwinders throws an error,
or for some reason we do something wrong/racy and end up calling
perror_with_name in the target.  In sync mode, this just triggers
cleanups being called and the current command is cancelled.  The
async code should do that same, terminating the whole debug
session is really nasty.  In order to do that, I've reinstated,
an "err" parameter to the continuations, that I had removed hastily
a couple of years ago when we were revamping async in order to add
non-stop.  It was a bad call at the time -- it's not always possible
to infer from other context whether the command is being cancelled.

I moved the clear_thread_inferior_resources out of free_thread
because clear_thread_inferior_resources calls the continuations,
which need to switch current thread to the thread the continuation
is attached to, and free_thread is too late for that.

This:

> Index: src/gdb/interps.c
> ===================================================================
> --- src.orig/gdb/interps.c	2011-05-30 18:15:07.000000000 +0100
> +++ src/gdb/interps.c	2011-05-30 18:15:41.664991398 +0100
> @@ -150,7 +150,7 @@ interp_set (struct interp *interp, int t
>  
>    if (current_interpreter != NULL)
>      {
> -      do_all_continuations ();
> +      do_all_continuations (1);

... is what we used to do before I had removed the "err" parameter
back in 2008, and so I reverted it like that, but I think this call
do_all_continuations call should just go away.  I'll do so on a
follow up patch.

Tested on x86_64-linux, sync|async, and checked in.

-- 
Pedro Alves

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.

---
 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 ++++----
 8 files changed, 132 insertions(+), 95 deletions(-)

Index: src/gdb/continuations.h
===================================================================
--- src.orig/gdb/continuations.h	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/continuations.h	2011-05-30 18:15:41.624991398 +0100
@@ -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_ftyp
 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_con
 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
Index: src/gdb/continuations.c
===================================================================
--- src.orig/gdb/continuations.c	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/continuations.c	2011-05-30 18:15:41.574991398 +0100
@@ -51,14 +51,14 @@ make_continuation (struct continuation *
 }
 
 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 continuati
 }
 
 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 = 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_
 /* 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.  */
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c	2011-05-30 18:15:20.000000000 +0100
+++ src/gdb/inf-loop.c	2011-05-30 18:17:08.414991368 +0100
@@ -63,13 +63,12 @@ inferior_event_handler (enum inferior_ev
       /* 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_ev
       /* 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_ev
       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_ev
       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_ev
          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: 
Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/breakpoint.c	2011-05-30 18:15:41.574991398 +0100
@@ -9508,7 +9508,7 @@ struct until_break_command_continuation_
    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;
 
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/infcmd.c	2011-05-30 18:15:41.654991398 +0100
@@ -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 fr
   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_ty
    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;
 
-	  TRY_CATCH (ex, RETURN_MASK_ALL)
+	  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)
 	    {
-	      /* 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,
   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,
 
   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);
 }
 
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/infrun.c	2011-05-30 18:15:41.664991398 +0100
@@ -2393,12 +2393,10 @@ infrun_thread_stop_requested_callback (s
 
 	  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);
Index: src/gdb/interps.c
===================================================================
--- src.orig/gdb/interps.c	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/interps.c	2011-05-30 18:15:41.664991398 +0100
@@ -150,7 +150,7 @@ interp_set (struct interp *interp, int t
 
   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->
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c	2011-05-30 18:15:07.000000000 +0100
+++ src/gdb/thread.c	2011-05-30 18:15:41.664991398 +0100
@@ -125,8 +125,8 @@ clear_thread_inferior_resources (struct
 
   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
 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);
 }
 


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