Chromium Code Reviews| Index: mojo/edk/system/child_broker.cc |
| diff --git a/mojo/edk/system/child_broker.cc b/mojo/edk/system/child_broker.cc |
| index 6903c8204dbd23b393729c8e859407609dc983db..a9d1e75a0c16efa322e330f1ff88576920f5e5d6 100644 |
| --- a/mojo/edk/system/child_broker.cc |
| +++ b/mojo/edk/system/child_broker.cc |
| @@ -13,9 +13,15 @@ |
| #include "base/logging.h" |
| #include "mojo/edk/embedder/embedder_internal.h" |
| #include "mojo/edk/embedder/platform_channel_pair.h" |
| +#include "mojo/edk/embedder/platform_shared_buffer.h" |
| +#include "mojo/edk/embedder/platform_support.h" |
| #include "mojo/edk/system/broker_messages.h" |
| #include "mojo/edk/system/message_pipe_dispatcher.h" |
| +#if defined(OS_POSIX) |
| +#include "mojo/edk/embedder/platform_channel_utils_posix.h" |
| +#endif |
| + |
| namespace mojo { |
| namespace edk { |
| @@ -26,24 +32,30 @@ ChildBroker* ChildBroker::GetInstance() { |
| void ChildBroker::SetChildBrokerHostHandle(ScopedPlatformHandle handle) { |
| ScopedPlatformHandle parent_async_channel_handle; |
| + parent_sync_channel_ = std::move(handle); |
| + |
| +// We have two pipes to the parent. The first is for the token |
| +// exchange for creating and passing handles on Windows, and creating shared |
| +// buffers on POSIX, since the child needs the parent's help if it is |
| +// sandboxed. The second is used for multiplexing related messages. We |
| +// send the second over the first. |
| #if defined(OS_POSIX) |
| - parent_async_channel_handle = std::move(handle); |
| + std::deque<PlatformHandle> received_handles; |
| + char buf[1]; |
| + ssize_t result = PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, |
|
Eliot Courtney
2016/01/05 04:45:47
Does this need to be queried in a loop since it wo
jam
2016/01/06 02:58:16
ReadFile below specifies the number of bytes to re
Eliot Courtney
2016/01/07 02:26:09
Thanks! I've done this, although made it not tempo
jam
2016/01/08 22:37:40
great, i had some more statements in this comment
|
| + &received_handles); |
| + CHECK_EQ(1, result); |
| + CHECK_EQ(1u, received_handles.size()); |
| + parent_async_channel_handle.reset(received_handles.front()); |
| #else |
| - // On Windows we have two pipes to the parent. The first is for the token |
| - // exchange for creating and passing handles, since the child needs the |
| - // parent's help if it is sandboxed. The second is the same as POSIX, which is |
| - // used for multiplexing related messages. So on Windows, we send the second |
| - // pipe as the first string over the first one. |
| - parent_sync_channel_ = handle.Pass(); |
| - |
| HANDLE parent_handle = INVALID_HANDLE_VALUE; |
| DWORD bytes_read = 0; |
| BOOL rv = ReadFile(parent_sync_channel_.get().handle, &parent_handle, |
| sizeof(parent_handle), &bytes_read, NULL); |
| CHECK(rv); |
| parent_async_channel_handle.reset(PlatformHandle(parent_handle)); |
| - sync_channel_lock_.Unlock(); |
| #endif |
| + sync_channel_lock_.Unlock(); |
| internal::g_io_thread_task_runner->PostTask( |
| FROM_HERE, |
| @@ -99,6 +111,16 @@ void ChildBroker::TokenToHandle(const uint64_t* tokens, |
| sync_channel_lock_.Unlock(); |
| } |
| } |
| +#else |
| +scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBuffer( |
| + size_t num_bytes) { |
| + sync_channel_lock_.Lock(); |
| + scoped_refptr<PlatformSharedBuffer> shared_buffer = |
| + CreateSharedBufferNoLock(num_bytes); |
|
jam
2016/01/06 02:58:16
no need to have two methods for this. you can inli
Eliot Courtney
2016/01/07 02:26:09
Done.
|
| + sync_channel_lock_.Unlock(); |
| + |
| + return shared_buffer; |
| +} |
| #endif |
| void ChildBroker::ConnectMessagePipe(uint64_t pipe_id, |
| @@ -172,10 +194,8 @@ ChildBroker::ChildBroker() |
| in_process_pipes_channel2_(nullptr) { |
| DCHECK(!internal::g_broker); |
| internal::g_broker = this; |
| -#if defined(OS_WIN) |
| // Block any threads from calling this until we have a pipe to the parent. |
| sync_channel_lock_.Lock(); |
| -#endif |
| } |
| ChildBroker::~ChildBroker() { |
| @@ -285,12 +305,28 @@ void ChildBroker::AttachMessagePipe(MessagePipeDispatcher* message_pipe, |
| #if defined(OS_WIN) |
| +void ChildBroker::CreatePlatformChannelPairNoLock( |
| + ScopedPlatformHandle* server, |
| + ScopedPlatformHandle* client) { |
| + BrokerMessage message; |
| + message.size = kBrokerMessageHeaderSize; |
| + message.id = CREATE_PLATFORM_CHANNEL_PAIR; |
| + |
| + uint32_t response_size = 2 * sizeof(HANDLE); |
| + HANDLE handles[2]; |
| + if (WriteAndReadResponse(&message, handles, response_size)) { |
| + server->reset(PlatformHandle(handles[0])); |
| + client->reset(PlatformHandle(handles[1])); |
| + } |
| +} |
| + |
| bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, |
| void* response, |
| uint32_t response_size) { |
| CHECK(parent_sync_channel_.is_valid()); |
| bool result = true; |
| + |
|
jam
2016/01/06 02:58:16
nit: no need to change
Eliot Courtney
2016/01/07 02:26:09
Done.
|
| DWORD bytes_written = 0; |
| // This will always write in one chunk per |
| // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150.aspx. |
| @@ -316,21 +352,65 @@ bool ChildBroker::WriteAndReadResponse(BrokerMessage* message, |
| return result; |
| } |
| - |
| -void ChildBroker::CreatePlatformChannelPairNoLock( |
| - ScopedPlatformHandle* server, ScopedPlatformHandle* client) { |
| +#else |
| +scoped_refptr<PlatformSharedBuffer> ChildBroker::CreateSharedBufferNoLock( |
| + size_t num_bytes) { |
| BrokerMessage message; |
| - message.size = kBrokerMessageHeaderSize; |
| - message.id = CREATE_PLATFORM_CHANNEL_PAIR; |
| + message.size = kBrokerMessageHeaderSize + sizeof(uint32_t); |
| + message.id = CREATE_SHARED_BUFFER; |
| + message.num_bytes = num_bytes; |
| + |
| + std::deque<PlatformHandle> handles; |
| + if (WriteAndReadHandles(&message, &handles)) { |
| + DCHECK_EQ(1u, handles.size()); |
| + if (handles.empty()) { |
| + LOG(ERROR) |
| + << "ChildBroker did not receive handle when creating shared buffer"; |
| + return nullptr; |
| + } |
| - uint32_t response_size = 2 * sizeof(HANDLE); |
| - HANDLE handles[2]; |
| - if (WriteAndReadResponse(&message, handles, response_size)) { |
| - server->reset(PlatformHandle(handles[0])); |
| - client->reset(PlatformHandle(handles[1])); |
| + PlatformHandle handle = handles.front(); |
| + if (handle.is_valid()) |
| + return internal::g_platform_support->CreateSharedBufferFromHandle( |
| + num_bytes, ScopedPlatformHandle(handles.front())); |
| + else |
| + return nullptr; |
| } |
| + |
| + return nullptr; |
| } |
| +bool ChildBroker::WriteAndReadHandles(BrokerMessage* message, |
| + std::deque<PlatformHandle>* handles) { |
| + CHECK(parent_sync_channel_.is_valid()); |
| + |
| + uint32_t remaining_bytes = message->size; |
| + while (remaining_bytes > 0) { |
| + ssize_t bytes_written = PlatformChannelWrite( |
|
Eliot Courtney
2016/01/05 04:45:47
This loop is on top of a non-blocking function (Pl
jam
2016/01/06 02:58:16
i don't see how it would ever block in practice, b
Eliot Courtney
2016/01/07 02:26:09
I removed the O_NONBLOCK using fcntl like you sugg
|
| + parent_sync_channel_.get(), |
| + reinterpret_cast<uint8_t*>(message) + (message->size - remaining_bytes), |
| + remaining_bytes); |
| + |
| + if (bytes_written == -1 && errno != EAGAIN && errno != EWOULDBLOCK) |
| + return false; |
| + |
| + if (bytes_written != -1) |
| + remaining_bytes -= bytes_written; |
| + } |
| + |
| + while (1) { |
|
jam
2016/01/06 02:58:16
same as first comment in this file, why not make r
Eliot Courtney
2016/01/07 02:26:09
Done.
|
| + char buf[1]; |
| + ssize_t bytes_read = |
| + PlatformChannelRecvmsg(parent_sync_channel_.get(), buf, 1, handles); |
|
Eliot Courtney
2016/01/05 04:45:47
Same comment as above.
Eliot Courtney
2016/01/07 02:26:08
Done.
|
| + if (bytes_read == 0 || |
| + (bytes_read == -1 && errno != EAGAIN && errno != EWOULDBLOCK)) |
| + return false; |
| + |
| + if (handles->size() >= 1) |
| + break; |
| + } |
| + return true; |
| +} |
| #endif |
| } // namespace edk |