src/base/process/process_posix.cc
bool WaitForSingleNonChildProcess(base::ProcessHandle handle,
                                  base::TimeDelta wait) {
  DCHECK_GT(handle, 0);

  base::ScopedFD kq(kqueue());
  if (!kq.is_valid()) {
    DPLOG(ERROR) << "kqueue";
    return false;
  }

  struct kevent change = {0};
  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
  if (result == -1) {
    if (errno == ESRCH) {
      // If the process wasn't found, it must be dead.
      return true;
    }

    DPLOG(ERROR) << "kevent (setup " << handle << ")";
    return false;
  }

  // Keep track of the elapsed time to be able to restart kevent if it's
  // interrupted.
  bool wait_forever = (wait == base::TimeDelta::Max());
  base::TimeDelta remaining_delta;
  base::TimeTicks deadline;
  if (!wait_forever) {
    remaining_delta = wait;
    deadline = base::TimeTicks::Now() + remaining_delta;
  }

  result = -1;
  struct kevent event = {0};

  do {
    struct timespec remaining_timespec;
    struct timespec* remaining_timespec_ptr;
    if (wait_forever) {
      remaining_timespec_ptr = NULL;
    } else {
      remaining_timespec = remaining_delta.ToTimeSpec();
      remaining_timespec_ptr = &remaining_timespec;
    }

    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);

    if (result == -1 && errno == EINTR) {
      if (!wait_forever) {
        remaining_delta = deadline - base::TimeTicks::Now();
      }
      result = 0;
    } else {
      break;
    }
  } while (wait_forever || remaining_delta > base::TimeDelta());

  if (result < 0) {
    DPLOG(ERROR) << "kevent (wait " << handle << ")";
    return false;
  } else if (result > 1) {
    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
                << result;
    return false;
  } else if (result == 0) {
    // Timed out.
    return false;
  }

  DCHECK_EQ(result, 1);

  if (event.filter != EVFILT_PROC ||
      (event.fflags & NOTE_EXIT) == 0 ||
      event.ident != static_cast<uintptr_t>(handle)) {
    DLOG(ERROR) << "kevent (wait " << handle
                << "): unexpected event: filter=" << event.filter
                << ", fflags=" << event.fflags
                << ", ident=" << event.ident;
    return false;
  }

  return true;
}
// Using kqueue on Mac so that we can wait on non-child processes.
// We can't use kqueues on child processes because we need to reap
// our own children using wait.
Using kqueue on Mac so that we can wait on non-child processes.
We can't use kqueues on child processes because we need to reap
our own children using wait.
Using kqueue on Mac so that we can wait on non - child processes . We can ' t use kqueues on child processes because we need to reap our own children using wait .
bool WaitForSingleNonChildProcess(base::ProcessHandle handle,
                                  base::TimeDelta wait) {
  DCHECK_GT(handle, 0);
  base::ScopedFD kq(kqueue());
  if (!kq.is_valid()) {
    DPLOG(ERROR) << "kqueue";
    return false;
  }
  struct kevent change = {0};
  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
  if (result == -1) {
    if (errno == ESRCH) {
      return true;
    }
    DPLOG(ERROR) << "kevent (setup " << handle << ")";
    return false;
  }
  bool wait_forever = (wait == base::TimeDelta::Max());
  base::TimeDelta remaining_delta;
  base::TimeTicks deadline;
  if (!wait_forever) {
    remaining_delta = wait;
    deadline = base::TimeTicks::Now() + remaining_delta;
  }
  result = -1;
  struct kevent event = {0};
  do {
    struct timespec remaining_timespec;
    struct timespec* remaining_timespec_ptr;
    if (wait_forever) {
      remaining_timespec_ptr = NULL;
    } else {
      remaining_timespec = remaining_delta.ToTimeSpec();
      remaining_timespec_ptr = &remaining_timespec;
    }
    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
    if (result == -1 && errno == EINTR) {
      if (!wait_forever) {
        remaining_delta = deadline - base::TimeTicks::Now();
      }
      result = 0;
    } else {
      break;
    }
  } while (wait_forever || remaining_delta > base::TimeDelta());
  if (result < 0) {
    DPLOG(ERROR) << "kevent (wait " << handle << ")";
    return false;
  } else if (result > 1) {
    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
                << result;
    return false;
  } else if (result == 0) {
    return false;
  }
  DCHECK_EQ(result, 1);
  if (event.filter != EVFILT_PROC ||
      (event.fflags & NOTE_EXIT) == 0 ||
      event.ident != static_cast<uintptr_t>(handle)) {
    DLOG(ERROR) << "kevent (wait " << handle
                << "): unexpected event: filter=" << event.filter
                << ", fflags=" << event.fflags
                << ", ident=" << event.ident;
    return false;
  }
  return true;
}
bool WaitForSingleNonChildProcess ( base :: ProcessHandle handle , base :: TimeDelta wait ) { DCHECK_GT ( handle , 0 ) ; base :: ScopedFD kq ( kqueue ( ) ) ; if ( ! kq . is_valid ( ) ) { DPLOG ( ERROR ) << " " ; return false ; } struct kevent change = { 0 } ; EV_SET ( & change , handle , EVFILT_PROC , EV_ADD , NOTE_EXIT , 0 , NULL ) ; int result = HANDLE_EINTR ( kevent ( kq . get ( ) , & change , 1 , NULL , 0 , NULL ) ) ; if ( result == -1 ) { if ( errno == ESRCH ) { return true ; } DPLOG ( ERROR ) << " " << handle << " " ; return false ; } bool wait_forever = ( wait == base :: TimeDelta :: Max ( ) ) ; base :: TimeDelta remaining_delta ; base :: TimeTicks deadline ; if ( ! wait_forever ) { remaining_delta = wait ; deadline = base :: TimeTicks :: Now ( ) + remaining_delta ; } result = -1 ; struct kevent event = { 0 } ; do { struct timespec remaining_timespec ; struct timespec * remaining_timespec_ptr ; if ( wait_forever ) { remaining_timespec_ptr = NULL ; } else { remaining_timespec = remaining_delta . ToTimeSpec ( ) ; remaining_timespec_ptr = & remaining_timespec ; } result = kevent ( kq . get ( ) , NULL , 0 , & event , 1 , remaining_timespec_ptr ) ; if ( result == -1 && errno == EINTR ) { if ( ! wait_forever ) { remaining_delta = deadline - base :: TimeTicks :: Now ( ) ; } result = 0 ; } else { break ; } } while ( wait_forever || remaining_delta > base :: TimeDelta ( ) ) ; if ( result < 0 ) { DPLOG ( ERROR ) << " " << handle << " " ; return false ; } else if ( result > 1 ) { DLOG ( ERROR ) << " " << handle << " " << result ; return false ; } else if ( result == 0 ) { return false ; } DCHECK_EQ ( result , 1 ) ; if ( event . filter != EVFILT_PROC || ( event . fflags & NOTE_EXIT ) == 0 || event . ident != static_cast < uintptr_t > ( handle ) ) { DLOG ( ERROR ) << " " << handle << " " << event . filter << " " << event . fflags << " " << event . ident ; return false ; } return true ; }
Using kqueue on Mac so that we can wait on non-child processes.
Using kqueue on Mac so that we can wait on non - child processes .
// If the process wasn't found, it must be dead. // Keep track of the elapsed time to be able to restart kevent if it's // interrupted. // Timed out.