This source file includes following definitions.
- busy
- AddDispatcher
- GetTimeTicksNow
- Close
- Wait
- WaitMany
- CreateMessagePipe
- WriteMessage
- ReadMessage
- CreateDataPipe
- WriteData
- BeginWriteData
- EndWriteData
- ReadData
- BeginReadData
- EndReadData
- CreateSharedBuffer
- DuplicateBufferHandle
- MapBuffer
- UnmapBuffer
- GetDispatcher
- WaitManyInternal
#include "mojo/system/core_impl.h"
#include <vector>
#include "base/logging.h"
#include "base/time/time.h"
#include "mojo/system/constants.h"
#include "mojo/system/data_pipe.h"
#include "mojo/system/data_pipe_consumer_dispatcher.h"
#include "mojo/system/data_pipe_producer_dispatcher.h"
#include "mojo/system/dispatcher.h"
#include "mojo/system/local_data_pipe.h"
#include "mojo/system/memory.h"
#include "mojo/system/message_pipe.h"
#include "mojo/system/message_pipe_dispatcher.h"
#include "mojo/system/raw_shared_buffer.h"
#include "mojo/system/shared_buffer_dispatcher.h"
#include "mojo/system/waiter.h"
namespace mojo {
namespace system {
CoreImpl::HandleTableEntry::HandleTableEntry()
: busy(false) {
}
CoreImpl::HandleTableEntry::HandleTableEntry(
const scoped_refptr<Dispatcher>& dispatcher)
: dispatcher(dispatcher),
busy(false) {
}
CoreImpl::HandleTableEntry::~HandleTableEntry() {
DCHECK(!busy);
}
CoreImpl::CoreImpl() {
}
CoreImpl::~CoreImpl() {
}
MojoHandle CoreImpl::AddDispatcher(
const scoped_refptr<Dispatcher>& dispatcher) {
base::AutoLock locker(handle_table_lock_);
return handle_table_.AddDispatcher(dispatcher);
}
MojoTimeTicks CoreImpl::GetTimeTicksNow() {
return base::TimeTicks::Now().ToInternalValue();
}
MojoResult CoreImpl::Close(MojoHandle handle) {
if (handle == MOJO_HANDLE_INVALID)
return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<Dispatcher> dispatcher;
{
base::AutoLock locker(handle_table_lock_);
MojoResult result = handle_table_.GetAndRemoveDispatcher(handle,
&dispatcher);
if (result != MOJO_RESULT_OK)
return result;
}
return dispatcher->Close();
}
MojoResult CoreImpl::Wait(MojoHandle handle,
MojoWaitFlags flags,
MojoDeadline deadline) {
return WaitManyInternal(&handle, &flags, 1, deadline);
}
MojoResult CoreImpl::WaitMany(const MojoHandle* handles,
const MojoWaitFlags* flags,
uint32_t num_handles,
MojoDeadline deadline) {
if (!VerifyUserPointer<MojoHandle>(handles, num_handles))
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<MojoWaitFlags>(flags, 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, flags, num_handles, deadline);
}
MojoResult CoreImpl::CreateMessagePipe(MojoHandle* message_pipe_handle0,
MojoHandle* message_pipe_handle1) {
if (!VerifyUserPointer<MojoHandle>(message_pipe_handle0, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<MojoHandle>(message_pipe_handle1, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<MessagePipeDispatcher> dispatcher0(new MessagePipeDispatcher());
scoped_refptr<MessagePipeDispatcher> dispatcher1(new MessagePipeDispatcher());
std::pair<MojoHandle, MojoHandle> handle_pair;
{
base::AutoLock locker(handle_table_lock_);
handle_pair = handle_table_.AddDispatcherPair(dispatcher0, dispatcher1);
}
if (handle_pair.first == MOJO_HANDLE_INVALID) {
DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
LOG(ERROR) << "Handle table full";
dispatcher0->Close();
dispatcher1->Close();
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
scoped_refptr<MessagePipe> message_pipe(new MessagePipe());
dispatcher0->Init(message_pipe, 0);
dispatcher1->Init(message_pipe, 1);
*message_pipe_handle0 = handle_pair.first;
*message_pipe_handle1 = handle_pair.second;
return MOJO_RESULT_OK;
}
MojoResult CoreImpl::WriteMessage(MojoHandle message_pipe_handle,
const void* bytes,
uint32_t num_bytes,
const MojoHandle* handles,
uint32_t num_handles,
MojoWriteMessageFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles == 0)
return dispatcher->WriteMessage(bytes, num_bytes, NULL, flags);
if (!VerifyUserPointer<MojoHandle>(handles, num_handles))
return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles > kMaxMessageNumHandles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
std::vector<DispatcherTransport> transports(num_handles);
{
base::AutoLock locker(handle_table_lock_);
MojoResult result = handle_table_.MarkBusyAndStartTransport(
message_pipe_handle, handles, num_handles, &transports);
if (result != MOJO_RESULT_OK)
return result;
}
MojoResult rv = dispatcher->WriteMessage(bytes, num_bytes, &transports,
flags);
for (uint32_t i = 0; i < num_handles; i++)
transports[i].End();
{
base::AutoLock locker(handle_table_lock_);
if (rv == MOJO_RESULT_OK)
handle_table_.RemoveBusyHandles(handles, num_handles);
else
handle_table_.RestoreBusyHandles(handles, num_handles);
}
return rv;
}
MojoResult CoreImpl::ReadMessage(MojoHandle message_pipe_handle,
void* bytes,
uint32_t* num_bytes,
MojoHandle* handles,
uint32_t* num_handles,
MojoReadMessageFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(message_pipe_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles) {
if (!VerifyUserPointer<uint32_t>(num_handles, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<MojoHandle>(handles, *num_handles))
return MOJO_RESULT_INVALID_ARGUMENT;
}
if (!num_handles || *num_handles == 0)
return dispatcher->ReadMessage(bytes, num_bytes, NULL, num_handles, flags);
std::vector<scoped_refptr<Dispatcher> > 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";
for (size_t i = 0; i < dispatchers.size(); i++) {
if (dispatchers[i])
dispatchers[i]->Close();
}
}
}
return rv;
}
MojoResult CoreImpl::CreateDataPipe(const MojoCreateDataPipeOptions* options,
MojoHandle* data_pipe_producer_handle,
MojoHandle* data_pipe_consumer_handle) {
if (options) {
if (!VerifyUserPointer<uint32_t>(&options->struct_size, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<void>(options, options->struct_size))
return MOJO_RESULT_INVALID_ARGUMENT;
}
if (!VerifyUserPointer<MojoHandle>(data_pipe_producer_handle, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<MojoHandle>(data_pipe_consumer_handle, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
MojoCreateDataPipeOptions validated_options = { 0 };
MojoResult result = DataPipe::ValidateOptions(options, &validated_options);
if (result != MOJO_RESULT_OK)
return result;
scoped_refptr<DataPipeProducerDispatcher> producer_dispatcher(
new DataPipeProducerDispatcher());
scoped_refptr<DataPipeConsumerDispatcher> consumer_dispatcher(
new DataPipeConsumerDispatcher());
std::pair<MojoHandle, MojoHandle> handle_pair;
{
base::AutoLock locker(handle_table_lock_);
handle_pair = handle_table_.AddDispatcherPair(producer_dispatcher,
consumer_dispatcher);
}
if (handle_pair.first == MOJO_HANDLE_INVALID) {
DCHECK_EQ(handle_pair.second, MOJO_HANDLE_INVALID);
LOG(ERROR) << "Handle table full";
producer_dispatcher->Close();
consumer_dispatcher->Close();
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
DCHECK_NE(handle_pair.second, MOJO_HANDLE_INVALID);
scoped_refptr<DataPipe> data_pipe(new LocalDataPipe(validated_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;
return MOJO_RESULT_OK;
}
MojoResult CoreImpl::WriteData(MojoHandle data_pipe_producer_handle,
const void* elements,
uint32_t* num_bytes,
MojoWriteDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
return dispatcher->WriteData(elements, num_bytes, flags);
}
MojoResult CoreImpl::BeginWriteData(MojoHandle data_pipe_producer_handle,
void** buffer,
uint32_t* buffer_num_bytes,
MojoWriteDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
}
MojoResult CoreImpl::EndWriteData(MojoHandle data_pipe_producer_handle,
uint32_t num_bytes_written) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_producer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
return dispatcher->EndWriteData(num_bytes_written);
}
MojoResult CoreImpl::ReadData(MojoHandle data_pipe_consumer_handle,
void* elements,
uint32_t* num_bytes,
MojoReadDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
return dispatcher->ReadData(elements, num_bytes, flags);
}
MojoResult CoreImpl::BeginReadData(MojoHandle data_pipe_consumer_handle,
const void** buffer,
uint32_t* buffer_num_bytes,
MojoReadDataFlags flags) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
}
MojoResult CoreImpl::EndReadData(MojoHandle data_pipe_consumer_handle,
uint32_t num_bytes_read) {
scoped_refptr<Dispatcher> dispatcher(
GetDispatcher(data_pipe_consumer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
return dispatcher->EndReadData(num_bytes_read);
}
MojoResult CoreImpl::CreateSharedBuffer(
const MojoCreateSharedBufferOptions* options,
uint64_t num_bytes,
MojoHandle* shared_buffer_handle) {
if (options) {
if (!VerifyUserPointer<uint32_t>(&options->struct_size, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<void>(options, options->struct_size))
return MOJO_RESULT_INVALID_ARGUMENT;
}
if (!VerifyUserPointer<MojoHandle>(shared_buffer_handle, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
MojoCreateSharedBufferOptions validated_options = { 0 };
MojoResult result =
SharedBufferDispatcher::ValidateOptions(options, &validated_options);
if (result != MOJO_RESULT_OK)
return result;
scoped_refptr<SharedBufferDispatcher> dispatcher;
result = SharedBufferDispatcher::Create(validated_options, num_bytes,
&dispatcher);
if (result != MOJO_RESULT_OK) {
DCHECK(!dispatcher);
return result;
}
MojoHandle h = AddDispatcher(dispatcher);
if (h == MOJO_HANDLE_INVALID) {
LOG(ERROR) << "Handle table full";
dispatcher->Close();
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
*shared_buffer_handle = h;
return MOJO_RESULT_OK;
}
MojoResult CoreImpl::DuplicateBufferHandle(
MojoHandle buffer_handle,
const MojoDuplicateBufferHandleOptions* options,
MojoHandle* new_buffer_handle) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<MojoHandle>(new_buffer_handle, 1))
return MOJO_RESULT_INVALID_ARGUMENT;
scoped_refptr<Dispatcher> new_dispatcher;
MojoResult result = dispatcher->DuplicateBufferHandle(options,
&new_dispatcher);
if (result != MOJO_RESULT_OK)
return result;
MojoHandle new_handle = AddDispatcher(new_dispatcher);
if (new_handle == MOJO_HANDLE_INVALID) {
LOG(ERROR) << "Handle table full";
dispatcher->Close();
return MOJO_RESULT_RESOURCE_EXHAUSTED;
}
*new_buffer_handle = new_handle;
return MOJO_RESULT_OK;
}
MojoResult CoreImpl::MapBuffer(MojoHandle buffer_handle,
uint64_t offset,
uint64_t num_bytes,
void** buffer,
MojoMapBufferFlags flags) {
scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
if (!VerifyUserPointer<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)
return result;
DCHECK(mapping);
void* address = mapping->base();
{
base::AutoLock locker(mapping_table_lock_);
result = mapping_table_.AddMapping(mapping.Pass());
}
if (result != MOJO_RESULT_OK)
return result;
*buffer = address;
return MOJO_RESULT_OK;
}
MojoResult CoreImpl::UnmapBuffer(void* buffer) {
base::AutoLock locker(mapping_table_lock_);
return mapping_table_.RemoveMapping(buffer);
}
scoped_refptr<Dispatcher> CoreImpl::GetDispatcher(MojoHandle handle) {
if (handle == MOJO_HANDLE_INVALID)
return NULL;
base::AutoLock locker(handle_table_lock_);
return handle_table_.GetDispatcher(handle);
}
MojoResult CoreImpl::WaitManyInternal(const MojoHandle* handles,
const MojoWaitFlags* flags,
uint32_t num_handles,
MojoDeadline deadline) {
DCHECK_GT(num_handles, 0u);
std::vector<scoped_refptr<Dispatcher> > dispatchers;
dispatchers.reserve(num_handles);
for (uint32_t i = 0; i < num_handles; i++) {
scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handles[i]);
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;
dispatchers.push_back(dispatcher);
}
Waiter waiter;
waiter.Init();
uint32_t i;
MojoResult rv = MOJO_RESULT_OK;
for (i = 0; i < num_handles; i++) {
rv = dispatchers[i]->AddWaiter(&waiter,
flags[i],
static_cast<MojoResult>(i));
if (rv != MOJO_RESULT_OK)
break;
}
uint32_t num_added = i;
if (rv == MOJO_RESULT_ALREADY_EXISTS)
rv = static_cast<MojoResult>(i);
else if (rv == MOJO_RESULT_OK)
rv = waiter.Wait(deadline);
for (i = 0; i < num_added; i++)
dispatchers[i]->RemoveWaiter(&waiter);
return rv;
}
}
}