summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mojo/system/core.cc223
-rw-r--r--mojo/system/core.h62
-rw-r--r--mojo/system/core_test_base.cc12
-rw-r--r--mojo/system/core_unittest.cc423
-rw-r--r--mojo/system/entrypoints.cc77
-rw-r--r--mojo/system/mapping_table.cc5
-rw-r--r--mojo/system/mapping_table.h2
-rw-r--r--mojo/system/memory.cc36
-rw-r--r--mojo/system/memory.h270
9 files changed, 790 insertions, 320 deletions
diff --git a/mojo/system/core.cc b/mojo/system/core.cc
index d72198f..49c90db 100644
--- a/mojo/system/core.cc
+++ b/mojo/system/core.cc
@@ -123,34 +123,31 @@ MojoResult Core::Wait(MojoHandle handle,
return WaitManyInternal(&handle, &signals, 1, deadline);
}
-MojoResult Core::WaitMany(const MojoHandle* handles,
- const MojoHandleSignals* signals,
+MojoResult Core::WaitMany(UserPointer<const MojoHandle> handles,
+ UserPointer<const MojoHandleSignals> signals,
uint32_t num_handles,
MojoDeadline deadline) {
- if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointerWithCount<MojoHandleSignals>(signals, num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles < 1)
return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles > kMaxWaitManyNumHandles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
- return WaitManyInternal(handles, signals, num_handles, deadline);
+ UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
+ UserPointer<const MojoHandleSignals>::Reader signals_reader(signals,
+ num_handles);
+ return WaitManyInternal(handles_reader.GetPointer(),
+ signals_reader.GetPointer(), num_handles, deadline);
}
-MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1) {
+MojoResult Core::CreateMessagePipe(
+ UserPointer<const MojoCreateMessagePipeOptions> options,
+ UserPointer<MojoHandle> message_pipe_handle0,
+ UserPointer<MojoHandle> message_pipe_handle1) {
MojoCreateMessagePipeOptions validated_options = {};
// This will verify the |options| pointer.
MojoResult result = MessagePipeDispatcher::ValidateCreateOptions(
- options, &validated_options);
+ options.GetPointerUnsafe(), &validated_options);
if (result != MOJO_RESULT_OK)
return result;
- if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1))
- return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<MessagePipeDispatcher> dispatcher0(
new MessagePipeDispatcher(validated_options));
@@ -174,8 +171,8 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
dispatcher0->Init(message_pipe, 0);
dispatcher1->Init(message_pipe, 1);
- *message_pipe_handle0 = handle_pair.first;
- *message_pipe_handle1 = handle_pair.second;
+ message_pipe_handle0.Put(handle_pair.first);
+ message_pipe_handle1.Put(handle_pair.second);
return MOJO_RESULT_OK;
}
@@ -187,9 +184,9 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
// after the the message has been received and a new handle created (and
// possibly even after calls have been made on the new handle).
MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
+ UserPointer<const void> bytes,
uint32_t num_bytes,
- const MojoHandle* handles,
+ UserPointer<const MojoHandle> handles,
uint32_t num_handles,
MojoWriteMessageFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
@@ -197,8 +194,10 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
return MOJO_RESULT_INVALID_ARGUMENT;
// Easy case: not sending any handles.
- if (num_handles == 0)
- return dispatcher->WriteMessage(bytes, num_bytes, NULL, flags);
+ if (num_handles == 0) {
+ return dispatcher->WriteMessage(bytes.GetPointerUnsafe(), num_bytes, NULL,
+ flags);
+ }
// We have to handle |handles| here, since we have to mark them busy in the
// global handle table. We can't delegate this to the dispatcher, since the
@@ -208,11 +207,11 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
// validity, even for dispatchers that don't support |WriteMessage()| and will
// simply return failure unconditionally. It also breaks the usual
// left-to-right verification order of arguments.)
- if (!VerifyUserPointerWithCount<MojoHandle>(handles, num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles > kMaxMessageNumHandles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
+ UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
+
// We'll need to hold on to the dispatchers so that we can pass them on to
// |WriteMessage()| and also so that we can unlock their locks afterwards
// without accessing the handle table. These can be dumb pointers, since their
@@ -226,13 +225,14 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
{
base::AutoLock locker(handle_table_lock_);
MojoResult result = handle_table_.MarkBusyAndStartTransport(
- message_pipe_handle, handles, num_handles, &transports);
+ message_pipe_handle, handles_reader.GetPointer(), num_handles,
+ &transports);
if (result != MOJO_RESULT_OK)
return result;
}
- MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports,
- flags);
+ MojoResult rv = dispatcher->WriteMessage(bytes.GetPointerUnsafe(), num_bytes,
+ &transports, flags);
// We need to release the dispatcher locks before we take the handle table
// lock.
@@ -241,77 +241,84 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
{
base::AutoLock locker(handle_table_lock_);
- if (rv == MOJO_RESULT_OK)
- handle_table_.RemoveBusyHandles(handles, num_handles);
- else
- handle_table_.RestoreBusyHandles(handles, num_handles);
+ if (rv == MOJO_RESULT_OK) {
+ handle_table_.RemoveBusyHandles(handles_reader.GetPointer(), num_handles);
+ } else {
+ handle_table_.RestoreBusyHandles(handles_reader.GetPointer(),
+ num_handles);
+ }
}
return rv;
}
MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
+ UserPointer<void> bytes,
+ UserPointer<uint32_t> num_bytes,
+ UserPointer<MojoHandle> handles,
+ UserPointer<uint32_t> num_handles,
MojoReadMessageFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- if (num_handles) {
- if (!VerifyUserPointer<uint32_t>(num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointerWithCount<MojoHandle>(handles, *num_handles))
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- // Easy case: won't receive any handles.
- if (!num_handles || *num_handles == 0)
- return dispatcher->ReadMessage(bytes, num_bytes, NULL, num_handles, flags);
-
- DispatcherVector dispatchers;
- MojoResult rv = dispatcher->ReadMessage(bytes, num_bytes,
- &dispatchers, num_handles,
- flags);
- if (!dispatchers.empty()) {
- DCHECK_EQ(rv, MOJO_RESULT_OK);
- DCHECK(num_handles);
- DCHECK_LE(dispatchers.size(), static_cast<size_t>(*num_handles));
-
- bool success;
- {
- base::AutoLock locker(handle_table_lock_);
- success = handle_table_.AddDispatcherVector(dispatchers, handles);
- }
- if (!success) {
- LOG(ERROR) << "Received message with " << dispatchers.size()
- << " handles, but handle table full";
- // Close dispatchers (outside the lock).
- for (size_t i = 0; i < dispatchers.size(); i++) {
- if (dispatchers[i])
- dispatchers[i]->Close();
+ uint32_t num_handles_value = num_handles.IsNull() ? 0 : num_handles.Get();
+
+ MojoResult rv;
+ if (num_handles_value == 0) {
+ // Easy case: won't receive any handles.
+ rv = dispatcher->ReadMessage(bytes.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), NULL,
+ &num_handles_value, flags);
+ } else {
+ DispatcherVector dispatchers;
+ rv = dispatcher->ReadMessage(bytes.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), &dispatchers,
+ &num_handles_value, flags);
+ if (!dispatchers.empty()) {
+ DCHECK_EQ(rv, MOJO_RESULT_OK);
+ DCHECK(!num_handles.IsNull());
+ DCHECK_LE(dispatchers.size(), static_cast<size_t>(num_handles_value));
+
+ bool success;
+ UserPointer<MojoHandle>::Writer handles_writer(handles,
+ dispatchers.size());
+ {
+ base::AutoLock locker(handle_table_lock_);
+ success = handle_table_.AddDispatcherVector(
+ dispatchers, handles_writer.GetPointer());
+ }
+ if (success) {
+ handles_writer.Commit();
+ } else {
+ LOG(ERROR) << "Received message with " << dispatchers.size()
+ << " handles, but handle table full";
+ // Close dispatchers (outside the lock).
+ for (size_t i = 0; i < dispatchers.size(); i++) {
+ if (dispatchers[i])
+ dispatchers[i]->Close();
+ }
+ if (rv == MOJO_RESULT_OK)
+ rv = MOJO_RESULT_RESOURCE_EXHAUSTED;
}
}
}
+ if (!num_handles.IsNull())
+ num_handles.Put(num_handles_value);
return rv;
}
-MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle) {
+MojoResult Core::CreateDataPipe(
+ UserPointer<const MojoCreateDataPipeOptions> options,
+ UserPointer<MojoHandle> data_pipe_producer_handle,
+ UserPointer<MojoHandle> data_pipe_consumer_handle) {
MojoCreateDataPipeOptions validated_options = {};
// This will verify the |options| pointer.
- MojoResult result = DataPipe::ValidateCreateOptions(options,
- &validated_options);
+ MojoResult result = DataPipe::ValidateCreateOptions(
+ options.GetPointerUnsafe(), &validated_options);
if (result != MOJO_RESULT_OK)
return result;
- if (!VerifyUserPointer<MojoHandle>(data_pipe_producer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointer<MojoHandle>(data_pipe_consumer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher(
new DataPipeProducerDispatcher());
@@ -337,33 +344,35 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options,
producer_dispatcher->Init(data_pipe);
consumer_dispatcher->Init(data_pipe);
- *data_pipe_producer_handle = handle_pair.first;
- *data_pipe_consumer_handle = handle_pair.second;
+ data_pipe_producer_handle.Put(handle_pair.first);
+ data_pipe_consumer_handle.Put(handle_pair.second);
return MOJO_RESULT_OK;
}
MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_bytes,
+ UserPointer<const void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoWriteDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->WriteData(elements, num_bytes, flags);
+ return dispatcher->WriteData(elements.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoWriteDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
+ return dispatcher->BeginWriteData(buffer.GetPointerUnsafe(),
+ buffer_num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
@@ -377,27 +386,29 @@ MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
}
MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_bytes,
+ UserPointer<void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoReadDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->ReadData(elements, num_bytes, flags);
+ return dispatcher->ReadData(elements.GetPointerUnsafe(),
+ num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<const void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoReadDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
+ return dispatcher->BeginReadData(buffer.GetPointerUnsafe(),
+ buffer_num_bytes.GetPointerUnsafe(), flags);
}
MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
@@ -411,18 +422,16 @@ MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
}
MojoResult Core::CreateSharedBuffer(
- const MojoCreateSharedBufferOptions* options,
+ UserPointer<const MojoCreateSharedBufferOptions> options,
uint64_t num_bytes,
- MojoHandle* shared_buffer_handle) {
+ UserPointer<MojoHandle> shared_buffer_handle) {
MojoCreateSharedBufferOptions validated_options = {};
// This will verify the |options| pointer.
MojoResult result =
- SharedBufferDispatcher::ValidateCreateOptions(options,
+ SharedBufferDispatcher::ValidateCreateOptions(options.GetPointerUnsafe(),
&validated_options);
if (result != MOJO_RESULT_OK)
return result;
- if (!VerifyUserPointer<MojoHandle>(shared_buffer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<SharedBufferDispatcher> dispatcher;
result = SharedBufferDispatcher::Create(validated_options, num_bytes,
@@ -439,25 +448,22 @@ MojoResult Core::CreateSharedBuffer(
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
- *shared_buffer_handle = h;
+ shared_buffer_handle.Put(h);
return MOJO_RESULT_OK;
}
MojoResult Core::DuplicateBufferHandle(
MojoHandle buffer_handle,
- const MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle) {
+ UserPointer<const MojoDuplicateBufferHandleOptions> options,
+ UserPointer<MojoHandle> new_buffer_handle) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
// Don't verify |options| here; that's the dispatcher's job.
- if (!VerifyUserPointer<MojoHandle>(new_buffer_handle))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
scoped_refptr<Dispatcher> new_dispatcher;
- MojoResult result = dispatcher->DuplicateBufferHandle(options,
- &new_dispatcher);
+ MojoResult result = dispatcher->DuplicateBufferHandle(
+ options.GetPointerUnsafe(), &new_dispatcher);
if (result != MOJO_RESULT_OK)
return result;
@@ -468,22 +474,19 @@ MojoResult Core::DuplicateBufferHandle(
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
- *new_buffer_handle = new_handle;
+ new_buffer_handle.Put(new_handle);
return MOJO_RESULT_OK;
}
MojoResult Core::MapBuffer(MojoHandle buffer_handle,
uint64_t offset,
uint64_t num_bytes,
- void** buffer,
+ UserPointer<void*> buffer,
MojoMapBufferFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
if (!dispatcher)
return MOJO_RESULT_INVALID_ARGUMENT;
- if (!VerifyUserPointerWithCount<void*>(buffer, 1))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
scoped_ptr<RawSharedBufferMapping> mapping;
MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping);
if (result != MOJO_RESULT_OK)
@@ -498,13 +501,13 @@ MojoResult Core::MapBuffer(MojoHandle buffer_handle,
if (result != MOJO_RESULT_OK)
return result;
- *buffer = address;
+ buffer.Put(address);
return MOJO_RESULT_OK;
}
-MojoResult Core::UnmapBuffer(void* buffer) {
+MojoResult Core::UnmapBuffer(UserPointerValue<void> buffer) {
base::AutoLock locker(mapping_table_lock_);
- return mapping_table_.RemoveMapping(buffer);
+ return mapping_table_.RemoveMapping(buffer.GetValue());
}
// Note: We allow |handles| to repeat the same handle multiple times, since
diff --git a/mojo/system/core.h b/mojo/system/core.h
index a0bc293..ba811f8 100644
--- a/mojo/system/core.h
+++ b/mojo/system/core.h
@@ -15,6 +15,7 @@
#include "mojo/public/c/system/types.h"
#include "mojo/system/handle_table.h"
#include "mojo/system/mapping_table.h"
+#include "mojo/system/memory.h"
#include "mojo/system/system_impl_export.h"
namespace mojo {
@@ -44,61 +45,64 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
MojoResult Wait(MojoHandle handle,
MojoHandleSignals signals,
MojoDeadline deadline);
- MojoResult WaitMany(const MojoHandle* handles,
- const MojoHandleSignals* signals,
+ MojoResult WaitMany(UserPointer<const MojoHandle> handles,
+ UserPointer<const MojoHandleSignals> signals,
uint32_t num_handles,
MojoDeadline deadline);
- MojoResult CreateMessagePipe(const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1);
+ MojoResult CreateMessagePipe(
+ UserPointer<const MojoCreateMessagePipeOptions> options,
+ UserPointer<MojoHandle> message_pipe_handle0,
+ UserPointer<MojoHandle> message_pipe_handle1);
MojoResult WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
+ UserPointer<const void> bytes,
uint32_t num_bytes,
- const MojoHandle* handles,
+ UserPointer<const MojoHandle> handles,
uint32_t num_handles,
MojoWriteMessageFlags flags);
MojoResult ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
+ UserPointer<void> bytes,
+ UserPointer<uint32_t> num_bytes,
+ UserPointer<MojoHandle> handles,
+ UserPointer<uint32_t> num_handles,
MojoReadMessageFlags flags);
- MojoResult CreateDataPipe(const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle);
+ MojoResult CreateDataPipe(
+ UserPointer<const MojoCreateDataPipeOptions> options,
+ UserPointer<MojoHandle> data_pipe_producer_handle,
+ UserPointer<MojoHandle> data_pipe_consumer_handle);
MojoResult WriteData(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_bytes,
+ UserPointer<const void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoWriteDataFlags flags);
MojoResult BeginWriteData(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
MojoWriteDataFlags flags);
MojoResult EndWriteData(MojoHandle data_pipe_producer_handle,
uint32_t num_bytes_written);
MojoResult ReadData(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_bytes,
+ UserPointer<void> elements,
+ UserPointer<uint32_t> num_bytes,
MojoReadDataFlags flags);
MojoResult BeginReadData(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_bytes,
+ UserPointer<const void*> buffer,
+ UserPointer<uint32_t> buffer_num_bytes,
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(
+ UserPointer<const MojoCreateSharedBufferOptions> options,
+ uint64_t num_bytes,
+ UserPointer<MojoHandle> shared_buffer_handle);
MojoResult DuplicateBufferHandle(
MojoHandle buffer_handle,
- const MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle);
+ UserPointer<const MojoDuplicateBufferHandleOptions> options,
+ UserPointer<MojoHandle> new_buffer_handle);
MojoResult MapBuffer(MojoHandle buffer_handle,
uint64_t offset,
uint64_t num_bytes,
- void** buffer,
+ UserPointer<void*> buffer,
MojoMapBufferFlags flags);
- MojoResult UnmapBuffer(void* buffer);
+ MojoResult UnmapBuffer(UserPointerValue<void> buffer);
private:
friend bool internal::ShutdownCheckNoLeaks(Core*);
diff --git a/mojo/system/core_test_base.cc b/mojo/system/core_test_base.cc
index c91437c..c02b118 100644
--- a/mojo/system/core_test_base.cc
+++ b/mojo/system/core_test_base.cc
@@ -68,8 +68,8 @@ class MockDispatcher : public Dispatcher {
virtual MojoResult ReadMessageImplNoLock(
void* bytes,
uint32_t* num_bytes,
- DispatcherVector* /*dispatchers*/,
- uint32_t* /*num_dispatchers*/,
+ DispatcherVector* dispatchers,
+ uint32_t* num_dispatchers,
MojoReadMessageFlags /*flags*/) OVERRIDE {
info_->IncrementReadMessageCallCount();
lock().AssertAcquired();
@@ -77,6 +77,14 @@ class MockDispatcher : public Dispatcher {
if (num_bytes && !VerifyUserPointerWithSize<1>(bytes, *num_bytes))
return MOJO_RESULT_INVALID_ARGUMENT;
+ if (num_dispatchers) {
+ *num_dispatchers = 1;
+ if (dispatchers) {
+ // Okay to leave an invalid dispatcher.
+ dispatchers->resize(1);
+ }
+ }
+
return MOJO_RESULT_OK;
}
diff --git a/mojo/system/core_unittest.cc b/mojo/system/core_unittest.cc
index af3d0c1..59ff1c8 100644
--- a/mojo/system/core_unittest.cc
+++ b/mojo/system/core_unittest.cc
@@ -38,38 +38,45 @@ TEST_F(CoreTest, Basic) {
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h, NULL, 0, NULL, 0,
+ core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 1, NULL, 0,
+ core()->WriteMessage(h, NullUserPointer(), 1, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(2u, info.GetWriteMessageCallCount());
EXPECT_EQ(0u, info.GetReadMessageCallCount());
uint32_t num_bytes = 0;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL,
+ core()->ReadMessage(h, NullUserPointer(),
+ MakeUserPointer(&num_bytes), NullUserPointer(),
+ NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetReadMessageCallCount());
num_bytes = 1;
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(h, NULL, &num_bytes, NULL, NULL,
+ core()->ReadMessage(h, NullUserPointer(),
+ MakeUserPointer(&num_bytes), NullUserPointer(),
+ NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(2u, info.GetReadMessageCallCount());
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, NULL, NULL, NULL, NULL,
+ core()->ReadMessage(h, NullUserPointer(), NullUserPointer(),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(3u, info.GetReadMessageCallCount());
EXPECT_EQ(0u, info.GetWriteDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->WriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE));
+ core()->WriteData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteDataCallCount());
EXPECT_EQ(0u, info.GetBeginWriteDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->BeginWriteData(h, NULL, NULL, MOJO_WRITE_DATA_FLAG_NONE));
+ core()->BeginWriteData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetBeginWriteDataCallCount());
EXPECT_EQ(0u, info.GetEndWriteDataCallCount());
@@ -79,12 +86,14 @@ TEST_F(CoreTest, Basic) {
EXPECT_EQ(0u, info.GetReadDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->ReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE));
+ core()->ReadData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetReadDataCallCount());
EXPECT_EQ(0u, info.GetBeginReadDataCallCount());
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->BeginReadData(h, NULL, NULL, MOJO_READ_DATA_FLAG_NONE));
+ core()->BeginReadData(h, NullUserPointer(), NullUserPointer(),
+ MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(1u, info.GetBeginReadDataCallCount());
EXPECT_EQ(0u, info.GetEndReadDataCallCount());
@@ -105,7 +114,9 @@ TEST_F(CoreTest, Basic) {
EXPECT_EQ(3u, info.GetAddWaiterCallCount());
MojoHandleSignals handle_signals = ~MOJO_HANDLE_SIGNAL_NONE;
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WaitMany(&h, &handle_signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(&h),
+ MakeUserPointer(&handle_signals), 1,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(4u, info.GetAddWaiterCallCount());
EXPECT_EQ(0u, info.GetDtorCallCount());
@@ -152,81 +163,78 @@ TEST_F(CoreTest, InvalidArguments) {
MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE,
~MOJO_HANDLE_SIGNAL_NONE};
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 0, MOJO_DEADLINE_INDEFINITE));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(NULL, signals, 0, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 0,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, NULL, 0, MOJO_DEADLINE_INDEFINITE));
-
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(NULL, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 0,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, NULL, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 0,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 1,
+ MOJO_DEADLINE_INDEFINITE));
MockHandleInfo info[2];
handles[0] = CreateMockHandle(&info[0]);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WaitMany(handles, signals, 1, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 1,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
handles[1] = handles[0] + 1; // Invalid handle.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
handles[1] = CreateMockHandle(&info[1]);
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WaitMany(handles, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ core()->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[0]));
EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[1]));
}
- // |CreateMessagePipe()|:
- {
- MojoHandle h;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->CreateMessagePipe(NULL, NULL, NULL));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->CreateMessagePipe(NULL, &h, NULL));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->CreateMessagePipe(NULL, NULL, &h));
- }
+ // |CreateMessagePipe()|: Nothing to check (apart from things that cause
+ // death).
// |WriteMessage()|:
// Only check arguments checked by |Core|, namely |handle|, |handles|, and
// |num_handles|.
{
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(MOJO_HANDLE_INVALID, NULL, 0, NULL, 0,
+ core()->WriteMessage(MOJO_HANDLE_INVALID, NullUserPointer(), 0,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MockHandleInfo info;
MojoHandle h = CreateMockHandle(&info);
MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
- // Null |handles| with nonzero |num_handles|.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, NULL, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- // Checked by |Core|, shouldn't go through to the dispatcher.
- EXPECT_EQ(0u, info.GetWriteMessageCallCount());
-
// Huge handle count (implausibly big on some systems -- more than can be
// stored in a 32-bit address space).
// Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or
// |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or
// not.
EXPECT_NE(MOJO_RESULT_OK,
- core()->WriteMessage(h, NULL, 0, handles,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles),
std::numeric_limits<uint32_t>::max(),
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
// Huge handle count (plausibly big).
EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->WriteMessage(h, NULL, 0, handles,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles),
std::numeric_limits<uint32_t>::max() /
sizeof(handles[0]),
MOJO_WRITE_MESSAGE_FLAG_NONE));
@@ -234,20 +242,23 @@ TEST_F(CoreTest, InvalidArguments) {
// Invalid handle in |handles|.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, handles, 1,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
// Two invalid handles in |handles|.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
// Can't send a handle over itself.
handles[0] = h;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h, NULL, 0, handles, 1,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(0u, info.GetWriteMessageCallCount());
@@ -257,27 +268,31 @@ TEST_F(CoreTest, InvalidArguments) {
// This is "okay", but |MockDispatcher| doesn't implement it.
handles[0] = h2;
EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->WriteMessage(h, NULL, 0, handles, 1,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
// One of the |handles| is still invalid.
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
// One of the |handles| is the same as |handle|.
handles[1] = h;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
// Can't send a handle twice in the same message.
handles[1] = h2;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h, NULL, 0, handles, 2,
+ core()->WriteMessage(h, NullUserPointer(), 0,
+ MakeUserPointer(handles), 2,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, info.GetWriteMessageCallCount());
@@ -293,23 +308,20 @@ TEST_F(CoreTest, InvalidArguments) {
// |num_handles|.
{
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(MOJO_HANDLE_INVALID, NULL, NULL, NULL, NULL,
+ core()->ReadMessage(MOJO_HANDLE_INVALID, NullUserPointer(),
+ NullUserPointer(), NullUserPointer(),
+ NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
MockHandleInfo info;
MojoHandle h = CreateMockHandle(&info);
- uint32_t handle_count = 1;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(h, NULL, NULL, NULL, &handle_count,
- MOJO_READ_MESSAGE_FLAG_NONE));
- // Checked by |Core|, shouldn't go through to the dispatcher.
- EXPECT_EQ(0u, info.GetReadMessageCallCount());
-
// Okay.
- handle_count = 0;
+ uint32_t handle_count = 0;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, NULL, NULL, NULL, &handle_count,
+ core()->ReadMessage(h, NullUserPointer(), NullUserPointer(),
+ NullUserPointer(),
+ MakeUserPointer(&handle_count),
MOJO_READ_MESSAGE_FLAG_NONE));
// Checked by |Core|, shouldn't go through to the dispatcher.
EXPECT_EQ(1u, info.GetReadMessageCallCount());
@@ -318,6 +330,82 @@ TEST_F(CoreTest, InvalidArguments) {
}
}
+// These test invalid arguments that should cause death if we're being paranoid
+// about checking arguments (which we would want to do if, e.g., we were in a
+// true "kernel" situation, but we might not want to do otherwise for
+// performance reasons). Probably blatant errors like passing in null pointers
+// (for required pointer arguments) will still cause death, but perhaps not
+// predictably.
+TEST_F(CoreTest, InvalidArgumentsDeath) {
+ const char kMemoryCheckFailedRegex[] = "Check failed";
+
+ // |WaitMany()|:
+ {
+ MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
+ MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE,
+ ~MOJO_HANDLE_SIGNAL_NONE};
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->WaitMany(NullUserPointer(), MakeUserPointer(signals), 1,
+ MOJO_DEADLINE_INDEFINITE),
+ kMemoryCheckFailedRegex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->WaitMany(MakeUserPointer(handles), NullUserPointer(), 1,
+ MOJO_DEADLINE_INDEFINITE),
+ kMemoryCheckFailedRegex);
+ }
+
+ // |CreateMessagePipe()|:
+ {
+ MojoHandle h;
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(),
+ NullUserPointer()),
+ kMemoryCheckFailedRegex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h),
+ NullUserPointer()),
+ kMemoryCheckFailedRegex);
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->CreateMessagePipe(NullUserPointer(), NullUserPointer(),
+ MakeUserPointer(&h)),
+ kMemoryCheckFailedRegex);
+ }
+
+ // |WriteMessage()|:
+ // Only check arguments checked by |Core|, namely |handle|, |handles|, and
+ // |num_handles|.
+ {
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+
+ // Null |handles| with nonzero |num_handles|.
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->WriteMessage(h, NullUserPointer(), 0, NullUserPointer(),
+ 1, MOJO_WRITE_MESSAGE_FLAG_NONE),
+ kMemoryCheckFailedRegex);
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ }
+
+ // |ReadMessage()|:
+ // Only check arguments checked by |Core|, namely |handle|, |handles|, and
+ // |num_handles|.
+ {
+ MockHandleInfo info;
+ MojoHandle h = CreateMockHandle(&info);
+
+ uint32_t handle_count = 1;
+ EXPECT_DEATH_IF_SUPPORTED(
+ core()->ReadMessage(h, NullUserPointer(), NullUserPointer(),
+ NullUserPointer(),
+ MakeUserPointer(&handle_count),
+ MOJO_READ_MESSAGE_FLAG_NONE),
+ kMemoryCheckFailedRegex);
+
+ EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
+ }
+}
+
// TODO(vtl): test |Wait()| and |WaitMany()| properly
// - including |WaitMany()| with the same handle more than once (with
// same/different signals)
@@ -325,7 +413,9 @@ TEST_F(CoreTest, InvalidArguments) {
TEST_F(CoreTest, MessagePipe) {
MojoHandle h[2];
- EXPECT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(NULL, &h[0], &h[1]));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateMessagePipe(NullUserPointer(), MakeUserPointer(&h[0]),
+ MakeUserPointer(&h[1])));
// Should get two distinct, valid handles.
EXPECT_NE(h[0], MOJO_HANDLE_INVALID);
EXPECT_NE(h[1], MOJO_HANDLE_INVALID);
@@ -335,13 +425,16 @@ TEST_F(CoreTest, MessagePipe) {
MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
MOJO_HANDLE_SIGNAL_READABLE};
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
- core()->WaitMany(h, signals, 2, 0));
+ core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2,
+ 0));
// Try to read anyway.
char buffer[1] = {'a'};
uint32_t buffer_size = 1;
EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
- core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL,
+ core()->ReadMessage(h[0], UserPointer<void>(buffer),
+ MakeUserPointer(&buffer_size),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
// Check that it left its inputs alone.
EXPECT_EQ('a', buffer[0]);
@@ -356,31 +449,38 @@ TEST_F(CoreTest, MessagePipe) {
// Also check that |h[1]| is writable using |WaitMany()|.
signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
signals[1] = MOJO_HANDLE_SIGNAL_WRITABLE;
- EXPECT_EQ(1, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(1, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
// Write to |h[1]|.
buffer[0] = 'b';
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h[1], buffer, 1, NULL, 0,
+ core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// Check that |h[0]| is now readable.
signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
signals[1] = MOJO_HANDLE_SIGNAL_READABLE;
- EXPECT_EQ(0, core()->WaitMany(h, signals, 2, MOJO_DEADLINE_INDEFINITE));
+ EXPECT_EQ(0, core()->WaitMany(MakeUserPointer(h), MakeUserPointer(signals), 2,
+ MOJO_DEADLINE_INDEFINITE));
// Read from |h[0]|.
// First, get only the size.
buffer_size = 0;
EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->ReadMessage(h[0], NULL, &buffer_size, NULL, NULL,
+ core()->ReadMessage(h[0], NullUserPointer(),
+ MakeUserPointer(&buffer_size),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(1u, buffer_size);
// Then actually read it.
buffer[0] = 'c';
buffer_size = 1;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h[0], buffer, &buffer_size, NULL, NULL,
+ core()->ReadMessage(h[0], UserPointer<void>(buffer),
+ MakeUserPointer(&buffer_size),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ('b', buffer[0]);
EXPECT_EQ(1u, buffer_size);
@@ -392,7 +492,8 @@ TEST_F(CoreTest, MessagePipe) {
// Write to |h[0]|.
buffer[0] = 'd';
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h[0], buffer, 1, NULL, 0,
+ core()->WriteMessage(h[0], UserPointer<const void>(buffer), 1,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// Close |h[0]|.
@@ -408,7 +509,8 @@ TEST_F(CoreTest, MessagePipe) {
// Discard a message from |h[1]|.
EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->ReadMessage(h[1], NULL, NULL, NULL, NULL,
+ core()->ReadMessage(h[1], NullUserPointer(), NullUserPointer(),
+ NullUserPointer(), NullUserPointer(),
MOJO_READ_MESSAGE_FLAG_MAY_DISCARD));
// |h[1]| is no longer readable (and will never be).
@@ -418,7 +520,8 @@ TEST_F(CoreTest, MessagePipe) {
// Try writing to |h[1]|.
buffer[0] = 'e';
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- core()->WriteMessage(h[1], buffer, 1, NULL, 0,
+ core()->WriteMessage(h[1], UserPointer<const void>(buffer), 1,
+ NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[1]));
@@ -439,13 +542,14 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
MojoHandle h_passing[2];
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1]));
+ core()->CreateMessagePipe(NullUserPointer(),
+ MakeUserPointer(&h_passing[0]),
+ MakeUserPointer(&h_passing[1])));
// Make sure that |h_passing[]| work properly.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- NULL, 0,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -453,9 +557,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -464,34 +569,34 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
// Make sure that you can't pass either of the message pipe's handles over
// itself.
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &h_passing[0], 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&h_passing[0]), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &h_passing[1], 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&h_passing[1]), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoHandle h_passed[2];
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(NULL, &h_passed[0], &h_passed[1]));
+ core()->CreateMessagePipe(NullUserPointer(),
+ MakeUserPointer(&h_passed[0]),
+ MakeUserPointer(&h_passed[1])));
// Make sure that |h_passed[]| work properly.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passed[0],
- kHello, kHelloSize,
- NULL, 0,
+ core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello),
+ kHelloSize, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passed[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passed[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passed[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -499,9 +604,9 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
// Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kWorld, kWorldSize,
- &h_passed[1], 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld),
+ kWorldSize,
+ MakeUserPointer(&h_passed[1]), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -509,9 +614,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
@@ -531,18 +637,18 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
// Write to |h_passed[0]|. Should receive on |h_received|.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passed[0],
- kHello, kHelloSize,
- NULL, 0,
+ core()->WriteMessage(h_passed[0], UserPointer<const void>(kHello),
+ kHelloSize, NullUserPointer(), 0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_received,
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_received, UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -557,7 +663,9 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
TEST_F(CoreTest, DataPipe) {
MojoHandle ph, ch; // p is for producer and c is for consumer.
- EXPECT_EQ(MOJO_RESULT_OK, core()->CreateDataPipe(NULL, &ph, &ch));
+ EXPECT_EQ(MOJO_RESULT_OK,
+ core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph),
+ MakeUserPointer(&ch)));
// Should get two distinct, valid handles.
EXPECT_NE(ph, MOJO_HANDLE_INVALID);
EXPECT_NE(ch, MOJO_HANDLE_INVALID);
@@ -579,7 +687,8 @@ TEST_F(CoreTest, DataPipe) {
char elements[2] = {'A', 'B'};
uint32_t num_bytes = 2u;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph, elements, &num_bytes,
+ core()->WriteData(ph, UserPointer<const void>(elements),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(2u, num_bytes);
@@ -592,7 +701,8 @@ TEST_F(CoreTest, DataPipe) {
elements[1] = -1;
num_bytes = 1u;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, elements, &num_bytes,
+ core()->ReadData(ch, UserPointer<void>(elements),
+ MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ('A', elements[0]);
EXPECT_EQ(-1, elements[1]);
@@ -601,7 +711,8 @@ TEST_F(CoreTest, DataPipe) {
void* write_ptr = NULL;
num_bytes = 0u;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginWriteData(ph, &write_ptr, &num_bytes,
+ core()->BeginWriteData(ph, MakeUserPointer(&write_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
// We count on the default options providing a decent buffer size.
ASSERT_GE(num_bytes, 3u);
@@ -610,7 +721,8 @@ TEST_F(CoreTest, DataPipe) {
elements[0] = 'X';
num_bytes = 1u;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteData(ph, elements, &num_bytes,
+ core()->WriteData(ph, UserPointer<const void>(elements),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
// Actually write the data, and complete it now.
@@ -622,20 +734,21 @@ TEST_F(CoreTest, DataPipe) {
// Query how much data we have.
num_bytes = 0;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY));
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
+ MOJO_READ_DATA_FLAG_QUERY));
EXPECT_EQ(4u, num_bytes);
// Try to discard ten characters, in all-or-none mode. Should fail.
num_bytes = 10;
EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- core()->ReadData(ch, NULL, &num_bytes,
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_DISCARD |
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
// Discard two characters.
num_bytes = 2;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, NULL, &num_bytes,
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_DISCARD |
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
@@ -643,7 +756,8 @@ TEST_F(CoreTest, DataPipe) {
const void* read_ptr = NULL;
num_bytes = 2;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
+ core()->BeginReadData(ch, MakeUserPointer(&read_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
// Note: Count on still being able to do the contiguous read here.
ASSERT_EQ(2u, num_bytes);
@@ -651,7 +765,7 @@ TEST_F(CoreTest, DataPipe) {
// Discarding right now should fail.
num_bytes = 1;
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->ReadData(ch, NULL, &num_bytes,
+ core()->ReadData(ch, NullUserPointer(), MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_DISCARD));
// Actually check our data and end the two-phase read.
@@ -689,17 +803,19 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
MojoHandle h_passing[2];
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(NULL, &h_passing[0], &h_passing[1]));
+ core()->CreateMessagePipe(NullUserPointer(),
+ MakeUserPointer(&h_passing[0]),
+ MakeUserPointer(&h_passing[1])));
MojoHandle ph, ch;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->CreateDataPipe(NULL, &ph, &ch));
+ core()->CreateDataPipe(NullUserPointer(), MakeUserPointer(&ph),
+ MakeUserPointer(&ch)));
// Send |ch| from |h_passing[0]| to |h_passing[1]|.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ch, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ch), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -707,9 +823,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -730,22 +847,23 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
// Write to |ph|. Should receive on |ch_received|.
num_bytes = kWorldSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph, kWorld, &num_bytes,
+ core()->WriteData(ph, UserPointer<const void>(kWorld),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch_received, buffer, &num_bytes,
+ core()->ReadData(ch_received, UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
// Now pass |ph| in the same direction.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kWorld, kWorldSize,
- &ph, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld),
+ kWorldSize, MakeUserPointer(&ph), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(h_passing[1], MOJO_HANDLE_SIGNAL_READABLE,
@@ -753,9 +871,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
@@ -776,13 +895,15 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
// Write to |ph_received|. Should receive on |ch_received|.
num_bytes = kHelloSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph_received, kHello, &num_bytes,
+ core()->WriteData(ph_received, UserPointer<const void>(kHello),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
EXPECT_EQ(MOJO_RESULT_OK,
core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000));
num_bytes = kBufferSize;
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch_received, buffer, &num_bytes,
+ core()->ReadData(ch_received, UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -796,20 +917,19 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
void* write_ptr = NULL;
num_bytes = 0;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginWriteData(ph, &write_ptr, &num_bytes,
+ core()->BeginWriteData(ph, MakeUserPointer(&write_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_WRITE_DATA_FLAG_NONE));
ASSERT_GE(num_bytes, 1u);
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ph, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ph), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// But |ch| can, even if |ph| is in a two-phase write.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ch, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ch), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
ch = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK,
@@ -818,9 +938,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kHelloSize, num_bytes);
EXPECT_STREQ(kHello, buffer);
@@ -840,19 +961,18 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
const void* read_ptr = NULL;
num_bytes = 1;
ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
+ core()->BeginReadData(ch, MakeUserPointer(&read_ptr),
+ MakeUserPointer(&num_bytes),
MOJO_READ_DATA_FLAG_ALL_OR_NONE));
EXPECT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0],
- kHello, kHelloSize,
- &ch, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kHello),
+ kHelloSize, MakeUserPointer(&ch), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// But |ph| can, even if |ch| is in a two-phase read.
EXPECT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0],
- kWorld, kWorldSize,
- &ph, 1,
+ core()->WriteMessage(h_passing[0], UserPointer<const void>(kWorld),
+ kWorldSize, MakeUserPointer(&ph), 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
ph = MOJO_HANDLE_INVALID;
EXPECT_EQ(MOJO_RESULT_OK,
@@ -861,9 +981,10 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
num_bytes = kBufferSize;
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h_passing[1],
- buffer, &num_bytes,
- handles, &num_handles,
+ core()->ReadMessage(h_passing[1], UserPointer<void>(buffer),
+ MakeUserPointer(&num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(&num_handles),
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(kWorldSize, num_bytes);
EXPECT_STREQ(kWorld, buffer);
diff --git a/mojo/system/entrypoints.cc b/mojo/system/entrypoints.cc
index b70fcad..2ee2c3e 100644
--- a/mojo/system/entrypoints.cc
+++ b/mojo/system/entrypoints.cc
@@ -12,6 +12,9 @@
static mojo::system::Core* g_core = NULL;
+using mojo::system::MakeUserPointer;
+using mojo::system::MakeUserPointerValue;
+
namespace mojo {
namespace system {
namespace entrypoints {
@@ -49,14 +52,18 @@ MojoResult MojoWaitMany(const MojoHandle* handles,
const MojoHandleSignals* signals,
uint32_t num_handles,
MojoDeadline deadline) {
- return g_core->WaitMany(handles, signals, num_handles, deadline);
+ return g_core->WaitMany(MakeUserPointer(handles),
+ MakeUserPointer(signals),
+ num_handles,
+ deadline);
}
MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options,
MojoHandle* message_pipe_handle0,
MojoHandle* message_pipe_handle1) {
- return g_core->CreateMessagePipe(
- options, message_pipe_handle0, message_pipe_handle1);
+ return g_core->CreateMessagePipe(MakeUserPointer(options),
+ MakeUserPointer(message_pipe_handle0),
+ MakeUserPointer(message_pipe_handle1));
}
MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
@@ -65,41 +72,54 @@ MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
const MojoHandle* handles,
uint32_t num_handles,
MojoWriteMessageFlags flags) {
- return g_core->WriteMessage(
- message_pipe_handle, bytes, num_bytes, handles, num_handles, flags);
+ return g_core->WriteMessage(message_pipe_handle,
+ MakeUserPointer(bytes),
+ num_bytes,
+ MakeUserPointer(handles),
+ num_handles,
+ flags);
}
MojoResult MojoReadMessage(MojoHandle message_pipe_handle,
void* bytes,
uint32_t* num_bytes,
MojoHandle* handles,
- uint32_t* num_handles,
+ uint32_t* num_handles,
MojoReadMessageFlags flags) {
- return g_core->ReadMessage(
- message_pipe_handle, bytes, num_bytes, handles, num_handles, flags);
+ return g_core->ReadMessage(message_pipe_handle,
+ MakeUserPointer(bytes),
+ MakeUserPointer(num_bytes),
+ MakeUserPointer(handles),
+ MakeUserPointer(num_handles),
+ flags);
}
MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options,
MojoHandle* data_pipe_producer_handle,
MojoHandle* data_pipe_consumer_handle) {
- return g_core->CreateDataPipe(
- options, data_pipe_producer_handle, data_pipe_consumer_handle);
+ return g_core->CreateDataPipe(MakeUserPointer(options),
+ MakeUserPointer(data_pipe_producer_handle),
+ MakeUserPointer(data_pipe_consumer_handle));
}
MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle,
const void* elements,
uint32_t* num_elements,
MojoWriteDataFlags flags) {
- return g_core->WriteData(
- data_pipe_producer_handle, elements, num_elements, flags);
+ return g_core->WriteData(data_pipe_producer_handle,
+ MakeUserPointer(elements),
+ MakeUserPointer(num_elements),
+ flags);
}
MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
void** buffer,
uint32_t* buffer_num_elements,
MojoWriteDataFlags flags) {
- return g_core->BeginWriteData(
- data_pipe_producer_handle, buffer, buffer_num_elements, flags);
+ return g_core->BeginWriteData(data_pipe_producer_handle,
+ MakeUserPointer(buffer),
+ MakeUserPointer(buffer_num_elements),
+ flags);
}
MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle,
@@ -111,16 +131,20 @@ MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle,
void* elements,
uint32_t* num_elements,
MojoReadDataFlags flags) {
- return g_core->ReadData(
- data_pipe_consumer_handle, elements, num_elements, flags);
+ return g_core->ReadData(data_pipe_consumer_handle,
+ MakeUserPointer(elements),
+ MakeUserPointer(num_elements),
+ flags);
}
MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
const void** buffer,
uint32_t* buffer_num_elements,
MojoReadDataFlags flags) {
- return g_core->BeginReadData(
- data_pipe_consumer_handle, buffer, buffer_num_elements, flags);
+ return g_core->BeginReadData(data_pipe_consumer_handle,
+ MakeUserPointer(buffer),
+ MakeUserPointer(buffer_num_elements),
+ flags);
}
MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle,
@@ -132,15 +156,18 @@ MojoResult MojoCreateSharedBuffer(
const struct MojoCreateSharedBufferOptions* options,
uint64_t num_bytes,
MojoHandle* shared_buffer_handle) {
- return g_core->CreateSharedBuffer(options, num_bytes, shared_buffer_handle);
+ return g_core->CreateSharedBuffer(MakeUserPointer(options),
+ num_bytes,
+ MakeUserPointer(shared_buffer_handle));
}
MojoResult MojoDuplicateBufferHandle(
MojoHandle buffer_handle,
const struct MojoDuplicateBufferHandleOptions* options,
MojoHandle* new_buffer_handle) {
- return g_core->DuplicateBufferHandle(
- buffer_handle, options, new_buffer_handle);
+ return g_core->DuplicateBufferHandle(buffer_handle,
+ MakeUserPointer(options),
+ MakeUserPointer(new_buffer_handle));
}
MojoResult MojoMapBuffer(MojoHandle buffer_handle,
@@ -148,11 +175,15 @@ MojoResult MojoMapBuffer(MojoHandle buffer_handle,
uint64_t num_bytes,
void** buffer,
MojoMapBufferFlags flags) {
- return g_core->MapBuffer(buffer_handle, offset, num_bytes, buffer, flags);
+ return g_core->MapBuffer(buffer_handle,
+ offset,
+ num_bytes,
+ MakeUserPointer(buffer),
+ flags);
}
MojoResult MojoUnmapBuffer(void* buffer) {
- return g_core->UnmapBuffer(buffer);
+ return g_core->UnmapBuffer(MakeUserPointerValue(buffer));
}
} // extern "C"
diff --git a/mojo/system/mapping_table.cc b/mojo/system/mapping_table.cc
index a6e5bb3..6170679 100644
--- a/mojo/system/mapping_table.cc
+++ b/mojo/system/mapping_table.cc
@@ -33,9 +33,8 @@ MojoResult MappingTable::AddMapping(
return MOJO_RESULT_OK;
}
-MojoResult MappingTable::RemoveMapping(void* address) {
- AddressToMappingMap::iterator it =
- address_to_mapping_map_.find(reinterpret_cast<uintptr_t>(address));
+MojoResult MappingTable::RemoveMapping(uintptr_t address) {
+ AddressToMappingMap::iterator it = address_to_mapping_map_.find(address);
if (it == address_to_mapping_map_.end())
return MOJO_RESULT_INVALID_ARGUMENT;
RawSharedBufferMapping* mapping_to_delete = it->second;
diff --git a/mojo/system/mapping_table.h b/mojo/system/mapping_table.h
index 5268234..e21d685 100644
--- a/mojo/system/mapping_table.h
+++ b/mojo/system/mapping_table.h
@@ -39,7 +39,7 @@ class MOJO_SYSTEM_IMPL_EXPORT MappingTable {
// Tries to add a mapping. (Takes ownership of the mapping in all cases; on
// failure, it will be destroyed.)
MojoResult AddMapping(scoped_ptr<RawSharedBufferMapping> mapping);
- MojoResult RemoveMapping(void* address);
+ MojoResult RemoveMapping(uintptr_t address);
private:
friend bool internal::ShutdownCheckNoLeaks(Core*);
diff --git a/mojo/system/memory.cc b/mojo/system/memory.cc
index cee7e05..160e1e5 100644
--- a/mojo/system/memory.cc
+++ b/mojo/system/memory.cc
@@ -29,6 +29,11 @@ bool IsAligned<8>(const void* pointer) {
#endif
template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer) {
+ CHECK(pointer && IsAligned<alignment>(pointer));
+}
+
+template <size_t size, size_t alignment>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer) {
// TODO(vtl): If running in kernel mode, do a full verification. For now, just
// check that it's non-null and aligned. (A faster user mode implementation is
@@ -37,6 +42,12 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer) {
}
// Explicitly instantiate the sizes we need. Add instantiations as needed.
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<1, 1>(
+ const void*);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<4, 4>(
+ const void*);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<8, 8>(
+ const void*);
template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<1, 1>(
const void*);
template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<4, 4>(
@@ -49,16 +60,39 @@ template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<8, 8>(
// this in particular to check that various Options structs are aligned.
#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
template <>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper<4, 8>(
+ const void* pointer) {
+ CHECK(pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0);
+}
+template <>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper<4, 8>(
const void* pointer) {
return !!pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0;
}
#else
+template MOJO_SYSTEM_IMPL_EXPORT void CheckUserPointerHelper<4, 8>(
+ const void*);
template MOJO_SYSTEM_IMPL_EXPORT bool VerifyUserPointerHelper<4, 8>(
const void*);
#endif
template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper(
+ const void* pointer,
+ size_t count) {
+ CHECK_LE(count, std::numeric_limits<size_t>::max() / size);
+ CHECK(count == 0 || (pointer && IsAligned<alignment>(pointer)));
+}
+
+// Explicitly instantiate the sizes we need. Add instantiations as needed.
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<1, 1>(
+ const void*, size_t);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<4, 4>(
+ const void*, size_t);
+template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper<8, 8>(
+ const void*, size_t);
+
+template <size_t size, size_t alignment>
bool VerifyUserPointerWithCountHelper(const void* pointer, size_t count) {
if (count > std::numeric_limits<size_t>::max() / size)
return false;
@@ -77,7 +111,7 @@ template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper<4, 4>(
template bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper<8, 8>(
const void*, size_t);
-} // nameespace internal
+} // namespace internal
template <size_t alignment>
bool VerifyUserPointerWithSize(const void* pointer, size_t size) {
diff --git a/mojo/system/memory.h b/mojo/system/memory.h
index 96f800e..e19bfa8 100644
--- a/mojo/system/memory.h
+++ b/mojo/system/memory.h
@@ -6,7 +6,11 @@
#define MOJO_SYSTEM_MEMORY_H_
#include <stddef.h>
+#include <stdint.h>
+#include <string.h> // For |memcpy()|.
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "mojo/public/c/system/macros.h"
#include "mojo/system/system_impl_export.h"
@@ -15,6 +19,26 @@ namespace system {
namespace internal {
+// Removes |const| from |T| (available as |remove_const<T>::type|):
+// TODO(vtl): Remove these once we have the C++11 |remove_const|.
+template <typename T> struct remove_const { typedef T type; };
+template <typename T> struct remove_const<const T> { typedef T type; };
+
+// Yields |(const) char| if |T| is |(const) void|, else |T|:
+template <typename T> struct VoidToChar { typedef T type; };
+template <> struct VoidToChar<void> { typedef char type; };
+template <> struct VoidToChar<const void> { typedef const char type; };
+
+template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer);
+
+template <size_t size, size_t alignment>
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper(
+ const void* pointer,
+ size_t count);
+
+// TODO(vtl): Delete all the |Verify...()| things (and replace them with
+// |Check...()|.
template <size_t size, size_t alignment>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer);
@@ -26,6 +50,11 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper(
} // namespace internal
+// Forward declarations so that they can be friended.
+template <typename Type> class UserPointerReader;
+template <typename Type> class UserPointerWriter;
+template <typename Type> class UserPointerReaderWriter;
+
// Verify (insofar as possible/necessary) that a |T| can be read from the user
// |pointer|.
template <typename T>
@@ -50,6 +79,247 @@ template <size_t alignment>
bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer,
size_t size);
+// Provides a convenient way to implicitly get null |UserPointer<Type>|s.
+struct NullUserPointer {};
+
+// Represents a user pointer to a single |Type| (which must be POD), for Mojo
+// primitive parameters.
+//
+// Use a const |Type| for in parameters, and non-const |Type|s for out and
+// in-out parameters (in which case the |Put()| method is available).
+template <typename Type>
+class UserPointer {
+ public:
+ // Instead of explicitly using these constructors, you can often use
+ // |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common
+ // exception is when you have, e.g., a |char*| and want to get a
+ // |UserPointer<void>|.)
+ UserPointer() : pointer_(NULL) {}
+ explicit UserPointer(Type* pointer) : pointer_(pointer) {}
+ // Allow implicit conversion from the "null user pointer".
+ UserPointer(NullUserPointer) : pointer_(NULL) {}
+ ~UserPointer() {}
+
+ // Allow assignment from the "null user pointer".
+ UserPointer<Type>& operator=(NullUserPointer) {
+ pointer_ = NULL;
+ return *this;
+ }
+
+ // Allow conversion to a "non-const" |UserPointer|.
+ operator UserPointer<const Type>() const {
+ return UserPointer<const Type>(pointer_);
+ }
+
+ bool IsNull() const {
+ return !pointer_;
+ }
+
+ // We want to force a copy here, so return |Type| not |const Type&|.
+ Type Get() const {
+ internal::CheckUserPointerHelper<sizeof(Type),
+ MOJO_ALIGNOF(Type)>(pointer_);
+ return *pointer_;
+ }
+
+ // Note: This |Put()| method is not valid when |T| is const, e.g., |const
+ // uint32_t|, but it's okay to include them so long as this template is only
+ // implicitly instantiated (see 14.7.1 of the C++11 standard) and not
+ // explicitly instantiated. (On implicit instantiation, only the declarations
+ // need be valid, not the definitions.)
+ //
+ // If |Type| is |void|, we "convert" it to |char|, so that it makes sense.
+ // (Otherwise, we'd need a suitable specialization to exclude |Put()|.)
+ //
+ // In C++11, we could do something like:
+ // template <typename _Type = Type>
+ // typename enable_if<!is_const<_Type>::value &&
+ // !is_void<_Type>::value>::type Put(
+ // const _Type& value) { ... }
+ // (which obviously be correct), but C++03 doesn't allow default function
+ // template arguments.
+ void Put(const typename internal::VoidToChar<Type>::type& value) {
+ internal::CheckUserPointerHelper<sizeof(Type),
+ MOJO_ALIGNOF(Type)>(pointer_);
+ *pointer_ = value;
+ }
+
+ UserPointer At(size_t i) const {
+ return UserPointer(pointer_ + i);
+ }
+
+ // TODO(vtl): This is temporary. Get rid of this. (We should pass
+ // |UserPointer<>|s along appropriately, or access data in a safe way
+ // everywhere.)
+ Type* GetPointerUnsafe() const {
+ return pointer_;
+ }
+
+ // These provides safe (read-only/write-only/read-and-write) access to a
+ // |UserPointer<Type>| (probably pointing to an array) using just an ordinary
+ // pointer (obtained via |GetPointer()|).
+ //
+ // The memory returned by |GetPointer()| may be a copy of the original user
+ // memory, but should be modified only if the user is intended to eventually
+ // see the change.) If any changes are made, |Commit()| should be called to
+ // guarantee that the changes are written back to user memory (it may be
+ // called multiple times).
+ //
+ // Note: These classes are designed to allow fast, unsafe implementations (in
+ // which |GetPointer()| just returns the user pointer) if desired. Thus if
+ // |Commit()| is *not* called, changes may or may not be made visible to the
+ // user.
+ //
+ // Use these classes in the following way:
+ //
+ // MojoResult Core::PutFoos(UserPointer<const uint32_t> foos,
+ // uint32_t num_foos) {
+ // UserPointer<const uint32_t>::Reader foos_reader(foos, num_foos);
+ // return PutFoosImpl(foos_reader.GetPointer(), num_foos);
+ // }
+ //
+ // MojoResult Core::GetFoos(UserPointer<uint32_t> foos,
+ // uint32_t num_foos) {
+ // UserPointer<uint32_t>::Writer foos_writer(foos, num_foos);
+ // MojoResult rv = GetFoosImpl(foos.GetPointer(), num_foos);
+ // foos_writer.Commit();
+ // return rv;
+ // }
+ //
+ // TODO(vtl): Possibly, since we're not really being safe, we should just not
+ // copy for Release builds.
+ typedef UserPointerReader<Type> Reader;
+ typedef UserPointerWriter<Type> Writer;
+ typedef UserPointerReaderWriter<Type> ReaderWriter;
+
+ private:
+ friend class UserPointerReader<Type>;
+ friend class UserPointerWriter<Type>;
+ friend class UserPointerReaderWriter<Type>;
+
+ Type* pointer_;
+ // Allow copy and assignment.
+};
+
+// Provides a convenient way to make a |UserPointer<Type>|.
+template <typename Type>
+inline UserPointer<Type> MakeUserPointer(Type* pointer) {
+ return UserPointer<Type>(pointer);
+}
+
+// Implementation of |UserPointer<Type>::Reader|.
+template <typename Type>
+class UserPointerReader {
+ private:
+ typedef typename internal::remove_const<Type>::type TypeNoConst;
+
+ public:
+ UserPointerReader(UserPointer<const Type> user_pointer, size_t count) {
+ Init(user_pointer.pointer_, count);
+ }
+ UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) {
+ Init(user_pointer.pointer_, count);
+ }
+
+ const Type* GetPointer() const { return buffer_.get(); }
+
+ private:
+ void Init(const Type* user_pointer, size_t count) {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer, count);
+ buffer_.reset(new TypeNoConst[count]);
+ memcpy(buffer_.get(), user_pointer, count * sizeof(Type));
+ }
+
+ scoped_ptr<TypeNoConst[]> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserPointerReader);
+};
+
+// Implementation of |UserPointer<Type>::Writer|.
+template <typename Type>
+class UserPointerWriter {
+ public:
+ UserPointerWriter(UserPointer<Type> user_pointer, size_t count)
+ : user_pointer_(user_pointer),
+ count_(count) {
+ buffer_.reset(new Type[count_]);
+ memset(buffer_.get(), 0, count_ * sizeof(Type));
+ }
+
+ Type* GetPointer() const { return buffer_.get(); }
+
+ void Commit() {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_);
+ memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type));
+ }
+
+ private:
+ UserPointer<Type> user_pointer_;
+ size_t count_;
+ scoped_ptr<Type[]> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserPointerWriter);
+};
+
+// Implementation of |UserPointer<Type>::ReaderWriter|.
+template <typename Type>
+class UserPointerReaderWriter {
+ public:
+ UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count)
+ : user_pointer_(user_pointer),
+ count_(count) {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_);
+ buffer_.reset(new Type[count]);
+ memcpy(buffer_.get(), user_pointer.pointer_, count * sizeof(Type));
+ }
+
+ Type* GetPointer() const { return buffer_.get(); }
+ size_t GetCount() const { return count_; }
+
+ void Commit() {
+ internal::CheckUserPointerWithCountHelper<
+ sizeof(Type), MOJO_ALIGNOF(Type)>(user_pointer_.pointer_, count_);
+ memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type));
+ }
+
+ private:
+ UserPointer<Type> user_pointer_;
+ size_t count_;
+ scoped_ptr<Type[]> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter);
+};
+
+// Represents a user pointer that will never be dereferenced by the system. The
+// pointer value (i.e., the address) may be as a key for lookup, or may be a
+// value that is only passed to the user at some point.
+template <typename Type>
+class UserPointerValue {
+ public:
+ UserPointerValue() : pointer_() {}
+ explicit UserPointerValue(Type* pointer) : pointer_(pointer) {}
+ ~UserPointerValue() {}
+
+ // Returns the *value* of the pointer, which shouldn't be cast back to a
+ // pointer and dereferenced.
+ uintptr_t GetValue() const {
+ return reinterpret_cast<uintptr_t>(pointer_);
+ }
+
+ private:
+ Type* pointer_;
+ // Allow copy and assignment.
+};
+
+// Provides a convenient way to make a |UserPointerValue<Type>|.
+template <typename Type>
+inline UserPointerValue<Type> MakeUserPointerValue(Type* pointer) {
+ return UserPointerValue<Type>(pointer);
+}
+
} // namespace system
} // namespace mojo