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

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