diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-14 15:06:55 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-14 15:06:55 +0000 |
commit | 57d12ab669b4be8e9adcf4789da61dc73d2b375c (patch) | |
tree | d8363de60501d62a055462e24aabd5d8202649ae /mojo | |
parent | 1c008b629bd64603b9340999d40f4df738b2b67c (diff) | |
download | chromium_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')
-rw-r--r-- | mojo/mojo.gyp | 7 | ||||
-rw-r--r-- | mojo/shell/child_process.cc | 57 | ||||
-rw-r--r-- | mojo/shell/child_process.h | 56 | ||||
-rw-r--r-- | mojo/shell/child_process_host.cc | 95 | ||||
-rw-r--r-- | mojo/shell/child_process_host.h | 69 | ||||
-rw-r--r-- | mojo/shell/desktop/mojo_main.cc | 52 | ||||
-rw-r--r-- | mojo/shell/switches.cc | 5 | ||||
-rw-r--r-- | mojo/shell/switches.h | 3 | ||||
-rw-r--r-- | mojo/shell/task_runners.cc | 11 | ||||
-rw-r--r-- | mojo/shell/task_runners.h | 12 | ||||
-rw-r--r-- | mojo/shell/test_child_process.cc | 38 | ||||
-rw-r--r-- | mojo/shell/test_child_process.h | 28 |
12 files changed, 423 insertions, 10 deletions
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index d5cae4a..0351783 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -356,6 +356,7 @@ 'type': 'static_library', 'dependencies': [ '../base/base.gyp:base', + '../base/base.gyp:base_static', '../net/net.gyp:net', '../url/url.gyp:url_lib', 'mojo_gles2_impl', @@ -366,6 +367,10 @@ 'mojo_native_viewport_service', ], 'sources': [ + 'shell/child_process.cc', + 'shell/child_process.h', + 'shell/child_process_host.cc', + 'shell/child_process_host.h', 'shell/context.cc', 'shell/context.h', 'shell/dynamic_service_loader.cc', @@ -386,6 +391,8 @@ 'shell/switches.h', 'shell/task_runners.cc', 'shell/task_runners.h', + 'shell/test_child_process.cc', + 'shell/test_child_process.h', 'shell/url_request_context_getter.cc', 'shell/url_request_context_getter.h', ], 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_ |