Fixed SIGALRM race.
[debugger.git] / testsuite.c
index 9fa2a64..76a3d09 100644 (file)
 #define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig))
 
 
+static void detach_checked (struct attach_state_struct *attach_state)
+{
+  pid_t pid = attach_state_pid_get (attach_state);
+
+  if (attach_state_stopped_get (attach_state) != 0)
+    {
+      STATE (pid, 1 << STATE_STOPPED);
+      detach (attach_state);
+      STATE (pid, 1 << STATE_STOPPED);
+    }
+  else
+    {
+      STATE (pid, (1 << STATE_PTRACED));
+      detach (attach_state);
+      STATE (pid, ((1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
+    }
+}
+
 static volatile int spawned_threads_count;     /* Set for the specific spawner.  */
 
 static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect)
@@ -47,39 +65,25 @@ static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_ex
                   attach_state_redelivered_get (attach_state));
          abort ();
        }
-      if (attach_state_threads_count_get (attach_state)
-         == spawned_threads_count)
-        break;
       /* During the inferior's initialization we may catch less threads.  */
       assert (attach_state_threads_count_get (attach_state)
-             < spawned_threads_count);
+             <= spawned_threads_count);
+      if (attach_state_threads_count_get (attach_state)
+         == spawned_threads_count
+         /* Inferior may got stopped before it could initialize.  */
+         || attach_state_stopped_get (attach_state) == 1)
+       {
+         /* FIXME: Why also STATE_STOPPED?  */
+         STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
+         return attach_state;
+       }
       /* WARNING: Currently we never use REDELIVERED_EXPECT but we would have to
          probably reset it back to 0 otherwise.  */
       assert (redelivered_expect == 0);
+      detach_checked (attach_state);
     }
   while (loops++ < LOOPS_MIN || time (NULL) < timeout);
-
-  /* FIXME: Why also STATE_STOPPED?  */
-  STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
-  return attach_state;
-}
-
-static void detach_checked (struct attach_state_struct *attach_state)
-{
-  pid_t pid = attach_state_pid_get (attach_state);
-
-  if (attach_state_stopped_get (attach_state) != 0)
-    {
-      STATE (pid, 1 << STATE_STOPPED);
-      detach (attach_state);
-      STATE (pid, 1 << STATE_STOPPED);
-    }
-  else
-    {
-      STATE (pid, (1 << STATE_PTRACED));
-      detach (attach_state);
-      STATE (pid, ((1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
-    }
+  abort ();
 }
 
 struct registry
@@ -175,14 +179,12 @@ static void child_alrm_handler (int signo)
 
 static __attribute__((__noreturn__)) void child_alrm (void)
 {
-  void (*handler_orig) (int signo);
 #if 0
   int i;
   sigset_t oldset;
 #endif
 
-  handler_orig = signal (SIGALRM, child_alrm_handler);
-  assert (handler_orig == SIG_DFL);
+  /* Assumed already setup SIGALRM for CHILD_ALRM_HANDLER.  */
 
 #if 0
   i = sigprocmask (SIG_BLOCK, NULL, &oldset);
@@ -339,6 +341,7 @@ static void body_spawner (void *(*child) (void *data, void *input), void *data,
   pid_t inferior;
   struct attach_state_struct *attach_state;
   int i;
+  void (*handler_orig) (int signo);
 
   assert (input == NULL);
 
@@ -372,7 +375,12 @@ static void body_spawner (void *(*child) (void *data, void *input), void *data,
   murder (inferior);
 
   /* Attach to a stopped process with already pending SIGALRM.  */
+  /* Setup the handler already in the parent to avoid the child race.  */
+  handler_orig = signal (SIGALRM, child_alrm_handler);
+  assert (handler_orig == SIG_DFL);
   inferior = (unsigned long) (*child) (data, child_alrm);
+  handler_orig = signal (SIGALRM, handler_orig);
+  assert (handler_orig == child_alrm_handler);
   STATE (inferior, 1 << STATE_SLEEPING);
   delay ();
   i = tkill (inferior, SIGSTOP);