summaryrefslogtreecommitdiffstats
path: root/mojo/shell
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-14 15:06:55 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-14 15:06:55 +0000
commit57d12ab669b4be8e9adcf4789da61dc73d2b375c (patch)
treed8363de60501d62a055462e24aabd5d8202649ae /mojo/shell
parent1c008b629bd64603b9340999d40f4df738b2b67c (diff)
downloadchromium_src-57d12ab669b4be8e9adcf4789da61dc73d2b375c.zip
chromium_src-57d12ab669b4be8e9adcf4789da61dc73d2b375c.tar.gz
chromium_src-57d12ab669b4be8e9adcf4789da61dc73d2b375c.tar.bz2
Mojo: Add a simple child process launcher to the Mojo shell code.
R=sky@chromium.org Review URL: https://codereview.chromium.org/196023013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257112 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/shell')
-rw-r--r--mojo/shell/child_process.cc57
-rw-r--r--mojo/shell/child_process.h56
-rw-r--r--mojo/shell/child_process_host.cc95
-rw-r--r--mojo/shell/child_process_host.h69
-rw-r--r--mojo/shell/desktop/mojo_main.cc52
-rw-r--r--mojo/shell/switches.cc5
-rw-r--r--mojo/shell/switches.h3
-rw-r--r--mojo/shell/task_runners.cc11
-rw-r--r--mojo/shell/task_runners.h12
-rw-r--r--mojo/shell/test_child_process.cc38
-rw-r--r--mojo/shell/test_child_process.h28
11 files changed, 416 insertions, 10 deletions
diff --git a/mojo/shell/child_process.cc b/mojo/shell/child_process.cc
new file mode 100644
index 0000000..89a289a
--- /dev/null
+++ b/mojo/shell/child_process.cc
@@ -0,0 +1,57 @@
+// Copyright 2014 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 "mojo/shell/child_process.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "mojo/shell/switches.h"
+#include "mojo/shell/test_child_process.h"
+#include "mojo/system/embedder/platform_channel_pair.h"
+
+namespace mojo {
+namespace shell {
+
+ChildProcess::~ChildProcess() {
+}
+
+// static
+scoped_ptr<ChildProcess> ChildProcess::Create(const CommandLine& command_line) {
+ if (!command_line.HasSwitch(switches::kChildProcessType))
+ return scoped_ptr<ChildProcess>();
+
+ int type_as_int;
+ CHECK(base::StringToInt(command_line.GetSwitchValueASCII(
+ switches::kChildProcessType), &type_as_int));
+
+ scoped_ptr<ChildProcess> rv;
+ switch (type_as_int) {
+ case TYPE_TEST:
+ rv.reset(new TestChildProcess());
+ break;
+ default:
+ CHECK(false) << "Invalid child process type";
+ break;
+ }
+
+ if (rv) {
+ rv->platform_channel_ =
+ embedder::PlatformChannelPair::PassClientHandleFromParentProcess(
+ command_line);
+ CHECK(rv->platform_channel_.is_valid());
+ }
+
+ return rv.Pass();
+}
+
+void ChildProcess::Run() {
+ Main();
+}
+
+ChildProcess::ChildProcess() {
+}
+
+} // namespace shell
+} // namespace mojo
diff --git a/mojo/shell/child_process.h b/mojo/shell/child_process.h
new file mode 100644
index 0000000..e5ce65a
--- /dev/null
+++ b/mojo/shell/child_process.h
@@ -0,0 +1,56 @@
+// Copyright 2014 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.
+
+#ifndef MOJO_SHELL_CHILD_PROCESS_H_
+#define MOJO_SHELL_CHILD_PROCESS_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/system/embedder/scoped_platform_handle.h"
+
+class CommandLine;
+
+namespace mojo {
+namespace shell {
+
+// A base class for child processes -- i.e., code that is actually run within
+// the child process. (Instances are manufactured by |Create()|.)
+class ChildProcess {
+ public:
+ enum Type {
+ // TODO(vtl): Add real types here.
+ TYPE_TEST
+ };
+
+ // Returns null if the command line doesn't indicate that this is a child
+ // process. |main()| should call this, and if it returns non-null it should
+ // call |Run()| inside a main message loop.
+ static scoped_ptr<ChildProcess> Create(const CommandLine& command_line);
+
+ void Run();
+
+ virtual ~ChildProcess();
+
+ // To be implemented by subclasses. This is the "entrypoint" for a child
+ // process.
+ virtual void Main() = 0;
+
+ protected:
+ ChildProcess();
+
+ embedder::ScopedPlatformHandle* platform_channel() {
+ return &platform_channel_;
+ }
+
+ private:
+ // Available in |Main()| (after |Run()|).
+ embedder::ScopedPlatformHandle platform_channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildProcess);
+};
+
+} // namespace shell
+} // namespace mojo
+
+#endif // MOJO_SHELL_CHILD_PROCESS_H_
diff --git a/mojo/shell/child_process_host.cc b/mojo/shell/child_process_host.cc
new file mode 100644
index 0000000..66b7572
--- /dev/null
+++ b/mojo/shell/child_process_host.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 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 "mojo/shell/child_process_host.h"
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+#include "mojo/shell/context.h"
+#include "mojo/shell/switches.h"
+#include "mojo/system/embedder/platform_channel_pair.h"
+
+namespace mojo {
+namespace shell {
+
+ChildProcessHost::ChildProcessHost(Context* context, ChildProcess::Type type)
+ : process_launch_task_runner_(context->task_runners()->blocking_pool()),
+ type_(type),
+ child_process_handle_(base::kNullProcessHandle) {
+}
+
+ChildProcessHost::~ChildProcessHost() {
+ if (child_process_handle_ != base::kNullProcessHandle) {
+ LOG(WARNING) << "Destroying ChildProcessHost with unjoined child";
+ base::CloseProcessHandle(child_process_handle_);
+ child_process_handle_ = base::kNullProcessHandle;
+ }
+}
+
+void ChildProcessHost::Start(DidStartCallback callback) {
+ DCHECK_EQ(child_process_handle_, base::kNullProcessHandle);
+ CHECK(base::PostTaskAndReplyWithResult(
+ process_launch_task_runner_,
+ FROM_HERE,
+ base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)),
+ callback));
+}
+
+int ChildProcessHost::Join() {
+ DCHECK_NE(child_process_handle_, base::kNullProcessHandle);
+ int rv = -1;
+ LOG_IF(ERROR, !base::WaitForExitCode(child_process_handle_, &rv))
+ << "Failed to wait for child process";
+ base::CloseProcessHandle(child_process_handle_);
+ child_process_handle_ = base::kNullProcessHandle;
+ return rv;
+}
+
+bool ChildProcessHost::DoLaunch() {
+ static const char* kForwardSwitches[] = {
+ switches::kTraceToConsole,
+ switches::kV,
+ switches::kVModule,
+ };
+
+ const CommandLine* parent_command_line = CommandLine::ForCurrentProcess();
+ CommandLine child_command_line(parent_command_line->GetProgram());
+ child_command_line.CopySwitchesFrom(*parent_command_line, kForwardSwitches,
+ arraysize(kForwardSwitches));
+ child_command_line.AppendSwitchASCII(
+ switches::kChildProcessType, base::IntToString(static_cast<int>(type_)));
+
+ embedder::PlatformChannelPair platform_channel_pair;
+ embedder::HandlePassingInformation handle_passing_info;
+ platform_channel_pair.PrepareToPassClientHandleToChildProcess(
+ &child_command_line, &handle_passing_info);
+
+ base::LaunchOptions options;
+#if defined(OS_WIN)
+ options.start_hidden = true;
+ options.handles_to_inherit = &handle_passing_info;
+#elif defined(OS_POSIX)
+ options.fds_to_remap = &handle_passing_info;
+#endif
+
+ if (!base::LaunchProcess(child_command_line, options, &child_process_handle_))
+ return false;
+
+ platform_channel_pair.ChildProcessLaunched();
+ platform_channel_ = platform_channel_pair.PassServerHandle();
+ CHECK(platform_channel_.is_valid());
+ return true;
+}
+
+} // namespace shell
+} // namespace mojo
diff --git a/mojo/shell/child_process_host.h b/mojo/shell/child_process_host.h
new file mode 100644
index 0000000..b815c3b
--- /dev/null
+++ b/mojo/shell/child_process_host.h
@@ -0,0 +1,69 @@
+// Copyright 2014 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.
+
+#ifndef MOJO_SHELL_CHILD_PROCESS_HOST_H_
+#define MOJO_SHELL_CHILD_PROCESS_HOST_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/process/process_handle.h"
+#include "mojo/shell/child_process.h" // For |ChildProcess::Type|.
+#include "mojo/system/embedder/scoped_platform_handle.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace mojo {
+namespace shell {
+
+class Context;
+
+// (Base) class for a "child process host". Handles launching and connecting a
+// platform-specific "pipe" to the child, and supports joining the child
+// process. Intended for use as a base class, but may be used on its own in
+// simple cases.
+//
+// This class is not thread-safe. It should be created/used/destroyed on a
+// single thread.
+//
+// Note: Does not currently work on Windows before Vista.
+class ChildProcessHost {
+ public:
+ ChildProcessHost(Context* context, ChildProcess::Type type);
+ ~ChildProcessHost();
+
+ // |Start()|s a
+ typedef base::Callback<void(bool success)> DidStartCallback;
+ void Start(DidStartCallback callback);
+
+ // Waits for the child process to terminate, and returns its exit code.
+ // Note: If |Start()| has been called, this must not be called until the
+ // callback has been called.
+ int Join();
+
+ embedder::ScopedPlatformHandle* platform_channel() {
+ return &platform_channel_;
+ }
+
+ private:
+ bool DoLaunch();
+
+ scoped_refptr<base::TaskRunner> process_launch_task_runner_;
+ const ChildProcess::Type type_;
+
+ base::ProcessHandle child_process_handle_;
+
+ // Platform-specific "pipe" to the child process.
+ // Valid after the |Start()| callback has been completed (successfully).
+ embedder::ScopedPlatformHandle platform_channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildProcessHost);
+};
+
+} // namespace shell
+} // namespace mojo
+
+#endif // MOJO_SHELL_CHILD_PROCESS_HOST_H_
diff --git a/mojo/shell/desktop/mojo_main.cc b/mojo/shell/desktop/mojo_main.cc
index 9be9647..df05b6d 100644
--- a/mojo/shell/desktop/mojo_main.cc
+++ b/mojo/shell/desktop/mojo_main.cc
@@ -3,26 +3,64 @@
// found in the LICENSE file.
#include "base/at_exit.h"
-#include "base/bind.h"
+#include "base/bind.h" // TODO(vtl): Remove.
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "mojo/shell/child_process.h"
+#include "mojo/shell/child_process_host.h" // TODO(vtl): Remove.
#include "mojo/shell/context.h"
#include "mojo/shell/init.h"
#include "mojo/shell/run.h"
#include "ui/gl/gl_surface.h"
+namespace {
+
+// TODO(vtl): Remove.
+void DidStartTestChild(base::MessageLoop* message_loop, bool success) {
+ VLOG(2) << "DidStartTestChild: success = " << success;
+ message_loop->QuitWhenIdle();
+}
+
+} // namespace
+
int main(int argc, char** argv) {
base::AtExitManager at_exit;
CommandLine::Init(argc, argv);
-
mojo::shell::InitializeLogging();
- gfx::GLSurface::InitializeOneOff();
+ // TODO(vtl): Move this a proper test (and remove includes marked "remove").
+ if (CommandLine::ForCurrentProcess()->HasSwitch("run-test-child")) {
+ base::MessageLoop message_loop;
+ mojo::shell::Context context;
+ mojo::shell::ChildProcessHost child_process_host(
+ &context, mojo::shell::ChildProcess::TYPE_TEST);
+ child_process_host.Start(base::Bind(&DidStartTestChild, &message_loop));
+ message_loop.Run();
+ VLOG(2) << "Joined child: exit_code = " << child_process_host.Join();
+ return 0;
+ }
+
+ // TODO(vtl): Unify parent and child process cases to the extent possible.
+ if (scoped_ptr<mojo::shell::ChildProcess> child_process =
+ mojo::shell::ChildProcess::Create(
+ *CommandLine::ForCurrentProcess())) {
+ base::MessageLoop message_loop;
+ message_loop.PostTask(
+ FROM_HERE,
+ base::Bind(&mojo::shell::ChildProcess::Run,
+ base::Unretained(child_process.get())));
+
+ message_loop.Run();
+ } else {
+ gfx::GLSurface::InitializeOneOff();
+
+ base::MessageLoop message_loop;
+ mojo::shell::Context context;
+ message_loop.PostTask(FROM_HERE, base::Bind(mojo::shell::Run, &context));
- base::MessageLoop message_loop;
- mojo::shell::Context context;
- message_loop.PostTask(FROM_HERE, base::Bind(mojo::shell::Run, &context));
+ message_loop.Run();
+ }
- message_loop.Run();
return 0;
}
diff --git a/mojo/shell/switches.cc b/mojo/shell/switches.cc
index 260578a..a073c4a 100644
--- a/mojo/shell/switches.cc
+++ b/mojo/shell/switches.cc
@@ -6,9 +6,14 @@
namespace switches {
+// Used to specify the type of child process (switch values from
+// |ChildProcess::Type|).
+const char kChildProcessType[] = "child-process-type";
+
// Force dynamically loaded apps / services to be loaded irrespective of cache
// instructions.
const char kDisableCache[] = "disable-cache";
+
const char kOrigin[] = "origin";
} // namespace switches
diff --git a/mojo/shell/switches.h b/mojo/shell/switches.h
index b145c40..066f3de 100644
--- a/mojo/shell/switches.h
+++ b/mojo/shell/switches.h
@@ -7,6 +7,9 @@
namespace switches {
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kChildProcessType[];
extern const char kDisableCache[];
extern const char kOrigin[];
diff --git a/mojo/shell/task_runners.cc b/mojo/shell/task_runners.cc
index 119ccd1..ec1cffa 100644
--- a/mojo/shell/task_runners.cc
+++ b/mojo/shell/task_runners.cc
@@ -4,13 +4,15 @@
#include "mojo/shell/task_runners.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/threading/thread.h"
+#include "base/threading/sequenced_worker_pool.h"
namespace mojo {
namespace shell {
+
namespace {
+const size_t kMaxBlockingPoolThreads = 3;
+
scoped_ptr<base::Thread> CreateIOThread(const char* name) {
scoped_ptr<base::Thread> thread(new base::Thread(name));
base::Thread::Options options;
@@ -25,11 +27,14 @@ TaskRunners::TaskRunners(base::SingleThreadTaskRunner* ui_runner)
: ui_runner_(ui_runner),
cache_thread_(CreateIOThread("cache_thread")),
io_thread_(CreateIOThread("io_thread")),
- file_thread_(new base::Thread("file_thread")) {
+ file_thread_(new base::Thread("file_thread")),
+ blocking_pool_(new base::SequencedWorkerPool(kMaxBlockingPoolThreads,
+ "blocking_pool")) {
file_thread_->Start();
}
TaskRunners::~TaskRunners() {
+ blocking_pool_->Shutdown();
}
} // namespace shell
diff --git a/mojo/shell/task_runners.h b/mojo/shell/task_runners.h
index 7311cad..a6b59b4 100644
--- a/mojo/shell/task_runners.h
+++ b/mojo/shell/task_runners.h
@@ -5,10 +5,16 @@
#ifndef MOJO_SHELL_TASK_RUNNERS_H_
#define MOJO_SHELL_TASK_RUNNERS_H_
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/thread.h"
+namespace base {
+class SequencedWorkerPool;
+}
+
namespace mojo {
namespace shell {
@@ -34,6 +40,10 @@ class TaskRunners {
return cache_thread_->message_loop_proxy();
}
+ base::SequencedWorkerPool* blocking_pool() const {
+ return blocking_pool_.get();
+ }
+
private:
// TODO(beng): should this be named shell_runner_?
scoped_refptr<base::SingleThreadTaskRunner> ui_runner_;
@@ -41,6 +51,8 @@ class TaskRunners {
scoped_ptr<base::Thread> io_thread_;
scoped_ptr<base::Thread> file_thread_;
+ scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
+
DISALLOW_COPY_AND_ASSIGN(TaskRunners);
};
diff --git a/mojo/shell/test_child_process.cc b/mojo/shell/test_child_process.cc
new file mode 100644
index 0000000..ce55b83
--- /dev/null
+++ b/mojo/shell/test_child_process.cc
@@ -0,0 +1,38 @@
+// Copyright 2014 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 "mojo/shell/test_child_process.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+
+namespace mojo {
+namespace shell {
+
+namespace {
+
+void TrivialPostedTask() {
+ VLOG(2) << "TrivialPostedTask()";
+}
+
+} // namespace
+
+TestChildProcess::TestChildProcess() {
+}
+
+TestChildProcess::~TestChildProcess() {
+}
+
+void TestChildProcess::Main() {
+ VLOG(2) << "TestChildProcess::Main()";
+
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&TrivialPostedTask));
+ base::MessageLoop::current()->QuitWhenIdle();
+}
+
+} // namespace shell
+} // namespace mojo
diff --git a/mojo/shell/test_child_process.h b/mojo/shell/test_child_process.h
new file mode 100644
index 0000000..c2d440b
--- /dev/null
+++ b/mojo/shell/test_child_process.h
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+#ifndef MOJO_SHELL_TEST_CHILD_PROCESS_H_
+#define MOJO_SHELL_TEST_CHILD_PROCESS_H_
+
+#include "base/macros.h"
+#include "mojo/shell/child_process.h"
+
+namespace mojo {
+namespace shell {
+
+class TestChildProcess : public ChildProcess {
+ public:
+ TestChildProcess();
+ virtual ~TestChildProcess();
+
+ virtual void Main() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestChildProcess);
+};
+
+} // namespace shell
+} // namespace mojo
+
+#endif // MOJO_SHELL_TEST_CHILD_PROCESS_H_