NaCl: create a separate namespace for Mojo handles.
BUG=401761
R=viettrungluu@chromium.org
Review URL: https://codereview.chromium.org/1052723003
diff --git a/mojo/edk/embedder/BUILD.gn b/mojo/edk/embedder/BUILD.gn
index 9650209..2953982 100644
--- a/mojo/edk/embedder/BUILD.gn
+++ b/mojo/edk/embedder/BUILD.gn
@@ -16,6 +16,7 @@
"embedder.h",
"embedder_internal.h",
"entrypoints.cc",
+ "system_impl_private_entrypoints.cc",
# Test-only code:
# TODO(vtl): It's a little unfortunate that these end up in the same
@@ -37,6 +38,8 @@
":platform",
]
+ mojo_sdk_deps = [ "mojo/public/platform/native:system_impl_private_api" ]
+
mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
deps = [
diff --git a/mojo/edk/embedder/system_impl_private_entrypoints.cc b/mojo/edk/embedder/system_impl_private_entrypoints.cc
new file mode 100644
index 0000000..475ffa7
--- /dev/null
+++ b/mojo/edk/embedder/system_impl_private_entrypoints.cc
@@ -0,0 +1,260 @@
+// Copyright 2015 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/edk/embedder/embedder_internal.h"
+#include "mojo/edk/system/core.h"
+#include "mojo/edk/system/dispatcher.h"
+#include "mojo/public/c/system/buffer.h"
+#include "mojo/public/c/system/data_pipe.h"
+#include "mojo/public/c/system/functions.h"
+#include "mojo/public/c/system/message_pipe.h"
+#include "mojo/public/platform/native/system_impl_private.h"
+
+using mojo::embedder::internal::g_core;
+using mojo::system::Core;
+using mojo::system::Dispatcher;
+using mojo::system::MakeUserPointer;
+
+// Definitions of the system functions, but with an explicit parameter for the
+// core object rather than using the default singleton. Also includes functions
+// for manipulating core objects.
+extern "C" {
+
+MojoSystemImpl MojoSystemImplGetDefaultImpl() {
+ return static_cast<MojoSystemImpl>(g_core);
+}
+
+MojoSystemImpl MojoSystemImplCreateImpl() {
+ Core* created_core = new Core(g_core->platform_support());
+ return static_cast<MojoSystemImpl>(created_core);
+}
+
+MojoResult MojoSystemImplTransferHandle(MojoSystemImpl from_system,
+ MojoHandle handle,
+ MojoSystemImpl to_system,
+ MojoHandle* result_handle) {
+ Core* from_core = static_cast<Core*>(from_system);
+ if (from_core == nullptr)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ if (handle == MOJO_HANDLE_INVALID)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ Core* to_core = static_cast<Core*>(to_system);
+ if (to_core == nullptr)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ if (result_handle == nullptr)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ scoped_refptr<Dispatcher> d;
+ MojoResult result = from_core->GetAndRemoveDispatcher(handle, &d);
+ if (result != MOJO_RESULT_OK)
+ return result;
+
+ MojoHandle created_handle = to_core->AddDispatcher(d);
+ if (created_handle == MOJO_HANDLE_INVALID) {
+ // The handle has been lost, unfortunately. There's no guarentee we can put
+ // it back where it came from, or get the original ID back. Holding locks
+ // for multiple cores risks deadlock, so that isn't a solution. This case
+ // should not happen for reasonable uses of this API, however.
+ LOG(ERROR) << "Could not transfer handle";
+ d->Close();
+ return MOJO_RESULT_RESOURCE_EXHAUSTED;
+ }
+
+ MakeUserPointer(result_handle).Put(created_handle);
+ return MOJO_RESULT_OK;
+}
+
+MojoTimeTicks MojoSystemImplGetTimeTicksNow(MojoSystemImpl system) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->GetTimeTicksNow();
+}
+
+MojoResult MojoSystemImplClose(MojoSystemImpl system, MojoHandle handle) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->Close(handle);
+}
+
+MojoResult MojoSystemImplWait(MojoSystemImpl system,
+ MojoHandle handle,
+ MojoHandleSignals signals,
+ MojoDeadline deadline,
+ MojoHandleSignalsState* signals_state) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->Wait(handle, signals, deadline, MakeUserPointer(signals_state));
+}
+
+MojoResult MojoSystemImplWaitMany(MojoSystemImpl system,
+ const MojoHandle* handles,
+ const MojoHandleSignals* signals,
+ uint32_t num_handles,
+ MojoDeadline deadline,
+ uint32_t* result_index,
+ MojoHandleSignalsState* signals_states) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->WaitMany(MakeUserPointer(handles), MakeUserPointer(signals),
+ num_handles, deadline, MakeUserPointer(result_index),
+ MakeUserPointer(signals_states));
+}
+
+MojoResult MojoSystemImplCreateMessagePipe(
+ MojoSystemImpl system,
+ const MojoCreateMessagePipeOptions* options,
+ MojoHandle* message_pipe_handle0,
+ MojoHandle* message_pipe_handle1) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->CreateMessagePipe(MakeUserPointer(options),
+ MakeUserPointer(message_pipe_handle0),
+ MakeUserPointer(message_pipe_handle1));
+}
+
+MojoResult MojoSystemImplWriteMessage(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ const void* bytes,
+ uint32_t num_bytes,
+ const MojoHandle* handles,
+ uint32_t num_handles,
+ MojoWriteMessageFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->WriteMessage(message_pipe_handle, MakeUserPointer(bytes),
+ num_bytes, MakeUserPointer(handles), num_handles,
+ flags);
+}
+
+MojoResult MojoSystemImplReadMessage(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ void* bytes,
+ uint32_t* num_bytes,
+ MojoHandle* handles,
+ uint32_t* num_handles,
+ MojoReadMessageFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->ReadMessage(message_pipe_handle, MakeUserPointer(bytes),
+ MakeUserPointer(num_bytes), MakeUserPointer(handles),
+ MakeUserPointer(num_handles), flags);
+}
+
+MojoResult MojoSystemImplCreateDataPipe(
+ MojoSystemImpl system,
+ const MojoCreateDataPipeOptions* options,
+ MojoHandle* data_pipe_producer_handle,
+ MojoHandle* data_pipe_consumer_handle) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->CreateDataPipe(MakeUserPointer(options),
+ MakeUserPointer(data_pipe_producer_handle),
+ MakeUserPointer(data_pipe_consumer_handle));
+}
+
+MojoResult MojoSystemImplWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ const void* elements,
+ uint32_t* num_elements,
+ MojoWriteDataFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->WriteData(data_pipe_producer_handle, MakeUserPointer(elements),
+ MakeUserPointer(num_elements), flags);
+}
+
+MojoResult MojoSystemImplBeginWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoWriteDataFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->BeginWriteData(data_pipe_producer_handle,
+ MakeUserPointer(buffer),
+ MakeUserPointer(buffer_num_elements), flags);
+}
+
+MojoResult MojoSystemImplEndWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ uint32_t num_elements_written) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->EndWriteData(data_pipe_producer_handle, num_elements_written);
+}
+
+MojoResult MojoSystemImplReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ void* elements,
+ uint32_t* num_elements,
+ MojoReadDataFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->ReadData(data_pipe_consumer_handle, MakeUserPointer(elements),
+ MakeUserPointer(num_elements), flags);
+}
+
+MojoResult MojoSystemImplBeginReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ const void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoReadDataFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->BeginReadData(data_pipe_consumer_handle, MakeUserPointer(buffer),
+ MakeUserPointer(buffer_num_elements), flags);
+}
+
+MojoResult MojoSystemImplEndReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ uint32_t num_elements_read) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->EndReadData(data_pipe_consumer_handle, num_elements_read);
+}
+
+MojoResult MojoSystemImplCreateSharedBuffer(
+ MojoSystemImpl system,
+ const MojoCreateSharedBufferOptions* options,
+ uint64_t num_bytes,
+ MojoHandle* shared_buffer_handle) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->CreateSharedBuffer(MakeUserPointer(options), num_bytes,
+ MakeUserPointer(shared_buffer_handle));
+}
+
+MojoResult MojoSystemImplDuplicateBufferHandle(
+ MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ const MojoDuplicateBufferHandleOptions* options,
+ MojoHandle* new_buffer_handle) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->DuplicateBufferHandle(buffer_handle, MakeUserPointer(options),
+ MakeUserPointer(new_buffer_handle));
+}
+
+MojoResult MojoSystemImplMapBuffer(MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ uint64_t offset,
+ uint64_t num_bytes,
+ void** buffer,
+ MojoMapBufferFlags flags) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->MapBuffer(buffer_handle, offset, num_bytes,
+ MakeUserPointer(buffer), flags);
+}
+
+MojoResult MojoSystemImplUnmapBuffer(MojoSystemImpl system, void* buffer) {
+ mojo::system::Core* core = static_cast<mojo::system::Core*>(system);
+ DCHECK(core);
+ return core->UnmapBuffer(MakeUserPointer(buffer));
+}
+
+} // extern "C"
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc
index 80c3d36..887a9a7 100644
--- a/mojo/edk/system/core.cc
+++ b/mojo/edk/system/core.cc
@@ -97,6 +97,15 @@
return handle_table_.GetDispatcher(handle);
}
+MojoResult Core::GetAndRemoveDispatcher(MojoHandle handle,
+ scoped_refptr<Dispatcher>* dispatcher) {
+ if (handle == MOJO_HANDLE_INVALID)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ base::AutoLock locker(handle_table_lock_);
+ return handle_table_.GetAndRemoveDispatcher(handle, dispatcher);
+}
+
MojoResult Core::AsyncWait(MojoHandle handle,
MojoHandleSignals signals,
const base::Callback<void(MojoResult)>& callback) {
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h
index aadfb66..0c38008 100644
--- a/mojo/edk/system/core.h
+++ b/mojo/edk/system/core.h
@@ -52,6 +52,15 @@
// invalid.
scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
+ // Like |GetDispatcher()|, but also removes the handle from the handle table.
+ // On success, gets the dispatcher for a given handle (which should not be
+ // |MOJO_HANDLE_INVALID|) and removes it. (On failure, returns an appropriate
+ // result (and leaves |dispatcher| alone), namely
+ // |MOJO_RESULT_INVALID_ARGUMENT| if there's no dispatcher for the given
+ // handle or |MOJO_RESULT_BUSY| if the handle is marked as busy.)
+ MojoResult GetAndRemoveDispatcher(MojoHandle handle,
+ scoped_refptr<Dispatcher>* dispatcher);
+
// Watches on the given handle for the given signals, calling |callback| when
// a signal is satisfied or when all signals become unsatisfiable. |callback|
// must satisfy stringent requirements -- see |Awakable::Awake()| in
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn
index e8f55ad..8735708 100644
--- a/mojo/edk/test/BUILD.gn
+++ b/mojo/edk/test/BUILD.gn
@@ -90,6 +90,7 @@
":mojo_public_system_perftests",
":mojo_public_system_unittests",
":mojo_public_utility_unittests",
+ ":mojo_system_impl_private_unittests",
]
}
@@ -134,3 +135,10 @@
"../../public/cpp/utility/tests",
]
}
+
+test("mojo_system_impl_private_unittests") {
+ deps = [
+ ":run_all_unittests",
+ "../../public/platform/native:system_impl_private_tests",
+ ]
+}
diff --git a/mojo/public/platform/native/BUILD.gn b/mojo/public/platform/native/BUILD.gn
index 0e099f9..6a30d34 100644
--- a/mojo/public/platform/native/BUILD.gn
+++ b/mojo/public/platform/native/BUILD.gn
@@ -24,6 +24,42 @@
# source_set here, this flag change is not needed.
}
+# For internal use only.
+mojo_sdk_source_set("system_impl_private") {
+ sources = [
+ "system_impl_private_thunks.cc",
+ "system_impl_private_thunks.h",
+ ]
+ defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
+ deps = [
+ ":system_impl_private_api",
+ ]
+ mojo_sdk_deps = [ "mojo/public/c/system" ]
+}
+
+# For internal use only.
+mojo_sdk_source_set("system_impl_private_api") {
+ sources = [
+ "system_impl_private.h",
+ ]
+ mojo_sdk_deps = [ "mojo/public/c/system" ]
+}
+
+mojo_sdk_source_set("system_impl_private_tests") {
+ testonly = true
+
+ sources = [
+ "system_impl_private_unittest.cc",
+ ]
+
+ deps = [
+ ":system_impl_private_api",
+ "//testing/gtest",
+ ]
+
+ mojo_sdk_deps = [ "mojo/public/c/system" ]
+}
+
mojo_sdk_source_set("gles2") {
sources = [
"gles2_impl_chromium_miscellaneous_thunks.cc",
diff --git a/mojo/public/platform/native/system_impl_private.h b/mojo/public/platform/native/system_impl_private.h
new file mode 100644
index 0000000..ffb520d
--- /dev/null
+++ b/mojo/public/platform/native/system_impl_private.h
@@ -0,0 +1,142 @@
+// Copyright 2015 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.
+
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_IMPL_PRIVATE_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_IMPL_PRIVATE_H_
+
+#include "mojo/public/c/system/system_export.h"
+#include "mojo/public/c/system/types.h"
+
+// This interface provides the Mojo system API, but with the ability to confine
+// calls to a specific handle namespace. Handles in one namespace are unrelated
+// to handles in another namespace. Two ends of a pipe may live in different
+// handle namespaces, however.
+
+typedef void* MojoSystemImpl;
+
+extern "C" {
+// APIs for creating and manipulating MojoSystemImpls.
+
+// Returns the MojoSystemImpl implicitly used by the non-SystemImpl version of
+// the Mojo sytem APIs.
+MOJO_SYSTEM_EXPORT MojoSystemImpl MojoSystemImplGetDefaultImpl();
+
+// Creates and returns a new MojoSystemImpl. Currently there is no way to
+// destroy a MojoSystemImpl, once created.
+MOJO_SYSTEM_EXPORT MojoSystemImpl MojoSystemImplCreateImpl();
+
+// Moves a handle from one MojoSystemImpl to another.
+// On success, |result_handle| contains the name of the handle in the new
+// namespace.
+// If |MOJO_RESULT_RESOURCE_EXHAUSTED| is returned, the |handle| will have been
+// closed, and is now lost.
+// Busy handles cannot be transfered.
+// To avoid trouble, this API should only be used to bootstrap a newly created
+// |to_system| with a newly created |handle|.
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplTransferHandle(MojoSystemImpl from_system,
+ MojoHandle handle,
+ MojoSystemImpl to_system,
+ MojoHandle* result_handle);
+
+// APIs mirroring the Mojo system APIs, but also taking a MojoSystemImpl param.
+MOJO_SYSTEM_EXPORT MojoTimeTicks
+MojoSystemImplGetTimeTicksNow(MojoSystemImpl system);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplClose(MojoSystemImpl system, MojoHandle handle);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplWait(MojoSystemImpl system,
+ MojoHandle handle,
+ MojoHandleSignals signals,
+ MojoDeadline deadline,
+ struct MojoHandleSignalsState* signals_state);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplWaitMany(MojoSystemImpl system,
+ const MojoHandle* handles,
+ const MojoHandleSignals* signals,
+ uint32_t num_handles,
+ MojoDeadline deadline,
+ uint32_t* result_index,
+ struct MojoHandleSignalsState* signals_states);
+MOJO_SYSTEM_EXPORT MojoResult MojoSystemImplCreateMessagePipe(
+ MojoSystemImpl system,
+ const struct MojoCreateMessagePipeOptions* options,
+ MojoHandle* message_pipe_handle0,
+ MojoHandle* message_pipe_handle1);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplWriteMessage(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ const void* bytes,
+ uint32_t num_bytes,
+ const MojoHandle* handles,
+ uint32_t num_handles,
+ MojoWriteMessageFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplReadMessage(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ void* bytes,
+ uint32_t* num_bytes,
+ MojoHandle* handles,
+ uint32_t* num_handles,
+ MojoReadMessageFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplCreateDataPipe(MojoSystemImpl system,
+ const struct MojoCreateDataPipeOptions* options,
+ MojoHandle* data_pipe_producer_handle,
+ MojoHandle* data_pipe_consumer_handle);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ const void* elements,
+ uint32_t* num_elements,
+ MojoWriteDataFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplBeginWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoWriteDataFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplEndWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ uint32_t num_elements_written);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ void* elements,
+ uint32_t* num_elements,
+ MojoReadDataFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplBeginReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ const void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoReadDataFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplEndReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ uint32_t num_elements_read);
+MOJO_SYSTEM_EXPORT MojoResult MojoSystemImplCreateSharedBuffer(
+ MojoSystemImpl system,
+ const struct MojoCreateSharedBufferOptions* options,
+ uint64_t num_bytes,
+ MojoHandle* shared_buffer_handle);
+MOJO_SYSTEM_EXPORT MojoResult MojoSystemImplDuplicateBufferHandle(
+ MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ const struct MojoDuplicateBufferHandleOptions* options,
+ MojoHandle* new_buffer_handle);
+MOJO_SYSTEM_EXPORT MojoResult MojoSystemImplMapBuffer(MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ uint64_t offset,
+ uint64_t num_bytes,
+ void** buffer,
+ MojoMapBufferFlags flags);
+MOJO_SYSTEM_EXPORT MojoResult
+MojoSystemImplUnmapBuffer(MojoSystemImpl system, void* buffer);
+} // extern "C"
+
+#endif // MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_IMPL_PRIVATE_H_
diff --git a/mojo/public/platform/native/system_impl_private_thunks.cc b/mojo/public/platform/native/system_impl_private_thunks.cc
new file mode 100644
index 0000000..7012e73
--- /dev/null
+++ b/mojo/public/platform/native/system_impl_private_thunks.cc
@@ -0,0 +1,220 @@
+// Copyright 2015 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/public/platform/native/system_impl_private_thunks.h"
+
+#include <assert.h>
+
+#include "mojo/public/platform/native/thunk_export.h"
+
+extern "C" {
+
+static MojoSystemImplControlThunksPrivate g_system_impl_control_thunks = {0};
+static MojoSystemImplThunksPrivate g_system_impl_thunks = {0};
+
+MojoSystemImpl MojoSystemImplGetDefaultImpl() {
+ assert(g_system_impl_control_thunks.GetDefaultSystemImpl);
+ return g_system_impl_control_thunks.GetDefaultSystemImpl();
+}
+
+MojoSystemImpl MojoSystemImplCreateImpl() {
+ assert(g_system_impl_control_thunks.CreateSystemImpl);
+ return g_system_impl_control_thunks.CreateSystemImpl();
+}
+
+MojoResult MojoSystemImplTransferHandle(MojoSystemImpl from_system,
+ MojoHandle handle,
+ MojoSystemImpl to_system,
+ MojoHandle* result_handle) {
+ assert(g_system_impl_control_thunks.TransferHandle);
+ return g_system_impl_control_thunks.TransferHandle(from_system, handle,
+ to_system, result_handle);
+}
+
+MojoTimeTicks MojoSystemImplGetTimeTicksNow(MojoSystemImpl system) {
+ assert(g_system_impl_thunks.GetTimeTicksNow);
+ return g_system_impl_thunks.GetTimeTicksNow(system);
+}
+
+MojoResult MojoSystemImplClose(MojoSystemImpl system, MojoHandle handle) {
+ assert(g_system_impl_thunks.Close);
+ return g_system_impl_thunks.Close(system, handle);
+}
+
+MojoResult MojoSystemImplWait(MojoSystemImpl system,
+ MojoHandle handle,
+ MojoHandleSignals signals,
+ MojoDeadline deadline,
+ struct MojoHandleSignalsState* signals_state) {
+ assert(g_system_impl_thunks.Wait);
+ return g_system_impl_thunks.Wait(system, handle, signals, deadline,
+ signals_state);
+}
+
+MojoResult MojoSystemImplWaitMany(
+ MojoSystemImpl system,
+ const MojoHandle* handles,
+ const MojoHandleSignals* signals,
+ uint32_t num_handles,
+ MojoDeadline deadline,
+ uint32_t* result_index,
+ struct MojoHandleSignalsState* signals_states) {
+ assert(g_system_impl_thunks.WaitMany);
+ return g_system_impl_thunks.WaitMany(system, handles, signals, num_handles,
+ deadline, result_index, signals_states);
+}
+
+MojoResult MojoSystemImplCreateMessagePipe(
+ MojoSystemImpl system,
+ const struct MojoCreateMessagePipeOptions* options,
+ MojoHandle* message_pipe_handle0,
+ MojoHandle* message_pipe_handle1) {
+ assert(g_system_impl_thunks.CreateMessagePipe);
+ return g_system_impl_thunks.CreateMessagePipe(
+ system, options, message_pipe_handle0, message_pipe_handle1);
+}
+
+MojoResult MojoSystemImplWriteMessage(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ const void* bytes,
+ uint32_t num_bytes,
+ const MojoHandle* handles,
+ uint32_t num_handles,
+ MojoWriteMessageFlags flags) {
+ assert(g_system_impl_thunks.WriteMessage);
+ return g_system_impl_thunks.WriteMessage(system, message_pipe_handle, bytes,
+ num_bytes, handles, num_handles,
+ flags);
+}
+
+MojoResult MojoSystemImplReadMessage(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ void* bytes,
+ uint32_t* num_bytes,
+ MojoHandle* handles,
+ uint32_t* num_handles,
+ MojoReadMessageFlags flags) {
+ assert(g_system_impl_thunks.ReadMessage);
+ return g_system_impl_thunks.ReadMessage(system, message_pipe_handle, bytes,
+ num_bytes, handles, num_handles,
+ flags);
+}
+
+MojoResult MojoSystemImplCreateDataPipe(
+ MojoSystemImpl system,
+ const struct MojoCreateDataPipeOptions* options,
+ MojoHandle* data_pipe_producer_handle,
+ MojoHandle* data_pipe_consumer_handle) {
+ assert(g_system_impl_thunks.CreateDataPipe);
+ return g_system_impl_thunks.CreateDataPipe(
+ system, options, data_pipe_producer_handle, data_pipe_consumer_handle);
+}
+
+MojoResult MojoSystemImplWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ const void* elements,
+ uint32_t* num_elements,
+ MojoWriteDataFlags flags) {
+ assert(g_system_impl_thunks.WriteData);
+ return g_system_impl_thunks.WriteData(system, data_pipe_producer_handle,
+ elements, num_elements, flags);
+}
+
+MojoResult MojoSystemImplBeginWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoWriteDataFlags flags) {
+ assert(g_system_impl_thunks.BeginWriteData);
+ return g_system_impl_thunks.BeginWriteData(
+ system, data_pipe_producer_handle, buffer, buffer_num_elements, flags);
+}
+
+MojoResult MojoSystemImplEndWriteData(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ uint32_t num_elements_written) {
+ assert(g_system_impl_thunks.EndWriteData);
+ return g_system_impl_thunks.EndWriteData(system, data_pipe_producer_handle,
+ num_elements_written);
+}
+
+MojoResult MojoSystemImplReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ void* elements,
+ uint32_t* num_elements,
+ MojoReadDataFlags flags) {
+ assert(g_system_impl_thunks.ReadData);
+ return g_system_impl_thunks.ReadData(system, data_pipe_consumer_handle,
+ elements, num_elements, flags);
+}
+
+MojoResult MojoSystemImplBeginReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ const void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoReadDataFlags flags) {
+ assert(g_system_impl_thunks.BeginReadData);
+ return g_system_impl_thunks.BeginReadData(system, data_pipe_consumer_handle,
+ buffer, buffer_num_elements, flags);
+}
+
+MojoResult MojoSystemImplEndReadData(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ uint32_t num_elements_read) {
+ assert(g_system_impl_thunks.EndReadData);
+ return g_system_impl_thunks.EndReadData(system, data_pipe_consumer_handle,
+ num_elements_read);
+}
+
+MojoResult MojoSystemImplCreateSharedBuffer(
+ MojoSystemImpl system,
+ const struct MojoCreateSharedBufferOptions* options,
+ uint64_t num_bytes,
+ MojoHandle* shared_buffer_handle) {
+ assert(g_system_impl_thunks.CreateSharedBuffer);
+ return g_system_impl_thunks.CreateSharedBuffer(system, options, num_bytes,
+ shared_buffer_handle);
+}
+
+MojoResult MojoSystemImplDuplicateBufferHandle(
+ MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ const struct MojoDuplicateBufferHandleOptions* options,
+ MojoHandle* new_buffer_handle) {
+ assert(g_system_impl_thunks.DuplicateBufferHandle);
+ return g_system_impl_thunks.DuplicateBufferHandle(system, buffer_handle,
+ options, new_buffer_handle);
+}
+
+MojoResult MojoSystemImplMapBuffer(MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ uint64_t offset,
+ uint64_t num_bytes,
+ void** buffer,
+ MojoMapBufferFlags flags) {
+ assert(g_system_impl_thunks.MapBuffer);
+ return g_system_impl_thunks.MapBuffer(system, buffer_handle, offset,
+ num_bytes, buffer, flags);
+}
+
+MojoResult MojoSystemImplUnmapBuffer(MojoSystemImpl system, void* buffer) {
+ assert(g_system_impl_thunks.UnmapBuffer);
+ return g_system_impl_thunks.UnmapBuffer(system, buffer);
+}
+
+extern "C" THUNK_EXPORT size_t MojoSetSystemImplControlThunksPrivate(
+ const MojoSystemImplControlThunksPrivate* system_thunks) {
+ if (system_thunks->size >= sizeof(g_system_impl_control_thunks))
+ g_system_impl_control_thunks = *system_thunks;
+ return sizeof(g_system_impl_control_thunks);
+}
+
+extern "C" THUNK_EXPORT size_t MojoSetSystemImplThunksPrivate(
+ const MojoSystemImplThunksPrivate* system_thunks) {
+ if (system_thunks->size >= sizeof(g_system_impl_thunks))
+ g_system_impl_thunks = *system_thunks;
+ return sizeof(g_system_impl_thunks);
+}
+
+} // extern "C"
diff --git a/mojo/public/platform/native/system_impl_private_thunks.h b/mojo/public/platform/native/system_impl_private_thunks.h
new file mode 100644
index 0000000..c45167d
--- /dev/null
+++ b/mojo/public/platform/native/system_impl_private_thunks.h
@@ -0,0 +1,150 @@
+// Copyright 2015 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.
+
+// Note: This header should be compilable as C.
+
+#ifndef MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_IMPL_PRIVATE_THUNKS_H_
+#define MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_IMPL_PRIVATE_THUNKS_H_
+
+#include "mojo/public/c/system/core.h"
+#include "mojo/public/platform/native/system_impl_private.h"
+
+// Structure used to bind the basic Mojo Core functions of a DSO to those of
+// the embedder.
+// This is the ABI between the embedder and the DSO. It can only have new
+// functions added to the end. No other changes are supported.
+#pragma pack(push, 8)
+struct MojoSystemImplControlThunksPrivate {
+ size_t size; // Should be set to sizeof(MojoSystemImplThunks).
+ MojoSystemImpl (*GetDefaultSystemImpl)();
+ MojoSystemImpl (*CreateSystemImpl)();
+ MojoResult (*TransferHandle)(MojoSystemImpl from_system,
+ MojoHandle handle,
+ MojoSystemImpl to_system,
+ MojoHandle* result_handle);
+};
+
+struct MojoSystemImplThunksPrivate {
+ size_t size; // Should be set to sizeof(MojoExplicitThunksPrivate).
+ MojoTimeTicks (*GetTimeTicksNow)(MojoSystemImpl system);
+ MojoResult (*Close)(MojoSystemImpl system, MojoHandle handle);
+ MojoResult (*Wait)(MojoSystemImpl system,
+ MojoHandle handle,
+ MojoHandleSignals signals,
+ MojoDeadline deadline,
+ struct MojoHandleSignalsState* signals_state);
+ MojoResult (*WaitMany)(MojoSystemImpl system,
+ const MojoHandle* handles,
+ const MojoHandleSignals* signals,
+ uint32_t num_handles,
+ MojoDeadline deadline,
+ uint32_t* result_index,
+ struct MojoHandleSignalsState* signals_states);
+ MojoResult (*CreateMessagePipe)(
+ MojoSystemImpl system,
+ const struct MojoCreateMessagePipeOptions* options,
+ MojoHandle* message_pipe_handle0,
+ MojoHandle* message_pipe_handle1);
+ MojoResult (*WriteMessage)(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ const void* bytes,
+ uint32_t num_bytes,
+ const MojoHandle* handles,
+ uint32_t num_handles,
+ MojoWriteMessageFlags flags);
+ MojoResult (*ReadMessage)(MojoSystemImpl system,
+ MojoHandle message_pipe_handle,
+ void* bytes,
+ uint32_t* num_bytes,
+ MojoHandle* handles,
+ uint32_t* num_handles,
+ MojoReadMessageFlags flags);
+ MojoResult (*CreateDataPipe)(MojoSystemImpl system,
+ const struct MojoCreateDataPipeOptions* options,
+ MojoHandle* data_pipe_producer_handle,
+ MojoHandle* data_pipe_consumer_handle);
+ MojoResult (*WriteData)(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ const void* elements,
+ uint32_t* num_elements,
+ MojoWriteDataFlags flags);
+ MojoResult (*BeginWriteData)(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoWriteDataFlags flags);
+ MojoResult (*EndWriteData)(MojoSystemImpl system,
+ MojoHandle data_pipe_producer_handle,
+ uint32_t num_elements_written);
+ MojoResult (*ReadData)(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ void* elements,
+ uint32_t* num_elements,
+ MojoReadDataFlags flags);
+ MojoResult (*BeginReadData)(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ const void** buffer,
+ uint32_t* buffer_num_elements,
+ MojoReadDataFlags flags);
+ MojoResult (*EndReadData)(MojoSystemImpl system,
+ MojoHandle data_pipe_consumer_handle,
+ uint32_t num_elements_read);
+ MojoResult (*CreateSharedBuffer)(
+ MojoSystemImpl system,
+ const struct MojoCreateSharedBufferOptions* options,
+ uint64_t num_bytes,
+ MojoHandle* shared_buffer_handle);
+ MojoResult (*DuplicateBufferHandle)(
+ MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ const struct MojoDuplicateBufferHandleOptions* options,
+ MojoHandle* new_buffer_handle);
+ MojoResult (*MapBuffer)(MojoSystemImpl system,
+ MojoHandle buffer_handle,
+ uint64_t offset,
+ uint64_t num_bytes,
+ void** buffer,
+ MojoMapBufferFlags flags);
+ MojoResult (*UnmapBuffer)(MojoSystemImpl system, void* buffer);
+};
+#pragma pack(pop)
+
+#ifdef __cplusplus
+inline MojoSystemImplControlThunksPrivate
+MojoMakeSystemImplControlThunksPrivate() {
+ MojoSystemImplControlThunksPrivate system_thunks = {
+ sizeof(MojoSystemImplControlThunksPrivate),
+ MojoSystemImplGetDefaultImpl,
+ MojoSystemImplCreateImpl,
+ MojoSystemImplTransferHandle};
+ return system_thunks;
+}
+
+inline MojoSystemImplThunksPrivate MojoMakeSystemImplThunksPrivate() {
+ MojoSystemImplThunksPrivate system_thunks = {
+ sizeof(MojoSystemImplThunksPrivate),
+ MojoSystemImplGetTimeTicksNow,
+ MojoSystemImplClose,
+ MojoSystemImplWait,
+ MojoSystemImplWaitMany,
+ MojoSystemImplCreateMessagePipe,
+ MojoSystemImplWriteMessage,
+ MojoSystemImplReadMessage,
+ MojoSystemImplCreateDataPipe,
+ MojoSystemImplWriteData,
+ MojoSystemImplBeginWriteData,
+ MojoSystemImplEndWriteData,
+ MojoSystemImplReadData,
+ MojoSystemImplBeginReadData,
+ MojoSystemImplEndReadData,
+ MojoSystemImplCreateSharedBuffer,
+ MojoSystemImplDuplicateBufferHandle,
+ MojoSystemImplMapBuffer,
+ MojoSystemImplUnmapBuffer};
+ return system_thunks;
+}
+
+#endif
+
+#endif // MOJO_PUBLIC_PLATFORM_NATIVE_SYSTEM_IMPL_PRIVATE_THUNKS_H_
diff --git a/mojo/public/platform/native/system_impl_private_unittest.cc b/mojo/public/platform/native/system_impl_private_unittest.cc
new file mode 100644
index 0000000..4d0e1ba
--- /dev/null
+++ b/mojo/public/platform/native/system_impl_private_unittest.cc
@@ -0,0 +1,323 @@
+// Copyright 2015 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.
+
+// This file tests the C API, but using the explicit MojoSystemImpl parameter.
+
+#include <string.h>
+
+#include "mojo/public/c/system/core.h"
+#include "mojo/public/platform/native/system_impl_private.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace {
+
+const MojoHandleSignals kSignalReadadableWritable =
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE;
+
+const MojoHandleSignals kSignalAll = MOJO_HANDLE_SIGNAL_READABLE |
+ MOJO_HANDLE_SIGNAL_WRITABLE |
+ MOJO_HANDLE_SIGNAL_PEER_CLOSED;
+
+TEST(SystemImplTest, GetTimeTicksNow) {
+ MojoSystemImpl system = MojoSystemImplCreateImpl();
+ const MojoTimeTicks start = MojoSystemImplGetTimeTicksNow(system);
+ EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
+ << "MojoGetTimeTicksNow should return nonzero value";
+
+ // SystemImpl is leaked...
+}
+
+TEST(SystemImplTest, BasicMessagePipe) {
+ MojoSystemImpl sys0 = MojoSystemImplCreateImpl();
+ MojoSystemImpl sys1 = MojoSystemImplCreateImpl();
+ EXPECT_NE(sys0, sys1);
+
+ MojoHandle h0, h1;
+ MojoHandleSignals sig;
+ char buffer[10] = {0};
+ uint32_t buffer_size;
+
+ h0 = MOJO_HANDLE_INVALID;
+ h1 = MOJO_HANDLE_INVALID;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplCreateMessagePipe(sys0, nullptr, &h0, &h1));
+ EXPECT_NE(h0, MOJO_HANDLE_INVALID);
+ EXPECT_NE(h1, MOJO_HANDLE_INVALID);
+
+ // Move the other end of the pipe to a different SystemImpl.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplTransferHandle(sys0, h1, sys1, &h1));
+ EXPECT_NE(h1, MOJO_HANDLE_INVALID);
+
+ // Shouldn't be readable, we haven't written anything.
+ MojoHandleSignalsState state;
+ EXPECT_EQ(
+ MOJO_RESULT_DEADLINE_EXCEEDED,
+ MojoSystemImplWait(sys0, h0, MOJO_HANDLE_SIGNAL_READABLE, 0, &state));
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
+ EXPECT_EQ(kSignalAll, state.satisfiable_signals);
+
+ // Should be writable.
+ EXPECT_EQ(
+ MOJO_RESULT_OK,
+ MojoSystemImplWait(sys0, h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &state));
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
+ EXPECT_EQ(kSignalAll, state.satisfiable_signals);
+
+ // Last parameter is optional.
+ EXPECT_EQ(
+ MOJO_RESULT_OK,
+ MojoSystemImplWait(sys0, h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, nullptr));
+
+ // Try to read.
+ buffer_size = static_cast<uint32_t>(sizeof(buffer));
+ EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
+ MojoSystemImplReadMessage(sys0, h0, buffer, &buffer_size, nullptr,
+ nullptr, MOJO_READ_MESSAGE_FLAG_NONE));
+
+ // Write to |h1|.
+ static const char kHello[] = "hello";
+ buffer_size = static_cast<uint32_t>(sizeof(kHello));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplWriteMessage(sys1, h1, kHello, buffer_size, nullptr,
+ 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ // |h0| should be readable.
+ uint32_t result_index = 1;
+ MojoHandleSignalsState states[1];
+ sig = MOJO_HANDLE_SIGNAL_READABLE;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplWaitMany(sys0, &h0, &sig, 1, MOJO_DEADLINE_INDEFINITE,
+ &result_index, states));
+
+ EXPECT_EQ(0u, result_index);
+ EXPECT_EQ(kSignalReadadableWritable, states[0].satisfied_signals);
+ EXPECT_EQ(kSignalAll, states[0].satisfiable_signals);
+
+ // Read from |h0|.
+ buffer_size = static_cast<uint32_t>(sizeof(buffer));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplReadMessage(sys0, h0, buffer, &buffer_size, nullptr,
+ nullptr, MOJO_READ_MESSAGE_FLAG_NONE));
+ EXPECT_EQ(static_cast<uint32_t>(sizeof(kHello)), buffer_size);
+ EXPECT_STREQ(kHello, buffer);
+
+ // |h0| should no longer be readable.
+ EXPECT_EQ(
+ MOJO_RESULT_DEADLINE_EXCEEDED,
+ MojoSystemImplWait(sys0, h0, MOJO_HANDLE_SIGNAL_READABLE, 10, &state));
+
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
+ EXPECT_EQ(kSignalAll, state.satisfiable_signals);
+
+ // Close |h0|.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplClose(sys0, h0));
+
+ // |h1| should no longer be readable or writable.
+ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
+ MojoSystemImplWait(sys1, h1, MOJO_HANDLE_SIGNAL_READABLE |
+ MOJO_HANDLE_SIGNAL_WRITABLE,
+ 1000, &state));
+
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplClose(sys1, h1));
+
+ // 2 SystemImpls are leaked...
+}
+
+TEST(SystemImplTest, BasicDataPipe) {
+ MojoSystemImpl sys0 = MojoSystemImplCreateImpl();
+ MojoSystemImpl sys1 = MojoSystemImplCreateImpl();
+ EXPECT_NE(sys0, sys1);
+
+ MojoHandle hp, hc;
+ MojoHandleSignals sig;
+ char buffer[20] = {0};
+ uint32_t buffer_size;
+ void* write_pointer;
+ const void* read_pointer;
+
+ hp = MOJO_HANDLE_INVALID;
+ hc = MOJO_HANDLE_INVALID;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplCreateDataPipe(sys0, nullptr, &hp, &hc));
+ EXPECT_NE(hp, MOJO_HANDLE_INVALID);
+ EXPECT_NE(hc, MOJO_HANDLE_INVALID);
+
+ // Move the other end of the pipe to a different SystemImpl.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplTransferHandle(sys0, hc, sys1, &hc));
+ EXPECT_NE(hc, MOJO_HANDLE_INVALID);
+
+ // The consumer |hc| shouldn't be readable.
+ MojoHandleSignalsState state;
+ EXPECT_EQ(
+ MOJO_RESULT_DEADLINE_EXCEEDED,
+ MojoSystemImplWait(sys1, hc, MOJO_HANDLE_SIGNAL_READABLE, 0, &state));
+
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, state.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ state.satisfiable_signals);
+
+ // The producer |hp| should be writable.
+ EXPECT_EQ(
+ MOJO_RESULT_OK,
+ MojoSystemImplWait(sys0, hp, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &state));
+
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ state.satisfiable_signals);
+
+ // Try to read from |hc|.
+ buffer_size = static_cast<uint32_t>(sizeof(buffer));
+ EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
+ MojoSystemImplReadData(sys1, hc, buffer, &buffer_size,
+ MOJO_READ_DATA_FLAG_NONE));
+
+ // Try to begin a two-phase read from |hc|.
+ read_pointer = nullptr;
+ EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
+ MojoSystemImplBeginReadData(sys1, hc, &read_pointer, &buffer_size,
+ MOJO_READ_DATA_FLAG_NONE));
+
+ // Write to |hp|.
+ static const char kHello[] = "hello ";
+ // Don't include terminating null.
+ buffer_size = static_cast<uint32_t>(strlen(kHello));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplWriteData(sys0, hp, kHello, &buffer_size,
+ MOJO_WRITE_MESSAGE_FLAG_NONE));
+
+ // |hc| should be(come) readable.
+ uint32_t result_index = 1;
+ MojoHandleSignalsState states[1];
+ sig = MOJO_HANDLE_SIGNAL_READABLE;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplWaitMany(sys1, &hc, &sig, 1, MOJO_DEADLINE_INDEFINITE,
+ &result_index, states));
+
+ EXPECT_EQ(0u, result_index);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, states[0].satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ states[0].satisfiable_signals);
+
+ // Do a two-phase write to |hp|.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplBeginWriteData(sys0, hp, &write_pointer, &buffer_size,
+ MOJO_WRITE_DATA_FLAG_NONE));
+ static const char kWorld[] = "world";
+ ASSERT_GE(buffer_size, sizeof(kWorld));
+ // Include the terminating null.
+ memcpy(write_pointer, kWorld, sizeof(kWorld));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplEndWriteData(sys0, hp,
+ static_cast<uint32_t>(sizeof(kWorld))));
+
+ // Read one character from |hc|.
+ memset(buffer, 0, sizeof(buffer));
+ buffer_size = 1;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplReadData(sys1, hc, buffer, &buffer_size,
+ MOJO_READ_DATA_FLAG_NONE));
+
+ // Close |hp|.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplClose(sys0, hp));
+
+ // |hc| should still be readable.
+ EXPECT_EQ(
+ MOJO_RESULT_OK,
+ MojoSystemImplWait(sys1, hc, MOJO_HANDLE_SIGNAL_READABLE, 0, &state));
+
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ state.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ state.satisfiable_signals);
+
+ // Do a two-phase read from |hc|.
+ read_pointer = nullptr;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplBeginReadData(sys1, hc, &read_pointer, &buffer_size,
+ MOJO_READ_DATA_FLAG_NONE));
+ ASSERT_LE(buffer_size, sizeof(buffer) - 1);
+ memcpy(&buffer[1], read_pointer, buffer_size);
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplEndReadData(sys1, hc, buffer_size));
+ EXPECT_STREQ("hello world", buffer);
+
+ // |hc| should no longer be readable.
+ EXPECT_EQ(
+ MOJO_RESULT_FAILED_PRECONDITION,
+ MojoSystemImplWait(sys1, hc, MOJO_HANDLE_SIGNAL_READABLE, 1000, &state));
+
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
+ EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplClose(sys1, hc));
+
+ // TODO(vtl): Test the other way around -- closing the consumer should make
+ // the producer never-writable?
+
+ // 2 SystemImpls are leaked...
+}
+
+TEST(SystemImplTest, BasicSharedBuffer) {
+ MojoSystemImpl sys0 = MojoSystemImplCreateImpl();
+ MojoSystemImpl sys1 = MojoSystemImplCreateImpl();
+ EXPECT_NE(sys0, sys1);
+
+ MojoHandle h0, h1;
+ void* pointer;
+
+ // Create a shared buffer (|h0|).
+ h0 = MOJO_HANDLE_INVALID;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplCreateSharedBuffer(sys0, nullptr, 100, &h0));
+ EXPECT_NE(h0, MOJO_HANDLE_INVALID);
+
+ // Map everything.
+ pointer = nullptr;
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplMapBuffer(sys0, h0, 0, 100, &pointer,
+ MOJO_MAP_BUFFER_FLAG_NONE));
+ ASSERT_TRUE(pointer);
+ static_cast<char*>(pointer)[50] = 'x';
+
+ // Duplicate |h0| to |h1|.
+ h1 = MOJO_HANDLE_INVALID;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSystemImplDuplicateBufferHandle(sys0, h0, nullptr, &h1));
+ EXPECT_NE(h1, MOJO_HANDLE_INVALID);
+
+ // Move the other end of the pipe to a different SystemImpl.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplTransferHandle(sys0, h1, sys1, &h1));
+ EXPECT_NE(h1, MOJO_HANDLE_INVALID);
+
+ // Close |h0|.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplClose(sys0, h0));
+
+ // The mapping should still be good.
+ static_cast<char*>(pointer)[51] = 'y';
+
+ // Unmap it.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplUnmapBuffer(sys0, pointer));
+
+ // Map half of |h1|.
+ pointer = nullptr;
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplMapBuffer(sys1, h1, 50, 50, &pointer,
+ MOJO_MAP_BUFFER_FLAG_NONE));
+ ASSERT_TRUE(pointer);
+
+ // It should have what we wrote.
+ EXPECT_EQ('x', static_cast<char*>(pointer)[0]);
+ EXPECT_EQ('y', static_cast<char*>(pointer)[1]);
+
+ // Unmap it.
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplUnmapBuffer(sys1, pointer));
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoSystemImplClose(sys1, h1));
+
+ // 2 SystemImpls are leaked...
+}
+
+} // namespace
+} // namespace mojo
diff --git a/mojo/tools/data/unittests b/mojo/tools/data/unittests
index bce098f..ecfd2f9 100644
--- a/mojo/tools/data/unittests
+++ b/mojo/tools/data/unittests
@@ -24,6 +24,9 @@
{
"test": "mojo_public_utility_unittests",
},
+ {
+ "test": "mojo_system_impl_private_unittests",
+ },
# Non-system, non-public tests:
{