[2/3] PR remote/19496, interrupted syscall in forking-threads-plus-bkpt

Message ID 1453942111-1215-3-git-send-email-donb@codesourcery.com
State New, archived
Headers

Commit Message

Don Breazeal Jan. 28, 2016, 12:48 a.m. UTC
  This patch addresses "fork:Interrupted system call" (or wait:) failures
in gdb.threads/forking-threads-plus-breakpoint.exp.

The test program spawns ten threads, each of which do ten fork/waitpid
sequences.  The cause of the problem was that when one of the fork
children exited before the corresponding fork parent could initiate its
waitpid for that child, a SIGCHLD was delivered and interrupted a fork
or waitpid in another thread.

The fix was to wrap the system calls in a loop to retry the call if
it was interrupted, like:

do
  {
    pid = fork ();
  }
while (pid == -1 && errno == EINTR);

Since this is a Linux-only test I figure it is OK to use errno and EINTR.

Tested on Nios II Linux target with x86 Linux host.

Thanks,
--Don

gdb/testsuite/ChangeLog:
2016-01-27  Don Breazeal  <donb@codesourcery.com>

	PR remote/19496
	* gdb.threads/forking-threads-plus-breakpoint.c (thread_forks):
	Retry fork and waitpid on interrupted system call errors.

---
 .../gdb.threads/forking-threads-plus-breakpoint.c  |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)
  

Comments

Pedro Alves Feb. 1, 2016, 7:38 p.m. UTC | #1
On 01/28/2016 12:48 AM, Don Breazeal wrote:
> This patch addresses "fork:Interrupted system call" (or wait:) failures
> in gdb.threads/forking-threads-plus-breakpoint.exp.
> 
> The test program spawns ten threads, each of which do ten fork/waitpid
> sequences.  The cause of the problem was that when one of the fork
> children exited before the corresponding fork parent could initiate its
> waitpid for that child, a SIGCHLD was delivered and interrupted a fork
> or waitpid in another thread.
> 
> The fix was to wrap the system calls in a loop to retry the call if
> it was interrupted, like:
> 
> do
>   {
>     pid = fork ();
>   }
> while (pid == -1 && errno == EINTR);
> 
> Since this is a Linux-only test I figure it is OK to use errno and EINTR.
> 
> Tested on Nios II Linux target with x86 Linux host.

I'd prefer to avoid this if possible.  These loops potentially hide
bugs like ERESTARTSYS escaping out of a syscall and mishandling of
signals.  See bc9540e842eb5639ca59cb133adef211d252843c for example:
   https://sourceware.org/ml/gdb-patches/2015-02/msg00654.html

How about setting SIGCHLD to SIG_IGN, or making SIGCHLD be SA_RESTART?

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c b/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c
index fc64d93..c169e18 100644
--- a/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c
+++ b/gdb/testsuite/gdb.threads/forking-threads-plus-breakpoint.c
@@ -22,6 +22,7 @@ 
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <stdlib.h>
+#include <errno.h>
 
 /* Number of threads.  Each thread continuously spawns a fork and wait
    for it.  If we have another thread continuously start a step over,
@@ -49,14 +50,23 @@  thread_forks (void *arg)
     {
       pid_t pid;
 
-      pid = fork ();
+      do
+	{
+	  pid = fork ();
+	}
+      while (pid == -1 && errno == EINTR);
 
       if (pid > 0)
 	{
 	  int status;
 
 	  /* Parent.  */
-	  pid = waitpid (pid, &status, 0);
+	  do
+	    {
+	      pid = waitpid (pid, &status, 0);
+	    }
+	  while (pid == -1 && errno == EINTR);
+
 	  if (pid == -1)
 	    {
 	      perror ("wait");