diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-03 23:44:57 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-03 23:44:57 +0000 |
commit | 2f8f0c044fb4b4e715b0bf4d4e7148aa467b12de (patch) | |
tree | 63bad5b85985f3bdbc39d70a44d99891a9c976ed /mojo | |
parent | 1c0f34e2613ea5af8be7cf5618aee4e854463c1d (diff) | |
download | chromium_src-2f8f0c044fb4b4e715b0bf4d4e7148aa467b12de.zip chromium_src-2f8f0c044fb4b4e715b0bf4d4e7148aa467b12de.tar.gz chromium_src-2f8f0c044fb4b4e715b0bf4d4e7148aa467b12de.tar.bz2 |
Mojo: (POSIX) Pass channel handle to child.
R=darin@chromium.org
Review URL: https://codereview.chromium.org/103113002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238487 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/common/test/multiprocess_test_base.cc | 29 | ||||
-rw-r--r-- | mojo/common/test/multiprocess_test_base.h | 10 | ||||
-rw-r--r-- | mojo/common/test/multiprocess_test_base_unittest.cc | 15 | ||||
-rw-r--r-- | mojo/mojo.gyp | 1 | ||||
-rw-r--r-- | mojo/system/platform_channel.cc | 5 | ||||
-rw-r--r-- | mojo/system/platform_channel_handle.cc | 37 | ||||
-rw-r--r-- | mojo/system/platform_channel_handle.h | 4 | ||||
-rw-r--r-- | mojo/system/platform_channel_posix.cc | 70 |
8 files changed, 138 insertions, 33 deletions
diff --git a/mojo/common/test/multiprocess_test_base.cc b/mojo/common/test/multiprocess_test_base.cc index 85aaa76..e637e69 100644 --- a/mojo/common/test/multiprocess_test_base.cc +++ b/mojo/common/test/multiprocess_test_base.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/process/kill.h" #include "base/process/process_handle.h" +// TODO(vtl): Remove build_config.h include when fully implemented on Windows. #include "build/build_config.h" namespace mojo { @@ -28,7 +29,7 @@ void MultiprocessTestBase::SetUp() { // TODO(vtl): Not implemented on Windows yet. #if defined(OS_POSIX) - platform_server_channel_ = + platform_server_channel = system::PlatformServerChannel::Create("TestChannel"); #endif } @@ -36,13 +37,13 @@ void MultiprocessTestBase::SetUp() { void MultiprocessTestBase::TearDown() { CHECK_EQ(test_child_handle_, base::kNullProcessHandle); - platform_server_channel_.reset(); + platform_server_channel.reset(); MultiProcessTest::TearDown(); } void MultiprocessTestBase::StartChild(const std::string& test_child_name) { - CHECK(platform_server_channel_.get()); + CHECK(platform_server_channel.get()); CHECK(!test_child_name.empty()); CHECK_EQ(test_child_handle_, base::kNullProcessHandle); @@ -51,7 +52,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) { #if defined(OS_POSIX) CommandLine unused(CommandLine::NO_PROGRAM); base::FileHandleMappingVector fds_to_map; - platform_server_channel_->GetDataNeededToPassClientChannelToChildProcess( + platform_server_channel->GetDataNeededToPassClientChannelToChildProcess( &unused, &fds_to_map); test_child_handle_ = SpawnChild(test_child_main, fds_to_map, false); #elif defined(OS_WIN) @@ -61,7 +62,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) { #endif // TODO(vtl): Not implemented on Windows yet. #if defined(OS_POSIX) - platform_server_channel_->ChildProcessLaunched(); + platform_server_channel->ChildProcessLaunched(); #endif CHECK_NE(test_child_handle_, base::kNullProcessHandle); @@ -81,14 +82,14 @@ int MultiprocessTestBase::WaitForChildShutdown() { CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname, bool debug_on_start) { - CHECK(platform_server_channel_.get()); + CHECK(platform_server_channel.get()); CommandLine command_line = base::MultiProcessTest::MakeCmdLine(procname, debug_on_start); // TODO(vtl): Not implemented on Windows yet. #if defined(OS_POSIX) base::FileHandleMappingVector unused; - platform_server_channel_->GetDataNeededToPassClientChannelToChildProcess( + platform_server_channel->GetDataNeededToPassClientChannelToChildProcess( &command_line, &unused); #endif return command_line; @@ -96,9 +97,19 @@ CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname, // static void MultiprocessTestBase::ChildSetup() { - // TODO(vtl) - NOTIMPLEMENTED(); + CHECK(CommandLine::InitializedForCurrentProcess()); +// TODO(vtl): Not implemented on Windows yet. +#if defined(OS_POSIX) + platform_client_channel = + system::PlatformClientChannel::CreateFromParentProcess( + *CommandLine::ForCurrentProcess()); + CHECK(platform_client_channel.get()); +#endif } +// static +scoped_ptr<system::PlatformClientChannel> + MultiprocessTestBase::platform_client_channel; + } // namespace test } // namespace mojo diff --git a/mojo/common/test/multiprocess_test_base.h b/mojo/common/test/multiprocess_test_base.h index 08b66a3..c983df2 100644 --- a/mojo/common/test/multiprocess_test_base.h +++ b/mojo/common/test/multiprocess_test_base.h @@ -39,9 +39,11 @@ class MultiprocessTestBase : public base::MultiProcessTest { // For use by |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| only: static void ChildSetup(); - system::PlatformServerChannel* platform_server_channel() { - return platform_server_channel_.get(); - } + // For use in the main process: + scoped_ptr<system::PlatformServerChannel> platform_server_channel; + + // For use (and only valid) in the child process: + static scoped_ptr<system::PlatformClientChannel> platform_client_channel; private: virtual CommandLine MakeCmdLine(const std::string& procname, @@ -50,8 +52,6 @@ class MultiprocessTestBase : public base::MultiProcessTest { // Valid after |StartChild()| and before |WaitForChildShutdown()|. base::ProcessHandle test_child_handle_; - scoped_ptr<system::PlatformServerChannel> platform_server_channel_; - DISALLOW_COPY_AND_ASSIGN(MultiprocessTestBase); }; diff --git a/mojo/common/test/multiprocess_test_base_unittest.cc b/mojo/common/test/multiprocess_test_base_unittest.cc index 681d8bc4..be72bee 100644 --- a/mojo/common/test/multiprocess_test_base_unittest.cc +++ b/mojo/common/test/multiprocess_test_base_unittest.cc @@ -4,6 +4,10 @@ #include "mojo/common/test/multiprocess_test_base.h" +#include "base/logging.h" +// TODO(vtl): Remove build_config.h include when fully implemented on Windows. +#include "build/build_config.h" + namespace mojo { namespace { @@ -11,11 +15,22 @@ class MultiprocessTestBaseTest : public test::MultiprocessTestBase { }; TEST_F(MultiprocessTestBaseTest, RunChild) { +// TODO(vtl): Not implemented on Windows yet. +#if defined(OS_POSIX) + EXPECT_TRUE(platform_server_channel.get()); + EXPECT_TRUE(platform_server_channel->is_valid()); +#endif StartChild("RunChild"); EXPECT_EQ(123, WaitForChildShutdown()); } MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) { +// TODO(vtl): Not implemented on Windows yet. +#if defined(OS_POSIX) + CHECK(MultiprocessTestBaseTest::platform_client_channel.get()); + CHECK(MultiprocessTestBaseTest::platform_client_channel->is_valid()); + // TODO(vtl): Check the client channel. +#endif return 123; } diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index 1f0f013..df95f5e 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -92,6 +92,7 @@ 'system/message_pipe_endpoint.h', 'system/platform_channel.cc', 'system/platform_channel.h', + 'system/platform_channel_handle.cc', 'system/platform_channel_handle.h', 'system/platform_channel_posix.cc', 'system/proxy_message_pipe_endpoint.cc', diff --git a/mojo/system/platform_channel.cc b/mojo/system/platform_channel.cc index d5066b5..46657e6 100644 --- a/mojo/system/platform_channel.cc +++ b/mojo/system/platform_channel.cc @@ -10,9 +10,7 @@ namespace mojo { namespace system { PlatformChannel::~PlatformChannel() { - // Implementations must close the handle if necessary (e.g., if no one else - // has taken ownership). - DCHECK(!is_valid()); + handle_.CloseIfNecessary(); } PlatformChannelHandle PlatformChannel::PassHandle() { @@ -34,6 +32,7 @@ PlatformServerChannel::PlatformServerChannel(const std::string& name) // static scoped_ptr<PlatformClientChannel> PlatformClientChannel::CreateFromHandle( const PlatformChannelHandle& handle) { + DCHECK(handle.is_valid()); scoped_ptr<PlatformClientChannel> rv(new PlatformClientChannel()); *rv->mutable_handle() = handle; return rv.Pass(); diff --git a/mojo/system/platform_channel_handle.cc b/mojo/system/platform_channel_handle.cc new file mode 100644 index 0000000..f762c7a --- /dev/null +++ b/mojo/system/platform_channel_handle.cc @@ -0,0 +1,37 @@ +// Copyright 2013 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/system/platform_channel_handle.h" + +#include "build/build_config.h" +#if defined(OS_POSIX) +#include <unistd.h> +#elif defined(OS_WIN) +#include <windows.h> +#else +#error "Platform not yet supported." +#endif + +#include "base/logging.h" + +namespace mojo { +namespace system { + +void PlatformChannelHandle::CloseIfNecessary() { + if (!is_valid()) + return; + +#if defined(OS_POSIX) + DPCHECK(close(fd) == 0); + fd = -1; +#elif defined(OS_WIN) + DPCHECK(CloseHandle(handle)); + handle = INVALID_HANDLE_VALUE; +#else +#error "Platform not yet supported." +#endif +} + +} // namespace system +} // namespace mojo diff --git a/mojo/system/platform_channel_handle.h b/mojo/system/platform_channel_handle.h index abae838..3bb541b 100644 --- a/mojo/system/platform_channel_handle.h +++ b/mojo/system/platform_channel_handle.h @@ -19,6 +19,8 @@ struct PlatformChannelHandle { PlatformChannelHandle() : fd(-1) {} explicit PlatformChannelHandle(int fd) : fd(fd) {} + void CloseIfNecessary(); + bool is_valid() const { return fd != -1; } int fd; @@ -28,6 +30,8 @@ struct PlatformChannelHandle { PlatformChannelHandle() : handle(INVALID_HANDLE_VALUE) {} explicit PlatformChannelHandle(HANDLE handle) : handle(handle) {} + void CloseIfNecessary(); + bool is_valid() const { return handle != INVALID_HANDLE_VALUE; } HANDLE handle; diff --git a/mojo/system/platform_channel_posix.cc b/mojo/system/platform_channel_posix.cc index 0b64620..4c23657 100644 --- a/mojo/system/platform_channel_posix.cc +++ b/mojo/system/platform_channel_posix.cc @@ -9,20 +9,27 @@ #include <sys/types.h> #include <unistd.h> +#include "base/command_line.h" #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/posix/global_descriptors.h" +#include "base/strings/string_number_conversions.h" namespace mojo { namespace system { namespace { -void CloseIfNecessary(PlatformChannelHandle* handle) { - if (!handle->is_valid()) - return; +const char kMojoChannelDescriptorSwitch[] = "mojo-channel-descriptor"; - PCHECK(close(handle->fd) == 0); - *handle = PlatformChannelHandle(); +bool IsTargetDescriptorUsed( + const base::FileHandleMappingVector& file_handle_mapping, + int target_fd) { + for (size_t i = 0; i < file_handle_mapping.size(); i++) { + if (file_handle_mapping[i].second == target_fd) + return true; + } + return false; } class PlatformServerChannelPosix : public PlatformServerChannel { @@ -59,10 +66,7 @@ PlatformServerChannelPosix::PlatformServerChannelPosix( } PlatformServerChannelPosix::~PlatformServerChannelPosix() { - if (is_valid()) - CloseIfNecessary(mutable_handle()); - if (client_handle_.is_valid()) - CloseIfNecessary(&client_handle_); + client_handle_.CloseIfNecessary(); } scoped_ptr<PlatformClientChannel> @@ -82,13 +86,39 @@ scoped_ptr<PlatformClientChannel> void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess( CommandLine* command_line, base::FileHandleMappingVector* file_handle_mapping) const { - // TODO(vtl) - NOTIMPLEMENTED(); + DCHECK(command_line); + DCHECK(file_handle_mapping); + // This is an arbitrary sanity check. (Note that this guarantees that the loop + // below will terminate sanely.) + CHECK_LT(file_handle_mapping->size(), 1000u); + + DCHECK(client_handle_.is_valid()); + + // Find a suitable FD to map our client handle to in the child process. + // This has quadratic time complexity in the size of |*file_handle_mapping|, + // but |*file_handle_mapping| should be very small (usually/often empty). + int target_fd = base::GlobalDescriptors::kBaseDescriptor; + while (IsTargetDescriptorUsed(*file_handle_mapping, target_fd)) + target_fd++; + + file_handle_mapping->push_back(std::pair<int, int>(client_handle_.fd, + target_fd)); + // Log a warning if the command line already has the switch, but "clobber" it + // anyway, since it's reasonably likely that all the switches were just copied + // from the parent. + LOG_IF(WARNING, command_line->HasSwitch(kMojoChannelDescriptorSwitch)) + << "Child command line already has switch --" + << kMojoChannelDescriptorSwitch << "=" + << command_line->GetSwitchValueASCII(kMojoChannelDescriptorSwitch); + // (Any existing switch won't actually be removed from the command line, but + // the last one appended takes precedence.) + command_line->AppendSwitchASCII(kMojoChannelDescriptorSwitch, + base::IntToString(target_fd)); } void PlatformServerChannelPosix::ChildProcessLaunched() { - // TODO(vtl) - NOTIMPLEMENTED(); + DCHECK(client_handle_.is_valid()); + client_handle_.CloseIfNecessary(); } } // namespace @@ -110,9 +140,17 @@ scoped_ptr<PlatformServerChannel> PlatformServerChannel::Create( scoped_ptr<PlatformClientChannel> PlatformClientChannel::CreateFromParentProcess( const CommandLine& command_line) { - // TODO(vtl) - NOTIMPLEMENTED(); - return scoped_ptr<PlatformClientChannel>(); + std::string client_fd_string = + command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch); + int client_fd = -1; + if (client_fd_string.empty() || + !base::StringToInt(client_fd_string, &client_fd) || + client_fd < base::GlobalDescriptors::kBaseDescriptor) { + LOG(ERROR) << "Missing or invalid --" << kMojoChannelDescriptorSwitch; + return scoped_ptr<PlatformClientChannel>(); + } + + return CreateFromHandle(PlatformChannelHandle(client_fd)); } } // namespace system |