diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/base/process | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/base/process')
24 files changed, 347 insertions, 256 deletions
diff --git a/chromium/base/process/kill_fuchsia.cc b/chromium/base/process/kill_fuchsia.cc index d7bde1f4224..f4fdaae10b1 100644 --- a/chromium/base/process/kill_fuchsia.cc +++ b/chromium/base/process/kill_fuchsia.cc @@ -4,7 +4,7 @@ #include "base/process/kill.h" -#include <magenta/syscalls.h> +#include <zircon/syscalls.h> #include "base/process/process_iterator.h" #include "base/task_scheduler/post_task.h" @@ -14,20 +14,20 @@ namespace base { bool KillProcessGroup(ProcessHandle process_group_id) { // |process_group_id| is really a job on Fuchsia. - mx_status_t status = mx_task_kill(process_group_id); - DLOG_IF(ERROR, status != MX_OK) + zx_status_t status = zx_task_kill(process_group_id); + DLOG_IF(ERROR, status != ZX_OK) << "unable to terminate job " << process_group_id; - return status == MX_OK; + return status == ZX_OK; } TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { DCHECK(exit_code); - mx_info_process_t process_info; - mx_status_t status = - mx_object_get_info(handle, MX_INFO_PROCESS, &process_info, + zx_info_process_t process_info; + zx_status_t status = + zx_object_get_info(handle, ZX_INFO_PROCESS, &process_info, sizeof(process_info), nullptr, nullptr); - if (status != MX_OK) { + if (status != ZX_OK) { DLOG(ERROR) << "unable to get termination status for " << handle; *exit_code = 0; return TERMINATION_STATUS_NORMAL_TERMINATION; @@ -55,10 +55,10 @@ void EnsureProcessTerminated(Process process) { // Wait for up to two seconds for the process to terminate, and then kill it // forcefully if it hasn't already exited. - mx_signals_t signals; - if (mx_object_wait_one(process.Handle(), MX_TASK_TERMINATED, - mx_deadline_after(MX_SEC(2)), &signals) == MX_OK) { - DCHECK(signals & MX_TASK_TERMINATED); + zx_signals_t signals; + if (zx_object_wait_one(process.Handle(), ZX_TASK_TERMINATED, + zx_deadline_after(ZX_SEC(2)), &signals) == ZX_OK) { + DCHECK(signals & ZX_TASK_TERMINATED); // If already signaled, then the process is terminated. return; } diff --git a/chromium/base/process/launch.h b/chromium/base/process/launch.h index 9e7636da3e6..0c425a7a95c 100644 --- a/chromium/base/process/launch.h +++ b/chromium/base/process/launch.h @@ -28,7 +28,8 @@ #endif #if defined(OS_FUCHSIA) -#include <magenta/types.h> +#include <launchpad/launchpad.h> +#include <zircon/types.h> #endif namespace base { @@ -42,7 +43,7 @@ typedef std::vector<HANDLE> HandlesToInheritVector; #if defined(OS_FUCHSIA) struct HandleToTransfer { uint32_t id; - mx_handle_t handle; + zx_handle_t handle; }; typedef std::vector<HandleToTransfer> HandlesToTransferVector; #endif @@ -191,13 +192,22 @@ struct BASE_EXPORT LaunchOptions { #if defined(OS_FUCHSIA) // If valid, launches the application in that job object. - mx_handle_t job_handle = MX_HANDLE_INVALID; + zx_handle_t job_handle = ZX_HANDLE_INVALID; // Specifies additional handles to transfer (not duplicate) to the child // process. The handles remain valid in this process if launch fails. // Each entry is an <id,handle> pair, with an |id| created using the PA_HND() - // macro. The child retrieves the handle |mx_get_startup_handle(id)|. + // macro. The child retrieves the handle |zx_get_startup_handle(id)|. HandlesToTransferVector handles_to_transfer; + + // If set, specifies which capabilities should be granted (cloned) to the + // child process. + // A zero value indicates that the child process will receive + // no capabilities. + // By default the child will inherit the same capabilities, job, and CWD + // from the parent process. + uint32_t clone_flags = LP_CLONE_FDIO_NAMESPACE | LP_CLONE_DEFAULT_JOB | + LP_CLONE_FDIO_CWD | LP_CLONE_FDIO_STDIO; #endif // defined(OS_FUCHSIA) #if defined(OS_POSIX) diff --git a/chromium/base/process/launch_fuchsia.cc b/chromium/base/process/launch_fuchsia.cc index 3f370880b27..16ac513b570 100644 --- a/chromium/base/process/launch_fuchsia.cc +++ b/chromium/base/process/launch_fuchsia.cc @@ -5,9 +5,10 @@ #include "base/process/launch.h" #include <launchpad/launchpad.h> -#include <magenta/process.h> -#include <magenta/processargs.h> +#include <stdint.h> #include <unistd.h> +#include <zircon/process.h> +#include <zircon/processargs.h> #include "base/command_line.h" #include "base/fuchsia/default_job.h" @@ -61,6 +62,8 @@ Process LaunchProcess(const CommandLine& cmdline, return LaunchProcess(cmdline.argv(), options); } +// TODO(768416): Investigate whether we can make LaunchProcess() create +// unprivileged processes by default (no implicit capabilities are granted). Process LaunchProcess(const std::vector<std::string>& argv, const LaunchOptions& options) { std::vector<const char*> argv_cstr; @@ -74,15 +77,15 @@ Process LaunchProcess(const std::vector<std::string>& argv, // status is tracked in the launchpad_t object, and launchpad_go() reports on // the final status, and cleans up |lp| (assuming it was even created). launchpad_t* lp = nullptr; - mx_handle_t job = options.job_handle != MX_HANDLE_INVALID ? options.job_handle + zx_handle_t job = options.job_handle != ZX_HANDLE_INVALID ? options.job_handle : GetDefaultJob(); - DCHECK_NE(MX_HANDLE_INVALID, job); + DCHECK_NE(ZX_HANDLE_INVALID, job); launchpad_create(job, argv_cstr[0], &lp); launchpad_load_from_file(lp, argv_cstr[0]); launchpad_set_args(lp, argv.size(), argv_cstr.data()); - uint32_t to_clone = LP_CLONE_MXIO_NAMESPACE | LP_CLONE_DEFAULT_JOB; + uint32_t to_clone = options.clone_flags; std::unique_ptr<char* []> new_environ; char* const empty_environ = nullptr; @@ -93,20 +96,21 @@ Process LaunchProcess(const std::vector<std::string>& argv, EnvironmentMap environ_modifications = options.environ; if (!options.current_directory.empty()) { environ_modifications["PWD"] = options.current_directory.value(); - } else { - to_clone |= LP_CLONE_MXIO_CWD; + + // Don't clone the parent's CWD if we are overriding the child's PWD. + to_clone = to_clone & ~LP_CLONE_FDIO_CWD; } if (to_clone & LP_CLONE_DEFAULT_JOB) { // Override Fuchsia's built in default job cloning behavior with our own - // logic which uses |job| instead of mx_job_default(). + // logic which uses |job| instead of zx_job_default(). // This logic is based on the launchpad implementation. - mx_handle_t job_duplicate = MX_HANDLE_INVALID; - mx_status_t status = - mx_handle_duplicate(job, MX_RIGHT_SAME_RIGHTS, &job_duplicate); - if (status != MX_OK) { - LOG(ERROR) << "mx_handle_duplicate(job): " - << mx_status_get_string(status); + zx_handle_t job_duplicate = ZX_HANDLE_INVALID; + zx_status_t status = + zx_handle_duplicate(job, ZX_RIGHT_SAME_RIGHTS, &job_duplicate); + if (status != ZX_OK) { + LOG(ERROR) << "zx_handle_duplicate(job): " + << zx_status_get_string(status); return Process(); } launchpad_add_handle(lp, job_duplicate, PA_HND(PA_JOB_DEFAULT, 0)); @@ -127,26 +131,30 @@ Process LaunchProcess(const std::vector<std::string>& argv, bool stdio_already_mapped[3] = {false}; for (const auto& src_target : options.fds_to_remap) { if (static_cast<size_t>(src_target.second) < - arraysize(stdio_already_mapped)) + arraysize(stdio_already_mapped)) { stdio_already_mapped[src_target.second] = true; + } launchpad_clone_fd(lp, src_target.first, src_target.second); } - for (size_t stdio_fd = 0; stdio_fd < arraysize(stdio_already_mapped); - ++stdio_fd) { - if (!stdio_already_mapped[stdio_fd]) - launchpad_clone_fd(lp, stdio_fd, stdio_fd); + if (to_clone & LP_CLONE_FDIO_STDIO) { + for (size_t stdio_fd = 0; stdio_fd < arraysize(stdio_already_mapped); + ++stdio_fd) { + if (!stdio_already_mapped[stdio_fd]) + launchpad_clone_fd(lp, stdio_fd, stdio_fd); + } + to_clone &= ~LP_CLONE_FDIO_STDIO; } for (const auto& id_and_handle : options.handles_to_transfer) { launchpad_add_handle(lp, id_and_handle.handle, id_and_handle.id); } - mx_handle_t proc; + zx_handle_t proc; const char* errmsg; - mx_status_t status = launchpad_go(lp, &proc, &errmsg); - if (status != MX_OK) { + zx_status_t status = launchpad_go(lp, &proc, &errmsg); + if (status != ZX_OK) { LOG(ERROR) << "launchpad_go failed: " << errmsg - << ", status=" << mx_status_get_string(status); + << ", status=" << zx_status_get_string(status); return Process(); } diff --git a/chromium/base/process/launch_mac.cc b/chromium/base/process/launch_mac.cc index b8ff49ce1ac..dfa9257a51e 100644 --- a/chromium/base/process/launch_mac.cc +++ b/chromium/base/process/launch_mac.cc @@ -76,7 +76,7 @@ class PosixSpawnFileActions { void RestoreDefaultExceptionHandler() { // This function is tailored to remove the Breakpad exception handler. // exception_mask matches s_exception_mask in - // breakpad/src/client/mac/handler/exception_handler.cc + // third_party/breakpad/breakpad/src/client/mac/handler/exception_handler.cc const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | diff --git a/chromium/base/process/process.h b/chromium/base/process/process.h index a4d77dfad85..481d92ddc17 100644 --- a/chromium/base/process/process.h +++ b/chromium/base/process/process.h @@ -16,7 +16,7 @@ #endif #if defined(OS_FUCHSIA) -#include "base/fuchsia/scoped_mx_handle.h" +#include "base/fuchsia/scoped_zx_handle.h" #endif #if defined(OS_MACOSX) @@ -45,6 +45,8 @@ extern const Feature kMacAllowBackgroundingProcesses; // end up pointing to the wrong process. class BASE_EXPORT Process { public: + // On Windows, this takes ownership of |handle|. On POSIX, this does not take + // ownership of |handle|. explicit Process(ProcessHandle handle = kNullProcessHandle); Process(Process&& other); @@ -102,6 +104,16 @@ class BASE_EXPORT Process { // Close the process handle. This will not terminate the process. void Close(); + // Returns true if this process is still running. This is only safe on Windows + // (and maybe Fuchsia?), because the ProcessHandle will keep the zombie + // process information available until itself has been released. But on Posix, + // the OS may reuse the ProcessId. +#if defined(OS_WIN) + bool IsRunning() const { + return !WaitForExitWithTimeout(base::TimeDelta(), nullptr); + } +#endif + // Terminates the process with extreme prejudice. The given |exit_code| will // be the exit code of the process. If |wait| is true, this method will wait // for up to one minute for the process to actually terminate. @@ -143,9 +155,6 @@ class BASE_EXPORT Process { // Returns true if the priority was changed, false otherwise. If // |port_provider| is null, this is a no-op and it returns false. bool SetProcessBackgrounded(PortProvider* port_provider, bool value); - - // Returns |true| if helper processes should participate in AppNap. - static bool IsAppNapEnabled(); #else // A process is backgrounded when it's priority is lower than normal. // Return true if this process is backgrounded, false otherwise. @@ -172,7 +181,7 @@ class BASE_EXPORT Process { #if defined(OS_WIN) win::ScopedHandle process_; #elif defined(OS_FUCHSIA) - ScopedMxHandle process_; + ScopedZxHandle process_; #else ProcessHandle process_; #endif diff --git a/chromium/base/process/process_fuchsia.cc b/chromium/base/process/process_fuchsia.cc index 43efbf08805..57da2ae4368 100644 --- a/chromium/base/process/process_fuchsia.cc +++ b/chromium/base/process/process_fuchsia.cc @@ -4,8 +4,8 @@ #include "base/process/process.h" -#include <magenta/process.h> -#include <magenta/syscalls.h> +#include <zircon/process.h> +#include <zircon/syscalls.h> #include "base/debug/activity_tracker.h" #include "base/fuchsia/default_job.h" @@ -15,7 +15,7 @@ namespace base { Process::Process(ProcessHandle handle) : process_(handle), is_current_process_(false) { - CHECK_NE(handle, mx_process_self()); + CHECK_NE(handle, zx_process_self()); } Process::~Process() { @@ -48,12 +48,12 @@ Process Process::Open(ProcessId pid) { return Current(); // While a process with object id |pid| might exist, the job returned by - // mx_job_default() might not contain it, so this call can fail. - ScopedMxHandle handle; - mx_status_t status = mx_object_get_child( - GetDefaultJob(), pid, MX_RIGHT_SAME_RIGHTS, handle.receive()); - if (status != MX_OK) { - DLOG(ERROR) << "mx_object_get_child failed: " << status; + // zx_job_default() might not contain it, so this call can fail. + ScopedZxHandle handle; + zx_status_t status = zx_object_get_child( + GetDefaultJob(), pid, ZX_RIGHT_SAME_RIGHTS, handle.receive()); + if (status != ZX_OK) { + DLOG(ERROR) << "zx_object_get_child failed: " << status; return Process(); } return Process(handle.release()); @@ -68,10 +68,10 @@ Process Process::OpenWithExtraPrivileges(ProcessId pid) { // static Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) { DCHECK_NE(handle, GetCurrentProcessHandle()); - ScopedMxHandle out; - if (mx_handle_duplicate(handle, MX_RIGHT_SAME_RIGHTS, out.receive()) != - MX_OK) { - DLOG(ERROR) << "mx_handle_duplicate failed: " << handle; + ScopedZxHandle out; + if (zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, out.receive()) != + ZX_OK) { + DLOG(ERROR) << "zx_handle_duplicate failed: " << handle; return Process(); } @@ -93,7 +93,7 @@ bool Process::IsValid() const { } ProcessHandle Process::Handle() const { - return is_current_process_ ? mx_process_self() : process_.get(); + return is_current_process_ ? zx_process_self() : process_.get(); } Process Process::Duplicate() const { @@ -103,10 +103,10 @@ Process Process::Duplicate() const { if (!IsValid()) return Process(); - ScopedMxHandle out; - if (mx_handle_duplicate(process_.get(), MX_RIGHT_SAME_RIGHTS, - out.receive()) != MX_OK) { - DLOG(ERROR) << "mx_handle_duplicate failed: " << process_.get(); + ScopedZxHandle out; + if (zx_handle_duplicate(process_.get(), ZX_RIGHT_SAME_RIGHTS, + out.receive()) != ZX_OK) { + DLOG(ERROR) << "zx_handle_duplicate failed: " << process_.get(); return Process(); } @@ -129,19 +129,19 @@ void Process::Close() { bool Process::Terminate(int exit_code, bool wait) const { // exit_code isn't supportable. https://crbug.com/753490. - mx_status_t status = mx_task_kill(Handle()); + zx_status_t status = zx_task_kill(Handle()); // TODO(scottmg): Put these LOG/CHECK back to DLOG/DCHECK after // https://crbug.com/750756 is diagnosed. - if (status == MX_OK && wait) { - mx_signals_t signals; - status = mx_object_wait_one(Handle(), MX_TASK_TERMINATED, - mx_deadline_after(MX_SEC(60)), &signals); - if (status != MX_OK) { + if (status == ZX_OK && wait) { + zx_signals_t signals; + status = zx_object_wait_one(Handle(), ZX_TASK_TERMINATED, + zx_deadline_after(ZX_SEC(60)), &signals); + if (status != ZX_OK) { LOG(ERROR) << "Error waiting for process exit: " << status; } else { - CHECK(signals & MX_TASK_TERMINATED); + CHECK(signals & ZX_TASK_TERMINATED); } - } else if (status != MX_OK) { + } else if (status != ZX_OK) { LOG(ERROR) << "Unable to terminate process: " << status; } @@ -153,49 +153,53 @@ bool Process::WaitForExit(int* exit_code) const { } bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const { - DCHECK(!is_current_process_); + if (is_current_process_) + return false; // Record the event that this thread is blocking upon (for hang diagnosis). base::debug::ScopedProcessWaitActivity process_activity(this); - mx_time_t deadline = timeout == TimeDelta::Max() - ? MX_TIME_INFINITE - : (TimeTicks::Now() + timeout).ToMXTime(); + zx_time_t deadline = timeout == TimeDelta::Max() + ? ZX_TIME_INFINITE + : (TimeTicks::Now() + timeout).ToZxTime(); // TODO(scottmg): https://crbug.com/755282 const bool kOnBot = getenv("CHROME_HEADLESS") != nullptr; if (kOnBot) { LOG(ERROR) << base::StringPrintf( "going to wait for process %x (deadline=%zu, now=%zu)", process_.get(), - deadline, TimeTicks::Now().ToMXTime()); + deadline, TimeTicks::Now().ToZxTime()); } - mx_signals_t signals_observed = 0; - mx_status_t status = mx_object_wait_one(process_.get(), MX_TASK_TERMINATED, + zx_signals_t signals_observed = 0; + zx_status_t status = zx_object_wait_one(process_.get(), ZX_TASK_TERMINATED, deadline, &signals_observed); // TODO(scottmg): Make these LOGs into DLOGs after https://crbug.com/750756 is // fixed. - *exit_code = -1; - if (status != MX_OK && status != MX_ERR_TIMED_OUT) { - LOG(ERROR) << "mx_object_wait_one failed, status=" << status; + if (status != ZX_OK && status != ZX_ERR_TIMED_OUT) { + LOG(ERROR) << "zx_object_wait_one failed, status=" << status; return false; } - if (status == MX_ERR_TIMED_OUT) { - mx_time_t now = TimeTicks::Now().ToMXTime(); - LOG(ERROR) << "mx_object_wait_one timed out, signals=" << signals_observed + if (status == ZX_ERR_TIMED_OUT) { + zx_time_t now = TimeTicks::Now().ToZxTime(); + LOG(ERROR) << "zx_object_wait_one timed out, signals=" << signals_observed << ", deadline=" << deadline << ", now=" << now << ", delta=" << (now - deadline); return false; } - mx_info_process_t proc_info; - status = mx_object_get_info(process_.get(), MX_INFO_PROCESS, &proc_info, + zx_info_process_t proc_info; + status = zx_object_get_info(process_.get(), ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr); - if (status != MX_OK) { - LOG(ERROR) << "mx_object_get_info failed, status=" << status; + if (status != ZX_OK) { + LOG(ERROR) << "zx_object_get_info failed, status=" << status; + if (exit_code) + *exit_code = -1; return false; } - *exit_code = proc_info.return_code; + if (exit_code) + *exit_code = proc_info.return_code; + return true; } diff --git a/chromium/base/process/process_handle.h b/chromium/base/process/process_handle.h index 48b8aa48b09..ae54b72d999 100644 --- a/chromium/base/process/process_handle.h +++ b/chromium/base/process/process_handle.h @@ -17,7 +17,7 @@ #endif #if defined(OS_FUCHSIA) -#include <magenta/types.h> +#include <zircon/types.h> #endif namespace base { @@ -32,10 +32,10 @@ typedef HANDLE UserTokenHandle; const ProcessHandle kNullProcessHandle = NULL; const ProcessId kNullProcessId = 0; #elif defined(OS_FUCHSIA) -typedef mx_handle_t ProcessHandle; -typedef mx_koid_t ProcessId; -const ProcessHandle kNullProcessHandle = MX_HANDLE_INVALID; -const ProcessId kNullProcessId = MX_KOID_INVALID; +typedef zx_handle_t ProcessHandle; +typedef zx_koid_t ProcessId; +const ProcessHandle kNullProcessHandle = ZX_HANDLE_INVALID; +const ProcessId kNullProcessId = ZX_KOID_INVALID; #elif defined(OS_POSIX) // On POSIX, our ProcessHandle will just be the PID. typedef pid_t ProcessHandle; @@ -88,6 +88,8 @@ BASE_EXPORT ProcessId GetProcId(ProcessHandle process); #if !defined(OS_FUCHSIA) // Returns the ID for the parent of the given process. Not available on Fuchsia. +// Returning a negative value indicates an error, such as if the |process| does +// not exist. Returns 0 when |process| has no parent process. BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process); #endif // !defined(OS_FUCHSIA) diff --git a/chromium/base/process/process_handle_fuchsia.cc b/chromium/base/process/process_handle_fuchsia.cc index 2d6e1668b1c..c9d2a8e4d44 100644 --- a/chromium/base/process/process_handle_fuchsia.cc +++ b/chromium/base/process/process_handle_fuchsia.cc @@ -4,9 +4,9 @@ #include "base/process/process_handle.h" -#include <magenta/process.h> -#include <magenta/status.h> -#include <magenta/syscalls.h> +#include <zircon/process.h> +#include <zircon/status.h> +#include <zircon/syscalls.h> #include "base/logging.h" @@ -17,19 +17,19 @@ ProcessId GetCurrentProcId() { } ProcessHandle GetCurrentProcessHandle() { - // Note that mx_process_self() returns a real handle, and ownership is not + // Note that zx_process_self() returns a real handle, and ownership is not // transferred to the caller (i.e. this should never be closed). - return mx_process_self(); + return zx_process_self(); } ProcessId GetProcId(ProcessHandle process) { - mx_info_handle_basic_t basic; - mx_status_t status = mx_object_get_info(process, MX_INFO_HANDLE_BASIC, &basic, + zx_info_handle_basic_t basic; + zx_status_t status = zx_object_get_info(process, ZX_INFO_HANDLE_BASIC, &basic, sizeof(basic), nullptr, nullptr); - if (status != MX_OK) { - DLOG(ERROR) << "mx_object_get_info failed: " - << mx_status_get_string(status); - return MX_KOID_INVALID; + if (status != ZX_OK) { + DLOG(ERROR) << "zx_object_get_info failed: " + << zx_status_get_string(status); + return ZX_KOID_INVALID; } return basic.koid; } diff --git a/chromium/base/process/process_handle_linux.cc b/chromium/base/process/process_handle_linux.cc index 3a0460725e0..f921b426a36 100644 --- a/chromium/base/process/process_handle_linux.cc +++ b/chromium/base/process/process_handle_linux.cc @@ -20,6 +20,7 @@ ProcessId GetParentProcessId(ProcessHandle process) { #else internal::ReadProcStatsAndGetFieldAsInt64(process, internal::VM_PPID); #endif + // TODO(zijiehe): Returns 0 if |process| does not have a parent process. if (pid) return pid; return -1; diff --git a/chromium/base/process/process_handle_win.cc b/chromium/base/process/process_handle_win.cc index b8136d1e8cc..67986cd21d9 100644 --- a/chromium/base/process/process_handle_win.cc +++ b/chromium/base/process/process_handle_win.cc @@ -38,6 +38,8 @@ ProcessId GetParentProcessId(ProcessHandle process) { } while (Process32Next(snapshot.Get(), &process_entry)); } + // TODO(zijiehe): To match other platforms, -1 (UINT32_MAX) should be returned + // if |child_id| cannot be found in the |snapshot|. return 0u; } diff --git a/chromium/base/process/process_mac.cc b/chromium/base/process/process_mac.cc index bc045cd72aa..70bc4c20fd0 100644 --- a/chromium/base/process/process_mac.cc +++ b/chromium/base/process/process_mac.cc @@ -8,27 +8,15 @@ #include "base/feature_list.h" #include "base/mac/mach_logging.h" -#include "base/metrics/field_trial_params.h" namespace base { -namespace { -const char kAppNapFeatureParamName[] = "app_nap"; -} - // Enables backgrounding hidden renderers on Mac. const Feature kMacAllowBackgroundingProcesses{"MacAllowBackgroundingProcesses", FEATURE_DISABLED_BY_DEFAULT}; -bool Process::IsAppNapEnabled() { - return !base::GetFieldTrialParamValueByFeature( - kMacAllowBackgroundingProcesses, kAppNapFeatureParamName) - .empty(); -} - bool Process::CanBackgroundProcesses() { - return FeatureList::IsEnabled(kMacAllowBackgroundingProcesses) && - !IsAppNapEnabled(); + return FeatureList::IsEnabled(kMacAllowBackgroundingProcesses); } bool Process::IsProcessBackgrounded(PortProvider* port_provider) const { @@ -83,19 +71,6 @@ bool Process::SetProcessBackgrounded(PortProvider* port_provider, return false; } - // Latency QoS regulates timer throttling/accuracy. Select default tier - // on foreground because precise timer firing isn't needed. - struct task_qos_policy qos_policy = { - background ? LATENCY_QOS_TIER_5 : LATENCY_QOS_TIER_UNSPECIFIED, - background ? THROUGHPUT_QOS_TIER_5 : THROUGHPUT_QOS_TIER_UNSPECIFIED}; - result = task_policy_set(task_port, TASK_OVERRIDE_QOS_POLICY, - reinterpret_cast<task_policy_t>(&qos_policy), - TASK_QOS_POLICY_COUNT); - if (result != KERN_SUCCESS) { - MACH_LOG(ERROR, result) << "task_policy_set TASK_OVERRIDE_QOS_POLICY"; - return false; - } - return true; } diff --git a/chromium/base/process/process_metrics.cc b/chromium/base/process/process_metrics.cc index f24901c3d99..0d9140a99e8 100644 --- a/chromium/base/process/process_metrics.cc +++ b/chromium/base/process/process_metrics.cc @@ -10,6 +10,40 @@ #include "base/values.h" #include "build/build_config.h" +#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_AIX) +namespace { +int CalculateEventsPerSecond(uint64_t event_count, + uint64_t* last_event_count, + base::TimeTicks* last_calculated) { + base::TimeTicks time = base::TimeTicks::Now(); + + if (*last_event_count == 0) { + // First call, just set the last values. + *last_calculated = time; + *last_event_count = event_count; + return 0; + } + + int64_t events_delta = event_count - *last_event_count; + int64_t time_delta = (time - *last_calculated).InMicroseconds(); + if (time_delta == 0) { + NOTREACHED(); + return 0; + } + + *last_calculated = time; + *last_event_count = event_count; + + int64_t events_delta_for_ms = + events_delta * base::Time::kMicrosecondsPerSecond; + // Round the result up by adding 1/2 (the second term resolves to 1/2 without + // dropping down into floating point). + return (events_delta_for_ms + time_delta / 2) / time_delta; +} + +} // namespace +#endif // defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_AIX) + namespace base { SystemMemoryInfoKB::SystemMemoryInfoKB() = default; @@ -59,46 +93,27 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateCurrentProcessMetrics() { #endif // !defined(OS_MACOSX) || defined(OS_IOS) } -double ProcessMetrics::GetPlatformIndependentCPUUsage() { -#if defined(OS_WIN) - return GetCPUUsage() * processor_count_; -#else - return GetCPUUsage(); -#endif -} - #if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_AIX) int ProcessMetrics::CalculateIdleWakeupsPerSecond( uint64_t absolute_idle_wakeups) { - TimeTicks time = TimeTicks::Now(); - - if (last_absolute_idle_wakeups_ == 0) { - // First call, just set the last values. - last_idle_wakeups_time_ = time; - last_absolute_idle_wakeups_ = absolute_idle_wakeups; - return 0; - } - - int64_t wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_; - int64_t time_delta = (time - last_idle_wakeups_time_).InMicroseconds(); - if (time_delta == 0) { - NOTREACHED(); - return 0; - } - - last_idle_wakeups_time_ = time; - last_absolute_idle_wakeups_ = absolute_idle_wakeups; - - int64_t wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond; - // Round the result up by adding 1/2 (the second term resolves to 1/2 without - // dropping down into floating point). - return (wakeups_delta_for_ms + time_delta / 2) / time_delta; + return CalculateEventsPerSecond(absolute_idle_wakeups, + &last_absolute_idle_wakeups_, + &last_idle_wakeups_time_); } #else int ProcessMetrics::GetIdleWakeupsPerSecond() { NOTIMPLEMENTED(); // http://crbug.com/120488 return 0; } -#endif // defined(OS_MACOSX) || defined(OS_LINUX) +#endif // defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_AIX) + +#if defined(OS_MACOSX) +int ProcessMetrics::CalculatePackageIdleWakeupsPerSecond( + uint64_t absolute_package_idle_wakeups) { + return CalculateEventsPerSecond(absolute_package_idle_wakeups, + &last_absolute_package_idle_wakeups_, + &last_package_idle_wakeups_time_); +} +#endif // defined(OS_MACOSX) } // namespace base diff --git a/chromium/base/process/process_metrics.h b/chromium/base/process/process_metrics.h index 644b463242f..844cd73cb4a 100644 --- a/chromium/base/process/process_metrics.h +++ b/chromium/base/process/process_metrics.h @@ -203,22 +203,40 @@ class BASE_EXPORT ProcessMetrics { size_t* locked_bytes) const; #endif - // Returns the CPU usage in percent since the last time this method or - // GetPlatformIndependentCPUUsage() was called. The first time this method - // is called it returns 0 and will return the actual CPU info on subsequent - // calls. On Windows, the CPU usage value is for all CPUs. So if you have - // 2 CPUs and your process is using all the cycles of 1 CPU and not the other - // CPU, this method returns 50. - double GetCPUUsage(); + // Returns the percentage of time spent executing, across all threads of the + // process, in the interval since the last time the method was called. Since + // this considers the total execution time across all threads in a process, + // the result can easily exceed 100% in multi-thread processes running on + // multi-core systems. In general the result is therefore a value in the + // range 0% to SysInfo::NumberOfProcessors() * 100%. + // + // To obtain the percentage of total available CPU resources consumed by this + // process over the interval, the caller must divide by NumberOfProcessors(). + // + // Since this API measures usage over an interval, it will return zero on the + // first call, and an actual value only on the second and subsequent calls. + double GetPlatformIndependentCPUUsage(); // Returns the number of average idle cpu wakeups per second since the last // call. int GetIdleWakeupsPerSecond(); - // Same as GetCPUUsage(), but will return consistent values on all platforms - // (cancelling the Windows exception mentioned above) by returning a value in - // the range of 0 to (100 * numCPUCores) everywhere. - double GetPlatformIndependentCPUUsage(); +#if defined(OS_MACOSX) + // Returns the number of average "package idle exits" per second, which have + // a higher energy impact than a regular wakeup, since the last call. + // + // From the powermetrics man page: + // "With the exception of some Mac Pro systems, Mac and + // iOS systems are typically single package systems, wherein all CPUs are + // part of a single processor complex (typically a single IC die) with shared + // logic that can include (depending on system specifics) shared last level + // caches, an integrated memory controller etc. When all CPUs in the package + // are idle, the hardware can power-gate significant portions of the shared + // logic in addition to each individual processor's logic, as well as take + // measures such as placing DRAM in to self-refresh (also referred to as + // auto-refresh), place interconnects into lower-power states etc" + int GetPackageIdleWakeupsPerSecond(); +#endif // Retrieves accounting information for all I/O operations performed by the // process. @@ -267,6 +285,12 @@ class BASE_EXPORT ProcessMetrics { #if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_AIX) int CalculateIdleWakeupsPerSecond(uint64_t absolute_idle_wakeups); #endif +#if defined(OS_MACOSX) + // The subset of wakeups that cause a "package exit" can be tracked on macOS. + // See |GetPackageIdleWakeupsForSecond| comment for more info. + int CalculatePackageIdleWakeupsPerSecond( + uint64_t absolute_package_idle_wakeups); +#endif #if defined(OS_WIN) win::ScopedHandle process_; @@ -274,8 +298,6 @@ class BASE_EXPORT ProcessMetrics { ProcessHandle process_; #endif - int processor_count_; - // Used to store the previous times and CPU usage counts so we can // compute the CPU usage between calls. TimeTicks last_cpu_time_; @@ -287,6 +309,12 @@ class BASE_EXPORT ProcessMetrics { uint64_t last_absolute_idle_wakeups_; #endif +#if defined(OS_MACOSX) + // And same thing for package idle exit wakeups. + TimeTicks last_package_idle_wakeups_time_; + uint64_t last_absolute_package_idle_wakeups_; +#endif + #if !defined(OS_IOS) #if defined(OS_MACOSX) // Queries the port provider if it's set. @@ -312,11 +340,11 @@ BASE_EXPORT size_t GetSystemCommitCharge(); // returned by GetPageSize(). BASE_EXPORT size_t GetPageSize(); -#if defined(OS_POSIX) // Returns the maximum number of file descriptors that can be open by a process // at once. If the number is unavailable, a conservative best guess is returned. BASE_EXPORT size_t GetMaxFds(); +#if defined(OS_POSIX) // Sets the file descriptor soft limit to |max_descriptors| or the OS hard // limit, whichever is lower. BASE_EXPORT void SetFdLimit(unsigned int max_descriptors); diff --git a/chromium/base/process/process_metrics_freebsd.cc b/chromium/base/process/process_metrics_freebsd.cc index 4f5adf790f6..10d0868d198 100644 --- a/chromium/base/process/process_metrics_freebsd.cc +++ b/chromium/base/process/process_metrics_freebsd.cc @@ -11,13 +11,11 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/sys_info.h" namespace base { ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), - processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0), last_cpu_(0) {} @@ -84,7 +82,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { return true; } -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { struct kinfo_proc info; int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ }; size_t length = sizeof(info); diff --git a/chromium/base/process/process_metrics_fuchsia.cc b/chromium/base/process/process_metrics_fuchsia.cc index 6fcdb5ce2d0..a5234c40a79 100644 --- a/chromium/base/process/process_metrics_fuchsia.cc +++ b/chromium/base/process/process_metrics_fuchsia.cc @@ -19,7 +19,7 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( return nullptr; } -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { NOTIMPLEMENTED(); // TODO(fuchsia): https://crbug.com/706592. return 0.0; } diff --git a/chromium/base/process/process_metrics_ios.cc b/chromium/base/process/process_metrics_ios.cc index 2ed65ab37f9..31c812dee03 100644 --- a/chromium/base/process/process_metrics_ios.cc +++ b/chromium/base/process/process_metrics_ios.cc @@ -38,7 +38,7 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( return WrapUnique(new ProcessMetrics(process)); } -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { NOTIMPLEMENTED(); return 0; } diff --git a/chromium/base/process/process_metrics_linux.cc b/chromium/base/process/process_metrics_linux.cc index d6b28bd48a0..6a32964d22d 100644 --- a/chromium/base/process/process_metrics_linux.cc +++ b/chromium/base/process/process_metrics_linux.cc @@ -24,7 +24,6 @@ #include "base/strings/string_split.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" -#include "base/sys_info.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" @@ -256,7 +255,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { return GetWorkingSetKBytesStatm(ws_usage); } -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { TimeTicks time = TimeTicks::Now(); if (last_cpu_ == 0) { @@ -405,7 +404,6 @@ ProcessMetrics::ProcessMetrics(ProcessHandle process) last_absolute_idle_wakeups_(0), #endif last_cpu_(0) { - processor_count_ = SysInfo::NumberOfProcessors(); } #if defined(OS_CHROMEOS) diff --git a/chromium/base/process/process_metrics_mac.cc b/chromium/base/process/process_metrics_mac.cc index 710f096069b..98793ff2413 100644 --- a/chromium/base/process/process_metrics_mac.cc +++ b/chromium/base/process/process_metrics_mac.cc @@ -19,7 +19,6 @@ #include "base/memory/ptr_util.h" #include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" -#include "base/sys_info.h" namespace base { @@ -105,6 +104,18 @@ MachVMRegionResult ParseOutputFromMachVMRegion(kern_return_t kr) { return MachVMRegionResult::Success; } +bool GetPowerInfo(mach_port_t task, task_power_info* power_info_data) { + if (task == MACH_PORT_NULL) + return false; + + mach_msg_type_number_t power_info_count = TASK_POWER_INFO_COUNT; + kern_return_t kr = task_info(task, TASK_POWER_INFO, + reinterpret_cast<task_info_t>(power_info_data), + &power_info_count); + // Most likely cause for failure: |task| is a zombie. + return kr == KERN_SUCCESS; +} + } // namespace // Getting a mach task from a pid for another process requires permissions in @@ -309,7 +320,7 @@ ProcessMetrics::TaskVMInfo ProcessMetrics::GetTaskVMInfo() const { (r)->tv_usec = (a)->microseconds; \ } while (0) -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { mach_port_t task = TaskForPid(process_); if (task == MACH_PORT_NULL) return 0; @@ -366,22 +377,11 @@ double ProcessMetrics::GetCPUUsage() { return static_cast<double>(system_time_delta * 100.0) / time_delta; } -int ProcessMetrics::GetIdleWakeupsPerSecond() { +int ProcessMetrics::GetPackageIdleWakeupsPerSecond() { mach_port_t task = TaskForPid(process_); - if (task == MACH_PORT_NULL) - return 0; - task_power_info power_info_data; - mach_msg_type_number_t power_info_count = TASK_POWER_INFO_COUNT; - kern_return_t kr = task_info(task, - TASK_POWER_INFO, - reinterpret_cast<task_info_t>(&power_info_data), - &power_info_count); - if (kr != KERN_SUCCESS) { - // Most likely cause: |task| is a zombie, or this is on a pre-10.8.4 system - // where TASK_POWER_INFO isn't supported yet. - return 0; - } + + GetPowerInfo(task, &power_info_data); // The task_power_info struct contains two wakeup counters: // task_interrupt_wakeups and task_platform_idle_wakeups. @@ -393,10 +393,19 @@ int ProcessMetrics::GetIdleWakeupsPerSecond() { // in a greater power increase than the other interrupts which occur while the // CPU is already working, and reducing them has a greater overall impact on // power usage. See the powermetrics man page for more info. - return CalculateIdleWakeupsPerSecond( + return CalculatePackageIdleWakeupsPerSecond( power_info_data.task_platform_idle_wakeups); } +int ProcessMetrics::GetIdleWakeupsPerSecond() { + mach_port_t task = TaskForPid(process_); + task_power_info power_info_data; + + GetPowerInfo(task, &power_info_data); + + return CalculateIdleWakeupsPerSecond(power_info_data.task_interrupt_wakeups); +} + bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { return false; } @@ -406,9 +415,8 @@ ProcessMetrics::ProcessMetrics(ProcessHandle process, : process_(process), last_system_time_(0), last_absolute_idle_wakeups_(0), - port_provider_(port_provider) { - processor_count_ = SysInfo::NumberOfProcessors(); -} + last_absolute_package_idle_wakeups_(0), + port_provider_(port_provider) {} mach_port_t ProcessMetrics::TaskForPid(ProcessHandle process) const { mach_port_t task = MACH_PORT_NULL; diff --git a/chromium/base/process/process_metrics_openbsd.cc b/chromium/base/process/process_metrics_openbsd.cc index d8fbe7e3710..c863313233b 100644 --- a/chromium/base/process/process_metrics_openbsd.cc +++ b/chromium/base/process/process_metrics_openbsd.cc @@ -11,7 +11,6 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/sys_info.h" namespace base { @@ -112,7 +111,7 @@ static int GetProcessCPU(pid_t pid) { return info.p_pctcpu; } -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { TimeTicks time = TimeTicks::Now(); if (last_cpu_ == 0) { @@ -140,7 +139,6 @@ double ProcessMetrics::GetCPUUsage() { ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process), - processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0), last_cpu_(0) {} diff --git a/chromium/base/process/process_metrics_unittest.cc b/chromium/base/process/process_metrics_unittest.cc index a09b6648382..2a187151e6a 100644 --- a/chromium/base/process/process_metrics_unittest.cc +++ b/chromium/base/process/process_metrics_unittest.cc @@ -361,15 +361,15 @@ TEST_F(SystemMetricsTest, ParseVmstat) { #if defined(OS_LINUX) || defined(OS_CHROMEOS) -// Test that ProcessMetrics::GetCPUUsage() doesn't return negative values when -// the number of threads running on the process decreases between two successive -// calls to it. +// Test that ProcessMetrics::GetPlatformIndependentCPUUsage() doesn't return +// negative values when the number of threads running on the process decreases +// between two successive calls to it. TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { ProcessHandle handle = GetCurrentProcessHandle(); std::unique_ptr<ProcessMetrics> metrics( ProcessMetrics::CreateProcessMetrics(handle)); - EXPECT_GE(metrics->GetCPUUsage(), 0.0); + EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); Thread thread1("thread1"); Thread thread2("thread2"); Thread thread3("thread3"); @@ -390,16 +390,16 @@ TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) { thread2.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec2)); thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3)); - EXPECT_GE(metrics->GetCPUUsage(), 0.0); + EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); thread1.Stop(); - EXPECT_GE(metrics->GetCPUUsage(), 0.0); + EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); thread2.Stop(); - EXPECT_GE(metrics->GetCPUUsage(), 0.0); + EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); thread3.Stop(); - EXPECT_GE(metrics->GetCPUUsage(), 0.0); + EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0); } #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) diff --git a/chromium/base/process/process_metrics_win.cc b/chromium/base/process/process_metrics_win.cc index 9de34496920..e5643ecb814 100644 --- a/chromium/base/process/process_metrics_win.cc +++ b/chromium/base/process/process_metrics_win.cc @@ -37,6 +37,11 @@ typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( ProcessMetrics::~ProcessMetrics() { } +size_t GetMaxFds() { + // Windows is only limited by the amount of physical memory. + return std::numeric_limits<size_t>::max(); +} + // static std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics( ProcessHandle process) { @@ -279,7 +284,7 @@ static uint64_t FileTimeToUTC(const FILETIME& ftime) { return li.QuadPart; } -double ProcessMetrics::GetCPUUsage() { +double ProcessMetrics::GetPlatformIndependentCPUUsage() { FILETIME creation_time; FILETIME exit_time; FILETIME kernel_time; @@ -292,9 +297,7 @@ double ProcessMetrics::GetCPUUsage() { // not yet received the notification. return 0; } - int64_t system_time = - (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) / - processor_count_; + int64_t system_time = FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time); TimeTicks time = TimeTicks::Now(); if (last_system_time_ == 0) { @@ -315,15 +318,14 @@ double ProcessMetrics::GetCPUUsage() { last_system_time_ = system_time; last_cpu_time_ = time; - return static_cast<double>(system_time_delta * 100.0) / time_delta; + return static_cast<double>(system_time_delta * 100) / time_delta; } bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { return GetProcessIoCounters(process_.Get(), io_counters) != FALSE; } -ProcessMetrics::ProcessMetrics(ProcessHandle process) - : processor_count_(SysInfo::NumberOfProcessors()), last_system_time_(0) { +ProcessMetrics::ProcessMetrics(ProcessHandle process) : last_system_time_(0) { if (process) { HANDLE duplicate_handle; BOOL result = ::DuplicateHandle(::GetCurrentProcess(), process, diff --git a/chromium/base/process/process_posix.cc b/chromium/base/process/process_posix.cc index 282923bd002..11f48f75acb 100644 --- a/chromium/base/process/process_posix.cc +++ b/chromium/base/process/process_posix.cc @@ -95,7 +95,6 @@ bool WaitpidWithTimeout(base::ProcessHandle handle, static bool WaitForSingleNonChildProcess(base::ProcessHandle handle, base::TimeDelta wait) { DCHECK_GT(handle, 0); - DCHECK_GT(wait, base::TimeDelta()); base::ScopedFD kq(kqueue()); if (!kq.is_valid()) { @@ -129,7 +128,7 @@ static bool WaitForSingleNonChildProcess(base::ProcessHandle handle, result = -1; struct kevent event = {0}; - while (wait_forever || remaining_delta > base::TimeDelta()) { + do { struct timespec remaining_timespec; struct timespec* remaining_timespec_ptr; if (wait_forever) { @@ -149,7 +148,7 @@ static bool WaitForSingleNonChildProcess(base::ProcessHandle handle, } else { break; } - } + } while (wait_forever || remaining_delta > base::TimeDelta()); if (result < 0) { DPLOG(ERROR) << "kevent (wait " << handle << ")"; @@ -182,10 +181,16 @@ static bool WaitForSingleNonChildProcess(base::ProcessHandle handle, bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle, int* exit_code, base::TimeDelta timeout) { - base::ProcessHandle parent_pid = base::GetParentProcessId(handle); - base::ProcessHandle our_pid = base::GetCurrentProcessHandle(); + const base::ProcessHandle our_pid = base::GetCurrentProcessHandle(); + if (handle == our_pid) { + // We won't be able to wait for ourselves to exit. + return false; + } - if (parent_pid != our_pid) { + const base::ProcessHandle parent_pid = base::GetParentProcessId(handle); + const bool exited = (parent_pid < 0); + + if (!exited && parent_pid != our_pid) { #if defined(OS_MACOSX) // On Mac we can wait on non child processes. return WaitForSingleNonChildProcess(handle, timeout); @@ -197,7 +202,7 @@ bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle, int status; if (!WaitpidWithTimeout(handle, &status, timeout)) - return false; + return exited; if (WIFSIGNALED(status)) { if (exit_code) *exit_code = -1; @@ -208,7 +213,7 @@ bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle, *exit_code = WEXITSTATUS(status); return true; } - return false; + return exited; } #endif // !defined(OS_NACL_NONSFI) diff --git a/chromium/base/process/process_unittest.cc b/chromium/base/process/process_unittest.cc index 8fcb9b92eb6..d9c2409fb16 100644 --- a/chromium/base/process/process_unittest.cc +++ b/chromium/base/process/process_unittest.cc @@ -287,6 +287,34 @@ TEST_F(ProcessTest, SetProcessBackgroundedSelf) { EXPECT_EQ(old_priority, new_priority); } +// Consumers can use WaitForExitWithTimeout(base::TimeDelta(), nullptr) to check +// whether the process is still running. This may not be safe because of the +// potential reusing of the process id. So we won't export Process::IsRunning() +// on all platforms. But for the controllable scenario in the test cases, the +// behavior should be guaranteed. +TEST_F(ProcessTest, CurrentProcessIsRunning) { + EXPECT_FALSE(Process::Current().WaitForExitWithTimeout( + base::TimeDelta(), nullptr)); +} + +#if defined(OS_MACOSX) +// On Mac OSX, we can detect whether a non-child process is running. +TEST_F(ProcessTest, PredefinedProcessIsRunning) { + // Process 1 is the /sbin/launchd, it should be always running. + EXPECT_FALSE(Process::Open(1).WaitForExitWithTimeout( + base::TimeDelta(), nullptr)); +} +#endif + +TEST_F(ProcessTest, ChildProcessIsRunning) { + Process process(SpawnChild("SleepyChildProcess")); + EXPECT_FALSE(process.WaitForExitWithTimeout( + base::TimeDelta(), nullptr)); + process.Terminate(0, true); + EXPECT_TRUE(process.WaitForExitWithTimeout( + base::TimeDelta(), nullptr)); +} + #if defined(OS_CHROMEOS) // Tests that the function IsProcessBackgroundedCGroup() can parse the contents diff --git a/chromium/base/process/process_util_unittest.cc b/chromium/base/process/process_util_unittest.cc index 366ec4c2d8d..74c22505f49 100644 --- a/chromium/base/process/process_util_unittest.cc +++ b/chromium/base/process/process_util_unittest.cc @@ -64,9 +64,9 @@ #include "third_party/lss/linux_syscall_support.h" #endif #if defined(OS_FUCHSIA) -#include <magenta/process.h> -#include <magenta/processargs.h> -#include <magenta/syscalls.h> +#include <zircon/process.h> +#include <zircon/processargs.h> +#include <zircon/syscalls.h> #endif using base::FilePath; @@ -742,27 +742,27 @@ TEST_F(ProcessUtilTest, FDRemappingIncludesStdio) { #if defined(OS_FUCHSIA) const uint16_t kStartupHandleId = 43; MULTIPROCESS_TEST_MAIN(ProcessUtilsVerifyHandle) { - mx_handle_t handle = - mx_get_startup_handle(PA_HND(PA_USER0, kStartupHandleId)); - CHECK_NE(MX_HANDLE_INVALID, handle); + zx_handle_t handle = + zx_get_startup_handle(PA_HND(PA_USER0, kStartupHandleId)); + CHECK_NE(ZX_HANDLE_INVALID, handle); // Write to the pipe so the parent process can observe output. size_t bytes_written = 0; - mx_status_t result = mx_socket_write(handle, 0, &kPipeValue, + zx_status_t result = zx_socket_write(handle, 0, &kPipeValue, sizeof(kPipeValue), &bytes_written); - CHECK_EQ(MX_OK, result); + CHECK_EQ(ZX_OK, result); CHECK_EQ(1u, bytes_written); - CHECK_EQ(MX_OK, mx_handle_close(handle)); + CHECK_EQ(ZX_OK, zx_handle_close(handle)); return 0; } TEST_F(ProcessUtilTest, LaunchWithHandleTransfer) { // Create a pipe to pass to the child process. - mx_handle_t handles[2]; - mx_status_t result = - mx_socket_create(MX_SOCKET_STREAM, &handles[0], &handles[1]); - ASSERT_EQ(MX_OK, result); + zx_handle_t handles[2]; + zx_status_t result = + zx_socket_create(ZX_SOCKET_STREAM, &handles[0], &handles[1]); + ASSERT_EQ(ZX_OK, result); // Launch the test process, and pass it one end of the pipe. base::LaunchOptions options; @@ -773,20 +773,20 @@ TEST_F(ProcessUtilTest, LaunchWithHandleTransfer) { ASSERT_TRUE(process.IsValid()); // Read from the pipe to verify that the child received it. - mx_signals_t signals = 0; - result = mx_object_wait_one(handles[1], MX_SOCKET_READABLE, - mx_deadline_after(MX_SEC(5)), &signals); - EXPECT_EQ(MX_OK, result); - EXPECT_TRUE(signals & MX_SOCKET_READABLE); + zx_signals_t signals = 0; + result = zx_object_wait_one(handles[1], ZX_SOCKET_READABLE, + zx_deadline_after(ZX_SEC(5)), &signals); + EXPECT_EQ(ZX_OK, result); + EXPECT_TRUE(signals & ZX_SOCKET_READABLE); size_t bytes_read = 0; char buf[16] = {0}; - result = mx_socket_read(handles[1], 0, buf, sizeof(buf), &bytes_read); - EXPECT_EQ(MX_OK, result); + result = zx_socket_read(handles[1], 0, buf, sizeof(buf), &bytes_read); + EXPECT_EQ(ZX_OK, result); EXPECT_EQ(1u, bytes_read); EXPECT_EQ(kPipeValue, buf[0]); - CHECK_EQ(MX_OK, mx_handle_close(handles[1])); + CHECK_EQ(ZX_OK, zx_handle_close(handles[1])); int exit_code; ASSERT_TRUE(process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5), @@ -982,12 +982,12 @@ TEST_F(ProcessUtilTest, GetParentProcessId) { // TODO(port): port those unit tests. bool IsProcessDead(base::ProcessHandle child) { #if defined(OS_FUCHSIA) - // ProcessHandle is an mx_handle_t, not a pid on Fuchsia, so waitpid() doesn't + // ProcessHandle is an zx_handle_t, not a pid on Fuchsia, so waitpid() doesn't // make sense. - mx_signals_t signals; + zx_signals_t signals; // Timeout of 0 to check for termination, but non-blocking. - if (mx_object_wait_one(child, MX_TASK_TERMINATED, 0, &signals) == MX_OK) { - DCHECK(signals & MX_TASK_TERMINATED); + if (zx_object_wait_one(child, ZX_TASK_TERMINATED, 0, &signals) == ZX_OK) { + DCHECK(signals & ZX_TASK_TERMINATED); return true; } return false; |