Bug 1706374 - Part 3: Get mojo/core/ports building in libxul, r=handyman

This involves replacing a number of types normally provided by chromium's
`base` with their XPCOM counterparts etc.

Differential Revision: https://phabricator.services.mozilla.com/D112767
This commit is contained in:
Nika Layzell 2021-06-22 18:17:18 +00:00
Родитель d1f7ecf8e1
Коммит 03f4afa8fb
19 изменённых файлов: 275 добавлений и 359 удалений

Просмотреть файл

@ -29,6 +29,14 @@ UNIFIED_SOURCES += [
"src/chrome/common/chrome_switches.cc",
"src/chrome/common/ipc_channel_utils.cc",
"src/chrome/common/ipc_message.cc",
"src/mojo/core/ports/event.cc",
"src/mojo/core/ports/message_queue.cc",
"src/mojo/core/ports/name.cc",
"src/mojo/core/ports/node.cc",
"src/mojo/core/ports/port.cc",
"src/mojo/core/ports/port_locker.cc",
"src/mojo/core/ports/port_ref.cc",
"src/mojo/core/ports/user_message.cc",
]
if os_win:

Просмотреть файл

@ -23,7 +23,6 @@
namespace base {
#define DVLOG(x) CHROMIUM_LOG(ERROR)
#define CHECK_GT DCHECK_GT
#define CHECK_LT DCHECK_LT

Просмотреть файл

@ -106,6 +106,8 @@ const mozilla::EmptyLog& operator<<(const mozilla::EmptyLog& log, const T&) {
while (false && (condition)) mozilla::EmptyLog()
#endif
#define DVLOG(level) DLOG(INFO)
#undef LOG_ASSERT
#define LOG_ASSERT(cond) CHECK(0)
#define DLOG_ASSERT(cond) DCHECK(0)

Просмотреть файл

@ -1,61 +0,0 @@
# Copyright 2016 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.
import("//build/config/compiler/compiler.gni")
import("//testing/test.gni")
component("ports") {
output_name = "mojo_core_ports"
sources = [
"event.cc",
"event.h",
"message_filter.h",
"message_queue.cc",
"message_queue.h",
"name.cc",
"name.h",
"node.cc",
"node.h",
"node_delegate.h",
"port.cc",
"port.h",
"port_locker.cc",
"port_locker.h",
"port_ref.cc",
"port_ref.h",
"user_data.h",
"user_message.cc",
"user_message.h",
]
defines = [ "IS_MOJO_CORE_PORTS_IMPL" ]
public_deps = [ "//base" ]
if (!is_nacl) {
deps = [ "//crypto" ]
}
if (!is_debug && !optimize_for_size) {
configs -= [ "//build/config/compiler:default_optimization" ]
configs += [ "//build/config/compiler:optimize_max" ]
}
}
source_set("tests") {
testonly = true
sources = [
"name_unittest.cc",
"ports_unittest.cc",
]
deps = [
":ports",
"//base",
"//base/test:test_support",
"//testing/gtest",
]
}

Просмотреть файл

@ -8,8 +8,9 @@
#include <string.h>
#include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "mojo/core/ports/user_message.h"
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
namespace mojo {
namespace core {
@ -156,7 +157,7 @@ UserMessageEvent::UserMessageEvent(size_t num_ports)
ReservePorts(num_ports);
}
void UserMessageEvent::AttachMessage(std::unique_ptr<UserMessage> message) {
void UserMessageEvent::AttachMessage(mozilla::UniquePtr<UserMessage> message) {
DCHECK(!message_);
message_ = std::move(message);
}
@ -178,17 +179,16 @@ ScopedEvent UserMessageEvent::Deserialize(const PortName& port_name,
if (num_bytes < sizeof(UserMessageEventData)) return nullptr;
const auto* data = static_cast<const UserMessageEventData*>(buffer);
base::CheckedNumeric<size_t> port_data_size = data->num_ports;
mozilla::CheckedInt<size_t> port_data_size = data->num_ports;
port_data_size *= sizeof(PortDescriptor) + sizeof(PortName);
if (!port_data_size.IsValid()) return nullptr;
if (!port_data_size.isValid()) return nullptr;
base::CheckedNumeric<size_t> total_size = port_data_size.ValueOrDie();
mozilla::CheckedInt<size_t> total_size = port_data_size.value();
total_size += sizeof(UserMessageEventData);
if (!total_size.IsValid() || num_bytes < total_size.ValueOrDie())
return nullptr;
if (!total_size.isValid() || num_bytes < total_size.value()) return nullptr;
auto event =
base::WrapUnique(new UserMessageEvent(port_name, data->sequence_num));
mozilla::WrapUnique(new UserMessageEvent(port_name, data->sequence_num));
event->ReservePorts(data->num_ports);
const auto* in_descriptors =
reinterpret_cast<const PortDescriptor*>(data + 1);
@ -198,7 +198,7 @@ ScopedEvent UserMessageEvent::Deserialize(const PortName& port_name,
const auto* in_names =
reinterpret_cast<const PortName*>(in_descriptors + data->num_ports);
std::copy(in_names, in_names + data->num_ports, event->ports());
return std::move(event);
return event;
}
UserMessageEvent::UserMessageEvent(const PortName& port_name,
@ -212,19 +212,22 @@ size_t UserMessageEvent::GetSizeIfSerialized() const {
size_t UserMessageEvent::GetSerializedDataSize() const {
DCHECK_EQ(ports_.size(), port_descriptors_.size());
base::CheckedNumeric<size_t> size = sizeof(UserMessageEventData);
base::CheckedNumeric<size_t> ports_size =
mozilla::CheckedInt<size_t> size = sizeof(UserMessageEventData);
mozilla::CheckedInt<size_t> ports_size =
sizeof(PortDescriptor) + sizeof(PortName);
ports_size *= ports_.size();
return (size + ports_size.ValueOrDie()).ValueOrDie();
mozilla::CheckedInt<size_t> combined = size + ports_size;
MOZ_RELEASE_ASSERT(combined.isValid());
return combined.value();
}
void UserMessageEvent::SerializeData(void* buffer) const {
DCHECK_EQ(ports_.size(), port_descriptors_.size());
auto* data = static_cast<UserMessageEventData*>(buffer);
data->sequence_num = sequence_num_;
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(ports_.size()));
data->num_ports = static_cast<uint32_t>(ports_.size());
mozilla::CheckedInt<uint32_t> num_ports{ports_.size()};
DCHECK(num_ports.isValid());
data->num_ports = num_ports.value();
data->padding = 0;
auto* ports_data = reinterpret_cast<PortDescriptor*>(data + 1);
@ -244,7 +247,7 @@ PortAcceptedEvent::~PortAcceptedEvent() = default;
ScopedEvent PortAcceptedEvent::Deserialize(const PortName& port_name,
const void* buffer,
size_t num_bytes) {
return std::make_unique<PortAcceptedEvent>(port_name);
return mozilla::MakeUnique<PortAcceptedEvent>(port_name);
}
size_t PortAcceptedEvent::GetSerializedDataSize() const { return 0; }
@ -271,7 +274,7 @@ ScopedEvent ObserveProxyEvent::Deserialize(const PortName& port_name,
if (num_bytes < sizeof(ObserveProxyEventData)) return nullptr;
const auto* data = static_cast<const ObserveProxyEventData*>(buffer);
return std::make_unique<ObserveProxyEvent>(
return mozilla::MakeUnique<ObserveProxyEvent>(
port_name, data->proxy_node_name, data->proxy_port_name,
data->proxy_target_node_name, data->proxy_target_port_name);
}
@ -289,7 +292,7 @@ void ObserveProxyEvent::SerializeData(void* buffer) const {
}
ScopedEvent ObserveProxyEvent::Clone() const {
return std::make_unique<ObserveProxyEvent>(
return mozilla::MakeUnique<ObserveProxyEvent>(
port_name(), proxy_node_name_, proxy_port_name_, proxy_target_node_name_,
proxy_target_port_name_);
}
@ -308,7 +311,7 @@ ScopedEvent ObserveProxyAckEvent::Deserialize(const PortName& port_name,
if (num_bytes < sizeof(ObserveProxyAckEventData)) return nullptr;
const auto* data = static_cast<const ObserveProxyAckEventData*>(buffer);
return std::make_unique<ObserveProxyAckEvent>(port_name,
return mozilla::MakeUnique<ObserveProxyAckEvent>(port_name,
data->last_sequence_num);
}
@ -322,7 +325,7 @@ void ObserveProxyAckEvent::SerializeData(void* buffer) const {
}
ScopedEvent ObserveProxyAckEvent::Clone() const {
return std::make_unique<ObserveProxyAckEvent>(port_name(),
return mozilla::MakeUnique<ObserveProxyAckEvent>(port_name(),
last_sequence_num_);
}
@ -340,7 +343,7 @@ ScopedEvent ObserveClosureEvent::Deserialize(const PortName& port_name,
if (num_bytes < sizeof(ObserveClosureEventData)) return nullptr;
const auto* data = static_cast<const ObserveClosureEventData*>(buffer);
return std::make_unique<ObserveClosureEvent>(port_name,
return mozilla::MakeUnique<ObserveClosureEvent>(port_name,
data->last_sequence_num);
}
@ -354,7 +357,8 @@ void ObserveClosureEvent::SerializeData(void* buffer) const {
}
ScopedEvent ObserveClosureEvent::Clone() const {
return std::make_unique<ObserveClosureEvent>(port_name(), last_sequence_num_);
return mozilla::MakeUnique<ObserveClosureEvent>(port_name(),
last_sequence_num_);
}
MergePortEvent::MergePortEvent(const PortName& port_name,
@ -372,7 +376,7 @@ ScopedEvent MergePortEvent::Deserialize(const PortName& port_name,
if (num_bytes < sizeof(MergePortEventData)) return nullptr;
const auto* data = static_cast<const MergePortEventData*>(buffer);
return std::make_unique<MergePortEvent>(port_name, data->new_port_name,
return mozilla::MakeUnique<MergePortEvent>(port_name, data->new_port_name,
data->new_port_descriptor);
}
@ -400,7 +404,7 @@ ScopedEvent UserMessageReadAckRequestEvent::Deserialize(
const auto* data =
static_cast<const UserMessageReadAckRequestEventData*>(buffer);
return std::make_unique<UserMessageReadAckRequestEvent>(
return mozilla::MakeUnique<UserMessageReadAckRequestEvent>(
port_name, data->sequence_num_to_acknowledge);
}
@ -427,7 +431,7 @@ ScopedEvent UserMessageReadAckEvent::Deserialize(const PortName& port_name,
if (num_bytes < sizeof(UserMessageReadAckEventData)) return nullptr;
const auto* data = static_cast<const UserMessageReadAckEventData*>(buffer);
return std::make_unique<UserMessageReadAckEvent>(
return mozilla::MakeUnique<UserMessageReadAckEvent>(
port_name, data->sequence_num_acknowledged);
}

Просмотреть файл

@ -7,11 +7,9 @@
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "mojo/core/ports/name.h"
#include "mojo/core/ports/user_message.h"
@ -21,11 +19,11 @@ namespace ports {
class Event;
using ScopedEvent = std::unique_ptr<Event>;
using ScopedEvent = mozilla::UniquePtr<Event>;
// A Event is the fundamental unit of operation and communication within and
// between Nodes.
class COMPONENT_EXPORT(MOJO_CORE_PORTS) Event {
class Event {
public:
enum Type : uint32_t {
// A user message event contains arbitrary user-specified payload data
@ -85,8 +83,8 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Event {
static ScopedEvent Deserialize(const void* buffer, size_t num_bytes);
template <typename T>
static std::unique_ptr<T> Cast(ScopedEvent* event) {
return base::WrapUnique(static_cast<T*>(event->release()));
static mozilla::UniquePtr<T> Cast(ScopedEvent* event) {
return mozilla::WrapUnique(static_cast<T*>(event->release()));
}
Type type() const { return type_; }
@ -110,13 +108,13 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Event {
DISALLOW_COPY_AND_ASSIGN(Event);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageEvent : public Event {
class UserMessageEvent : public Event {
public:
explicit UserMessageEvent(size_t num_ports);
~UserMessageEvent() override;
bool HasMessage() const { return !!message_; }
void AttachMessage(std::unique_ptr<UserMessage> message);
void AttachMessage(mozilla::UniquePtr<UserMessage> message);
template <typename T>
T* GetMessage() {
@ -156,12 +154,12 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageEvent : public Event {
uint64_t sequence_num_ = 0;
std::vector<PortDescriptor> port_descriptors_;
std::vector<PortName> ports_;
std::unique_ptr<UserMessage> message_;
mozilla::UniquePtr<UserMessage> message_;
DISALLOW_COPY_AND_ASSIGN(UserMessageEvent);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) PortAcceptedEvent : public Event {
class PortAcceptedEvent : public Event {
public:
explicit PortAcceptedEvent(const PortName& port_name);
~PortAcceptedEvent() override;
@ -176,7 +174,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) PortAcceptedEvent : public Event {
DISALLOW_COPY_AND_ASSIGN(PortAcceptedEvent);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) ObserveProxyEvent : public Event {
class ObserveProxyEvent : public Event {
public:
ObserveProxyEvent(const PortName& port_name, const NodeName& proxy_node_name,
const PortName& proxy_port_name,
@ -209,7 +207,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) ObserveProxyEvent : public Event {
DISALLOW_COPY_AND_ASSIGN(ObserveProxyEvent);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) ObserveProxyAckEvent : public Event {
class ObserveProxyAckEvent : public Event {
public:
ObserveProxyAckEvent(const PortName& port_name, uint64_t last_sequence_num);
~ObserveProxyAckEvent() override;
@ -229,7 +227,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) ObserveProxyAckEvent : public Event {
DISALLOW_COPY_AND_ASSIGN(ObserveProxyAckEvent);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) ObserveClosureEvent : public Event {
class ObserveClosureEvent : public Event {
public:
ObserveClosureEvent(const PortName& port_name, uint64_t last_sequence_num);
~ObserveClosureEvent() override;
@ -252,7 +250,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) ObserveClosureEvent : public Event {
DISALLOW_COPY_AND_ASSIGN(ObserveClosureEvent);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) MergePortEvent : public Event {
class MergePortEvent : public Event {
public:
MergePortEvent(const PortName& port_name, const PortName& new_port_name,
const PortDescriptor& new_port_descriptor);
@ -276,8 +274,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) MergePortEvent : public Event {
DISALLOW_COPY_AND_ASSIGN(MergePortEvent);
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageReadAckRequestEvent
: public Event {
class UserMessageReadAckRequestEvent : public Event {
public:
UserMessageReadAckRequestEvent(const PortName& port_name,
uint64_t sequence_num_to_acknowledge);
@ -297,7 +294,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageReadAckRequestEvent
uint64_t sequence_num_to_acknowledge_;
};
class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageReadAckEvent : public Event {
class UserMessageReadAckEvent : public Event {
public:
UserMessageReadAckEvent(const PortName& port_name,
uint64_t sequence_num_acknowledged);

Просмотреть файл

@ -9,14 +9,15 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "mojo/core/ports/message_filter.h"
#include "mozilla/Likely.h"
namespace mojo {
namespace core {
namespace ports {
// Used by std::{push,pop}_heap functions
inline bool operator<(const std::unique_ptr<UserMessageEvent>& a,
const std::unique_ptr<UserMessageEvent>& b) {
inline bool operator<(const mozilla::UniquePtr<UserMessageEvent>& a,
const mozilla::UniquePtr<UserMessageEvent>& b) {
return a->sequence_num() > b->sequence_num();
}
@ -29,11 +30,15 @@ MessageQueue::MessageQueue(uint64_t next_sequence_num)
}
MessageQueue::~MessageQueue() {
#if DCHECK_IS_ON()
#ifdef DEBUG
size_t num_leaked_ports = 0;
for (const auto& message : heap_) num_leaked_ports += message->num_ports();
DVLOG_IF(1, num_leaked_ports > 0)
<< "Leaking " << num_leaked_ports << " ports in unreceived messages";
for (const auto& message : heap_) {
num_leaked_ports += message->num_ports();
}
if (num_leaked_ports > 0) {
DVLOG(1) << "Leaking " << num_leaked_ports
<< " ports in unreceived messages";
}
#endif
}
@ -41,7 +46,7 @@ bool MessageQueue::HasNextMessage() const {
return !heap_.empty() && heap_[0]->sequence_num() == next_sequence_num_;
}
void MessageQueue::GetNextMessage(std::unique_ptr<UserMessageEvent>* message,
void MessageQueue::GetNextMessage(mozilla::UniquePtr<UserMessageEvent>* message,
MessageFilter* filter) {
if (!HasNextMessage() || (filter && !filter->Match(*heap_[0]))) {
message->reset();
@ -58,7 +63,7 @@ void MessageQueue::GetNextMessage(std::unique_ptr<UserMessageEvent>* message,
// here is somewhat arbitrary.
constexpr size_t kHeapMinimumShrinkSize = 16;
constexpr size_t kHeapShrinkInterval = 512;
if (UNLIKELY(heap_.size() > kHeapMinimumShrinkSize &&
if (MOZ_UNLIKELY(heap_.size() > kHeapMinimumShrinkSize &&
heap_.size() % kHeapShrinkInterval == 0)) {
heap_.shrink_to_fit();
}
@ -66,7 +71,7 @@ void MessageQueue::GetNextMessage(std::unique_ptr<UserMessageEvent>* message,
next_sequence_num_++;
}
void MessageQueue::AcceptMessage(std::unique_ptr<UserMessageEvent> message,
void MessageQueue::AcceptMessage(mozilla::UniquePtr<UserMessageEvent> message,
bool* has_next_message) {
// TODO: Handle sequence number roll-over.
@ -82,7 +87,7 @@ void MessageQueue::AcceptMessage(std::unique_ptr<UserMessageEvent> message,
}
void MessageQueue::TakeAllMessages(
std::vector<std::unique_ptr<UserMessageEvent>>* messages) {
std::vector<mozilla::UniquePtr<UserMessageEvent>>* messages) {
*messages = std::move(heap_);
total_queued_bytes_ = 0;
}

Просмотреть файл

@ -11,8 +11,6 @@
#include <memory>
#include <vector>
#include "base/component_export.h"
#include "base/macros.h"
#include "mojo/core/ports/event.h"
namespace mojo {
@ -28,12 +26,15 @@ class MessageFilter;
// known sequence number and can indicate whether the next sequential message is
// available. Thus the queue enforces message ordering for the consumer without
// enforcing it for the producer (see AcceptMessage() below.)
class COMPONENT_EXPORT(MOJO_CORE_PORTS) MessageQueue {
class MessageQueue {
public:
explicit MessageQueue();
explicit MessageQueue(uint64_t next_sequence_num);
~MessageQueue();
MessageQueue(const MessageQueue&) = delete;
void operator=(const MessageQueue&) = delete;
void set_signalable(bool value) { signalable_ = value; }
uint64_t next_sequence_num() const { return next_sequence_num_; }
@ -42,7 +43,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) MessageQueue {
// Gives ownership of the message. If |filter| is non-null, the next message
// will only be retrieved if the filter successfully matches it.
void GetNextMessage(std::unique_ptr<UserMessageEvent>* message,
void GetNextMessage(mozilla::UniquePtr<UserMessageEvent>* message,
MessageFilter* filter);
// Takes ownership of the message. Note: Messages are ordered, so while we
@ -54,13 +55,13 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) MessageQueue {
// until GetNextMessage is called enough times to return a null message.
// In other words, has_next_message acts like an edge trigger.
//
void AcceptMessage(std::unique_ptr<UserMessageEvent> message,
void AcceptMessage(mozilla::UniquePtr<UserMessageEvent> message,
bool* has_next_message);
// Takes all messages from this queue. Used to safely destroy queued messages
// without holding any Port lock.
void TakeAllMessages(
std::vector<std::unique_ptr<UserMessageEvent>>* messages);
std::vector<mozilla::UniquePtr<UserMessageEvent>>* messages);
// The number of messages queued here, regardless of whether the next expected
// message has arrived yet.
@ -71,12 +72,10 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) MessageQueue {
size_t queued_num_bytes() const { return total_queued_bytes_; }
private:
std::vector<std::unique_ptr<UserMessageEvent>> heap_;
std::vector<mozilla::UniquePtr<UserMessageEvent>> heap_;
uint64_t next_sequence_num_;
bool signalable_ = true;
size_t total_queued_bytes_ = 0;
DISALLOW_COPY_AND_ASSIGN(MessageQueue);
};
} // namespace ports

Просмотреть файл

@ -20,6 +20,14 @@ std::ostream& operator<<(std::ostream& stream, const Name& name) {
return stream;
}
mozilla::Logger& operator<<(mozilla::Logger& log, const Name& name) {
log.printf("%" PRIX64, name.v1);
if (name.v2 != 0) {
log.printf(".%" PRIX64, name.v2);
}
return log;
}
} // namespace ports
} // namespace core
} // namespace mojo

Просмотреть файл

@ -10,14 +10,14 @@
#include <ostream>
#include <tuple>
#include "base/component_export.h"
#include "base/hash/hash.h"
#include "base/logging.h"
#include "mozilla/HashFunctions.h"
namespace mojo {
namespace core {
namespace ports {
struct COMPONENT_EXPORT(MOJO_CORE_PORTS) Name {
struct Name {
Name(uint64_t v1, uint64_t v2) : v1(v1), v2(v2) {}
uint64_t v1, v2;
};
@ -32,22 +32,22 @@ inline bool operator<(const Name& a, const Name& b) {
return std::tie(a.v1, a.v2) < std::tie(b.v1, b.v2);
}
COMPONENT_EXPORT(MOJO_CORE_PORTS)
std::ostream& operator<<(std::ostream& stream, const Name& name);
mozilla::Logger& operator<<(mozilla::Logger& log, const Name& name);
struct COMPONENT_EXPORT(MOJO_CORE_PORTS) PortName : Name {
struct PortName : Name {
PortName() : Name(0, 0) {}
PortName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
};
extern COMPONENT_EXPORT(MOJO_CORE_PORTS) const PortName kInvalidPortName;
extern const PortName kInvalidPortName;
struct COMPONENT_EXPORT(MOJO_CORE_PORTS) NodeName : Name {
struct NodeName : Name {
NodeName() : Name(0, 0) {}
NodeName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
};
extern COMPONENT_EXPORT(MOJO_CORE_PORTS) const NodeName kInvalidNodeName;
extern const NodeName kInvalidNodeName;
} // namespace ports
} // namespace core
@ -56,16 +56,18 @@ extern COMPONENT_EXPORT(MOJO_CORE_PORTS) const NodeName kInvalidNodeName;
namespace std {
template <>
struct COMPONENT_EXPORT(MOJO_CORE_PORTS) hash<mojo::core::ports::PortName> {
struct hash<mojo::core::ports::PortName> {
std::size_t operator()(const mojo::core::ports::PortName& name) const {
return base::HashInts64(name.v1, name.v2);
// FIXME: HashGeneric only generates a 32-bit hash
return mozilla::HashGeneric(name.v1, name.v2);
}
};
template <>
struct COMPONENT_EXPORT(MOJO_CORE_PORTS) hash<mojo::core::ports::NodeName> {
struct hash<mojo::core::ports::NodeName> {
std::size_t operator()(const mojo::core::ports::NodeName& name) const {
return base::HashInts64(name.v1, name.v2);
// FIXME: HashGeneric only generates a 32-bit hash
return mozilla::HashGeneric(name.v1, name.v2);
}
};

Просмотреть файл

@ -12,69 +12,21 @@
#include <utility>
#include <vector>
#include "base/containers/stack_container.h"
#include "base/lazy_instance.h"
#include "mozilla/Mutex.h"
#include "mozilla/RandomNum.h"
#include "nsTArray.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/notreached.h"
#include "base/optional.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_local.h"
#include "build/build_config.h"
#include "mojo/core/ports/event.h"
#include "mojo/core/ports/node_delegate.h"
#include "mojo/core/ports/port_locker.h"
#if !defined(OS_NACL)
# include "crypto/random.h"
#else
# include "base/rand_util.h"
#endif
namespace mojo {
namespace core {
namespace ports {
namespace {
constexpr size_t kRandomNameCacheSize = 256;
// Random port name generator which maintains a cache of random bytes to draw
// from. This amortizes the cost of random name generation on platforms where
// RandBytes may have significant per-call overhead.
//
// Note that the use of this cache means one has to be careful about fork()ing
// a process once any port names have been generated, as that behavior can lead
// to collisions between independently generated names in different processes.
class RandomNameGenerator {
public:
RandomNameGenerator() = default;
~RandomNameGenerator() = default;
PortName GenerateRandomPortName() {
base::AutoLock lock(lock_);
if (cache_index_ == kRandomNameCacheSize) {
#if defined(OS_NACL)
base::RandBytes(cache_, sizeof(PortName) * kRandomNameCacheSize);
#else
crypto::RandBytes(cache_, sizeof(PortName) * kRandomNameCacheSize);
#endif
cache_index_ = 0;
}
return cache_[cache_index_++];
}
private:
base::Lock lock_;
PortName cache_[kRandomNameCacheSize];
size_t cache_index_ = kRandomNameCacheSize;
DISALLOW_COPY_AND_ASSIGN(RandomNameGenerator);
};
base::LazyInstance<RandomNameGenerator>::Leaky g_name_generator =
LAZY_INSTANCE_INITIALIZER;
int DebugError(const char* message, int error_code) {
NOTREACHED() << "Oops: " << message;
return error_code;
@ -97,7 +49,10 @@ bool CanAcceptMoreMessages(const Port* port) {
}
void GenerateRandomPortName(PortName* name) {
*name = g_name_generator.Get().GenerateRandomPortName();
// FIXME: Chrome uses a cache to avoid extra calls to the system RNG when
// generating port names to keep this overhead down. If this method starts
// showing up on profiles we should consider doing the same.
*name = PortName{mozilla::RandomUint64OrDie(), mozilla::RandomUint64OrDie()};
}
} // namespace
@ -111,10 +66,10 @@ Node::~Node() {
bool Node::CanShutdownCleanly(ShutdownPolicy policy) {
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_lock(ports_lock_);
mozilla::MutexAutoLock ports_lock(ports_lock_);
if (policy == ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS) {
#if DCHECK_IS_ON()
#ifdef DEBUG
for (auto& entry : ports_) {
DVLOG(2) << "Port " << entry.first << " referencing node "
<< entry.second->peer_node_name << " is blocking shutdown of "
@ -136,7 +91,7 @@ bool Node::CanShutdownCleanly(ShutdownPolicy policy) {
auto* port = locker.port();
if (port->peer_node_name != name_ && port->state != Port::kReceiving) {
can_shutdown = false;
#if DCHECK_IS_ON()
#ifdef DEBUG
DVLOG(2) << "Port " << entry.first << " referencing node "
<< port->peer_node_name << " is blocking shutdown of "
<< "node " << name_ << " (state=" << port->state << ")";
@ -152,7 +107,7 @@ bool Node::CanShutdownCleanly(ShutdownPolicy policy) {
int Node::GetPort(const PortName& port_name, PortRef* port_ref) {
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock lock(ports_lock_);
mozilla::MutexAutoLock lock(ports_lock_);
auto iter = ports_.find(port_name);
if (iter == ports_.end()) return ERROR_PORT_UNKNOWN;
@ -169,7 +124,7 @@ int Node::CreateUninitializedPort(PortRef* port_ref) {
PortName port_name;
GenerateRandomPortName(&port_name);
scoped_refptr<Port> port(new Port(kInitialSequenceNum, kInitialSequenceNum));
RefPtr<Port> port(new Port(kInitialSequenceNum, kInitialSequenceNum));
int rv = AddPortWithName(port_name, port);
if (rv != OK) return rv;
@ -183,7 +138,7 @@ int Node::InitializePort(const PortRef& port_ref,
{
// Must be acquired for UpdatePortPeerAddress below.
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_locker(ports_lock_);
mozilla::MutexAutoLock ports_lock(ports_lock_);
SinglePortLocker locker(&port_ref);
auto* port = locker.port();
@ -217,8 +172,7 @@ int Node::CreatePortPair(PortRef* port0_ref, PortRef* port1_ref) {
return OK;
}
int Node::SetUserData(const PortRef& port_ref,
scoped_refptr<UserData> user_data) {
int Node::SetUserData(const PortRef& port_ref, RefPtr<UserData> user_data) {
SinglePortLocker locker(&port_ref);
auto* port = locker.port();
if (port->state == Port::kClosed) return ERROR_PORT_STATE_UNEXPECTED;
@ -228,8 +182,7 @@ int Node::SetUserData(const PortRef& port_ref,
return OK;
}
int Node::GetUserData(const PortRef& port_ref,
scoped_refptr<UserData>* user_data) {
int Node::GetUserData(const PortRef& port_ref, RefPtr<UserData>* user_data) {
SinglePortLocker locker(&port_ref);
auto* port = locker.port();
if (port->state == Port::kClosed) return ERROR_PORT_STATE_UNEXPECTED;
@ -240,7 +193,7 @@ int Node::GetUserData(const PortRef& port_ref,
}
int Node::ClosePort(const PortRef& port_ref) {
std::vector<std::unique_ptr<UserMessageEvent>> undelivered_messages;
std::vector<mozilla::UniquePtr<UserMessageEvent>> undelivered_messages;
NodeName peer_node_name;
PortName peer_port_name;
uint64_t last_sequence_num = 0;
@ -280,7 +233,7 @@ int Node::ClosePort(const PortRef& port_ref) {
DVLOG(2) << "Sending ObserveClosure from " << port_ref.name() << "@"
<< name_ << " to " << peer_port_name << "@" << peer_node_name;
delegate_->ForwardEvent(peer_node_name,
std::make_unique<ObserveClosureEvent>(
mozilla::MakeUnique<ObserveClosureEvent>(
peer_port_name, last_sequence_num));
for (const auto& message : undelivered_messages) {
for (size_t i = 0; i < message->num_ports(); ++i) {
@ -312,7 +265,7 @@ int Node::GetStatus(const PortRef& port_ref, PortStatus* port_status) {
}
int Node::GetMessage(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent>* message,
mozilla::UniquePtr<UserMessageEvent>* message,
MessageFilter* filter) {
*message = nullptr;
@ -336,7 +289,7 @@ int Node::GetMessage(const PortRef& port_ref,
if (*message &&
(*message)->sequence_num() == port->sequence_num_to_acknowledge) {
peer_node_name = port->peer_node_name;
ack_event = std::make_unique<UserMessageReadAckEvent>(
ack_event = mozilla::MakeUnique<UserMessageReadAckEvent>(
port->peer_port_name, port->sequence_num_to_acknowledge);
}
}
@ -366,7 +319,7 @@ int Node::GetMessage(const PortRef& port_ref,
}
int Node::SendUserMessage(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent> message) {
mozilla::UniquePtr<UserMessageEvent> message) {
int rv = SendUserMessageInternal(port_ref, &message);
if (rv != OK) {
// If send failed, close all carried ports. Note that we're careful not to
@ -403,7 +356,7 @@ int Node::SetAcknowledgeRequestInterval(
}
delegate_->ForwardEvent(peer_node_name,
std::make_unique<UserMessageReadAckRequestEvent>(
mozilla::MakeUnique<UserMessageReadAckRequestEvent>(
peer_port_name, sequence_num_to_request_ack));
return OK;
}
@ -439,7 +392,7 @@ int Node::MergePorts(const PortRef& port_ref,
{
// Must be held for ConvertToProxy.
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_locker(ports_lock_);
mozilla::MutexAutoLock ports_locker(ports_lock_);
SinglePortLocker locker(&port_ref);
@ -464,7 +417,7 @@ int Node::MergePorts(const PortRef& port_ref,
delegate_->ForwardEvent(
destination_node_name,
std::make_unique<MergePortEvent>(destination_port_name, new_port_name,
mozilla::MakeUnique<MergePortEvent>(destination_port_name, new_port_name,
new_port_descriptor));
return OK;
}
@ -487,10 +440,10 @@ int Node::LostConnectionToNode(const NodeName& node_name) {
return OK;
}
int Node::OnUserMessage(std::unique_ptr<UserMessageEvent> message) {
int Node::OnUserMessage(mozilla::UniquePtr<UserMessageEvent> message) {
PortName port_name = message->port_name();
#if DCHECK_IS_ON()
#ifdef DEBUG
std::ostringstream ports_buf;
for (size_t i = 0; i < message->num_ports(); ++i) {
if (i > 0) ports_buf << ",";
@ -574,11 +527,11 @@ int Node::OnUserMessage(std::unique_ptr<UserMessageEvent> message) {
return OK;
}
int Node::OnPortAccepted(std::unique_ptr<PortAcceptedEvent> event) {
int Node::OnPortAccepted(mozilla::UniquePtr<PortAcceptedEvent> event) {
PortRef port_ref;
if (GetPort(event->port_name(), &port_ref) != OK) return ERROR_PORT_UNKNOWN;
#if DCHECK_IS_ON()
#ifdef DEBUG
{
SinglePortLocker locker(&port_ref);
DVLOG(2) << "PortAccepted at " << port_ref.name() << "@" << name_
@ -590,7 +543,7 @@ int Node::OnPortAccepted(std::unique_ptr<PortAcceptedEvent> event) {
return BeginProxying(port_ref);
}
int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
int Node::OnObserveProxy(mozilla::UniquePtr<ObserveProxyEvent> event) {
if (event->port_name() == kInvalidPortName) {
// An ObserveProxy with an invalid target port name is a broadcast used to
// inform ports when their peer (which was itself a proxy) has become
@ -627,7 +580,7 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
{
// Must be acquired for UpdatePortPeerAddress below.
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_locker(ports_lock_);
mozilla::MutexAutoLock ports_locker(ports_lock_);
SinglePortLocker locker(&port_ref);
auto* port = locker.port();
@ -639,7 +592,7 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
event->proxy_target_node_name(),
event->proxy_target_port_name());
event_target_node = event->proxy_node_name();
event_to_forward = std::make_unique<ObserveProxyAckEvent>(
event_to_forward = mozilla::MakeUnique<ObserveProxyAckEvent>(
event->proxy_port_name(), port->next_sequence_num_to_send - 1);
peer_changed = true;
DVLOG(2) << "Forwarding ObserveProxyAck from " << event->port_name()
@ -660,10 +613,10 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
<< "@" << event->proxy_node_name();
port->send_on_proxy_removal =
std::make_unique<std::pair<NodeName, ScopedEvent>>(
mozilla::MakeUnique<std::pair<NodeName, ScopedEvent>>(
event->proxy_node_name(),
std::make_unique<ObserveProxyAckEvent>(event->proxy_port_name(),
kInvalidSequenceNum));
mozilla::MakeUnique<ObserveProxyAckEvent>(
event->proxy_port_name(), kInvalidSequenceNum));
}
} else {
// Forward this event along to our peer. Eventually, it should find the
@ -689,7 +642,7 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
return OK;
}
int Node::OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event) {
int Node::OnObserveProxyAck(mozilla::UniquePtr<ObserveProxyAckEvent> event) {
DVLOG(2) << "ObserveProxyAck at " << event->port_name() << "@" << name_
<< " (last_sequence_num=" << event->last_sequence_num() << ")";
@ -725,7 +678,7 @@ int Node::OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event) {
return OK;
}
int Node::OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event) {
int Node::OnObserveClosure(mozilla::UniquePtr<ObserveClosureEvent> event) {
// OK if the port doesn't exist, as it may have been closed already.
PortRef port_ref;
if (GetPort(event->port_name(), &port_ref) != OK) return OK;
@ -799,7 +752,7 @@ int Node::OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event) {
return OK;
}
int Node::OnMergePort(std::unique_ptr<MergePortEvent> event) {
int Node::OnMergePort(mozilla::UniquePtr<MergePortEvent> event) {
PortRef port_ref;
GetPort(event->port_name(), &port_ref);
@ -835,7 +788,7 @@ int Node::OnMergePort(std::unique_ptr<MergePortEvent> event) {
}
int Node::OnUserMessageReadAckRequest(
std::unique_ptr<UserMessageReadAckRequestEvent> event) {
mozilla::UniquePtr<UserMessageReadAckRequestEvent> event) {
PortRef port_ref;
GetPort(event->port_name(), &port_ref);
@ -845,7 +798,7 @@ int Node::OnUserMessageReadAckRequest(
if (!port_ref.is_valid()) return ERROR_PORT_UNKNOWN;
NodeName peer_node_name;
std::unique_ptr<Event> event_to_send;
mozilla::UniquePtr<Event> event_to_send;
{
SinglePortLocker locker(&port_ref);
auto* port = locker.port();
@ -863,7 +816,7 @@ int Node::OnUserMessageReadAckRequest(
if (current_sequence_num >= event->sequence_num_to_acknowledge()) {
// If the current sequence number to read already exceeds the ack
// request, send an ack immediately.
event_to_send = std::make_unique<UserMessageReadAckEvent>(
event_to_send = mozilla::MakeUnique<UserMessageReadAckEvent>(
port->peer_port_name, current_sequence_num);
// This might be a late or duplicate acknowledge request, that's
@ -897,7 +850,8 @@ int Node::OnUserMessageReadAckRequest(
return OK;
}
int Node::OnUserMessageReadAck(std::unique_ptr<UserMessageReadAckEvent> event) {
int Node::OnUserMessageReadAck(
mozilla::UniquePtr<UserMessageReadAckEvent> event) {
PortRef port_ref;
GetPort(event->port_name(), &port_ref);
@ -929,7 +883,7 @@ int Node::OnUserMessageReadAck(std::unique_ptr<UserMessageReadAckEvent> event) {
// not been closed.
if (port->sequence_num_acknowledge_interval && !port->peer_closed) {
peer_node_name = port->peer_node_name;
ack_request_event = std::make_unique<UserMessageReadAckRequestEvent>(
ack_request_event = mozilla::MakeUnique<UserMessageReadAckRequestEvent>(
port->peer_port_name, port->last_sequence_num_acknowledged +
port->sequence_num_acknowledge_interval);
}
@ -942,9 +896,9 @@ int Node::OnUserMessageReadAck(std::unique_ptr<UserMessageReadAckEvent> event) {
return OK;
}
int Node::AddPortWithName(const PortName& port_name, scoped_refptr<Port> port) {
int Node::AddPortWithName(const PortName& port_name, RefPtr<Port> port) {
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock lock(ports_lock_);
mozilla::MutexAutoLock lock(ports_lock_);
if (port->peer_port_name != kInvalidPortName) {
DCHECK_NE(kInvalidNodeName, port->peer_node_name);
peer_port_maps_[port->peer_node_name][port->peer_port_name].emplace(
@ -958,9 +912,9 @@ int Node::AddPortWithName(const PortName& port_name, scoped_refptr<Port> port) {
void Node::ErasePort(const PortName& port_name) {
PortLocker::AssertNoPortsLockedOnCurrentThread();
scoped_refptr<Port> port;
RefPtr<Port> port;
{
base::AutoLock lock(ports_lock_);
mozilla::MutexAutoLock lock(ports_lock_);
auto it = ports_.find(port_name);
if (it == ports_.end()) return;
port = std::move(it->second);
@ -970,7 +924,7 @@ void Node::ErasePort(const PortName& port_name) {
}
// NOTE: We are careful not to release the port's messages while holding any
// locks, since they may run arbitrary user code upon destruction.
std::vector<std::unique_ptr<UserMessageEvent>> messages;
std::vector<mozilla::UniquePtr<UserMessageEvent>> messages;
{
PortRef port_ref(port_name, std::move(port));
SinglePortLocker locker(&port_ref);
@ -979,9 +933,9 @@ void Node::ErasePort(const PortName& port_name) {
DVLOG(2) << "Deleted port " << port_name << "@" << name_;
}
int Node::SendUserMessageInternal(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent>* message) {
std::unique_ptr<UserMessageEvent>& m = *message;
int Node::SendUserMessageInternal(
const PortRef& port_ref, mozilla::UniquePtr<UserMessageEvent>* message) {
mozilla::UniquePtr<UserMessageEvent>& m = *message;
for (size_t i = 0; i < m->num_ports(); ++i) {
if (m->ports()[i] == port_ref.name()) return ERROR_PORT_CANNOT_SEND_SELF;
}
@ -1018,9 +972,10 @@ int Node::MergePortsInternal(const PortRef& port0_ref, const PortRef& port1_ref,
{
// Needed to swap peer map entries below.
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::ReleasableAutoLock ports_locker(&ports_lock_);
mozilla::Maybe<mozilla::MutexAutoLock> ports_locker(std::in_place,
ports_lock_);
base::Optional<PortLocker> locker(base::in_place, port_refs, 2);
mozilla::Maybe<PortLocker> locker(std::in_place, port_refs, size_t(2));
auto* port0 = locker->GetPort(port0_ref);
auto* port1 = locker->GetPort(port1_ref);
@ -1049,7 +1004,7 @@ int Node::MergePortsInternal(const PortRef& port0_ref, const PortRef& port1_ref,
const bool close_port1 =
port1->state == Port::kReceiving || allow_close_on_bad_state;
locker.reset();
ports_locker.Release();
ports_locker.reset();
if (close_port0) ClosePort(port0_ref);
if (close_port1) ClosePort(port1_ref);
return ERROR_PORT_STATE_UNEXPECTED;
@ -1080,7 +1035,7 @@ int Node::MergePortsInternal(const PortRef& port0_ref, const PortRef& port1_ref,
// If either end of the port cycle is closed, we propagate an
// ObserveClosure event.
closure_event_target_node = port->peer_node_name;
closure_event = std::make_unique<ObserveClosureEvent>(
closure_event = mozilla::MakeUnique<ObserveClosureEvent>(
port->peer_port_name, port->last_sequence_num_to_receive);
}
}
@ -1102,7 +1057,7 @@ int Node::MergePortsInternal(const PortRef& port0_ref, const PortRef& port1_ref,
// consistent state by undoing the peer swap and closing the ports.
{
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_locker(ports_lock_);
mozilla::MutexAutoLock ports_locker(ports_lock_);
PortLocker locker(port_refs, 2);
auto* port0 = locker.GetPort(port0_ref);
auto* port1 = locker.GetPort(port1_ref);
@ -1158,8 +1113,8 @@ void Node::ConvertToProxy(Port* port, const NodeName& to_node_name,
int Node::AcceptPort(const PortName& port_name,
const Event::PortDescriptor& port_descriptor) {
scoped_refptr<Port> port =
base::MakeRefCounted<Port>(port_descriptor.next_sequence_num_to_send,
RefPtr<Port> port =
mozilla::MakeRefPtr<Port>(port_descriptor.next_sequence_num_to_send,
port_descriptor.next_sequence_num_to_receive);
port->state = Port::kReceiving;
port->peer_node_name = port_descriptor.peer_node_name;
@ -1181,9 +1136,9 @@ int Node::AcceptPort(const PortName& port_name,
if (rv != OK) return rv;
// Allow referring port to forward messages.
delegate_->ForwardEvent(
port_descriptor.referring_node_name,
std::make_unique<PortAcceptedEvent>(port_descriptor.referring_port_name));
delegate_->ForwardEvent(port_descriptor.referring_node_name,
mozilla::MakeUnique<PortAcceptedEvent>(
port_descriptor.referring_port_name));
return OK;
}
@ -1204,30 +1159,31 @@ int Node::PrepareToForwardUserMessage(const PortRef& forwarding_port_ref,
// it only while no port locks are held on the calling thread.
if (target_node_name != name_) {
if (!message->NotifyWillBeRoutedExternally()) {
LOG(ERROR) << "NotifyWillBeRoutedExternally failed unexpectedly.";
CHROMIUM_LOG(ERROR)
<< "NotifyWillBeRoutedExternally failed unexpectedly.";
return ERROR_PORT_STATE_UNEXPECTED;
}
}
// Must be held because ConvertToProxy needs to update |peer_port_maps_|.
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_locker(ports_lock_);
mozilla::MutexAutoLock ports_locker(ports_lock_);
// Simultaneously lock the forwarding port as well as all attached ports.
base::StackVector<PortRef, 4> attached_port_refs;
base::StackVector<const PortRef*, 5> ports_to_lock;
attached_port_refs.container().resize(message->num_ports());
ports_to_lock.container().resize(message->num_ports() + 1);
ports_to_lock[0] = &forwarding_port_ref;
AutoTArray<PortRef, 4> attached_port_refs;
AutoTArray<const PortRef*, 5> ports_to_lock;
attached_port_refs.SetCapacity(message->num_ports());
ports_to_lock.SetCapacity(message->num_ports() + 1);
ports_to_lock.AppendElement(&forwarding_port_ref);
for (size_t i = 0; i < message->num_ports(); ++i) {
const PortName& attached_port_name = message->ports()[i];
auto iter = ports_.find(attached_port_name);
DCHECK(iter != ports_.end());
attached_port_refs[i] = PortRef(attached_port_name, iter->second);
ports_to_lock[i + 1] = &attached_port_refs[i];
attached_port_refs.AppendElement(
PortRef(attached_port_name, iter->second));
ports_to_lock.AppendElement(&attached_port_refs[i]);
}
PortLocker locker(ports_to_lock.container().data(),
ports_to_lock.container().size());
PortLocker locker(ports_to_lock.Elements(), ports_to_lock.Length());
auto* forwarding_port = locker.GetPort(forwarding_port_ref);
if (forwarding_port->peer_node_name != target_node_name) {
@ -1251,7 +1207,7 @@ int Node::PrepareToForwardUserMessage(const PortRef& forwarding_port_ref,
// a proxy. Otherwise, use the next outgoing sequence number.
if (message->sequence_num() == 0)
message->set_sequence_num(forwarding_port->next_sequence_num_to_send++);
#if DCHECK_IS_ON()
#ifdef DEBUG
std::ostringstream ports_buf;
for (size_t i = 0; i < message->num_ports(); ++i) {
if (i > 0) ports_buf << ",";
@ -1263,7 +1219,7 @@ int Node::PrepareToForwardUserMessage(const PortRef& forwarding_port_ref,
// Sanity check to make sure we can actually send all the attached ports.
// They must all be in the |kReceiving| state and must not be the sender's
// own peer.
DCHECK_EQ(message->num_ports(), attached_port_refs.container().size());
DCHECK_EQ(message->num_ports(), attached_port_refs.Length());
for (size_t i = 0; i < message->num_ports(); ++i) {
auto* attached_port = locker.GetPort(attached_port_refs[i]);
int error = OK;
@ -1296,7 +1252,7 @@ int Node::PrepareToForwardUserMessage(const PortRef& forwarding_port_ref,
}
}
#if DCHECK_IS_ON()
#ifdef DEBUG
DVLOG(4) << "Sending message " << message->sequence_num()
<< " [ports=" << ports_buf.str() << "]"
<< " from " << forwarding_port_ref.name() << "@" << name_ << " to "
@ -1353,7 +1309,7 @@ int Node::BeginProxying(const PortRef& port_ref) {
if (try_remove_proxy_immediately) {
// Make sure we propagate closure to our current peer.
closure_target_node = port->peer_node_name;
closure_event = std::make_unique<ObserveClosureEvent>(
closure_event = mozilla::MakeUnique<ObserveClosureEvent>(
port->peer_port_name, port->last_sequence_num_to_receive);
}
}
@ -1374,7 +1330,7 @@ int Node::ForwardUserMessagesFromProxy(const PortRef& port_ref) {
// the message queue's notion of next sequence number. That's useful for the
// proxy removal process as we can tell when this port has seen all of the
// messages it is expected to see.
std::unique_ptr<UserMessageEvent> message;
mozilla::UniquePtr<UserMessageEvent> message;
{
SinglePortLocker locker(&port_ref);
locker.port()->message_queue.GetNextMessage(&message, nullptr);
@ -1407,7 +1363,7 @@ void Node::InitiateProxyRemoval(const PortRef& port_ref) {
// Eventually, this node will receive ObserveProxyAck (or ObserveClosure if
// the peer was closed in the meantime).
delegate_->ForwardEvent(peer_node_name,
std::make_unique<ObserveProxyEvent>(
mozilla::MakeUnique<ObserveProxyEvent>(
peer_port_name, name_, port_ref.name(),
peer_node_name, peer_port_name));
}
@ -1451,11 +1407,11 @@ void Node::DestroyAllPortsWithPeer(const NodeName& node_name,
std::vector<PortRef> ports_to_notify;
std::vector<PortName> dead_proxies_to_broadcast;
std::vector<std::unique_ptr<UserMessageEvent>> undelivered_messages;
std::vector<mozilla::UniquePtr<UserMessageEvent>> undelivered_messages;
{
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock ports_lock(ports_lock_);
mozilla::MutexAutoLock ports_lock(ports_lock_);
auto node_peer_port_map_iter = peer_port_maps_.find(node_name);
if (node_peer_port_map_iter == peer_port_maps_.end()) return;
@ -1506,7 +1462,7 @@ void Node::DestroyAllPortsWithPeer(const NodeName& node_name,
// inefficient but rare.
if (port->state != Port::kReceiving) {
dead_proxies_to_broadcast.push_back(local_port_ref.name());
std::vector<std::unique_ptr<UserMessageEvent>> messages;
std::vector<mozilla::UniquePtr<UserMessageEvent>> messages;
port->message_queue.TakeAllMessages(&messages);
for (auto& message : messages)
undelivered_messages.emplace_back(std::move(message));
@ -1525,7 +1481,7 @@ void Node::DestroyAllPortsWithPeer(const NodeName& node_name,
for (const auto& proxy_name : dead_proxies_to_broadcast) {
// Broadcast an event signifying that this proxy is no longer functioning.
delegate_->BroadcastEvent(std::make_unique<ObserveProxyEvent>(
delegate_->BroadcastEvent(mozilla::MakeUnique<ObserveProxyEvent>(
kInvalidPortName, name_, proxy_name, kInvalidNodeName,
kInvalidPortName));
@ -1549,7 +1505,7 @@ void Node::UpdatePortPeerAddress(const PortName& local_port_name,
Port* local_port,
const NodeName& new_peer_node,
const PortName& new_peer_port) {
ports_lock_.AssertAcquired();
ports_lock_.AssertCurrentThreadOwns();
local_port->AssertLockAcquired();
RemoveFromPeerPortMap(local_port_name, local_port);
@ -1557,8 +1513,7 @@ void Node::UpdatePortPeerAddress(const PortName& local_port_name,
local_port->peer_port_name = new_peer_port;
if (new_peer_port != kInvalidPortName) {
peer_port_maps_[new_peer_node][new_peer_port].emplace(
local_port_name,
PortRef(local_port_name, base::WrapRefCounted<Port>(local_port)));
local_port_name, PortRef(local_port_name, RefPtr<Port>{local_port}));
}
}
@ -1581,7 +1536,7 @@ void Node::RemoveFromPeerPortMap(const PortName& local_port_name,
void Node::SwapPortPeers(const PortName& port0_name, Port* port0,
const PortName& port1_name, Port* port1) {
ports_lock_.AssertAcquired();
ports_lock_.AssertCurrentThreadOwns();
port0->AssertLockAcquired();
port1->AssertLockAcquired();
@ -1591,10 +1546,8 @@ void Node::SwapPortPeers(const PortName& port0_name, Port* port0,
peer_port_maps_[port1->peer_node_name][port1->peer_port_name];
peer0_ports.erase(port0_name);
peer1_ports.erase(port1_name);
peer0_ports.emplace(port1_name,
PortRef(port1_name, base::WrapRefCounted<Port>(port1)));
peer1_ports.emplace(port0_name,
PortRef(port0_name, base::WrapRefCounted<Port>(port0)));
peer0_ports.emplace(port1_name, PortRef(port1_name, RefPtr<Port>{port1}));
peer1_ports.emplace(port0_name, PortRef(port0_name, RefPtr<Port>{port0}));
std::swap(port0->peer_node_name, port1->peer_node_name);
std::swap(port0->peer_port_name, port1->peer_port_name);
@ -1611,7 +1564,7 @@ void Node::MaybeResendAckRequest(const PortRef& port_ref) {
if (!port->sequence_num_acknowledge_interval) return;
peer_node_name = port->peer_node_name;
ack_request_event = std::make_unique<UserMessageReadAckRequestEvent>(
ack_request_event = mozilla::MakeUnique<UserMessageReadAckRequestEvent>(
port->peer_port_name, port->last_sequence_num_acknowledged +
port->sequence_num_acknowledge_interval);
}
@ -1630,7 +1583,7 @@ void Node::MaybeForwardAckRequest(const PortRef& port_ref) {
if (!port->sequence_num_to_acknowledge) return;
peer_node_name = port->peer_node_name;
ack_request_event = std::make_unique<UserMessageReadAckRequestEvent>(
ack_request_event = mozilla::MakeUnique<UserMessageReadAckRequestEvent>(
port->peer_port_name, port->sequence_num_to_acknowledge);
port->sequence_num_to_acknowledge = 0;
@ -1652,7 +1605,7 @@ void Node::MaybeResendAck(const PortRef& port_ref) {
if (!port->sequence_num_to_acknowledge || !last_sequence_num_read) return;
peer_node_name = port->peer_node_name;
ack_event = std::make_unique<UserMessageReadAckEvent>(
ack_event = mozilla::MakeUnique<UserMessageReadAckEvent>(
port->peer_port_name, last_sequence_num_read);
}
@ -1666,10 +1619,10 @@ Node::DelegateHolder::DelegateHolder(Node* node, NodeDelegate* delegate)
Node::DelegateHolder::~DelegateHolder() = default;
#if DCHECK_IS_ON()
#ifdef DEBUG
void Node::DelegateHolder::EnsureSafeDelegateAccess() const {
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock lock(node_->ports_lock_);
mozilla::MutexAutoLock lock(node_->ports_lock_);
}
#endif

Просмотреть файл

@ -11,16 +11,13 @@
#include <queue>
#include <unordered_map>
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "mojo/core/ports/event.h"
#include "mojo/core/ports/name.h"
#include "mojo/core/ports/port.h"
#include "mojo/core/ports/port_ref.h"
#include "mojo/core/ports/user_data.h"
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
namespace mojo {
namespace core {
@ -66,7 +63,7 @@ class NodeDelegate;
// by Nodes to coordinate Port behavior and lifetime within and across Nodes.
// See Event documentation for description of different types of events used by
// a Node to coordinate behavior.
class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
class Node {
public:
enum class ShutdownPolicy {
DONT_ALLOW_LOCAL_PORTS,
@ -77,6 +74,9 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
Node(const NodeName& name, NodeDelegate* delegate);
~Node();
Node(const Node&) = delete;
void operator=(const Node&) = delete;
// Returns true iff there are no open ports referring to another node or ports
// in the process of being transferred from this node to another. If this
// returns false, then to ensure clean shutdown, it is necessary to keep the
@ -108,8 +108,8 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref);
// User data associated with the port.
int SetUserData(const PortRef& port_ref, scoped_refptr<UserData> user_data);
int GetUserData(const PortRef& port_ref, scoped_refptr<UserData>* user_data);
int SetUserData(const PortRef& port_ref, RefPtr<UserData> user_data);
int GetUserData(const PortRef& port_ref, RefPtr<UserData>* user_data);
// Prevents further messages from being sent from this port or delivered to
// this port. The port is removed, and the port's peer is notified of the
@ -131,14 +131,14 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
// available. Ownership of |filter| is not taken, and it must outlive the
// extent of this call.
int GetMessage(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent>* message,
mozilla::UniquePtr<UserMessageEvent>* message,
MessageFilter* filter);
// Sends a message from the specified port to its peer. Note that the message
// notification may arrive synchronously (via PortStatusChanged() on the
// delegate) if the peer is local to this Node.
int SendUserMessage(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent> message);
mozilla::UniquePtr<UserMessageEvent> message);
// Makes the port send acknowledge requests to its conjugate to acknowledge
// at least every |sequence_number_acknowledge_interval| messages as they're
@ -184,13 +184,16 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
DelegateHolder(Node* node, NodeDelegate* delegate);
~DelegateHolder();
DelegateHolder(const DelegateHolder&) = delete;
void operator=(const DelegateHolder&) = delete;
NodeDelegate* operator->() const {
EnsureSafeDelegateAccess();
return delegate_;
}
private:
#if DCHECK_IS_ON()
#ifdef DEBUG
void EnsureSafeDelegateAccess() const;
#else
void EnsureSafeDelegateAccess() const {}
@ -198,25 +201,23 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
Node* const node_;
NodeDelegate* const delegate_;
DISALLOW_COPY_AND_ASSIGN(DelegateHolder);
};
int OnUserMessage(std::unique_ptr<UserMessageEvent> message);
int OnPortAccepted(std::unique_ptr<PortAcceptedEvent> event);
int OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event);
int OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event);
int OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event);
int OnMergePort(std::unique_ptr<MergePortEvent> event);
int OnUserMessage(mozilla::UniquePtr<UserMessageEvent> message);
int OnPortAccepted(mozilla::UniquePtr<PortAcceptedEvent> event);
int OnObserveProxy(mozilla::UniquePtr<ObserveProxyEvent> event);
int OnObserveProxyAck(mozilla::UniquePtr<ObserveProxyAckEvent> event);
int OnObserveClosure(mozilla::UniquePtr<ObserveClosureEvent> event);
int OnMergePort(mozilla::UniquePtr<MergePortEvent> event);
int OnUserMessageReadAckRequest(
std::unique_ptr<UserMessageReadAckRequestEvent> event);
int OnUserMessageReadAck(std::unique_ptr<UserMessageReadAckEvent> event);
mozilla::UniquePtr<UserMessageReadAckRequestEvent> event);
int OnUserMessageReadAck(mozilla::UniquePtr<UserMessageReadAckEvent> event);
int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port);
int AddPortWithName(const PortName& port_name, RefPtr<Port> port);
void ErasePort(const PortName& port_name);
int SendUserMessageInternal(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent>* message);
mozilla::UniquePtr<UserMessageEvent>* message);
int MergePortsInternal(const PortRef& port0_ref, const PortRef& port1_ref,
bool allow_close_on_bad_state);
void ConvertToProxy(Port* port, const NodeName& to_node_name,
@ -286,24 +287,27 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
// Because UserMessage events may execute arbitrary user code during
// destruction, it is also important to ensure that such events are never
// destroyed while this (or any individual Port) lock is held.
base::Lock ports_lock_;
std::unordered_map<LocalPortName, scoped_refptr<Port>> ports_;
mozilla::Mutex ports_lock_{"Ports Lock"};
std::unordered_map<LocalPortName, RefPtr<Port>> ports_;
// Maps a peer port name to a list of PortRefs for all local ports which have
// the port name key designated as their peer port. The set of local ports
// which have the same peer port is expected to always be relatively small and
// usually 1. Hence we just use a flat_map of local PortRefs keyed on each
// local port's name.
//
// FIXME(nika): We don't have `base::flat_map` or a super equivalent type with
// the same API, so just use a nested `std::unordered_map` for now. We should
// probably change all of this to instead use our types eventually.
using PeerPortMap =
std::unordered_map<PeerPortName, base::flat_map<LocalPortName, PortRef>>;
std::unordered_map<PeerPortName,
std::unordered_map<LocalPortName, PortRef>>;
// A reverse mapping which can be used to find all local ports that reference
// a given peer node or a local port that references a specific given peer
// port on a peer node. The key to this map is the corresponding peer node
// name.
std::unordered_map<NodeName, PeerPortMap> peer_port_maps_;
DISALLOW_COPY_AND_ASSIGN(Node);
};
} // namespace ports

Просмотреть файл

@ -10,12 +10,12 @@
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "mojo/core/ports/event.h"
#include "mojo/core/ports/message_queue.h"
#include "mojo/core/ports/user_data.h"
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "nsISupportsImpl.h"
namespace mojo {
namespace core {
@ -61,7 +61,9 @@ class PortLocker;
// which is only possible using a PortLocker. PortLocker ensures that
// overlapping Port lock acquisitions on a single thread are always acquired in
// a globally consistent order.
class Port : public base::RefCountedThreadSafe<Port> {
class Port {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Port)
public:
// The state of a given Port. A Port may only exist in one of these states at
// any given time.
@ -149,12 +151,12 @@ class Port : public base::RefCountedThreadSafe<Port> {
// In some edge cases, a Node may need to remember to route a single special
// event upon destruction of this (proxying) Port. That event is stashed here
// in the interim.
std::unique_ptr<std::pair<NodeName, ScopedEvent>> send_on_proxy_removal;
mozilla::UniquePtr<std::pair<NodeName, ScopedEvent>> send_on_proxy_removal;
// Arbitrary user data attached to the Port. In practice, Mojo uses this to
// stash an observer interface which can be notified about various Port state
// changes.
scoped_refptr<UserData> user_data;
RefPtr<UserData> user_data;
// Indicates that this (proxying) Port has received acknowledgement that no
// new user messages will be routed to it. If |true|, the proxy will be
@ -176,21 +178,17 @@ class Port : public base::RefCountedThreadSafe<Port> {
Port(uint64_t next_sequence_num_to_send,
uint64_t next_sequence_num_to_receive);
void AssertLockAcquired() {
#if DCHECK_IS_ON()
lock_.AssertAcquired();
#endif
}
Port(const Port&) = delete;
void operator=(const Port&) = delete;
void AssertLockAcquired() { lock_.AssertCurrentThreadOwns(); }
private:
friend class base::RefCountedThreadSafe<Port>;
friend class PortLocker;
~Port();
base::Lock lock_;
DISALLOW_COPY_AND_ASSIGN(Port);
mozilla::Mutex lock_{"Port State"};
};
} // namespace ports

Просмотреть файл

@ -8,8 +8,8 @@
#include "mojo/core/ports/port.h"
#if DCHECK_IS_ON()
# include "base/threading/thread_local.h"
#ifdef DEBUG
# include "base/thread_local.h"
#endif
namespace mojo {
@ -18,7 +18,7 @@ namespace ports {
namespace {
#if DCHECK_IS_ON()
#ifdef DEBUG
void UpdateTLS(PortLocker* old_locker, PortLocker* new_locker) {
// Sanity check when DCHECK is on to make sure there is only ever one
// PortLocker extant on the current thread.
@ -32,7 +32,7 @@ void UpdateTLS(PortLocker* old_locker, PortLocker* new_locker) {
PortLocker::PortLocker(const PortRef** port_refs, size_t num_ports)
: port_refs_(port_refs), num_ports_(num_ports) {
#if DCHECK_IS_ON()
#ifdef DEBUG
UpdateTLS(nullptr, this);
#endif
@ -43,20 +43,19 @@ PortLocker::PortLocker(const PortRef** port_refs, size_t num_ports)
for (size_t i = 0; i < num_ports_; ++i) {
// TODO(crbug.com/725605): Remove this CHECK.
CHECK(port_refs_[i]->port());
port_refs_[i]->port()->lock_.Acquire();
port_refs_[i]->port()->lock_.Lock();
}
}
PortLocker::~PortLocker() {
for (size_t i = 0; i < num_ports_; ++i)
port_refs_[i]->port()->lock_.Release();
for (size_t i = 0; i < num_ports_; ++i) port_refs_[i]->port()->lock_.Unlock();
#if DCHECK_IS_ON()
#ifdef DEBUG
UpdateTLS(this, nullptr);
#endif
}
#if DCHECK_IS_ON()
#ifdef DEBUG
// static
void PortLocker::AssertNoPortsLockedOnCurrentThread() {
// Forces a DCHECK if the TLS PortLocker is anything other than null.

Просмотреть файл

@ -7,7 +7,7 @@
#include <stdint.h>
#include "base/macros.h"
#include "base/logging.h"
#include "mojo/core/ports/port_ref.h"
namespace mojo {
@ -31,14 +31,17 @@ class PortLocker {
PortLocker(const PortRef** port_refs, size_t num_ports);
~PortLocker();
PortLocker(const PortLocker&) = delete;
void operator=(const PortLocker&) = delete;
// Provides safe access to a PortRef's Port. Note that in release builds this
// doesn't do anything other than pass through to the private accessor on
// |port_ref|, but it does force callers to go through a PortLocker to get to
// the state, thus minimizing the likelihood that they'll go and do something
// stupid.
Port* GetPort(const PortRef& port_ref) const {
#if DCHECK_IS_ON()
// Sanity check when DCHECK is on to ensure this is actually a port whose
#ifdef DEBUG
// Sanity check when DEBUG is on to ensure this is actually a port whose
// lock is held by this PortLocker.
bool is_port_locked = false;
for (size_t i = 0; i < num_ports_ && !is_port_locked; ++i)
@ -50,7 +53,7 @@ class PortLocker {
// A helper which can be used to verify that no Port locks are held on the
// current thread. In non-DCHECK builds this is a no-op.
#if DCHECK_IS_ON()
#ifdef DEBUG
static void AssertNoPortsLockedOnCurrentThread();
#else
static void AssertNoPortsLockedOnCurrentThread() {}
@ -59,8 +62,6 @@ class PortLocker {
private:
const PortRef** const port_refs_;
const size_t num_ports_;
DISALLOW_COPY_AND_ASSIGN(PortLocker);
};
// Convenience wrapper for a PortLocker that locks a single port.
@ -69,13 +70,14 @@ class SinglePortLocker {
explicit SinglePortLocker(const PortRef* port_ref);
~SinglePortLocker();
SinglePortLocker(const SinglePortLocker&) = delete;
void operator=(const SinglePortLocker&) = delete;
Port* port() const { return locker_.GetPort(*port_ref_); }
private:
const PortRef* port_ref_;
PortLocker locker_;
DISALLOW_COPY_AND_ASSIGN(SinglePortLocker);
};
} // namespace ports

Просмотреть файл

@ -14,7 +14,7 @@ PortRef::~PortRef() = default;
PortRef::PortRef() = default;
PortRef::PortRef(const PortName& name, scoped_refptr<Port> port)
PortRef::PortRef(const PortName& name, RefPtr<Port> port)
: name_(name), port_(std::move(port)) {}
PortRef::PortRef(const PortRef& other) = default;

Просмотреть файл

@ -5,9 +5,8 @@
#ifndef MOJO_CORE_PORTS_PORT_REF_H_
#define MOJO_CORE_PORTS_PORT_REF_H_
#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "mojo/core/ports/name.h"
#include "mozilla/RefPtr.h"
namespace mojo {
namespace core {
@ -16,11 +15,11 @@ namespace ports {
class Port;
class PortLocker;
class COMPONENT_EXPORT(MOJO_CORE_PORTS) PortRef {
class PortRef {
public:
~PortRef();
PortRef();
PortRef(const PortName& name, scoped_refptr<Port> port);
PortRef(const PortName& name, RefPtr<Port> port);
PortRef(const PortRef& other);
PortRef(PortRef&& other);
@ -38,7 +37,7 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) PortRef {
Port* port() const { return port_.get(); }
PortName name_;
scoped_refptr<Port> port_;
RefPtr<Port> port_;
};
} // namespace ports

Просмотреть файл

@ -5,16 +5,16 @@
#ifndef MOJO_CORE_PORTS_USER_DATA_H_
#define MOJO_CORE_PORTS_USER_DATA_H_
#include "base/memory/ref_counted.h"
#include "nsISupportsImpl.h"
namespace mojo {
namespace core {
namespace ports {
class UserData : public base::RefCountedThreadSafe<UserData> {
protected:
friend class base::RefCountedThreadSafe<UserData>;
class UserData {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UserData);
protected:
virtual ~UserData() = default;
};

Просмотреть файл

@ -7,9 +7,6 @@
#include <stddef.h>
#include "base/component_export.h"
#include "base/macros.h"
namespace mojo {
namespace core {
namespace ports {
@ -24,13 +21,16 @@ namespace ports {
// |kUserMessageTypeInfo| and pass its address down to the UserMessage
// constructor. The type of a UserMessage can then be dynamically inspected by
// comparing |type_info()| to any subclass's |&kUserMessageTypeInfo|.
class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessage {
class UserMessage {
public:
struct TypeInfo {};
explicit UserMessage(const TypeInfo* type_info);
virtual ~UserMessage();
UserMessage(const UserMessage&) = delete;
void operator=(const UserMessage&) = delete;
const TypeInfo* type_info() const { return type_info_; }
// Invoked immediately before the system asks the embedder to forward this
@ -47,8 +47,6 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessage {
private:
const TypeInfo* const type_info_;
DISALLOW_COPY_AND_ASSIGN(UserMessage);
};
} // namespace ports