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]

This a couple problems around PTRACE_EVENT_CLONE handling of signals in the new clone


This fixes two problems around PTRACE_EVENT_CLONE handling of
signals in the new clone.

 - if some other signal != SIGSTOP comes out first on the new
   clone (because a signal with a number < SIGSTOP was pending,
   and the LWP dequeued it), we're currently just passing it on
   to the inferior.  GDBserver will need fixing too, and even
   has a comment to that effect:

	    /* Pass the signal on.  This is what GDB does - except
	       shouldn't we really report it instead?  */

 - It's possible for the core to see the new thread/lwp, and
   ask it to stop, queueing it a SIGSTOP, before we
   have a chance of handling the PTHREAD_EVENT_CLONE event.
   (e.g., non-stop; info threads; interrupt -a; while threads 
   are spawning) (see comment in patch).  In that case, we'd
   always resume the new thread, while the core would forever
   expect it to report a stop.  I trigger this more easily with
   some later patches that make the core stop all threads, rather
   than the target.

Tested on x86_64-linux, and applied.

-- 
Pedro Alves

2011-10-10  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* linux-nat.c (linux_handle_extended_wait): Don't resume the new
	new clone lwp if the core asked it to stop.  Don't pass on
	unexpected signals to the new clone; leave them pending instead.

---
 gdb/linux-nat.c |   64 +++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 43 insertions(+), 21 deletions(-)

Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c	2011-10-10 15:46:31.967659200 +0100
+++ src/gdb/linux-nat.c	2011-10-10 15:50:45.637659153 +0100
@@ -2237,7 +2237,29 @@ linux_handle_extended_wait (struct lwp_i
 	      new_lp->signalled = 1;
 	    }
 	  else
-	    status = 0;
+	    {
+	      struct thread_info *tp;
+
+	      /* When we stop for an event in some other thread, and
+		 pull the thread list just as this thread has cloned,
+		 we'll have seen the new thread in the thread_db list
+		 before handling the CLONE event (glibc's
+		 pthread_create adds the new thread to the thread list
+		 before clone'ing, and has the kernel fill in the
+		 thread's tid on the clone call with
+		 CLONE_PARENT_SETTID).  If that happened, and the core
+		 had requested the new thread to stop, we'll have
+		 killed it with SIGSTOP.  But since SIGSTOP is not an
+		 RT signal, it can only be queued once.  We need to be
+		 careful to not resume the LWP if we wanted it to
+		 stop.  In that case, we'll leave the SIGSTOP pending.
+		 It will later be reported as TARGET_SIGNAL_0.  */
+	      tp = find_thread_ptid (new_lp->ptid);
+	      if (tp != NULL && tp->stop_requested)
+		new_lp->last_resume_kind = resume_stop;
+	      else
+		status = 0;
+	    }
 
 	  if (non_stop)
 	    {
@@ -2266,39 +2288,39 @@ linux_handle_extended_wait (struct lwp_i
 		}
 	    }
 
+	  if (status != 0)
+	    {
+	      /* We created NEW_LP so it cannot yet contain STATUS.  */
+	      gdb_assert (new_lp->status == 0);
+
+	      /* Save the wait status to report later.  */
+	      if (debug_linux_nat)
+		fprintf_unfiltered (gdb_stdlog,
+				    "LHEW: waitpid of new LWP %ld, "
+				    "saving status %s\n",
+				    (long) GET_LWP (new_lp->ptid),
+				    status_to_str (status));
+	      new_lp->status = status;
+	    }
+
 	  /* Note the need to use the low target ops to resume, to
 	     handle resuming with PT_SYSCALL if we have syscall
 	     catchpoints.  */
 	  if (!stopping)
 	    {
-	      enum target_signal signo;
-
-	      new_lp->stopped = 0;
 	      new_lp->resumed = 1;
-	      new_lp->last_resume_kind = resume_continue;
-
-	      signo = (status
-		       ? target_signal_from_host (WSTOPSIG (status))
-		       : TARGET_SIGNAL_0);
 
-	      linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
-				    0, signo);
-	    }
-	  else
-	    {
-	      if (status != 0)
+	      if (status == 0)
 		{
-		  /* We created NEW_LP so it cannot yet contain STATUS.  */
-		  gdb_assert (new_lp->status == 0);
-
-		  /* Save the wait status to report later.  */
 		  if (debug_linux_nat)
 		    fprintf_unfiltered (gdb_stdlog,
 					"LHEW: waitpid of new LWP %ld, "
-					"saving status %s\n",
+					"resuming %s\n",
 					(long) GET_LWP (new_lp->ptid),
 					status_to_str (status));
-		  new_lp->status = status;
+		  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
+					0, TARGET_SIGNAL_0);
+		  new_lp->stopped = 0;
 		}
 	    }
 


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