Blame SOURCES/gdb-rhbz1184724-gdb-internal-error-num-lwps.patch

7b26da
From 6681535d2cecea1f67255c140f11b217518a2f4e Mon Sep 17 00:00:00 2001
7b26da
From: Pedro Alves <palves@redhat.com>
7b26da
Date: Wed, 17 Jun 2015 20:41:05 +0100
7b26da
Subject: [PATCH] Fix BZ1184724 - gdb output a internal-error: Assertion
7b26da
 `num_lwps (GET_PID (inferior_ptid)) == 1'
7b26da
7b26da
The real issue with this bug is in the ptrace error:
7b26da
7b26da
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7b26da
  (gdb) c
7b26da
  Continuing.
7b26da
  netcfStateCleanup () at interface/interface_backend_netcf.c:116
7b26da
  116	}
7b26da
  ptrace: No such process.
7b26da
  ^^^^^^^^^^^^^^^^^^^^^^^^
7b26da
  (gdb) quit
7b26da
	  Inferior 1 [process 11205] will be detached.
7b26da
  Quit anyway? (y or n) y
7b26da
  [Thread 0x7fefdf322880 (LWP 11205) exited]
7b26da
7b26da
  ../../gdb/linux-nat.c:1869: internal-error: linux_nat_detach: Assertion `num_lwps (GET_PID (inferior_ptid)) == 1' failed.
7b26da
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7b26da
7b26da
The assertion is just a consequence.
7b26da
7b26da
So the main fix is to backport the GDB [1] bits of upstream 23f238d3
7b26da
(Fix race exposed by gdb.threads/killed.exp).  That makes
7b26da
linux_resume_one_lwp detect when the LWP being resumed disappears.
7b26da
However, we need to backport also part of 8a99810d (linux-nat.c: clean
7b26da
up pending status checking and resuming LWPs), which is what
7b26da
introduced the centralized linux_resume_one_lwp in the first place,
7b26da
and also one bit from 8817a6f2 (PR gdb/15713 - errors from
7b26da
i386_linux_resume lead to lock-up), which makes linux_nat_resume not
7b26da
clear the leader LWP's lwp->stopped flag too early, otherwise we'd hit
7b26da
the new assertion in check_ptrace_stopped_lwp_gone.
7b26da
7b26da
The test is new (not a backport), and without the fix triggers the
7b26da
"detach" assertion shown above.
7b26da
7b26da
[1] - The equivalent GDBserver bits are harder to backport, as they
7b26da
rely on GDB exceptions, which GDBserver 7.6.1 doesn't support yet.
7b26da
Fortunately, GDBserver already handles ESRCH from within its
7b26da
linux_resume_one_lwp, so doesn't trigger this particular bug and
7b26da
passes the test.
7b26da
7b26da
gdb/ChangeLog:
7b26da
2015-06-17  Pedro Alves  <palves@redhat.com>
7b26da
7b26da
	* common/linux-procfs.c (linux_proc_pid_is_trace_stopped): New
7b26da
	function.
7b26da
	* common/linux-procfs.h (linux_proc_pid_is_trace_stopped): New
7b26da
	declaration.
7b26da
	* linux-nat.c (linux_resume_one_lwp_throw, check_ptrace_stopped_lwp_gone)
7b26da
	(linux_resume_one_lwp): New functions.
7b26da
	(resume_lwp): Use linux_resume_one_lwp.
7b26da
	(linux_nat_resume_callback): Skip if LWP is the same as the passed
7b26da
	in data pointer.
7b26da
	(linux_nat_resume): Don't clear the selected LWP's stopped flag
7b26da
	before resuming the sibling LWPs.  Instead pass LWP to
7b26da
	linux_nat_resume_callback.  Use linux_resume_one_lwp.
7b26da
	(linux_handle_extended_wait, linux_nat_filter_event)
7b26da
	(linux_nat_wait_1): Use linux_resume_one_lwp.
7b26da
	(resume_stopped_resumed_lwps): Try register reads in TRY/CATCH and
7b26da
	swallows errors if the LWP is gone.  Use
7b26da
	linux_resume_one_lwp_throw instead of linux_resume_one_lwp.
7b26da
7b26da
gdb/testsuite/ChangeLog:
7b26da
2015-06-17  Pedro Alves  <palves@redhat.com>
7b26da
7b26da
	* gdb.threads/thread-kills-process.c: New file.
7b26da
	* gdb.threads/thread-kills-process.exp: New file.
7b26da
---
7b26da
 gdb/ChangeLog                                      |  13 ++
7b26da
 gdb/common/linux-procfs.c                          |   6 +
7b26da
 gdb/common/linux-procfs.h                          |   2 +
7b26da
 gdb/linux-nat.c                                    | 200 +++++++++++++--------
7b26da
 gdb/testsuite/gdb.threads/thread-kills-process.c   |  62 +++++++
7b26da
 gdb/testsuite/gdb.threads/thread-kills-process.exp |  70 ++++++++
7b26da
 6 files changed, 277 insertions(+), 76 deletions(-)
7b26da
 create mode 100644 gdb/testsuite/gdb.threads/thread-kills-process.c
7b26da
 create mode 100644 gdb/testsuite/gdb.threads/thread-kills-process.exp
7b26da
7b26da
Index: gdb-7.6.1/gdb/common/linux-procfs.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/common/linux-procfs.c
7b26da
+++ gdb-7.6.1/gdb/common/linux-procfs.c
7b26da
@@ -111,6 +111,12 @@ linux_proc_pid_is_stopped (pid_t pid)
7b26da
   return linux_proc_pid_has_state (pid, "T (stopped)");
7b26da
 }
7b26da
 
7b26da
+int
7b26da
+linux_proc_pid_is_trace_stopped (pid_t pid)
7b26da
+{
7b26da
+  return linux_proc_pid_has_state (pid, "T (tracing stop)");
7b26da
+}
7b26da
+
7b26da
 /* See linux-procfs.h declaration.  */
7b26da
 
7b26da
 int
7b26da
Index: gdb-7.6.1/gdb/common/linux-procfs.h
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/common/linux-procfs.h
7b26da
+++ gdb-7.6.1/gdb/common/linux-procfs.h
7b26da
@@ -36,6 +36,8 @@ extern pid_t linux_proc_get_tracerpid (p
7b26da
 
7b26da
 extern int linux_proc_pid_is_stopped (pid_t pid);
7b26da
 
7b26da
+extern int linux_proc_pid_is_trace_stopped (pid_t pid);
7b26da
+
7b26da
 /* Return non-zero if PID is a zombie.  */
7b26da
 
7b26da
 extern int linux_proc_pid_is_zombie (pid_t pid);
7b26da
Index: gdb-7.6.1/gdb/linux-nat.c
7b26da
===================================================================
7b26da
--- gdb-7.6.1.orig/gdb/linux-nat.c
7b26da
+++ gdb-7.6.1/gdb/linux-nat.c
7b26da
@@ -1928,6 +1928,85 @@ linux_nat_detach (struct target_ops *ops
7b26da
     linux_ops->to_detach (ops, args, from_tty);
7b26da
 }
7b26da
 
7b26da
+/* Resume execution of the inferior process.  If STEP is nonzero,
7b26da
+   single-step it.  If SIGNAL is nonzero, give it that signal.  */
7b26da
+
7b26da
+static void
7b26da
+linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
7b26da
+			    enum gdb_signal signo)
7b26da
+{
7b26da
+  ptid_t ptid;
7b26da
+
7b26da
+  lp->step = step;
7b26da
+
7b26da
+  if (linux_nat_prepare_to_resume != NULL)
7b26da
+    linux_nat_prepare_to_resume (lp);
7b26da
+
7b26da
+  ptid = pid_to_ptid (GET_LWP (lp->ptid));
7b26da
+  linux_ops->to_resume (linux_ops, ptid, step, signo);
7b26da
+
7b26da
+  /* Successfully resumed.  Clear state that no longer makes sense,
7b26da
+     and mark the LWP as running.  Must not do this before resuming
7b26da
+     otherwise if that fails other code will be confused.  E.g., we'd
7b26da
+     later try to stop the LWP and hang forever waiting for a stop
7b26da
+     status.  Note that we must not throw after this is cleared,
7b26da
+     otherwise handle_zombie_lwp_error would get confused.  */
7b26da
+  lp->stopped = 0;
7b26da
+  lp->stopped_by_watchpoint = 0;
7b26da
+  registers_changed_ptid (lp->ptid);
7b26da
+}
7b26da
+
7b26da
+/* Called when we try to resume a stopped LWP and that errors out.  If
7b26da
+   the LWP is no longer in ptrace-stopped state (meaning it's zombie,
7b26da
+   or about to become), discard the error, clear any pending status
7b26da
+   the LWP may have, and return true (we'll collect the exit status
7b26da
+   soon enough).  Otherwise, return false.  */
7b26da
+
7b26da
+static int
7b26da
+check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
7b26da
+{
7b26da
+  /* If we get an error after resuming the LWP successfully, we'd
7b26da
+     confuse !T state for the LWP being gone.  */
7b26da
+  gdb_assert (lp->stopped);
7b26da
+
7b26da
+  /* We can't just check whether the LWP is in 'Z (Zombie)' state,
7b26da
+     because even if ptrace failed with ESRCH, the tracee may be "not
7b26da
+     yet fully dead", but already refusing ptrace requests.  In that
7b26da
+     case the tracee has 'R (Running)' state for a little bit
7b26da
+     (observed in Linux 3.18).  See also the note on ESRCH in the
7b26da
+     ptrace(2) man page.  Instead, check whether the LWP has any state
7b26da
+     other than ptrace-stopped.  */
7b26da
+
7b26da
+  /* Don't assume anything if /proc/PID/status can't be read.  */
7b26da
+  if (linux_proc_pid_is_trace_stopped (ptid_get_lwp (lp->ptid)) == 0)
7b26da
+    {
7b26da
+      lp->status = 0;
7b26da
+      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
7b26da
+      lp->stopped_by_watchpoint = 0;
7b26da
+      return 1;
7b26da
+    }
7b26da
+  return 0;
7b26da
+}
7b26da
+
7b26da
+/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP
7b26da
+   disappears while we try to resume it.  */
7b26da
+
7b26da
+static void
7b26da
+linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
7b26da
+{
7b26da
+  volatile struct gdb_exception ex;
7b26da
+
7b26da
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
7b26da
+    {
7b26da
+      linux_resume_one_lwp_throw (lp, step, signo);
7b26da
+    }
7b26da
+  if (ex.reason < 0)
7b26da
+    {
7b26da
+      if (!check_ptrace_stopped_lwp_gone (lp))
7b26da
+	throw_exception (ex);
7b26da
+    }
7b26da
+}
7b26da
+
7b26da
 /* Resume LP.  */
7b26da
 
7b26da
 static void
7b26da
@@ -1956,14 +2035,7 @@ resume_lwp (struct lwp_info *lp, int ste
7b26da
 				 : "0"),
7b26da
 				step ? "step" : "resume");
7b26da
 
7b26da
-	  if (linux_nat_prepare_to_resume != NULL)
7b26da
-	    linux_nat_prepare_to_resume (lp);
7b26da
-	  linux_ops->to_resume (linux_ops,
7b26da
-				pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-				step, signo);
7b26da
-	  lp->stopped = 0;
7b26da
-	  lp->step = step;
7b26da
-	  lp->stopped_by_watchpoint = 0;
7b26da
+	  linux_resume_one_lwp (lp, step, signo);
7b26da
 	}
7b26da
       else
7b26da
 	{
7b26da
@@ -1982,13 +2054,17 @@ resume_lwp (struct lwp_info *lp, int ste
7b26da
     }
7b26da
 }
7b26da
 
7b26da
-/* Resume LWP, with the last stop signal, if it is in pass state.  */
7b26da
+/* Callback for iterate_over_lwps.  If LWP is EXCEPT, do nothing.
7b26da
+   Resume LWP with the last stop signal, if it is in pass state.  */
7b26da
 
7b26da
 static int
7b26da
-linux_nat_resume_callback (struct lwp_info *lp, void *data)
7b26da
+linux_nat_resume_callback (struct lwp_info *lp, void *except)
7b26da
 {
7b26da
   enum gdb_signal signo = GDB_SIGNAL_0;
7b26da
 
7b26da
+  if (lp == except)
7b26da
+    return 0;
7b26da
+
7b26da
   if (lp->stopped)
7b26da
     {
7b26da
       struct thread_info *thread;
7b26da
@@ -2108,20 +2184,10 @@ linux_nat_resume (struct target_ops *ops
7b26da
       return;
7b26da
     }
7b26da
 
7b26da
-  /* Mark LWP as not stopped to prevent it from being continued by
7b26da
-     linux_nat_resume_callback.  */
7b26da
-  lp->stopped = 0;
7b26da
-
7b26da
   if (resume_many)
7b26da
-    iterate_over_lwps (ptid, linux_nat_resume_callback, NULL);
7b26da
+    iterate_over_lwps (ptid, linux_nat_resume_callback, lp);
7b26da
 
7b26da
-  /* Convert to something the lower layer understands.  */
7b26da
-  ptid = pid_to_ptid (GET_LWP (lp->ptid));
7b26da
-
7b26da
-  if (linux_nat_prepare_to_resume != NULL)
7b26da
-    linux_nat_prepare_to_resume (lp);
7b26da
-  linux_ops->to_resume (linux_ops, ptid, step, signo);
7b26da
-  lp->stopped_by_watchpoint = 0;
7b26da
+  linux_resume_one_lwp (lp, step, signo);
7b26da
 
7b26da
   if (debug_linux_nat)
7b26da
     fprintf_unfiltered (gdb_stdlog,
7b26da
@@ -2287,11 +2353,7 @@ linux_handle_syscall_trap (struct lwp_in
7b26da
 
7b26da
   /* Note that gdbarch_get_syscall_number may access registers, hence
7b26da
      fill a regcache.  */
7b26da
-  registers_changed ();
7b26da
-  if (linux_nat_prepare_to_resume != NULL)
7b26da
-    linux_nat_prepare_to_resume (lp);
7b26da
-  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-			lp->step, GDB_SIGNAL_0);
7b26da
+  linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
7b26da
   return 1;
7b26da
 }
7b26da
 
7b26da
@@ -2486,22 +2548,15 @@ linux_handle_extended_wait (struct lwp_i
7b26da
 		    fprintf_unfiltered (gdb_stdlog,
7b26da
 					"LHEW: resuming new LWP %ld\n",
7b26da
 					GET_LWP (new_lp->ptid));
7b26da
-		  if (linux_nat_prepare_to_resume != NULL)
7b26da
-		    linux_nat_prepare_to_resume (new_lp);
7b26da
-		  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
7b26da
-					0, GDB_SIGNAL_0);
7b26da
-		  new_lp->stopped = 0;
7b26da
+
7b26da
+		  linux_resume_one_lwp (new_lp, 0, GDB_SIGNAL_0);
7b26da
 		}
7b26da
 	    }
7b26da
 
7b26da
 	  if (debug_linux_nat)
7b26da
 	    fprintf_unfiltered (gdb_stdlog,
7b26da
 				"LHEW: resuming parent LWP %d\n", pid);
7b26da
-	  if (linux_nat_prepare_to_resume != NULL)
7b26da
-	    linux_nat_prepare_to_resume (lp);
7b26da
-	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-				0, GDB_SIGNAL_0);
7b26da
-
7b26da
+	  linux_resume_one_lwp (lp, 0, GDB_SIGNAL_0);
7b26da
 	  return 1;
7b26da
 	}
7b26da
 
7b26da
@@ -3382,12 +3437,7 @@ linux_nat_filter_event (int lwpid, int s
7b26da
 	{
7b26da
 	  /* This is a delayed SIGSTOP.  */
7b26da
 
7b26da
-	  registers_changed ();
7b26da
-
7b26da
-	  if (linux_nat_prepare_to_resume != NULL)
7b26da
-	    linux_nat_prepare_to_resume (lp);
7b26da
-	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-			    lp->step, GDB_SIGNAL_0);
7b26da
+	  linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
7b26da
 	  if (debug_linux_nat)
7b26da
 	    fprintf_unfiltered (gdb_stdlog,
7b26da
 				"LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
7b26da
@@ -3395,7 +3445,6 @@ linux_nat_filter_event (int lwpid, int s
7b26da
 				"PTRACE_SINGLESTEP" : "PTRACE_CONT",
7b26da
 				target_pid_to_str (lp->ptid));
7b26da
 
7b26da
-	  lp->stopped = 0;
7b26da
 	  gdb_assert (lp->resumed);
7b26da
 
7b26da
 	  /* Discard the event.  */
7b26da
@@ -3416,11 +3465,7 @@ linux_nat_filter_event (int lwpid, int s
7b26da
       /* This is a delayed SIGINT.  */
7b26da
       lp->ignore_sigint = 0;
7b26da
 
7b26da
-      registers_changed ();
7b26da
-      if (linux_nat_prepare_to_resume != NULL)
7b26da
-	linux_nat_prepare_to_resume (lp);
7b26da
-      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-			    lp->step, GDB_SIGNAL_0);
7b26da
+      linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
7b26da
       if (debug_linux_nat)
7b26da
 	fprintf_unfiltered (gdb_stdlog,
7b26da
 			    "LLW: %s %s, 0, 0 (discard SIGINT)\n",
7b26da
@@ -3428,7 +3473,6 @@ linux_nat_filter_event (int lwpid, int s
7b26da
 			    "PTRACE_SINGLESTEP" : "PTRACE_CONT",
7b26da
 			    target_pid_to_str (lp->ptid));
7b26da
 
7b26da
-      lp->stopped = 0;
7b26da
       gdb_assert (lp->resumed);
7b26da
 
7b26da
       /* Discard the event.  */
7b26da
@@ -3796,11 +3840,7 @@ retry:
7b26da
 	     other threads to run.  On the other hand, not resuming
7b26da
 	     newly attached threads may cause an unwanted delay in
7b26da
 	     getting them running.  */
7b26da
-	  registers_changed ();
7b26da
-	  if (linux_nat_prepare_to_resume != NULL)
7b26da
-	    linux_nat_prepare_to_resume (lp);
7b26da
-	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-				lp->step, signo);
7b26da
+	  linux_resume_one_lwp (lp, lp->step, signo);
7b26da
 	  if (debug_linux_nat)
7b26da
 	    fprintf_unfiltered (gdb_stdlog,
7b26da
 				"LLW: %s %s, %s (preempt 'handle')\n",
7b26da
@@ -3810,7 +3850,6 @@ retry:
7b26da
 				(signo != GDB_SIGNAL_0
7b26da
 				 ? strsignal (gdb_signal_to_host (signo))
7b26da
 				 : "0"));
7b26da
-	  lp->stopped = 0;
7b26da
 	  goto retry;
7b26da
 	}
7b26da
 
7b26da
@@ -3935,32 +3974,41 @@ resume_stopped_resumed_lwps (struct lwp_
7b26da
     {
7b26da
       struct regcache *regcache = get_thread_regcache (lp->ptid);
7b26da
       struct gdbarch *gdbarch = get_regcache_arch (regcache);
7b26da
-      CORE_ADDR pc = regcache_read_pc (regcache);
7b26da
+      volatile struct gdb_exception ex;
7b26da
 
7b26da
       gdb_assert (is_executing (lp->ptid));
7b26da
 
7b26da
-      /* Don't bother if there's a breakpoint at PC that we'd hit
7b26da
-	 immediately, and we're not waiting for this LWP.  */
7b26da
-      if (!ptid_match (lp->ptid, *wait_ptid_p))
7b26da
+      TRY_CATCH (ex, RETURN_MASK_ERROR)
7b26da
 	{
7b26da
-	  if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
7b26da
-	    return 0;
7b26da
-	}
7b26da
+	  CORE_ADDR pc = regcache_read_pc (regcache);
7b26da
+	  int leave_stopped = 0;
7b26da
 
7b26da
-      if (debug_linux_nat)
7b26da
-	fprintf_unfiltered (gdb_stdlog,
7b26da
-			    "RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
7b26da
-			    target_pid_to_str (lp->ptid),
7b26da
-			    paddress (gdbarch, pc),
7b26da
-			    lp->step);
7b26da
+	  /* Don't bother if there's a breakpoint at PC that we'd hit
7b26da
+	     immediately, and we're not waiting for this LWP.  */
7b26da
+	  if (!ptid_match (lp->ptid, *wait_ptid_p))
7b26da
+	    {
7b26da
+	      if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
7b26da
+		leave_stopped = 1;
7b26da
+	    }
7b26da
 
7b26da
-      registers_changed ();
7b26da
-      if (linux_nat_prepare_to_resume != NULL)
7b26da
-	linux_nat_prepare_to_resume (lp);
7b26da
-      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
7b26da
-			    lp->step, GDB_SIGNAL_0);
7b26da
-      lp->stopped = 0;
7b26da
-      lp->stopped_by_watchpoint = 0;
7b26da
+	  if (!leave_stopped)
7b26da
+	    {
7b26da
+	      if (debug_linux_nat)
7b26da
+		fprintf_unfiltered (gdb_stdlog,
7b26da
+				    "RSRL: resuming stopped-resumed LWP %s at "
7b26da
+				    "%s: step=%d\n",
7b26da
+				    target_pid_to_str (lp->ptid),
7b26da
+				    paddress (gdbarch, pc),
7b26da
+				    lp->step);
7b26da
+
7b26da
+	      linux_resume_one_lwp_throw (lp, lp->step, GDB_SIGNAL_0);
7b26da
+	    }
7b26da
+	}
7b26da
+      if (ex.reason < 0)
7b26da
+	{
7b26da
+	  if (!check_ptrace_stopped_lwp_gone (lp))
7b26da
+	    throw_exception (ex);
7b26da
+	}
7b26da
     }
7b26da
 
7b26da
   return 0;
7b26da
Index: gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.c
7b26da
===================================================================
7b26da
--- /dev/null
7b26da
+++ gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.c
7b26da
@@ -0,0 +1,62 @@
7b26da
+/* Copyright 2015 Free Software Foundation, Inc.
7b26da
+
7b26da
+   This file is part of GDB.
7b26da
+
7b26da
+   This program is free software; you can redistribute it and/or modify
7b26da
+   it under the terms of the GNU General Public License as published by
7b26da
+   the Free Software Foundation; either version 3 of the License, or
7b26da
+   (at your option) any later version.
7b26da
+
7b26da
+   This program is distributed in the hope that it will be useful,
7b26da
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
7b26da
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7b26da
+   GNU General Public License for more details.
7b26da
+
7b26da
+   You should have received a copy of the GNU General Public License
7b26da
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
7b26da
+
7b26da
+#include <pthread.h>
7b26da
+#include <unistd.h>
7b26da
+
7b26da
+volatile int call_exit;
7b26da
+static pthread_barrier_t barrier;
7b26da
+#define NUMTHREADS 256
7b26da
+
7b26da
+void *
7b26da
+thread_function (void *arg)
7b26da
+{
7b26da
+  pthread_barrier_wait (&barrier);
7b26da
+
7b26da
+  while (!call_exit)
7b26da
+    usleep (1);
7b26da
+
7b26da
+  _exit (0);
7b26da
+  return NULL;
7b26da
+}
7b26da
+
7b26da
+void
7b26da
+all_threads_started (void)
7b26da
+{
7b26da
+  call_exit = 1;
7b26da
+}
7b26da
+
7b26da
+int
7b26da
+main (int argc, char **argv)
7b26da
+{
7b26da
+  pthread_t threads[NUMTHREADS];
7b26da
+  int i;
7b26da
+
7b26da
+  pthread_barrier_init (&barrier, NULL, NUMTHREADS + 1);
7b26da
+
7b26da
+  for (i = 0; i < NUMTHREADS; ++i)
7b26da
+    pthread_create (&threads[i], NULL, thread_function, NULL);
7b26da
+
7b26da
+  pthread_barrier_wait (&barrier);
7b26da
+
7b26da
+  all_threads_started ();
7b26da
+
7b26da
+  for (i = 0; i < NUMTHREADS; ++i)
7b26da
+    pthread_join (threads[i], NULL);
7b26da
+
7b26da
+  return 0;
7b26da
+}
7b26da
Index: gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.exp
7b26da
===================================================================
7b26da
--- /dev/null
7b26da
+++ gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.exp
7b26da
@@ -0,0 +1,70 @@
7b26da
+# Copyright (C) 2015 Free Software Foundation, Inc.
7b26da
+
7b26da
+# This program is free software; you can redistribute it and/or modify
7b26da
+# it under the terms of the GNU General Public License as published by
7b26da
+# the Free Software Foundation; either version 3 of the License, or
7b26da
+# (at your option) any later version.
7b26da
+#
7b26da
+# This program is distributed in the hope that it will be useful,
7b26da
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
7b26da
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7b26da
+# GNU General Public License for more details.
7b26da
+#
7b26da
+# You should have received a copy of the GNU General Public License
7b26da
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
7b26da
+
7b26da
+standard_testfile
7b26da
+
7b26da
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
7b26da
+    return -1
7b26da
+}
7b26da
+
7b26da
+clean_restart ${binfile}
7b26da
+if {![runto_main]} {
7b26da
+    fail "Couldn't run to main"
7b26da
+    return
7b26da
+}
7b26da
+
7b26da
+gdb_breakpoint "all_threads_started"
7b26da
+
7b26da
+gdb_continue_to_breakpoint "all_threads_started"
7b26da
+
7b26da
+# Update the thread list, otherwise when testing against GDBserver,
7b26da
+# GDB won't know about thread 2.  (Only necessary with GDB < 7.9.)
7b26da
+gdb_test "info threads" ".*"
7b26da
+
7b26da
+# Select any thread but the leader.
7b26da
+gdb_test "thread 2" ".*" "switch to non-leader thread"
7b26da
+
7b26da
+# Delete breakpoints so that GDB doesn't switch back the to leader to
7b26da
+# step over its breakpoint.
7b26da
+delete_breakpoints
7b26da
+
7b26da
+# Let threads exit the process on next resume.
7b26da
+gdb_test "p call_exit = 0" " = 0"
7b26da
+
7b26da
+# While GDB is busy resuming all threads one by one, one of the
7b26da
+# threads should manage to exit the process.  GDB should handle that
7b26da
+# gracefully instead of erroring out.
7b26da
+#
7b26da
+# gdb_continue_to_end doesn't work with GDBserver until the
7b26da
+# introduction of the "exit_is_reliable" board variable
7b26da
+# (b477a5e649150) in GDB 7.7.
7b26da
+#gdb_continue_to_end "" continue 1
7b26da
+gdb_test "continue" "$inferior_exited_re normally.*"
7b26da
+
7b26da
+# On the buggy GDB where the "continue" above would error out, a
7b26da
+# subsequent "detach" (e.g., the user tries to quit GDB, and quit
7b26da
+# offers to detach) would hit this assertion:
7b26da
+#
7b26da
+#   linux-nat.c:1869: internal-error: linux_nat_detach: Assertion `num_lwps (GET_PID (inferior_ptid)) == 1' failed.
7b26da
+
7b26da
+# That was a consequence of the original bug, but let's make sure that
7b26da
+# even when "continue" is handled properly, detach doesn't stumble on
7b26da
+# anything stale.
7b26da
+gdb_test "detach" "The program is not being run\\." \
7b26da
+    "detach after exit"
7b26da
+
7b26da
+# Likewise "continue".
7b26da
+gdb_test "continue" "The program is not being run\\." \
7b26da
+    "continue after exit"