summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-13 22:40:06 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-13 22:40:06 +0000
commitd1e0c221a522f1e9a4691faf4bee7fb6a3de99de (patch)
tree97286786eb1927e7d87d3f40c1bcbd593939fa22 /mojo
parent2ef8ba538b567d2c4e175a5cf55eb63a34778a6b (diff)
downloadchromium_src-d1e0c221a522f1e9a4691faf4bee7fb6a3de99de.zip
chromium_src-d1e0c221a522f1e9a4691faf4bee7fb6a3de99de.tar.gz
chromium_src-d1e0c221a522f1e9a4691faf4bee7fb6a3de99de.tar.bz2
Mojo: Add a dispatcher that wraps a PlatformHandle (for use by the embedder).
Still to do: more tests -- test the embedder API and see if they can be sent over a message pipe across processes (on POSIX; it's theoretically implemented for POSIX and not yet implemented on Windows). R=darin@chromium.org Review URL: https://codereview.chromium.org/287663002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270230 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
-rw-r--r--mojo/embedder/embedder.cc41
-rw-r--r--mojo/embedder/embedder.h15
-rw-r--r--mojo/mojo.gyp3
-rw-r--r--mojo/system/core.cc27
-rw-r--r--mojo/system/core.h32
-rw-r--r--mojo/system/dispatcher.h5
-rw-r--r--mojo/system/handle_table.cc1
-rw-r--r--mojo/system/message_pipe_dispatcher.cc2
-rw-r--r--mojo/system/message_pipe_dispatcher_unittest.cc1
-rw-r--r--mojo/system/platform_handle_dispatcher.cc89
-rw-r--r--mojo/system/platform_handle_dispatcher.h57
-rw-r--r--mojo/system/platform_handle_dispatcher_unittest.cc102
12 files changed, 343 insertions, 32 deletions
diff --git a/mojo/embedder/embedder.cc b/mojo/embedder/embedder.cc
index 16de202..61d7932 100644
--- a/mojo/embedder/embedder.cc
+++ b/mojo/embedder/embedder.cc
@@ -14,6 +14,7 @@
#include "mojo/system/message_in_transit.h"
#include "mojo/system/message_pipe.h"
#include "mojo/system/message_pipe_dispatcher.h"
+#include "mojo/system/platform_handle_dispatcher.h"
#include "mojo/system/raw_channel.h"
namespace mojo {
@@ -134,5 +135,45 @@ void DestroyChannelOnIOThread(ChannelInfo* channel_info) {
delete channel_info;
}
+MojoResult CreatePlatformHandleWrapper(
+ ScopedPlatformHandle platform_handle,
+ MojoHandle* platform_handle_wrapper_handle) {
+ DCHECK(platform_handle_wrapper_handle);
+
+ scoped_refptr<system::Dispatcher> dispatcher(
+ new system::PlatformHandleDispatcher(platform_handle.Pass()));
+
+ system::Core* core = system::entrypoints::GetCore();
+ DCHECK(core);
+ MojoHandle h = core->AddDispatcher(dispatcher);
+ if (h == MOJO_HANDLE_INVALID) {
+ LOG(ERROR) << "Handle table full";
+ dispatcher->Close();
+ return MOJO_RESULT_RESOURCE_EXHAUSTED;
+ }
+
+ *platform_handle_wrapper_handle = h;
+ return MOJO_RESULT_OK;
+}
+
+MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
+ ScopedPlatformHandle* platform_handle) {
+ DCHECK(platform_handle);
+
+ system::Core* core = system::entrypoints::GetCore();
+ DCHECK(core);
+ scoped_refptr<system::Dispatcher> dispatcher(
+ core->GetDispatcher(platform_handle_wrapper_handle));
+ if (!dispatcher.get())
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ if (dispatcher->GetType() != system::Dispatcher::kTypePlatformHandle)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ *platform_handle = static_cast<system::PlatformHandleDispatcher*>(
+ dispatcher.get())->PassPlatformHandle().Pass();
+ return MOJO_RESULT_OK;
+}
+
} // namespace embedder
} // namespace mojo
diff --git a/mojo/embedder/embedder.h b/mojo/embedder/embedder.h
index 9914104..148e5d6 100644
--- a/mojo/embedder/embedder.h
+++ b/mojo/embedder/embedder.h
@@ -56,6 +56,21 @@ MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle CreateChannel(
MOJO_SYSTEM_IMPL_EXPORT void DestroyChannelOnIOThread(
ChannelInfo* channel_info);
+// Creates a |MojoHandle| that wraps the given |PlatformHandle| (taking
+// ownership of it). This |MojoHandle| can then, e.g., be passed through message
+// pipes. Note: This takes ownership (and thus closes) |platform_handle| even on
+// failure, which is different from what you'd expect from a Mojo API, but it
+// makes for a more convenient embedder API.
+MOJO_SYSTEM_IMPL_EXPORT MojoResult CreatePlatformHandleWrapper(
+ ScopedPlatformHandle platform_handle,
+ MojoHandle* platform_handle_wrapper_handle);
+// Retrieves the |PlatformHandle| that was wrapped into a |MojoHandle| (using
+// |CreatePlatformHandleWrapper()| above). Note that the |MojoHandle| must still
+// be closed separately.
+MOJO_SYSTEM_IMPL_EXPORT MojoResult PassWrappedPlatformHandle(
+ MojoHandle platform_handle_wrapper_handle,
+ ScopedPlatformHandle* platform_handle);
+
} // namespace embedder
} // namespace mojo
diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp
index 56c9997..dd167b8 100644
--- a/mojo/mojo.gyp
+++ b/mojo/mojo.gyp
@@ -188,6 +188,8 @@
'system/message_pipe_dispatcher.h',
'system/message_pipe_endpoint.cc',
'system/message_pipe_endpoint.h',
+ 'system/platform_handle_dispatcher.cc',
+ 'system/platform_handle_dispatcher.h',
'system/proxy_message_pipe_endpoint.cc',
'system/proxy_message_pipe_endpoint.h',
'system/raw_channel.cc',
@@ -243,6 +245,7 @@
'system/message_pipe_dispatcher_unittest.cc',
'system/message_pipe_unittest.cc',
'system/multiprocess_message_pipe_unittest.cc',
+ 'system/platform_handle_dispatcher_unittest.cc',
'system/raw_channel_unittest.cc',
'system/raw_shared_buffer_unittest.cc',
'system/remote_message_pipe_unittest.cc',
diff --git a/mojo/system/core.cc b/mojo/system/core.cc
index 90e6d40..6a4dfdc 100644
--- a/mojo/system/core.cc
+++ b/mojo/system/core.cc
@@ -27,12 +27,11 @@ namespace system {
// Implementation notes
//
-// Mojo primitives are implemented by the singleton |Core| object. Most
-// calls are for a "primary" handle (the first argument).
-// |Core::GetDispatcher()| is used to look up a |Dispatcher| object for a
-// given handle. That object implements most primitives for that object. The
-// wait primitives are not attached to objects and are implemented by |Core|
-// itself.
+// Mojo primitives are implemented by the singleton |Core| object. Most calls
+// are for a "primary" handle (the first argument). |Core::GetDispatcher()| is
+// used to look up a |Dispatcher| object for a given handle. That object
+// implements most primitives for that object. The wait primitives are not
+// attached to objects and are implemented by |Core| itself.
//
// Some objects have multiple handles associated to them, e.g., message pipes
// (which have two). In such a case, there is still a |Dispatcher| (e.g.,
@@ -86,6 +85,14 @@ MojoHandle Core::AddDispatcher(
return handle_table_.AddDispatcher(dispatcher);
}
+scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
+ if (handle == MOJO_HANDLE_INVALID)
+ return NULL;
+
+ base::AutoLock locker(handle_table_lock_);
+ return handle_table_.GetDispatcher(handle);
+}
+
MojoTimeTicks Core::GetTimeTicksNow() {
return base::TimeTicks::Now().ToInternalValue();
}
@@ -505,14 +512,6 @@ MojoResult Core::UnmapBuffer(void* buffer) {
return mapping_table_.RemoveMapping(buffer);
}
-scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
- if (handle == MOJO_HANDLE_INVALID)
- return NULL;
-
- base::AutoLock locker(handle_table_lock_);
- return handle_table_.GetDispatcher(handle);
-}
-
// Note: We allow |handles| to repeat the same handle multiple times, since
// different flags may be specified.
// TODO(vtl): This incurs a performance cost in |RemoveWaiter()|. Analyze this
diff --git a/mojo/system/core.h b/mojo/system/core.h
index 7bce6e3..76828d6 100644
--- a/mojo/system/core.h
+++ b/mojo/system/core.h
@@ -22,11 +22,18 @@ class Dispatcher;
// are thread-safe.
class MOJO_SYSTEM_IMPL_EXPORT Core {
public:
- // These methods are only to be used by via the embedder API.
+ // These methods are only to be used by via the embedder API (and internally).
Core();
virtual ~Core();
+
+ // Adds |dispatcher| to the handle table, returning the handle for it. Returns
+ // |MOJO_HANDLE_INVALID| on failure, namely if the handle table is full.
MojoHandle AddDispatcher(const scoped_refptr<Dispatcher>& dispatcher);
+ // Looks up the dispatcher for the given handle. Returns null if the handle is
+ // invalid.
+ scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
+
// System calls implementation.
MojoTimeTicks GetTimeTicksNow();
MojoResult Close(MojoHandle handle);
@@ -37,9 +44,8 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
const MojoWaitFlags* flags,
uint32_t num_handles,
MojoDeadline deadline);
- MojoResult CreateMessagePipe(
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1);
+ MojoResult CreateMessagePipe(MojoHandle* message_pipe_handle0,
+ MojoHandle* message_pipe_handle1);
MojoResult WriteMessage(MojoHandle message_pipe_handle,
const void* bytes,
uint32_t num_bytes,
@@ -52,10 +58,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
MojoHandle* handles,
uint32_t* num_handles,
MojoReadMessageFlags flags);
- MojoResult CreateDataPipe(
- const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle);
+ MojoResult CreateDataPipe(const MojoCreateDataPipeOptions* options,
+ MojoHandle* data_pipe_producer_handle,
+ MojoHandle* data_pipe_consumer_handle);
MojoResult WriteData(MojoHandle data_pipe_producer_handle,
const void* elements,
uint32_t* num_bytes,
@@ -76,10 +81,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
MojoReadDataFlags flags);
MojoResult EndReadData(MojoHandle data_pipe_consumer_handle,
uint32_t num_bytes_read);
- MojoResult CreateSharedBuffer(
- const MojoCreateSharedBufferOptions* options,
- uint64_t num_bytes,
- MojoHandle* shared_buffer_handle);
+ MojoResult CreateSharedBuffer(const MojoCreateSharedBufferOptions* options,
+ uint64_t num_bytes,
+ MojoHandle* shared_buffer_handle);
MojoResult DuplicateBufferHandle(
MojoHandle buffer_handle,
const MojoDuplicateBufferHandleOptions* options,
@@ -94,10 +98,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
private:
friend bool internal::ShutdownCheckNoLeaks(Core*);
- // Looks up the dispatcher for the given handle. Returns null if the handle is
- // invalid.
- scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
-
// Internal implementation of |Wait()| and |WaitMany()|; doesn't do basic
// validation of arguments.
MojoResult WaitManyInternal(const MojoHandle* handles,
diff --git a/mojo/system/dispatcher.h b/mojo/system/dispatcher.h
index 4e9e13f..3a28097 100644
--- a/mojo/system/dispatcher.h
+++ b/mojo/system/dispatcher.h
@@ -55,7 +55,10 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher :
kTypeMessagePipe,
kTypeDataPipeProducer,
kTypeDataPipeConsumer,
- kTypeSharedBuffer
+ kTypeSharedBuffer,
+
+ // "Private" types (not exposed via the public interface):
+ kTypePlatformHandle = -1
};
virtual Type GetType() const = 0;
diff --git a/mojo/system/handle_table.cc b/mojo/system/handle_table.cc
index dd5a5f4..2e4d22a 100644
--- a/mojo/system/handle_table.cc
+++ b/mojo/system/handle_table.cc
@@ -111,6 +111,7 @@ MojoResult HandleTable::MarkBusyAndStartTransport(
DCHECK(handles);
DCHECK_LE(num_handles, kMaxMessageNumHandles);
DCHECK(transports);
+ DCHECK_EQ(transports->size(), num_handles);
std::vector<Entry*> entries(num_handles);
diff --git a/mojo/system/message_pipe_dispatcher.cc b/mojo/system/message_pipe_dispatcher.cc
index 6d82583..3cee844 100644
--- a/mojo/system/message_pipe_dispatcher.cc
+++ b/mojo/system/message_pipe_dispatcher.cc
@@ -203,7 +203,7 @@ bool MessagePipeDispatcher::EndSerializeAndCloseImplNoLock(
Channel* channel,
void* destination,
size_t* actual_size,
- std::vector<embedder::PlatformHandle>* platform_handles) {
+ std::vector<embedder::PlatformHandle>* /*platform_handles*/) {
DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
// Convert the local endpoint to a proxy endpoint (moving the message queue).
diff --git a/mojo/system/message_pipe_dispatcher_unittest.cc b/mojo/system/message_pipe_dispatcher_unittest.cc
index 3ef26bf..bfd4ddb 100644
--- a/mojo/system/message_pipe_dispatcher_unittest.cc
+++ b/mojo/system/message_pipe_dispatcher_unittest.cc
@@ -41,6 +41,7 @@ TEST(MessagePipeDispatcherTest, Basic) {
// Run this test both with |d0| as port 0, |d1| as port 1 and vice versa.
for (unsigned i = 0; i < 2; i++) {
scoped_refptr<MessagePipeDispatcher> d0(new MessagePipeDispatcher());
+ EXPECT_EQ(Dispatcher::kTypeMessagePipe, d0->GetType());
scoped_refptr<MessagePipeDispatcher> d1(new MessagePipeDispatcher());
{
scoped_refptr<MessagePipe> mp(new MessagePipe());
diff --git a/mojo/system/platform_handle_dispatcher.cc b/mojo/system/platform_handle_dispatcher.cc
new file mode 100644
index 0000000..1d7d9b1
--- /dev/null
+++ b/mojo/system/platform_handle_dispatcher.cc
@@ -0,0 +1,89 @@
+// 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/system/platform_handle_dispatcher.h"
+
+#include "base/logging.h"
+
+namespace mojo {
+namespace system {
+
+namespace {
+
+const size_t kInvalidPlatformHandleIndex = static_cast<size_t>(-1);
+
+struct SerializedPlatformHandleDispatcher {
+ size_t platform_handle_index; // (Or |kInvalidPlatformHandleIndex|.)
+};
+
+} // namespace
+
+PlatformHandleDispatcher::PlatformHandleDispatcher(
+ embedder::ScopedPlatformHandle platform_handle)
+ : platform_handle_(platform_handle.Pass()) {
+}
+
+embedder::ScopedPlatformHandle PlatformHandleDispatcher::PassPlatformHandle() {
+ base::AutoLock locker(lock());
+ return platform_handle_.Pass();
+}
+
+Dispatcher::Type PlatformHandleDispatcher::GetType() const {
+ return kTypePlatformHandle;
+}
+
+PlatformHandleDispatcher::~PlatformHandleDispatcher() {
+}
+
+void PlatformHandleDispatcher::CloseImplNoLock() {
+ lock().AssertAcquired();
+ platform_handle_.reset();
+}
+
+scoped_refptr<Dispatcher>
+ PlatformHandleDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() {
+ lock().AssertAcquired();
+ return scoped_refptr<Dispatcher>(
+ new PlatformHandleDispatcher(platform_handle_.Pass()));
+}
+
+void PlatformHandleDispatcher::StartSerializeImplNoLock(
+ Channel* /*channel*/,
+ size_t* max_size,
+ size_t* max_platform_handles) {
+ DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
+ *max_size = sizeof(SerializedPlatformHandleDispatcher);
+ *max_platform_handles = 1;
+}
+
+bool PlatformHandleDispatcher::EndSerializeAndCloseImplNoLock(
+ Channel* /*channel*/,
+ void* destination,
+ size_t* actual_size,
+ std::vector<embedder::PlatformHandle>* platform_handles) {
+ DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
+
+ SerializedPlatformHandleDispatcher* serialization =
+ static_cast<SerializedPlatformHandleDispatcher*>(destination);
+ if (platform_handle_.is_valid()) {
+ serialization->platform_handle_index = platform_handles->size();
+ platform_handles->push_back(platform_handle_.release());
+ } else {
+ serialization->platform_handle_index = kInvalidPlatformHandleIndex;
+ }
+
+ *actual_size = sizeof(SerializedPlatformHandleDispatcher);
+ return true;
+}
+
+MojoWaitFlags PlatformHandleDispatcher::SatisfiedFlagsNoLock() const {
+ return MOJO_WAIT_FLAG_NONE;
+}
+
+MojoWaitFlags PlatformHandleDispatcher::SatisfiableFlagsNoLock() const {
+ return MOJO_WAIT_FLAG_NONE;
+}
+
+} // namespace system
+} // namespace mojo
diff --git a/mojo/system/platform_handle_dispatcher.h b/mojo/system/platform_handle_dispatcher.h
new file mode 100644
index 0000000..eef0649
--- /dev/null
+++ b/mojo/system/platform_handle_dispatcher.h
@@ -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.
+
+#ifndef MOJO_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
+#define MOJO_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
+
+#include "base/macros.h"
+#include "mojo/embedder/scoped_platform_handle.h"
+#include "mojo/system/simple_dispatcher.h"
+#include "mojo/system/system_impl_export.h"
+
+namespace mojo {
+namespace system {
+
+// A dispatcher that simply wraps/transports a |PlatformHandle| (only for use by
+// the embedder).
+class MOJO_SYSTEM_IMPL_EXPORT PlatformHandleDispatcher
+ : public SimpleDispatcher {
+ public:
+ explicit PlatformHandleDispatcher(
+ embedder::ScopedPlatformHandle platform_handle);
+
+ embedder::ScopedPlatformHandle PassPlatformHandle();
+
+ // |Dispatcher| public methods:
+ virtual Type GetType() const OVERRIDE;
+
+ private:
+ virtual ~PlatformHandleDispatcher();
+
+ // |Dispatcher| protected methods:
+ virtual void CloseImplNoLock() OVERRIDE;
+ virtual scoped_refptr<Dispatcher>
+ CreateEquivalentDispatcherAndCloseImplNoLock() OVERRIDE;
+ virtual void StartSerializeImplNoLock(Channel* channel,
+ size_t* max_size,
+ size_t* max_platform_handles) OVERRIDE;
+ virtual bool EndSerializeAndCloseImplNoLock(
+ Channel* channel,
+ void* destination,
+ size_t* actual_size,
+ std::vector<embedder::PlatformHandle>* platform_handles) OVERRIDE;
+
+ // |SimpleDispatcher| methods:
+ virtual MojoWaitFlags SatisfiedFlagsNoLock() const OVERRIDE;
+ virtual MojoWaitFlags SatisfiableFlagsNoLock() const OVERRIDE;
+
+ embedder::ScopedPlatformHandle platform_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformHandleDispatcher);
+};
+
+} // namespace system
+} // namespace mojo
+
+#endif // MOJO_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
diff --git a/mojo/system/platform_handle_dispatcher_unittest.cc b/mojo/system/platform_handle_dispatcher_unittest.cc
new file mode 100644
index 0000000..5c22f55
--- /dev/null
+++ b/mojo/system/platform_handle_dispatcher_unittest.cc
@@ -0,0 +1,102 @@
+// 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/system/platform_handle_dispatcher.h"
+
+#include <stdio.h>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/ref_counted.h"
+#include "mojo/common/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace system {
+namespace {
+
+TEST(PlatformHandleDispatcherTest, Basic) {
+ static const char kHelloWorld[] = "hello world";
+
+ base::FilePath unused;
+ base::ScopedFILE fp(CreateAndOpenTemporaryFile(&unused));
+ ASSERT_TRUE(fp);
+ EXPECT_EQ(sizeof(kHelloWorld),
+ fwrite(kHelloWorld, 1, sizeof(kHelloWorld), fp.get()));
+
+ embedder::ScopedPlatformHandle
+ h(mojo::test::PlatformHandleFromFILE(fp.Pass()));
+ EXPECT_FALSE(fp);
+ ASSERT_TRUE(h.is_valid());
+
+ scoped_refptr<PlatformHandleDispatcher> dispatcher(
+ new PlatformHandleDispatcher(h.Pass()));
+ EXPECT_FALSE(h.is_valid());
+ EXPECT_EQ(Dispatcher::kTypePlatformHandle, dispatcher->GetType());
+
+ h = dispatcher->PassPlatformHandle().Pass();
+ EXPECT_TRUE(h.is_valid());
+
+ fp = mojo::test::FILEFromPlatformHandle(h.Pass(), "rb").Pass();
+ EXPECT_FALSE(h.is_valid());
+ EXPECT_TRUE(fp);
+
+ rewind(fp.get());
+ char read_buffer[1000] = {};
+ EXPECT_EQ(sizeof(kHelloWorld),
+ fread(read_buffer, 1, sizeof(read_buffer), fp.get()));
+ EXPECT_STREQ(kHelloWorld, read_buffer);
+
+ // Try getting the handle again. (It should fail cleanly.)
+ h = dispatcher->PassPlatformHandle().Pass();
+ EXPECT_FALSE(h.is_valid());
+
+ EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
+}
+
+TEST(PlatformHandleDispatcherTest, CreateEquivalentDispatcherAndClose) {
+ static const char kFooBar[] = "foo bar";
+
+ base::FilePath unused;
+ base::ScopedFILE fp(CreateAndOpenTemporaryFile(&unused));
+ EXPECT_EQ(sizeof(kFooBar), fwrite(kFooBar, 1, sizeof(kFooBar), fp.get()));
+
+ scoped_refptr<PlatformHandleDispatcher> dispatcher(
+ new PlatformHandleDispatcher(
+ mojo::test::PlatformHandleFromFILE(fp.Pass())));
+
+ DispatcherTransport transport(
+ test::DispatcherTryStartTransport(dispatcher.get()));
+ EXPECT_TRUE(transport.is_valid());
+ EXPECT_EQ(Dispatcher::kTypePlatformHandle, transport.GetType());
+ EXPECT_FALSE(transport.IsBusy());
+
+ scoped_refptr<Dispatcher> generic_dispatcher =
+ transport.CreateEquivalentDispatcherAndClose();
+ ASSERT_TRUE(generic_dispatcher);
+
+ transport.End();
+ EXPECT_TRUE(dispatcher->HasOneRef());
+ dispatcher = NULL;
+
+ ASSERT_EQ(Dispatcher::kTypePlatformHandle, generic_dispatcher->GetType());
+ dispatcher = static_cast<PlatformHandleDispatcher*>(generic_dispatcher.get());
+
+ fp = mojo::test::FILEFromPlatformHandle(dispatcher->PassPlatformHandle(),
+ "rb").Pass();
+ EXPECT_TRUE(fp);
+
+ rewind(fp.get());
+ char read_buffer[1000] = {};
+ EXPECT_EQ(sizeof(kFooBar),
+ fread(read_buffer, 1, sizeof(read_buffer), fp.get()));
+ EXPECT_STREQ(kFooBar, read_buffer);
+
+ EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
+}
+
+} // namespace
+} // namespace system
+} // namespace mojo