inf-ptrace: Support async targets in inf_ptrace_target::wait.
authorJohn Baldwin <jhb@FreeBSD.org>
Tue, 22 Feb 2022 19:22:14 +0000 (11:22 -0800)
committerJohn Baldwin <jhb@FreeBSD.org>
Tue, 22 Feb 2022 19:22:14 +0000 (11:22 -0800)
- Handle TARGET_WNOHANG by passing WNOHANG to waitpid and returning
  TARGET_WAITKIND_IGNORE if there are no events to report.

- Handle a race in async mode where SIGCHLD might signal the event
  pipe for an event that has already been reported.  If the event was
  the exit of the last child process, waitpid() will fail with ECHILD
  rather than returning a pid of 0.  For this case, return
  TARGET_WAITKIND_NO_RESUMED.

gdb/inf-ptrace.c

index 0b94aad54d7d9013928dbc5b639cdb1925c19d9b..ebcc409b989ce31ff70fe8dcf46e15e1fa94661c 100644 (file)
@@ -289,10 +289,14 @@ inf_ptrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
 
 ptid_t
 inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
-                        target_wait_flags options)
+                        target_wait_flags target_options)
 {
   pid_t pid;
-  int status, save_errno;
+  int options, status, save_errno;
+
+  options = 0;
+  if (target_options & TARGET_WNOHANG)
+    options |= WNOHANG;
 
   do
     {
@@ -300,15 +304,32 @@ inf_ptrace_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus,
 
       do
        {
-         pid = waitpid (ptid.pid (), &status, 0);
+         pid = waitpid (ptid.pid (), &status, options);
          save_errno = errno;
        }
       while (pid == -1 && errno == EINTR);
 
       clear_sigint_trap ();
 
+      if (pid == 0)
+       {
+         gdb_assert (target_options & TARGET_WNOHANG);
+         ourstatus->set_ignore ();
+         return minus_one_ptid;
+       }
+
       if (pid == -1)
        {
+         /* In async mode the SIGCHLD might have raced and triggered
+            a check for an event that had already been reported.  If
+            the event was the exit of the only remaining child,
+            waitpid() will fail with ECHILD.  */
+         if (ptid == minus_one_ptid && save_errno == ECHILD)
+           {
+             ourstatus->set_no_resumed ();
+             return minus_one_ptid;
+           }
+
          fprintf_unfiltered (gdb_stderr,
                              _("Child process unexpectedly missing: %s.\n"),
                              safe_strerror (save_errno));