Index: services/native_support/process_controller_impl.cc |
diff --git a/services/native_support/process_controller_impl.cc b/services/native_support/process_controller_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d4a9919417ec63cdf9b44f9ea31c4932b57686c7 |
--- /dev/null |
+++ b/services/native_support/process_controller_impl.cc |
@@ -0,0 +1,122 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "services/native_support/process_controller_impl.h" |
+ |
+#include <errno.h> |
+#include <signal.h> |
+#include <sys/types.h> |
+ |
+#include <utility> |
+ |
+#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/location.h" |
+#include "base/logging.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/task_runner.h" |
+#include "base/threading/simple_thread.h" |
+#include "mojo/services/files/public/interfaces/types.mojom.h" |
+#include "services/native_support/process_io_redirection.h" |
+ |
+namespace native_support { |
+ |
+namespace { |
+ |
+void WaitForProcess( |
+ base::Process process, |
+ scoped_refptr<base::TaskRunner> done_runner, |
+ const base::Callback<void(mojo::files::Error, int32_t)>& done_callback) { |
+ int exit_status = 0; |
+ mojo::files::Error result = process.WaitForExit(&exit_status) |
+ ? mojo::files::ERROR_OK |
+ : mojo::files::ERROR_UNKNOWN; |
+ done_runner->PostTask( |
+ FROM_HERE, |
+ base::Bind(done_callback, result, static_cast<int32_t>(exit_status))); |
+} |
+ |
+void TerminateProcess(base::Process process) { |
+ if (!process.Terminate(-1, true)) |
+ LOG(ERROR) << "Failed to kill PID " << process.Pid(); |
+} |
+ |
+} // namespace |
+ |
+ProcessControllerImpl::ProcessControllerImpl( |
+ scoped_refptr<base::TaskRunner> worker_runner, |
+ mojo::InterfaceRequest<ProcessController> request, |
+ base::Process process, |
+ std::unique_ptr<ProcessIORedirection> process_io_redirection) |
+ : worker_runner_(worker_runner.Pass()), |
+ binding_(this, request.Pass()), |
+ process_(process.Pass()), |
+ process_io_redirection_(std::move(process_io_redirection)), |
+ weak_factory_(this) { |
+ DCHECK(process_.IsValid()); |
+} |
+ |
+ProcessControllerImpl::~ProcessControllerImpl() { |
+ if (process_.IsValid()) { |
+ worker_runner_->PostTask( |
+ FROM_HERE, base::Bind(&TerminateProcess, base::Passed(&process_))); |
+ } |
+} |
+ |
+void ProcessControllerImpl::Wait(const WaitCallback& callback) { |
+ if (!process_.IsValid()) { |
+ // TODO(vtl): This isn't quite right. |
+ callback.Run(mojo::files::ERROR_UNAVAILABLE, 0); |
+ return; |
+ } |
+ |
+ worker_runner_->PostTask( |
+ FROM_HERE, base::Bind(&WaitForProcess, base::Passed(&process_), |
+ base::MessageLoop::current()->task_runner(), |
+ base::Bind(&ProcessControllerImpl::OnWaitComplete, |
+ weak_factory_.GetWeakPtr(), callback))); |
+} |
+ |
+void ProcessControllerImpl::Kill(int32_t signal, const KillCallback& callback) { |
+ callback.Run(KillHelper(signal)); |
+} |
+ |
+void ProcessControllerImpl::OnWaitComplete(const WaitCallback& callback, |
+ mojo::files::Error result, |
+ int32_t exit_status) { |
+ callback.Run(result, exit_status); |
+} |
+ |
+mojo::files::Error ProcessControllerImpl::KillHelper(int32_t signal) { |
+ if (signal < 0) |
+ return mojo::files::ERROR_INVALID_ARGUMENT; |
+ |
+ if (!process_.IsValid()) { |
+ LOG(ERROR) << "Kill() called after Wait()"; |
+ // TODO(vtl): This error code isn't quite right, but "unavailable" (which |
+ // would also be wrong) is used for a more appropriate purpose below. |
+ return mojo::files::ERROR_INVALID_ARGUMENT; |
+ } |
+ |
+ // |base::HandleType| is just a typedef for |pid_t|. |
+ pid_t pid = process_.Handle(); |
+ |
+ // Note: |kill()| is not interruptible. |
+ if (kill(pid, static_cast<int>(signal)) == 0) |
+ return mojo::files::ERROR_OK; |
+ |
+ switch (errno) { |
+ case EINVAL: |
+ return mojo::files::ERROR_INVALID_ARGUMENT; |
+ case EPERM: |
+ return mojo::files::ERROR_PERMISSION_DENIED; |
+ case ESRCH: |
+ return mojo::files::ERROR_UNAVAILABLE; |
+ default: |
+ break; |
+ } |
+ return mojo::files::ERROR_UNKNOWN; |
+} |
+ |
+} // namespace native_support |