chromium/base/process/process_posix.cc

// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process/process.h"

#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <sys/resource.h>
#include <sys/wait.h>

#include <utility>

#include "base/clang_profiling_buildflags.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/notimplemented.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "base/trace_event/base_tracing.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_MAC)
#include <sys/event.h>
#endif

#if BUILDFLAG(CLANG_PROFILING)
#include "base/test/clang_profiling.h"
#endif

#if BUILDFLAG(IS_IOS)
#include "TargetConditionals.h"
#endif

namespace {

#if !BUILDFLAG(IS_IOS) || (BUILDFLAG(IS_IOS) && TARGET_OS_SIMULATOR)
bool WaitpidWithTimeout(base::ProcessHandle handle,
                        int* status,
                        base::TimeDelta wait) {}
#endif

#if BUILDFLAG(IS_MAC)
// 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) {
      // 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.is_positive());

  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;
}
#endif  // BUILDFLAG(IS_MAC)

}  // namespace

namespace base {

Process::Process(ProcessHandle handle) :{}

Process::Process(Process&& other) :{}

Process& Process::operator=(Process&& other) {}

Process::~Process() = default;

// static
Process Process::Current() {}

// static
Process Process::Open(ProcessId pid) {}

// static
Process Process::OpenWithExtraPrivileges(ProcessId pid) {}

// static
void Process::TerminateCurrentProcessImmediately(int exit_code) {}

bool Process::IsValid() const {}

ProcessHandle Process::Handle() const {}

Process Process::Duplicate() const {}

ProcessHandle Process::Release() {}

ProcessId Process::Pid() const {}

bool Process::is_current() const {}

void Process::Close() {}

#if !BUILDFLAG(IS_IOS)
bool Process::Terminate(int exit_code, bool wait) const {}
#endif

#if !BUILDFLAG(IS_IOS) || (BUILDFLAG(USE_BLINK) && TARGET_OS_SIMULATOR)
bool Process::TerminateInternal(int exit_code, bool wait) const {}
#endif

bool Process::WaitForExit(int* exit_code) const {}

#if !BUILDFLAG(IS_IOS)
bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const {}
#endif

#if !BUILDFLAG(IS_IOS) || (BUILDFLAG(USE_BLINK) && TARGET_OS_SIMULATOR)
bool Process::WaitForExitWithTimeoutImpl(base::ProcessHandle handle,
                                         int* exit_code,
                                         base::TimeDelta timeout) const {}
#endif

void Process::Exited(int exit_code) const {}

int Process::GetOSPriority() const {}

}  // namespace base