Commit e6bc5ffa authored by Brian Geffon's avatar Brian Geffon Committed by Chromium LUCI CQ

Mojo: Add a ChannelPosix header so it can be extended

This CL adds a declaration for ChannelPosix so it can be extended. This
will keep things cleaner when we add a Fast PosixChannel, otherwise
things would become unweildy in a single file.

Bug: b:173022729
Change-Id: Ie4ed21b885a62e4d755ae393484aa2717e0668b3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2586045
Commit-Queue: Ken Rockot <rockot@google.com>
Auto-Submit: Brian Geffon <bgeffon@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/master@{#840261}
parent 861cfb97
...@@ -121,6 +121,7 @@ template("core_impl_source_set") { ...@@ -121,6 +121,7 @@ template("core_impl_source_set") {
sources += [ sources += [
"broker_posix.cc", "broker_posix.cc",
"channel_posix.cc", "channel_posix.cc",
"channel_posix.h",
] ]
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "mojo/core/channel.h" #include "mojo/core/channel_posix.h"
#include <errno.h> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
...@@ -37,12 +37,12 @@ namespace mojo { ...@@ -37,12 +37,12 @@ namespace mojo {
namespace core { namespace core {
namespace { namespace {
#if !defined(OS_NACL) #if !defined(OS_NACL)
std::atomic<bool> g_use_writev{false}; std::atomic<bool> g_use_writev{false};
#endif #endif
const size_t kMaxBatchReadCapacity = 256 * 1024; const size_t kMaxBatchReadCapacity = 256 * 1024;
} // namespace
// A view over a Channel::Message object. The write queue uses these since // A view over a Channel::Message object. The write queue uses these since
// large messages may need to be sent in chunks. // large messages may need to be sent in chunks.
...@@ -110,11 +110,8 @@ class MessageView { ...@@ -110,11 +110,8 @@ class MessageView {
DISALLOW_COPY_AND_ASSIGN(MessageView); DISALLOW_COPY_AND_ASSIGN(MessageView);
}; };
class ChannelPosix : public Channel, ChannelPosix::ChannelPosix(
public base::CurrentThread::DestructionObserver, Delegate* delegate,
public base::MessagePumpForIO::FdWatcher {
public:
ChannelPosix(Delegate* delegate,
ConnectionParams connection_params, ConnectionParams connection_params,
HandlePolicy handle_policy, HandlePolicy handle_policy,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
...@@ -127,24 +124,29 @@ class ChannelPosix : public Channel, ...@@ -127,24 +124,29 @@ class ChannelPosix : public Channel,
socket_ = connection_params.TakeEndpoint().TakePlatformHandle().TakeFD(); socket_ = connection_params.TakeEndpoint().TakePlatformHandle().TakeFD();
CHECK(server_.is_valid() || socket_.is_valid()); CHECK(server_.is_valid() || socket_.is_valid());
} }
void Start() override { ChannelPosix::~ChannelPosix() {
DCHECK(!read_watcher_);
DCHECK(!write_watcher_);
}
void ChannelPosix::Start() {
if (io_task_runner_->RunsTasksInCurrentSequence()) { if (io_task_runner_->RunsTasksInCurrentSequence()) {
StartOnIOThread(); StartOnIOThread();
} else { } else {
io_task_runner_->PostTask( io_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ChannelPosix::StartOnIOThread, this)); FROM_HERE, base::BindOnce(&ChannelPosix::StartOnIOThread, this));
} }
} }
void ShutDownImpl() override { void ChannelPosix::ShutDownImpl() {
// Always shut down asynchronously when called through the public interface. // Always shut down asynchronously when called through the public interface.
io_task_runner_->PostTask( io_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ChannelPosix::ShutDownOnIOThread, this)); FROM_HERE, base::BindOnce(&ChannelPosix::ShutDownOnIOThread, this));
} }
void Write(MessagePtr message) override { void ChannelPosix::Write(MessagePtr message) {
UMA_HISTOGRAM_COUNTS_100000("Mojo.Channel.WriteMessageSize", UMA_HISTOGRAM_COUNTS_100000("Mojo.Channel.WriteMessageSize",
message->data_num_bytes()); message->data_num_bytes());
UMA_HISTOGRAM_COUNTS_100("Mojo.Channel.WriteMessageHandles", UMA_HISTOGRAM_COUNTS_100("Mojo.Channel.WriteMessageHandles",
...@@ -167,25 +169,25 @@ class ChannelPosix : public Channel, ...@@ -167,25 +169,25 @@ class ChannelPosix : public Channel,
if (write_error) { if (write_error) {
// Invoke OnWriteError() asynchronously on the IO thread, in case Write() // Invoke OnWriteError() asynchronously on the IO thread, in case Write()
// was called by the delegate, in which case we should not re-enter it. // was called by the delegate, in which case we should not re-enter it.
io_task_runner_->PostTask( io_task_runner_->PostTask(FROM_HERE,
FROM_HERE, base::BindOnce(&ChannelPosix::OnWriteError, this, base::BindOnce(&ChannelPosix::OnWriteError, this,
Error::kDisconnected)); Error::kDisconnected));
} }
UMA_HISTOGRAM_BOOLEAN("Mojo.Channel.WriteQueued", queued); UMA_HISTOGRAM_BOOLEAN("Mojo.Channel.WriteQueued", queued);
} }
void LeakHandle() override { void ChannelPosix::LeakHandle() {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
leak_handle_ = true; leak_handle_ = true;
} }
bool GetReadPlatformHandles(const void* payload, bool ChannelPosix::GetReadPlatformHandles(const void* payload,
size_t payload_size, size_t payload_size,
size_t num_handles, size_t num_handles,
const void* extra_header, const void* extra_header,
size_t extra_header_size, size_t extra_header_size,
std::vector<PlatformHandle>* handles, std::vector<PlatformHandle>* handles,
bool* deferred) override { bool* deferred) {
if (num_handles > std::numeric_limits<uint16_t>::max()) if (num_handles > std::numeric_limits<uint16_t>::max())
return false; return false;
if (incoming_fds_.size() < num_handles) if (incoming_fds_.size() < num_handles)
...@@ -198,19 +200,12 @@ class ChannelPosix : public Channel, ...@@ -198,19 +200,12 @@ class ChannelPosix : public Channel,
} }
return true; return true;
} }
private:
~ChannelPosix() override {
DCHECK(!read_watcher_);
DCHECK(!write_watcher_);
}
void StartOnIOThread() { void ChannelPosix::StartOnIOThread() {
DCHECK(!read_watcher_); DCHECK(!read_watcher_);
DCHECK(!write_watcher_); DCHECK(!write_watcher_);
read_watcher_.reset( read_watcher_.reset(new base::MessagePumpForIO::FdWatchController(FROM_HERE));
new base::MessagePumpForIO::FdWatchController(FROM_HERE));
base::CurrentThread::Get()->AddDestructionObserver(this); base::CurrentThread::Get()->AddDestructionObserver(this);
if (server_.is_valid()) { if (server_.is_valid()) {
base::CurrentIOThread::Get()->WatchFileDescriptor( base::CurrentIOThread::Get()->WatchFileDescriptor(
...@@ -225,14 +220,14 @@ class ChannelPosix : public Channel, ...@@ -225,14 +220,14 @@ class ChannelPosix : public Channel,
base::AutoLock lock(write_lock_); base::AutoLock lock(write_lock_);
FlushOutgoingMessagesNoLock(); FlushOutgoingMessagesNoLock();
} }
} }
void WaitForWriteOnIOThread() { void ChannelPosix::WaitForWriteOnIOThread() {
base::AutoLock lock(write_lock_); base::AutoLock lock(write_lock_);
WaitForWriteOnIOThreadNoLock(); WaitForWriteOnIOThreadNoLock();
} }
void WaitForWriteOnIOThreadNoLock() { void ChannelPosix::WaitForWriteOnIOThreadNoLock() {
if (pending_write_) if (pending_write_)
return; return;
if (!write_watcher_) if (!write_watcher_)
...@@ -244,12 +239,11 @@ class ChannelPosix : public Channel, ...@@ -244,12 +239,11 @@ class ChannelPosix : public Channel,
base::MessagePumpForIO::WATCH_WRITE, write_watcher_.get(), this); base::MessagePumpForIO::WATCH_WRITE, write_watcher_.get(), this);
} else { } else {
io_task_runner_->PostTask( io_task_runner_->PostTask(
FROM_HERE, FROM_HERE, base::BindOnce(&ChannelPosix::WaitForWriteOnIOThread, this));
base::BindOnce(&ChannelPosix::WaitForWriteOnIOThread, this));
}
} }
}
void ShutDownOnIOThread() { void ChannelPosix::ShutDownOnIOThread() {
base::CurrentThread::Get()->RemoveDestructionObserver(this); base::CurrentThread::Get()->RemoveDestructionObserver(this);
read_watcher_.reset(); read_watcher_.reset();
...@@ -267,17 +261,15 @@ class ChannelPosix : public Channel, ...@@ -267,17 +261,15 @@ class ChannelPosix : public Channel,
// May destroy the |this| if it was the last reference. // May destroy the |this| if it was the last reference.
self_ = nullptr; self_ = nullptr;
} }
// base::CurrentThread::DestructionObserver: void ChannelPosix::WillDestroyCurrentMessageLoop() {
void WillDestroyCurrentMessageLoop() override {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
if (self_) if (self_)
ShutDownOnIOThread(); ShutDownOnIOThread();
} }
// base::MessagePumpForIO::FdWatcher: void ChannelPosix::OnFileCanReadWithoutBlocking(int fd) {
void OnFileCanReadWithoutBlocking(int fd) override {
if (server_.is_valid()) { if (server_.is_valid()) {
CHECK_EQ(fd, server_.platform_handle().GetFD().get()); CHECK_EQ(fd, server_.platform_handle().GetFD().get());
#if !defined(OS_NACL) #if !defined(OS_NACL)
...@@ -343,9 +335,9 @@ class ChannelPosix : public Channel, ...@@ -343,9 +335,9 @@ class ChannelPosix : public Channel,
else else
OnError(Error::kDisconnected); OnError(Error::kDisconnected);
} }
} }
void OnFileCanWriteWithoutBlocking(int fd) override { void ChannelPosix::OnFileCanWriteWithoutBlocking(int fd) {
bool write_error = false; bool write_error = false;
{ {
base::AutoLock lock(write_lock_); base::AutoLock lock(write_lock_);
...@@ -355,12 +347,12 @@ class ChannelPosix : public Channel, ...@@ -355,12 +347,12 @@ class ChannelPosix : public Channel,
} }
if (write_error) if (write_error)
OnWriteError(Error::kDisconnected); OnWriteError(Error::kDisconnected);
} }
// Attempts to write a message directly to the channel. If the full message // Attempts to write a message directly to the channel. If the full message
// cannot be written, it's queued and a wait is initiated to write the message // cannot be written, it's queued and a wait is initiated to write the message
// ASAP on the I/O thread. // ASAP on the I/O thread.
bool WriteNoLock(MessageView message_view) { bool ChannelPosix::WriteNoLock(MessageView message_view) {
if (server_.is_valid()) { if (server_.is_valid()) {
outgoing_messages_.emplace_front(std::move(message_view)); outgoing_messages_.emplace_front(std::move(message_view));
return true; return true;
...@@ -454,9 +446,9 @@ class ChannelPosix : public Channel, ...@@ -454,9 +446,9 @@ class ChannelPosix : public Channel,
bytes_written < message_view.data_num_bytes()); bytes_written < message_view.data_num_bytes());
return FlushOutgoingMessagesNoLock(); return FlushOutgoingMessagesNoLock();
} }
bool FlushOutgoingMessagesNoLock() { bool ChannelPosix::FlushOutgoingMessagesNoLock() {
#if !defined(OS_NACL) #if !defined(OS_NACL)
if (g_use_writev) if (g_use_writev)
return FlushOutgoingMessagesWritevNoLock(); return FlushOutgoingMessagesWritevNoLock();
...@@ -491,10 +483,27 @@ class ChannelPosix : public Channel, ...@@ -491,10 +483,27 @@ class ChannelPosix : public Channel,
} }
return true; return true;
}
void ChannelPosix::OnWriteError(Error error) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
DCHECK(reject_writes_);
if (error == Error::kDisconnected) {
// If we can't write because the pipe is disconnected then continue
// reading to fetch any in-flight messages, relying on end-of-stream to
// signal the actual disconnection.
if (read_watcher_) {
write_watcher_.reset();
return;
}
} }
OnError(error);
}
#if !defined(OS_NACL) #if !defined(OS_NACL)
bool WriteOutgoingMessagesWithWritev() { bool ChannelPosix::WriteOutgoingMessagesWithWritev() {
if (outgoing_messages_.empty()) if (outgoing_messages_.empty())
return true; return true;
...@@ -519,8 +528,7 @@ class ChannelPosix : public Channel, ...@@ -519,8 +528,7 @@ class ChannelPosix : public Channel,
num_iovs_set++; num_iovs_set++;
} }
UMA_HISTOGRAM_COUNTS_1000("Mojo.Channel.WritevBatchedMessages", UMA_HISTOGRAM_COUNTS_1000("Mojo.Channel.WritevBatchedMessages", num_iovs_set);
num_iovs_set);
size_t iov_offset = 0; size_t iov_offset = 0;
while (iov_offset < num_iovs_set) { while (iov_offset < num_iovs_set) {
...@@ -558,15 +566,15 @@ class ChannelPosix : public Channel, ...@@ -558,15 +566,15 @@ class ChannelPosix : public Channel,
} }
return true; return true;
} }
// FlushOutgoingMessagesWritevNoLock is equivalent to // FlushOutgoingMessagesWritevNoLock is equivalent to
// FlushOutgoingMessagesNoLock except it looks for opportunities to make only // FlushOutgoingMessagesNoLock except it looks for opportunities to make only
// a single write syscall by using writev(2) instead of write(2). In most // a single write syscall by using writev(2) instead of write(2). In most
// situations this is very straight forward; however, when a handle needs to // situations this is very straight forward; however, when a handle needs to
// be transferred we cannot use writev(2) and instead will fall back to the // be transferred we cannot use writev(2) and instead will fall back to the
// standard write. // standard write.
bool FlushOutgoingMessagesWritevNoLock() { bool ChannelPosix::FlushOutgoingMessagesWritevNoLock() {
do { do {
// If the first message contains a handle we will flush it first using a // If the first message contains a handle we will flush it first using a
// standard write, we will also use the standard write if we only have a // standard write, we will also use the standard write if we only have a
...@@ -596,14 +604,14 @@ class ChannelPosix : public Channel, ...@@ -596,14 +604,14 @@ class ChannelPosix : public Channel,
// FileHandles before attempting writev(2) again. // FileHandles before attempting writev(2) again.
} while (!outgoing_messages_.empty()); } while (!outgoing_messages_.empty());
return true; return true;
} }
#endif // !defined(OS_NACL) #endif // !defined(OS_NACL)
#if defined(OS_IOS) #if defined(OS_IOS)
bool OnControlMessage(Message::MessageType message_type, bool ChannelPosix::OnControlMessage(Message::MessageType message_type,
const void* payload, const void* payload,
size_t payload_size, size_t payload_size,
std::vector<PlatformHandle> handles) override { std::vector<PlatformHandle> handles) {
switch (message_type) { switch (message_type) {
case Message::MessageType::HANDLES_SENT: { case Message::MessageType::HANDLES_SENT: {
if (payload_size == 0) if (payload_size == 0)
...@@ -631,11 +639,11 @@ class ChannelPosix : public Channel, ...@@ -631,11 +639,11 @@ class ChannelPosix : public Channel,
} }
return false; return false;
} }
// Closes handles referenced by |fds|. Returns false if |num_fds| is 0, or if // Closes handles referenced by |fds|. Returns false if |num_fds| is 0, or if
// |fds| does not match a sequence of handles in |fds_to_close_|. // |fds| does not match a sequence of handles in |fds_to_close_|.
bool CloseHandles(const int* fds, size_t num_fds) { bool ChannelPosix::CloseHandles(const int* fds, size_t num_fds) {
base::AutoLock l(fds_to_close_lock_); base::AutoLock l(fds_to_close_lock_);
if (!num_fds) if (!num_fds)
return false; return false;
...@@ -664,63 +672,9 @@ class ChannelPosix : public Channel, ...@@ -664,63 +672,9 @@ class ChannelPosix : public Channel,
// Close the FDs by erase()ing their ScopedFDs. // Close the FDs by erase()ing their ScopedFDs.
fds_to_close_.erase(start, it); fds_to_close_.erase(start, it);
return true; return true;
} }
#endif // defined(OS_IOS)
void OnWriteError(Error error) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
DCHECK(reject_writes_);
if (error == Error::kDisconnected) {
// If we can't write because the pipe is disconnected then continue
// reading to fetch any in-flight messages, relying on end-of-stream to
// signal the actual disconnection.
if (read_watcher_) {
write_watcher_.reset();
return;
}
}
OnError(error);
}
// Keeps the Channel alive at least until explicit shutdown on the IO thread.
scoped_refptr<Channel> self_;
// We may be initialized with a server socket, in which case this will be
// valid until it accepts an incoming connection.
PlatformChannelServerEndpoint server_;
// The socket over which to communicate. May be passed in at construction time
// or accepted over |server_|.
base::ScopedFD socket_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// These watchers must only be accessed on the IO thread.
std::unique_ptr<base::MessagePumpForIO::FdWatchController> read_watcher_;
std::unique_ptr<base::MessagePumpForIO::FdWatchController> write_watcher_;
base::circular_deque<base::ScopedFD> incoming_fds_;
// Protects |pending_write_| and |outgoing_messages_|.
base::Lock write_lock_;
bool pending_write_ = false;
bool reject_writes_ = false;
base::circular_deque<MessageView> outgoing_messages_;
bool leak_handle_ = false;
#if defined(OS_IOS)
base::Lock fds_to_close_lock_;
std::vector<base::ScopedFD> fds_to_close_;
#endif // defined(OS_IOS) #endif // defined(OS_IOS)
DISALLOW_COPY_AND_ASSIGN(ChannelPosix);
};
} // namespace
// static // static
#if !defined(OS_NACL) #if !defined(OS_NACL)
void Channel::set_posix_use_writev(bool use_writev) { void Channel::set_posix_use_writev(bool use_writev) {
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_CORE_CHANNEL_POSIX_H_
#define MOJO_CORE_CHANNEL_POSIX_H_
#include "mojo/core/channel.h"
#include "base/containers/queue.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_pump_for_io.h"
#include "base/synchronization/lock.h"
#include "base/task/current_thread.h"
#include "base/task_runner.h"
#include "build/build_config.h"
#include "mojo/core/core.h"
namespace mojo {
namespace core {
class MessageView;
class ChannelPosix : public Channel,
public base::CurrentThread::DestructionObserver,
public base::MessagePumpForIO::FdWatcher {
public:
ChannelPosix(Delegate* delegate,
ConnectionParams connection_params,
HandlePolicy handle_policy,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
void Start() override;
void ShutDownImpl() override;
void Write(MessagePtr message) override;
void LeakHandle() override;
bool GetReadPlatformHandles(const void* payload,
size_t payload_size,
size_t num_handles,
const void* extra_header,
size_t extra_header_size,
std::vector<PlatformHandle>* handles,
bool* deferred) override;
private:
~ChannelPosix() override;
void StartOnIOThread();
void WaitForWriteOnIOThread();
void WaitForWriteOnIOThreadNoLock();
void ShutDownOnIOThread();
// base::CurrentThread::DestructionObserver:
void WillDestroyCurrentMessageLoop() override;
// base::MessagePumpForIO::FdWatcher:
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override;
// Attempts to write a message directly to the channel. If the full message
// cannot be written, it's queued and a wait is initiated to write the message
// ASAP on the I/O thread.
bool WriteNoLock(MessageView message_view);
bool FlushOutgoingMessagesNoLock();
#if !defined(OS_NACL)
bool WriteOutgoingMessagesWithWritev();
// FlushOutgoingMessagesWritevNoLock is equivalent to
// FlushOutgoingMessagesNoLock except it looks for opportunities to make
// only a single write syscall by using writev(2) instead of write(2). In
// most situations this is very straight forward; however, when a handle
// needs to be transferred we cannot use writev(2) and instead will fall
// back to the standard write.
bool FlushOutgoingMessagesWritevNoLock();
#endif // !defined(OS_NACL)
#if defined(OS_IOS)
bool OnControlMessage(Message::MessageType message_type,
const void* payload,
size_t payload_size,
std::vector<PlatformHandle> handles) override;
bool CloseHandles(const int* fds, size_t num_fds);
#endif // defined(OS_IOS)
void OnWriteError(Error error);
// Keeps the Channel alive at least until explicit shutdown on the IO thread.
scoped_refptr<Channel> self_;
// We may be initialized with a server socket, in which case this will be
// valid until it accepts an incoming connection.
PlatformChannelServerEndpoint server_;
// The socket over which to communicate. May be passed in at construction time
// or accepted over |server_|.
base::ScopedFD socket_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// These watchers must only be accessed on the IO thread.
std::unique_ptr<base::MessagePumpForIO::FdWatchController> read_watcher_;
std::unique_ptr<base::MessagePumpForIO::FdWatchController> write_watcher_;
base::circular_deque<base::ScopedFD> incoming_fds_;
// Protects |pending_write_| and |outgoing_messages_|.
base::Lock write_lock_;
bool pending_write_ = false;
bool reject_writes_ = false;
base::circular_deque<MessageView> outgoing_messages_;
bool leak_handle_ = false;
#if defined(OS_IOS)
base::Lock fds_to_close_lock_;
std::vector<base::ScopedFD> fds_to_close_;
#endif // defined(OS_IOS)
DISALLOW_COPY_AND_ASSIGN(ChannelPosix);
};
} // namespace core
} // namespace mojo
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment