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
parent 1c0f34e2
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/process/kill.h" #include "base/process/kill.h"
#include "base/process/process_handle.h" #include "base/process/process_handle.h"
// TODO(vtl): Remove build_config.h include when fully implemented on Windows.
#include "build/build_config.h" #include "build/build_config.h"
namespace mojo { namespace mojo {
...@@ -28,7 +29,7 @@ void MultiprocessTestBase::SetUp() { ...@@ -28,7 +29,7 @@ void MultiprocessTestBase::SetUp() {
// TODO(vtl): Not implemented on Windows yet. // TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX) #if defined(OS_POSIX)
platform_server_channel_ = platform_server_channel =
system::PlatformServerChannel::Create("TestChannel"); system::PlatformServerChannel::Create("TestChannel");
#endif #endif
} }
...@@ -36,13 +37,13 @@ void MultiprocessTestBase::SetUp() { ...@@ -36,13 +37,13 @@ void MultiprocessTestBase::SetUp() {
void MultiprocessTestBase::TearDown() { void MultiprocessTestBase::TearDown() {
CHECK_EQ(test_child_handle_, base::kNullProcessHandle); CHECK_EQ(test_child_handle_, base::kNullProcessHandle);
platform_server_channel_.reset(); platform_server_channel.reset();
MultiProcessTest::TearDown(); MultiProcessTest::TearDown();
} }
void MultiprocessTestBase::StartChild(const std::string& test_child_name) { 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(!test_child_name.empty());
CHECK_EQ(test_child_handle_, base::kNullProcessHandle); CHECK_EQ(test_child_handle_, base::kNullProcessHandle);
...@@ -51,7 +52,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) { ...@@ -51,7 +52,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) {
#if defined(OS_POSIX) #if defined(OS_POSIX)
CommandLine unused(CommandLine::NO_PROGRAM); CommandLine unused(CommandLine::NO_PROGRAM);
base::FileHandleMappingVector fds_to_map; base::FileHandleMappingVector fds_to_map;
platform_server_channel_->GetDataNeededToPassClientChannelToChildProcess( platform_server_channel->GetDataNeededToPassClientChannelToChildProcess(
&unused, &fds_to_map); &unused, &fds_to_map);
test_child_handle_ = SpawnChild(test_child_main, fds_to_map, false); test_child_handle_ = SpawnChild(test_child_main, fds_to_map, false);
#elif defined(OS_WIN) #elif defined(OS_WIN)
...@@ -61,7 +62,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) { ...@@ -61,7 +62,7 @@ void MultiprocessTestBase::StartChild(const std::string& test_child_name) {
#endif #endif
// TODO(vtl): Not implemented on Windows yet. // TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX) #if defined(OS_POSIX)
platform_server_channel_->ChildProcessLaunched(); platform_server_channel->ChildProcessLaunched();
#endif #endif
CHECK_NE(test_child_handle_, base::kNullProcessHandle); CHECK_NE(test_child_handle_, base::kNullProcessHandle);
...@@ -81,14 +82,14 @@ int MultiprocessTestBase::WaitForChildShutdown() { ...@@ -81,14 +82,14 @@ int MultiprocessTestBase::WaitForChildShutdown() {
CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname, CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname,
bool debug_on_start) { bool debug_on_start) {
CHECK(platform_server_channel_.get()); CHECK(platform_server_channel.get());
CommandLine command_line = CommandLine command_line =
base::MultiProcessTest::MakeCmdLine(procname, debug_on_start); base::MultiProcessTest::MakeCmdLine(procname, debug_on_start);
// TODO(vtl): Not implemented on Windows yet. // TODO(vtl): Not implemented on Windows yet.
#if defined(OS_POSIX) #if defined(OS_POSIX)
base::FileHandleMappingVector unused; base::FileHandleMappingVector unused;
platform_server_channel_->GetDataNeededToPassClientChannelToChildProcess( platform_server_channel->GetDataNeededToPassClientChannelToChildProcess(
&command_line, &unused); &command_line, &unused);
#endif #endif
return command_line; return command_line;
...@@ -96,9 +97,19 @@ CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname, ...@@ -96,9 +97,19 @@ CommandLine MultiprocessTestBase::MakeCmdLine(const std::string& procname,
// static // static
void MultiprocessTestBase::ChildSetup() { void MultiprocessTestBase::ChildSetup() {
// TODO(vtl) CHECK(CommandLine::InitializedForCurrentProcess());
NOTIMPLEMENTED(); // 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 test
} // namespace mojo } // namespace mojo
...@@ -39,9 +39,11 @@ class MultiprocessTestBase : public base::MultiProcessTest { ...@@ -39,9 +39,11 @@ class MultiprocessTestBase : public base::MultiProcessTest {
// For use by |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| only: // For use by |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| only:
static void ChildSetup(); static void ChildSetup();
system::PlatformServerChannel* platform_server_channel() { // For use in the main process:
return platform_server_channel_.get(); 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: private:
virtual CommandLine MakeCmdLine(const std::string& procname, virtual CommandLine MakeCmdLine(const std::string& procname,
...@@ -50,8 +52,6 @@ class MultiprocessTestBase : public base::MultiProcessTest { ...@@ -50,8 +52,6 @@ class MultiprocessTestBase : public base::MultiProcessTest {
// Valid after |StartChild()| and before |WaitForChildShutdown()|. // Valid after |StartChild()| and before |WaitForChildShutdown()|.
base::ProcessHandle test_child_handle_; base::ProcessHandle test_child_handle_;
scoped_ptr<system::PlatformServerChannel> platform_server_channel_;
DISALLOW_COPY_AND_ASSIGN(MultiprocessTestBase); DISALLOW_COPY_AND_ASSIGN(MultiprocessTestBase);
}; };
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
#include "mojo/common/test/multiprocess_test_base.h" #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 mojo {
namespace { namespace {
...@@ -11,11 +15,22 @@ class MultiprocessTestBaseTest : public test::MultiprocessTestBase { ...@@ -11,11 +15,22 @@ class MultiprocessTestBaseTest : public test::MultiprocessTestBase {
}; };
TEST_F(MultiprocessTestBaseTest, RunChild) { 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"); StartChild("RunChild");
EXPECT_EQ(123, WaitForChildShutdown()); EXPECT_EQ(123, WaitForChildShutdown());
} }
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) { 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; return 123;
} }
......
...@@ -92,6 +92,7 @@ ...@@ -92,6 +92,7 @@
'system/message_pipe_endpoint.h', 'system/message_pipe_endpoint.h',
'system/platform_channel.cc', 'system/platform_channel.cc',
'system/platform_channel.h', 'system/platform_channel.h',
'system/platform_channel_handle.cc',
'system/platform_channel_handle.h', 'system/platform_channel_handle.h',
'system/platform_channel_posix.cc', 'system/platform_channel_posix.cc',
'system/proxy_message_pipe_endpoint.cc', 'system/proxy_message_pipe_endpoint.cc',
......
...@@ -10,9 +10,7 @@ namespace mojo { ...@@ -10,9 +10,7 @@ namespace mojo {
namespace system { namespace system {
PlatformChannel::~PlatformChannel() { PlatformChannel::~PlatformChannel() {
// Implementations must close the handle if necessary (e.g., if no one else handle_.CloseIfNecessary();
// has taken ownership).
DCHECK(!is_valid());
} }
PlatformChannelHandle PlatformChannel::PassHandle() { PlatformChannelHandle PlatformChannel::PassHandle() {
...@@ -34,6 +32,7 @@ PlatformServerChannel::PlatformServerChannel(const std::string& name) ...@@ -34,6 +32,7 @@ PlatformServerChannel::PlatformServerChannel(const std::string& name)
// static // static
scoped_ptr<PlatformClientChannel> PlatformClientChannel::CreateFromHandle( scoped_ptr<PlatformClientChannel> PlatformClientChannel::CreateFromHandle(
const PlatformChannelHandle& handle) { const PlatformChannelHandle& handle) {
DCHECK(handle.is_valid());
scoped_ptr<PlatformClientChannel> rv(new PlatformClientChannel()); scoped_ptr<PlatformClientChannel> rv(new PlatformClientChannel());
*rv->mutable_handle() = handle; *rv->mutable_handle() = handle;
return rv.Pass(); return rv.Pass();
......
// 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
...@@ -19,6 +19,8 @@ struct PlatformChannelHandle { ...@@ -19,6 +19,8 @@ struct PlatformChannelHandle {
PlatformChannelHandle() : fd(-1) {} PlatformChannelHandle() : fd(-1) {}
explicit PlatformChannelHandle(int fd) : fd(fd) {} explicit PlatformChannelHandle(int fd) : fd(fd) {}
void CloseIfNecessary();
bool is_valid() const { return fd != -1; } bool is_valid() const { return fd != -1; }
int fd; int fd;
...@@ -28,6 +30,8 @@ struct PlatformChannelHandle { ...@@ -28,6 +30,8 @@ struct PlatformChannelHandle {
PlatformChannelHandle() : handle(INVALID_HANDLE_VALUE) {} PlatformChannelHandle() : handle(INVALID_HANDLE_VALUE) {}
explicit PlatformChannelHandle(HANDLE handle) : handle(handle) {} explicit PlatformChannelHandle(HANDLE handle) : handle(handle) {}
void CloseIfNecessary();
bool is_valid() const { return handle != INVALID_HANDLE_VALUE; } bool is_valid() const { return handle != INVALID_HANDLE_VALUE; }
HANDLE handle; HANDLE handle;
......
...@@ -9,20 +9,27 @@ ...@@ -9,20 +9,27 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "base/command_line.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/posix/global_descriptors.h"
#include "base/strings/string_number_conversions.h"
namespace mojo { namespace mojo {
namespace system { namespace system {
namespace { namespace {
void CloseIfNecessary(PlatformChannelHandle* handle) { const char kMojoChannelDescriptorSwitch[] = "mojo-channel-descriptor";
if (!handle->is_valid())
return;
PCHECK(close(handle->fd) == 0); bool IsTargetDescriptorUsed(
*handle = PlatformChannelHandle(); 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 { class PlatformServerChannelPosix : public PlatformServerChannel {
...@@ -59,10 +66,7 @@ PlatformServerChannelPosix::PlatformServerChannelPosix( ...@@ -59,10 +66,7 @@ PlatformServerChannelPosix::PlatformServerChannelPosix(
} }
PlatformServerChannelPosix::~PlatformServerChannelPosix() { PlatformServerChannelPosix::~PlatformServerChannelPosix() {
if (is_valid()) client_handle_.CloseIfNecessary();
CloseIfNecessary(mutable_handle());
if (client_handle_.is_valid())
CloseIfNecessary(&client_handle_);
} }
scoped_ptr<PlatformClientChannel> scoped_ptr<PlatformClientChannel>
...@@ -82,13 +86,39 @@ scoped_ptr<PlatformClientChannel> ...@@ -82,13 +86,39 @@ scoped_ptr<PlatformClientChannel>
void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess( void PlatformServerChannelPosix::GetDataNeededToPassClientChannelToChildProcess(
CommandLine* command_line, CommandLine* command_line,
base::FileHandleMappingVector* file_handle_mapping) const { base::FileHandleMappingVector* file_handle_mapping) const {
// TODO(vtl) DCHECK(command_line);
NOTIMPLEMENTED(); 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() { void PlatformServerChannelPosix::ChildProcessLaunched() {
// TODO(vtl) DCHECK(client_handle_.is_valid());
NOTIMPLEMENTED(); client_handle_.CloseIfNecessary();
} }
} // namespace } // namespace
...@@ -110,9 +140,17 @@ scoped_ptr<PlatformServerChannel> PlatformServerChannel::Create( ...@@ -110,9 +140,17 @@ scoped_ptr<PlatformServerChannel> PlatformServerChannel::Create(
scoped_ptr<PlatformClientChannel> scoped_ptr<PlatformClientChannel>
PlatformClientChannel::CreateFromParentProcess( PlatformClientChannel::CreateFromParentProcess(
const CommandLine& command_line) { const CommandLine& command_line) {
// TODO(vtl) std::string client_fd_string =
NOTIMPLEMENTED(); command_line.GetSwitchValueASCII(kMojoChannelDescriptorSwitch);
return scoped_ptr<PlatformClientChannel>(); 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 } // namespace system
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment