mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Update to mojo dd010e1297c09b351dc82f7def154cfa63d795b1
This commit is contained in:
parent
8f06f346ee
commit
0847bbc2d0
@ -129,7 +129,6 @@ shared_library("mojo_java_unittests") {
|
||||
"//mojo/message_pump",
|
||||
"//mojo/public/cpp/bindings/tests:mojo_public_bindings_test_utils",
|
||||
"//mojo/public/cpp/environment",
|
||||
"//mojo/public/cpp/test_support:test_utils",
|
||||
]
|
||||
defines = [ "UNIT_TEST" ]
|
||||
}
|
||||
|
||||
@ -9,8 +9,7 @@ source_set("common") {
|
||||
sources = [
|
||||
"binding_set.h",
|
||||
"interface_ptr_set.h",
|
||||
"task_tracker.cc",
|
||||
"task_tracker.h",
|
||||
"strong_binding_set.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
@ -19,34 +18,38 @@ source_set("common") {
|
||||
]
|
||||
}
|
||||
|
||||
test("mojo_common_unittests") {
|
||||
source_set("tests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"binding_set_unittest.cc",
|
||||
"callback_binding_unittest.cc",
|
||||
"interface_ptr_set_unittest.cc",
|
||||
"task_tracker_unittest.cc",
|
||||
"strong_binding_set_unittest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":common",
|
||||
":test_interfaces",
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//mojo/message_pump",
|
||||
"//mojo/public/cpp/bindings",
|
||||
"//mojo/public/cpp/bindings:callback",
|
||||
"//mojo/public/cpp/system",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
|
||||
test("mojo_common_unittests") {
|
||||
deps = [
|
||||
":tests",
|
||||
"//mojo/converters/array_string:tests",
|
||||
"//mojo/converters/base:tests",
|
||||
"//mojo/converters/url:tests",
|
||||
"//mojo/data_pipe_utils:tests",
|
||||
"//mojo/edk/test:run_all_unittests",
|
||||
"//mojo/edk/test:test_support",
|
||||
"//mojo/environment:chromium",
|
||||
"//mojo/message_pump",
|
||||
"//mojo/message_pump:tests",
|
||||
"//mojo/public/cpp/bindings",
|
||||
"//mojo/public/cpp/bindings:callback",
|
||||
"//mojo/public/cpp/system",
|
||||
"//mojo/public/cpp/test_support:test_utils",
|
||||
"//testing/gtest",
|
||||
"//url",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -6,9 +6,11 @@
|
||||
#define MOJO_COMMON_BINDING_SET_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "mojo/public/cpp/bindings/binding.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -21,6 +23,9 @@ class BindingSet {
|
||||
BindingSet() {}
|
||||
~BindingSet() { CloseAllBindings(); }
|
||||
|
||||
// Adds a binding to the list and arranges for it to be removed when
|
||||
// a connection error occurs. Does not take ownership of |impl|, which
|
||||
// must outlive the binding set.
|
||||
void AddBinding(Interface* impl, InterfaceRequest<Interface> request) {
|
||||
bindings_.emplace_back(new Binding<Interface>(impl, request.Pass()));
|
||||
auto* binding = bindings_.back().get();
|
||||
|
||||
65
mojo/common/strong_binding_set.h
Normal file
65
mojo/common/strong_binding_set.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2014 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_COMMON_STRONG_BINDING_SET_H_
|
||||
#define MOJO_COMMON_STRONG_BINDING_SET_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "mojo/public/cpp/bindings/binding.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
// Use this class to manage a set of strong bindings each of which is
|
||||
// owned by the pipe it is bound to. The set takes ownership of the
|
||||
// interfaces and will delete them when the bindings are closed.
|
||||
template <typename Interface>
|
||||
class StrongBindingSet {
|
||||
public:
|
||||
StrongBindingSet() {}
|
||||
~StrongBindingSet() { CloseAllBindings(); }
|
||||
|
||||
// Adds a binding to the list and arranges for it to be removed when
|
||||
// a connection error occurs. Takes ownership of |impl|, which
|
||||
// will be deleted when the binding is closed.
|
||||
void AddBinding(Interface* impl, InterfaceRequest<Interface> request) {
|
||||
bindings_.emplace_back(new Binding<Interface>(impl, request.Pass()));
|
||||
auto* binding = bindings_.back().get();
|
||||
// Set the connection error handler for the newly added Binding to be a
|
||||
// function that will erase it from the vector.
|
||||
binding->set_connection_error_handler([this, binding]() {
|
||||
auto it =
|
||||
std::find_if(bindings_.begin(), bindings_.end(),
|
||||
[binding](const std::unique_ptr<Binding<Interface>>& b) {
|
||||
return (b.get() == binding);
|
||||
});
|
||||
DCHECK(it != bindings_.end());
|
||||
delete binding->impl();
|
||||
bindings_.erase(it);
|
||||
});
|
||||
}
|
||||
|
||||
// Closes all bindings and deletes their associated interfaces.
|
||||
void CloseAllBindings() {
|
||||
for (auto it = bindings_.begin(); it != bindings_.end(); ++it) {
|
||||
delete (*it)->impl();
|
||||
}
|
||||
bindings_.clear();
|
||||
}
|
||||
|
||||
size_t size() const { return bindings_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Binding<Interface>>> bindings_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StrongBindingSet);
|
||||
};
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_COMMON_STRONG_BINDING_SET_H_
|
||||
115
mojo/common/strong_binding_set_unittest.cc
Normal file
115
mojo/common/strong_binding_set_unittest.cc
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
#include "mojo/common/strong_binding_set.h"
|
||||
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "mojo/common/test_interfaces.mojom.h"
|
||||
#include "mojo/message_pump/message_pump_mojo.h"
|
||||
#include "mojo/public/cpp/bindings/binding.h"
|
||||
#include "mojo/public/cpp/bindings/interface_request.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace common {
|
||||
namespace {
|
||||
|
||||
class DummyImpl : public tests::Dummy {
|
||||
public:
|
||||
explicit DummyImpl(bool* deleted_flag) : deleted_flag_(deleted_flag) {}
|
||||
~DummyImpl() override { *deleted_flag_ = true; }
|
||||
|
||||
void Foo() override { call_count_++; }
|
||||
|
||||
int call_count() const { return call_count_; }
|
||||
|
||||
private:
|
||||
bool* deleted_flag_;
|
||||
int call_count_ = 0;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DummyImpl);
|
||||
};
|
||||
|
||||
// Tests all of the functionality of StrongBindingSet.
|
||||
TEST(StrongBindingSetTest, FullLifeCycle) {
|
||||
base::MessageLoop loop(MessagePumpMojo::Create());
|
||||
|
||||
// Create 10 InterfacePtrs and DummyImpls.
|
||||
const size_t kNumObjects = 10;
|
||||
InterfacePtr<tests::Dummy> intrfc_ptrs[kNumObjects];
|
||||
DummyImpl* impls[kNumObjects];
|
||||
bool deleted_flags[kNumObjects] = {};
|
||||
|
||||
// Create 10 message pipes, bind everything together, and add the
|
||||
// bindings to binding_set.
|
||||
StrongBindingSet<tests::Dummy> binding_set;
|
||||
EXPECT_EQ(0u, binding_set.size());
|
||||
for (size_t i = 0; i < kNumObjects; i++) {
|
||||
impls[i] = new DummyImpl(&deleted_flags[i]);
|
||||
binding_set.AddBinding(impls[i], GetProxy(&intrfc_ptrs[i]));
|
||||
}
|
||||
EXPECT_EQ(kNumObjects, binding_set.size());
|
||||
|
||||
// Check that initially all call counts are zero.
|
||||
for (const auto& impl : impls) {
|
||||
EXPECT_EQ(0, impl->call_count());
|
||||
}
|
||||
|
||||
// Invoke method foo() on all 10 InterfacePointers.
|
||||
for (InterfacePtr<tests::Dummy>& ptr : intrfc_ptrs) {
|
||||
ptr->Foo();
|
||||
}
|
||||
|
||||
// Check that now all call counts are one.
|
||||
loop.RunUntilIdle();
|
||||
for (const auto& impl : impls) {
|
||||
EXPECT_EQ(1, impl->call_count());
|
||||
}
|
||||
|
||||
// Close the first 5 message pipes and destroy the first five
|
||||
// InterfacePtrs.
|
||||
for (size_t i = 0; i < kNumObjects / 2; i++) {
|
||||
intrfc_ptrs[i].reset();
|
||||
}
|
||||
|
||||
// Check that the set contains only five elements now.
|
||||
loop.RunUntilIdle();
|
||||
EXPECT_EQ(kNumObjects / 2, binding_set.size());
|
||||
|
||||
// Check that the first 5 interfaces have all been deleted.
|
||||
for (size_t i = 0; i < kNumObjects; i++) {
|
||||
bool expected = (i < kNumObjects / 2);
|
||||
EXPECT_EQ(expected, deleted_flags[i]);
|
||||
}
|
||||
|
||||
// Invoke method foo() on the second five InterfacePointers.
|
||||
for (size_t i = kNumObjects / 2; i < kNumObjects; i++) {
|
||||
intrfc_ptrs[i]->Foo();
|
||||
}
|
||||
loop.RunUntilIdle();
|
||||
|
||||
// Check that now the second five counts are two.
|
||||
for (size_t i = kNumObjects / 2; i < kNumObjects; i++) {
|
||||
EXPECT_EQ(2, impls[i]->call_count());
|
||||
}
|
||||
|
||||
// Invoke CloseAllBindings
|
||||
binding_set.CloseAllBindings();
|
||||
EXPECT_EQ(0u, binding_set.size());
|
||||
|
||||
// Invoke method foo() on the second five InterfacePointers.
|
||||
for (size_t i = kNumObjects / 2; i < kNumObjects; i++) {
|
||||
intrfc_ptrs[i]->Foo();
|
||||
}
|
||||
loop.RunUntilIdle();
|
||||
|
||||
// Check that all interfaces have all been deleted.
|
||||
for (size_t i = 0; i < kNumObjects; i++) {
|
||||
EXPECT_TRUE(deleted_flags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace common
|
||||
} // namespace mojo
|
||||
@ -1,102 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
#include "mojo/common/task_tracker.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/threading/thread_local.h"
|
||||
#include "base/tracked_objects.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace common {
|
||||
|
||||
namespace {
|
||||
|
||||
class TrackingActivation {
|
||||
public:
|
||||
TrackingActivation() : birth_(nullptr) {}
|
||||
|
||||
bool Start(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const void* program_counter);
|
||||
void End();
|
||||
bool IsAlive() const { return birth_ != nullptr; }
|
||||
|
||||
private:
|
||||
tracked_objects::TaskStopwatch* stopwatch() {
|
||||
return reinterpret_cast<tracked_objects::TaskStopwatch*>(stopwatch_heap_);
|
||||
}
|
||||
|
||||
tracked_objects::Births* birth_;
|
||||
// TaskStopwatch isn't copyable, but we don't want to allocate it on the heap
|
||||
// so as not to slow things down, hence replacement new.
|
||||
char stopwatch_heap_[sizeof(tracked_objects::TaskStopwatch)];
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TrackingActivation);
|
||||
};
|
||||
|
||||
bool TrackingActivation::Start(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const void* program_counter) {
|
||||
// So far we don't track nested invocations.
|
||||
if (IsAlive())
|
||||
return false;
|
||||
birth_ = tracked_objects::ThreadData::TallyABirthIfActive(
|
||||
tracked_objects::Location(function_name, file_name, line_number,
|
||||
program_counter));
|
||||
if (!birth_)
|
||||
return false;
|
||||
|
||||
(new (stopwatch()) tracked_objects::TaskStopwatch())->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TrackingActivation::End() {
|
||||
DCHECK(IsAlive());
|
||||
stopwatch()->Stop();
|
||||
tracked_objects::ThreadData::TallyRunInAScopedRegionIfTracking(birth_,
|
||||
*stopwatch());
|
||||
stopwatch()->tracked_objects::TaskStopwatch::~TaskStopwatch();
|
||||
birth_ = nullptr;
|
||||
}
|
||||
|
||||
base::ThreadLocalPointer<TrackingActivation> g_activation;
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
intptr_t TaskTracker::StartTracking(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const void* program_counter) {
|
||||
TrackingActivation* activation = g_activation.Get();
|
||||
if (!activation) {
|
||||
// Leak this.
|
||||
activation = new TrackingActivation();
|
||||
g_activation.Set(activation);
|
||||
}
|
||||
|
||||
if (!activation->Start(function_name, file_name, line_number,
|
||||
program_counter))
|
||||
return 0;
|
||||
return reinterpret_cast<intptr_t>(activation);
|
||||
}
|
||||
|
||||
// static
|
||||
void TaskTracker::EndTracking(intptr_t id) {
|
||||
if (0 == id)
|
||||
return;
|
||||
// |EndTracking()| must be called from the same thread of |StartTracking()|.
|
||||
DCHECK_EQ(reinterpret_cast<TrackingActivation*>(id), g_activation.Get());
|
||||
reinterpret_cast<TrackingActivation*>(id)->End();
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace mojo
|
||||
@ -1,26 +0,0 @@
|
||||
// Copyright 2015 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_COMMON_TASK_TRACKER_H_
|
||||
#define MOJO_COMMON_TASK_TRACKER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mojo {
|
||||
namespace common {
|
||||
|
||||
class TaskTracker {
|
||||
public:
|
||||
static intptr_t StartTracking(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number,
|
||||
const void* program_counter);
|
||||
static void EndTracking(intptr_t id);
|
||||
static void Enable();
|
||||
};
|
||||
|
||||
} // namespace common
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_COMMON_TASK_TRACKER_H_
|
||||
@ -1,54 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
#include "mojo/common/task_tracker.h"
|
||||
|
||||
#include "base/tracked_objects.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace common {
|
||||
namespace test {
|
||||
|
||||
class TaskTrackerTest : public testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
tracked_objects::ThreadData::InitializeAndSetTrackingStatus(
|
||||
tracked_objects::ThreadData::PROFILING_ACTIVE);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
tracked_objects::ThreadData::InitializeAndSetTrackingStatus(
|
||||
tracked_objects::ThreadData::DEACTIVATED);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TaskTrackerTest, Nesting) {
|
||||
intptr_t id0 = TaskTracker::StartTracking("Foo", "foo.cc", 1, nullptr);
|
||||
intptr_t id1 = TaskTracker::StartTracking("Bar", "bar.cc", 1, nullptr);
|
||||
TaskTracker::EndTracking(id1);
|
||||
TaskTracker::EndTracking(id0);
|
||||
|
||||
tracked_objects::ProcessDataSnapshot snapshot;
|
||||
tracked_objects::ThreadData::Snapshot(0, &snapshot);
|
||||
|
||||
// Nested one is ignored.
|
||||
EXPECT_EQ(1U, snapshot.phased_snapshots[0].tasks.size());
|
||||
}
|
||||
|
||||
TEST_F(TaskTrackerTest, Twice) {
|
||||
intptr_t id0 = TaskTracker::StartTracking("Foo", "foo.cc", 1, nullptr);
|
||||
TaskTracker::EndTracking(id0);
|
||||
intptr_t id1 = TaskTracker::StartTracking("Bar", "bar.cc", 1, nullptr);
|
||||
TaskTracker::EndTracking(id1);
|
||||
|
||||
tracked_objects::ProcessDataSnapshot snapshot;
|
||||
tracked_objects::ThreadData::Snapshot(0, &snapshot);
|
||||
|
||||
EXPECT_EQ(2U, snapshot.phased_snapshots[0].tasks.size());
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace common
|
||||
} // namespace mojo
|
||||
@ -23,7 +23,7 @@ Array<uint8_t> TypeConverter<Array<uint8_t>, std::string>::Convert(
|
||||
const std::string& input) {
|
||||
auto result = Array<uint8_t>::New(input.size());
|
||||
memcpy(&result.front(), input.c_str(), input.size());
|
||||
return result.Pass();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
@ -11,7 +11,7 @@ PointPtr TypeConverter<PointPtr, gfx::Point>::Convert(const gfx::Point& input) {
|
||||
PointPtr point(Point::New());
|
||||
point->x = input.x();
|
||||
point->y = input.y();
|
||||
return point.Pass();
|
||||
return point;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -27,7 +27,7 @@ PointFPtr TypeConverter<PointFPtr, gfx::PointF>::Convert(
|
||||
PointFPtr point(PointF::New());
|
||||
point->x = input.x();
|
||||
point->y = input.y();
|
||||
return point.Pass();
|
||||
return point;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -43,7 +43,7 @@ SizePtr TypeConverter<SizePtr, gfx::Size>::Convert(const gfx::Size& input) {
|
||||
SizePtr size(Size::New());
|
||||
size->width = input.width();
|
||||
size->height = input.height();
|
||||
return size.Pass();
|
||||
return size;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -60,7 +60,7 @@ RectPtr TypeConverter<RectPtr, gfx::Rect>::Convert(const gfx::Rect& input) {
|
||||
rect->y = input.y();
|
||||
rect->width = input.width();
|
||||
rect->height = input.height();
|
||||
return rect.Pass();
|
||||
return rect;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -77,7 +77,7 @@ RectFPtr TypeConverter<RectFPtr, gfx::RectF>::Convert(const gfx::RectF& input) {
|
||||
rect->y = input.y();
|
||||
rect->width = input.width();
|
||||
rect->height = input.height();
|
||||
return rect.Pass();
|
||||
return rect;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -96,7 +96,7 @@ TransformPtr TypeConverter<TransformPtr, gfx::Transform>::Convert(
|
||||
matrix.Swap(&storage);
|
||||
TransformPtr transform(Transform::New());
|
||||
transform->matrix = matrix.Pass();
|
||||
return transform.Pass();
|
||||
return transform;
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@ -225,7 +225,7 @@ EventPtr TypeConverter<EventPtr, ui::Event>::Convert(const ui::Event& input) {
|
||||
}
|
||||
event->key_data = key_data.Pass();
|
||||
}
|
||||
return event.Pass();
|
||||
return event;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -283,6 +283,7 @@ scoped_ptr<ui::Event> TypeConverter<scoped_ptr<ui::Event>, EventPtr>::Convert(
|
||||
// TODO: last flags isn't right. Need to send changed_flags.
|
||||
scoped_ptr<ui::MouseEvent> event(new ui::MouseEvent(
|
||||
MojoMouseEventTypeToUIEvent(input), location, screen_location,
|
||||
base::TimeDelta::FromMilliseconds(input->time_stamp),
|
||||
ui::EventFlags(input->flags), ui::EventFlags(input->flags)));
|
||||
if (event->IsMouseWheelEvent()) {
|
||||
// This conversion assumes we're using the mojo meaning of these
|
||||
|
||||
@ -14,28 +14,28 @@ namespace mojo {
|
||||
// NOTE: the mojo input events do not necessarily provide a 1-1 mapping with
|
||||
// ui::Event types. Be careful in using them!
|
||||
template <>
|
||||
struct TypeConverter<EventType, ui::EventType> {
|
||||
static EventType Convert(ui::EventType type);
|
||||
struct TypeConverter<EventType, ::ui::EventType> {
|
||||
static EventType Convert(::ui::EventType type);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeConverter<EventPtr, ui::Event> {
|
||||
static EventPtr Convert(const ui::Event& input);
|
||||
struct TypeConverter<EventPtr, ::ui::Event> {
|
||||
static EventPtr Convert(const ::ui::Event& input);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeConverter<EventPtr, ui::KeyEvent> {
|
||||
static EventPtr Convert(const ui::KeyEvent& input);
|
||||
struct TypeConverter<EventPtr, ::ui::KeyEvent> {
|
||||
static EventPtr Convert(const ::ui::KeyEvent& input);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeConverter<EventPtr, ui::GestureEvent> {
|
||||
static EventPtr Convert(const ui::GestureEvent& input);
|
||||
struct TypeConverter<EventPtr, ::ui::GestureEvent> {
|
||||
static EventPtr Convert(const ::ui::GestureEvent& input);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct TypeConverter<scoped_ptr<ui::Event>, EventPtr> {
|
||||
static scoped_ptr<ui::Event> Convert(const EventPtr& input);
|
||||
struct TypeConverter<scoped_ptr<::ui::Event>, EventPtr> {
|
||||
static scoped_ptr<::ui::Event> Convert(const EventPtr& input);
|
||||
};
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
@ -26,7 +26,7 @@ DisplayModePtr TypeConverter<DisplayModePtr, ui::DisplayMode_Params>::Convert(
|
||||
out->size = Size::From<gfx::Size>(in.size);
|
||||
out->is_interlaced = in.is_interlaced;
|
||||
out->refresh_rate = in.refresh_rate;
|
||||
return out.Pass();
|
||||
return out;
|
||||
}
|
||||
|
||||
static_assert(static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_NONE) ==
|
||||
@ -102,7 +102,7 @@ TypeConverter<DisplaySnapshotPtr, ui::DisplaySnapshot_Params>::Convert(
|
||||
out->native_mode = DisplayMode::From<ui::DisplayMode_Params>(in.native_mode);
|
||||
out->product_id = in.product_id;
|
||||
out->string_representation = in.string_representation;
|
||||
return out.Pass();
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
@ -198,7 +198,7 @@ SurfaceIdPtr TypeConverter<SurfaceIdPtr, cc::SurfaceId>::Convert(
|
||||
SurfaceIdPtr id(SurfaceId::New());
|
||||
id->local = static_cast<uint32_t>(input.id);
|
||||
id->id_namespace = cc::SurfaceIdAllocator::NamespaceForId(input);
|
||||
return id.Pass();
|
||||
return id;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -214,7 +214,7 @@ cc::SurfaceId TypeConverter<cc::SurfaceId, SurfaceIdPtr>::Convert(
|
||||
ColorPtr TypeConverter<ColorPtr, SkColor>::Convert(const SkColor& input) {
|
||||
ColorPtr color(Color::New());
|
||||
color->rgba = input;
|
||||
return color.Pass();
|
||||
return color;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -228,7 +228,7 @@ RenderPassIdPtr TypeConverter<RenderPassIdPtr, cc::RenderPassId>::Convert(
|
||||
RenderPassIdPtr pass_id(RenderPassId::New());
|
||||
pass_id->layer_id = input.layer_id;
|
||||
pass_id->index = input.index;
|
||||
return pass_id.Pass();
|
||||
return pass_id;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -337,7 +337,7 @@ QuadPtr TypeConverter<QuadPtr, cc::DrawQuad>::Convert(
|
||||
default:
|
||||
NOTREACHED() << "Unsupported material " << input.material;
|
||||
}
|
||||
return quad.Pass();
|
||||
return quad;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -354,7 +354,7 @@ TypeConverter<SharedQuadStatePtr, cc::SharedQuadState>::Convert(
|
||||
state->opacity = input.opacity;
|
||||
state->blend_mode = static_cast<SkXfermode>(input.blend_mode);
|
||||
state->sorting_context_id = input.sorting_context_id;
|
||||
return state.Pass();
|
||||
return state;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -391,7 +391,7 @@ PassPtr TypeConverter<PassPtr, cc::RenderPass>::Convert(
|
||||
DCHECK_EQ(next_sqs_iter.index(), shared_quad_state.size());
|
||||
pass->quads = quads.Pass();
|
||||
pass->shared_quad_states = shared_quad_state.Pass();
|
||||
return pass.Pass();
|
||||
return pass;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -416,9 +416,9 @@ TypeConverter<scoped_ptr<cc::RenderPass>, PassPtr>::Convert(
|
||||
++sqs_iter;
|
||||
}
|
||||
if (!ConvertDrawQuad(quad, *sqs_iter, pass.get()))
|
||||
return scoped_ptr<cc::RenderPass>();
|
||||
return nullptr;
|
||||
}
|
||||
return pass.Pass();
|
||||
return pass;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -430,7 +430,7 @@ MailboxPtr TypeConverter<MailboxPtr, gpu::Mailbox>::Convert(
|
||||
}
|
||||
MailboxPtr mailbox(Mailbox::New());
|
||||
mailbox->name = name.Pass();
|
||||
return mailbox.Pass();
|
||||
return mailbox;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -449,7 +449,7 @@ MailboxHolderPtr TypeConverter<MailboxHolderPtr, gpu::MailboxHolder>::Convert(
|
||||
holder->mailbox = Mailbox::From<gpu::Mailbox>(input.mailbox);
|
||||
holder->texture_target = input.texture_target;
|
||||
holder->sync_point = input.sync_point;
|
||||
return holder.Pass();
|
||||
return holder;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -474,7 +474,7 @@ TypeConverter<TransferableResourcePtr, cc::TransferableResource>::Convert(
|
||||
transferable->mailbox_holder = MailboxHolder::From(input.mailbox_holder);
|
||||
transferable->is_repeated = input.is_repeated;
|
||||
transferable->is_software = input.is_software;
|
||||
return transferable.Pass();
|
||||
return transferable;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -501,7 +501,7 @@ Array<TransferableResourcePtr> TypeConverter<
|
||||
for (size_t i = 0; i < input.size(); ++i) {
|
||||
resources[i] = TransferableResource::From(input[i]);
|
||||
}
|
||||
return resources.Pass();
|
||||
return resources;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -524,7 +524,7 @@ TypeConverter<ReturnedResourcePtr, cc::ReturnedResource>::Convert(
|
||||
returned->sync_point = input.sync_point;
|
||||
returned->count = input.count;
|
||||
returned->lost = input.lost;
|
||||
return returned.Pass();
|
||||
return returned;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -547,7 +547,7 @@ TypeConverter<Array<ReturnedResourcePtr>, cc::ReturnedResourceArray>::Convert(
|
||||
for (size_t i = 0; i < input.size(); ++i) {
|
||||
resources[i] = ReturnedResource::From(input[i]);
|
||||
}
|
||||
return resources.Pass();
|
||||
return resources;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -563,7 +563,7 @@ FramePtr TypeConverter<FramePtr, cc::CompositorFrame>::Convert(
|
||||
for (size_t i = 0; i < pass_list.size(); ++i) {
|
||||
frame->passes[i] = Pass::From(*pass_list[i]);
|
||||
}
|
||||
return frame.Pass();
|
||||
return frame;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -584,7 +584,7 @@ TypeConverter<scoped_ptr<cc::CompositorFrame>, FramePtr>::Convert(
|
||||
}
|
||||
scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
|
||||
frame->delegated_frame_data = frame_data.Pass();
|
||||
return frame.Pass();
|
||||
return frame;
|
||||
}
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
@ -26,8 +26,6 @@ mojo_edk_source_set("embedder") {
|
||||
"test_embedder.h",
|
||||
]
|
||||
|
||||
defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
|
||||
|
||||
mojo_edk_configs = [ "mojo/edk/system:system_config" ]
|
||||
|
||||
public_deps = [
|
||||
@ -51,17 +49,13 @@ mojo_edk_source_set("platform") {
|
||||
# mojo_system_impl component.
|
||||
visibility = [ ":embedder" ]
|
||||
|
||||
mojo_edk_visibility = [
|
||||
"mojo/edk/system",
|
||||
"mojo/edk/system:test_utils",
|
||||
]
|
||||
mojo_edk_visibility = [ "mojo/edk/system/*" ]
|
||||
|
||||
sources = [
|
||||
"platform_channel_pair.cc",
|
||||
"platform_channel_pair.h",
|
||||
"platform_channel_pair_posix.cc",
|
||||
"platform_channel_utils_posix.cc",
|
||||
"platform_channel_utils_posix.h",
|
||||
"platform_channel_utils.cc",
|
||||
"platform_channel_utils.h",
|
||||
"platform_handle.cc",
|
||||
"platform_handle.h",
|
||||
"platform_handle_utils.h",
|
||||
@ -75,8 +69,6 @@ mojo_edk_source_set("platform") {
|
||||
"scoped_platform_handle.h",
|
||||
"simple_platform_shared_buffer.cc",
|
||||
"simple_platform_shared_buffer.h",
|
||||
"simple_platform_shared_buffer_android.cc",
|
||||
"simple_platform_shared_buffer_posix.cc",
|
||||
"simple_platform_support.cc",
|
||||
"simple_platform_support.h",
|
||||
]
|
||||
@ -116,26 +108,25 @@ mojo_edk_source_set("delegates") {
|
||||
mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
|
||||
}
|
||||
|
||||
mojo_edk_source_set("embedder_unittests") {
|
||||
mojo_edk_source_set("unittests") {
|
||||
testonly = true
|
||||
mojo_edk_visibility = [ "mojo/edk/system:mojo_system_unittests" ]
|
||||
|
||||
sources = [
|
||||
"embedder_unittest.cc",
|
||||
"platform_channel_pair_posix_unittest.cc",
|
||||
"platform_channel_pair_unittest.cc",
|
||||
"simple_platform_shared_buffer_unittest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//testing/gtest",
|
||||
]
|
||||
|
||||
mojo_edk_deps = [
|
||||
"mojo/edk/test:test_support",
|
||||
"mojo/edk/system",
|
||||
"mojo/edk/system:test_utils",
|
||||
"mojo/edk/system/test",
|
||||
"mojo/edk/util",
|
||||
]
|
||||
}
|
||||
|
||||
@ -25,7 +25,9 @@
|
||||
#include "mojo/edk/system/message_pipe_dispatcher.h"
|
||||
#include "mojo/edk/system/platform_handle_dispatcher.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
@ -134,8 +136,7 @@ MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
|
||||
|
||||
*platform_handle =
|
||||
static_cast<system::PlatformHandleDispatcher*>(dispatcher.get())
|
||||
->PassPlatformHandle()
|
||||
.Pass();
|
||||
->PassPlatformHandle();
|
||||
return MOJO_RESULT_OK;
|
||||
}
|
||||
|
||||
@ -185,7 +186,7 @@ ScopedMessagePipeHandle ConnectToSlave(
|
||||
internal::g_ipc_support->GenerateConnectionIdentifier();
|
||||
*platform_connection_id = connection_id.ToString();
|
||||
system::ChannelId channel_id = system::kInvalidChannelId;
|
||||
system::RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
internal::g_ipc_support->ConnectToSlave(
|
||||
connection_id, slave_info, platform_handle.Pass(),
|
||||
did_connect_to_slave_callback, std::move(did_connect_to_slave_runner),
|
||||
@ -212,7 +213,7 @@ ScopedMessagePipeHandle ConnectToMaster(
|
||||
CHECK(ok);
|
||||
|
||||
system::ChannelId channel_id = system::kInvalidChannelId;
|
||||
system::RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
internal::g_ipc_support->ConnectToMaster(
|
||||
connection_id, did_connect_to_master_callback,
|
||||
std::move(did_connect_to_master_runner), &channel_id);
|
||||
@ -236,7 +237,7 @@ ScopedMessagePipeHandle CreateChannelOnIOThread(
|
||||
internal::g_ipc_support->channel_manager();
|
||||
|
||||
*channel_info = new ChannelInfo(MakeChannelId());
|
||||
system::RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
channel_manager->CreateChannelOnIOThread((*channel_info)->channel_id,
|
||||
platform_handle.Pass());
|
||||
|
||||
@ -259,7 +260,7 @@ ScopedMessagePipeHandle CreateChannel(
|
||||
|
||||
system::ChannelId channel_id = MakeChannelId();
|
||||
std::unique_ptr<ChannelInfo> channel_info(new ChannelInfo(channel_id));
|
||||
system::RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
RefPtr<system::MessagePipeDispatcher> dispatcher =
|
||||
channel_manager->CreateChannel(
|
||||
channel_id, platform_handle.Pass(),
|
||||
base::Bind(did_create_channel_callback,
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/task_runner.h"
|
||||
#include "mojo/edk/embedder/channel_info_forward.h"
|
||||
#include "mojo/edk/embedder/platform_task_runner.h"
|
||||
@ -101,7 +100,7 @@ void InitIPCSupport(ProcessType process_type,
|
||||
void ShutdownIPCSupportOnIOThread();
|
||||
|
||||
// Like |ShutdownIPCSupportOnIOThread()|, but may be called from any thread,
|
||||
// signalling shutdown completion via the process delegate's
|
||||
// signaling shutdown completion via the process delegate's
|
||||
// |OnShutdownComplete()|.
|
||||
void ShutdownIPCSupport();
|
||||
|
||||
|
||||
@ -9,28 +9,30 @@
|
||||
#include <memory>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "mojo/edk/embedder/platform_channel_pair.h"
|
||||
#include "mojo/edk/embedder/test_embedder.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/test_command_line.h"
|
||||
#include "mojo/edk/system/test/test_io_thread.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/waitable_event.h"
|
||||
#include "mojo/edk/test/multiprocess_test_helper.h"
|
||||
#include "mojo/edk/test/scoped_ipc_support.h"
|
||||
#include "mojo/edk/test/test_io_thread.h"
|
||||
#include "mojo/edk/util/command_line.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/core.h"
|
||||
#include "mojo/public/cpp/system/handle.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "mojo/public/cpp/system/message_pipe.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::system::test::TestIOThread;
|
||||
using mojo::util::Mutex;
|
||||
using mojo::util::MutexLocker;
|
||||
|
||||
namespace mojo {
|
||||
|
||||
using test::TestIOThread;
|
||||
|
||||
namespace embedder {
|
||||
namespace {
|
||||
|
||||
@ -55,7 +57,6 @@ class ScopedTestChannel {
|
||||
// object is alive).
|
||||
explicit ScopedTestChannel(ScopedPlatformHandle platform_handle)
|
||||
: bootstrap_message_pipe_(MOJO_HANDLE_INVALID),
|
||||
event_(true, false), // Manual reset.
|
||||
channel_info_(nullptr),
|
||||
wait_on_shutdown_(true) {
|
||||
bootstrap_message_pipe_ =
|
||||
@ -72,7 +73,7 @@ class ScopedTestChannel {
|
||||
// the I/O thread must be alive and pumping messages.)
|
||||
~ScopedTestChannel() {
|
||||
// |WaitForChannelCreationCompletion()| must be called before destruction.
|
||||
CHECK(event_.IsSignaled());
|
||||
CHECK(event_.IsSignaledForTest());
|
||||
event_.Reset();
|
||||
if (wait_on_shutdown_) {
|
||||
DestroyChannel(channel_info_,
|
||||
@ -117,7 +118,7 @@ class ScopedTestChannel {
|
||||
// Set after channel creation has been completed (i.e., the callback to
|
||||
// |CreateChannel()| has been called). Also used in the destructor to wait for
|
||||
// |DestroyChannel()| completion.
|
||||
base::WaitableEvent event_;
|
||||
mojo::system::ManualResetWaitableEvent event_;
|
||||
|
||||
// Valid after channel creation completion until destruction.
|
||||
ChannelInfo* channel_info_;
|
||||
@ -196,25 +197,27 @@ TEST_F(EmbedderTest, ChannelsBasic) {
|
||||
|
||||
class TestAsyncWaiter {
|
||||
public:
|
||||
TestAsyncWaiter() : event_(true, false), wait_result_(MOJO_RESULT_UNKNOWN) {}
|
||||
TestAsyncWaiter() : wait_result_(MOJO_RESULT_UNKNOWN) {}
|
||||
|
||||
void Awake(MojoResult result) {
|
||||
system::MutexLocker l(&wait_result_mutex_);
|
||||
MutexLocker l(&wait_result_mutex_);
|
||||
wait_result_ = result;
|
||||
event_.Signal();
|
||||
}
|
||||
|
||||
bool TryWait() { return event_.TimedWait(TestTimeouts::action_timeout()); }
|
||||
bool TryWait() {
|
||||
return !event_.WaitWithTimeout(mojo::system::test::ActionTimeout());
|
||||
}
|
||||
|
||||
MojoResult wait_result() const {
|
||||
system::MutexLocker l(&wait_result_mutex_);
|
||||
MutexLocker l(&wait_result_mutex_);
|
||||
return wait_result_;
|
||||
}
|
||||
|
||||
private:
|
||||
base::WaitableEvent event_;
|
||||
mojo::system::ManualResetWaitableEvent event_;
|
||||
|
||||
mutable system::Mutex wait_result_mutex_;
|
||||
mutable Mutex wait_result_mutex_;
|
||||
MojoResult wait_result_ MOJO_GUARDED_BY(wait_result_mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(TestAsyncWaiter);
|
||||
@ -406,11 +409,12 @@ TEST_F(EmbedderTest, MAYBE_MultiprocessMasterSlave) {
|
||||
|
||||
mojo::test::MultiprocessTestHelper multiprocess_test_helper;
|
||||
std::string connection_id;
|
||||
base::WaitableEvent event(true, false);
|
||||
mojo::system::ManualResetWaitableEvent event;
|
||||
ChannelInfo* channel_info = nullptr;
|
||||
ScopedMessagePipeHandle mp = ConnectToSlave(
|
||||
nullptr, multiprocess_test_helper.server_platform_handle.Pass(),
|
||||
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)),
|
||||
base::Bind(&mojo::system::ManualResetWaitableEvent::Signal,
|
||||
base::Unretained(&event)),
|
||||
nullptr, &connection_id, &channel_info);
|
||||
ASSERT_TRUE(mp.is_valid());
|
||||
EXPECT_TRUE(channel_info);
|
||||
@ -424,9 +428,8 @@ TEST_F(EmbedderTest, MAYBE_MultiprocessMasterSlave) {
|
||||
MOJO_WRITE_MESSAGE_FLAG_NONE));
|
||||
|
||||
// Wait for a response.
|
||||
EXPECT_EQ(MOJO_RESULT_OK,
|
||||
Wait(mp.get(), MOJO_HANDLE_SIGNAL_READABLE,
|
||||
mojo::system::test::ActionDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, Wait(mp.get(), MOJO_HANDLE_SIGNAL_READABLE,
|
||||
mojo::system::test::ActionTimeout(), nullptr));
|
||||
|
||||
// The response message should say "world".
|
||||
char buffer[100];
|
||||
@ -441,7 +444,7 @@ TEST_F(EmbedderTest, MAYBE_MultiprocessMasterSlave) {
|
||||
|
||||
EXPECT_TRUE(multiprocess_test_helper.WaitForChildTestShutdown());
|
||||
|
||||
EXPECT_TRUE(event.TimedWait(TestTimeouts::action_timeout()));
|
||||
EXPECT_FALSE(event.WaitWithTimeout(mojo::system::test::ActionTimeout()));
|
||||
test_io_thread().PostTaskAndWait(
|
||||
base::Bind(&DestroyChannelOnIOThread, base::Unretained(channel_info)));
|
||||
}
|
||||
@ -480,17 +483,16 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlave) {
|
||||
mojo::test::ScopedSlaveIPCSupport ipc_support(
|
||||
test_io_thread.task_runner(), client_platform_handle.Pass());
|
||||
|
||||
const base::CommandLine& command_line =
|
||||
*base::CommandLine::ForCurrentProcess();
|
||||
ASSERT_TRUE(command_line.HasSwitch(kConnectionIdFlag));
|
||||
std::string connection_id =
|
||||
command_line.GetSwitchValueASCII(kConnectionIdFlag);
|
||||
std::string connection_id;
|
||||
ASSERT_TRUE(mojo::system::test::GetTestCommandLine()->GetOptionValue(
|
||||
kConnectionIdFlag, &connection_id));
|
||||
ASSERT_FALSE(connection_id.empty());
|
||||
base::WaitableEvent event(true, false);
|
||||
mojo::system::ManualResetWaitableEvent event;
|
||||
ChannelInfo* channel_info = nullptr;
|
||||
ScopedMessagePipeHandle mp = ConnectToMaster(
|
||||
connection_id,
|
||||
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)),
|
||||
base::Bind(&mojo::system::ManualResetWaitableEvent::Signal,
|
||||
base::Unretained(&event)),
|
||||
nullptr, &channel_info);
|
||||
ASSERT_TRUE(mp.is_valid());
|
||||
EXPECT_TRUE(channel_info);
|
||||
@ -498,7 +500,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlave) {
|
||||
// Wait for the master to send us a message.
|
||||
EXPECT_EQ(MOJO_RESULT_OK,
|
||||
Wait(mp.get(), MOJO_HANDLE_SIGNAL_READABLE,
|
||||
mojo::system::test::ActionDeadline(), nullptr));
|
||||
mojo::system::test::ActionTimeout(), nullptr));
|
||||
|
||||
// It should say "hello".
|
||||
char buffer[100];
|
||||
@ -515,7 +517,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlave) {
|
||||
|
||||
mp.reset();
|
||||
|
||||
EXPECT_TRUE(event.TimedWait(TestTimeouts::action_timeout()));
|
||||
EXPECT_FALSE(event.WaitWithTimeout(mojo::system::test::ActionTimeout()));
|
||||
test_io_thread.PostTaskAndWait(
|
||||
base::Bind(&DestroyChannelOnIOThread, base::Unretained(channel_info)));
|
||||
}
|
||||
|
||||
@ -4,14 +4,63 @@
|
||||
|
||||
#include "mojo/edk/embedder/platform_channel_pair.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/global_descriptors.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/edk/embedder/platform_handle.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsTargetDescriptorUsed(
|
||||
const base::FileHandleMappingVector& file_handle_mapping,
|
||||
int target_fd) {
|
||||
for (size_t i = 0; i < file_handle_mapping.size(); i++) {
|
||||
if (file_handle_mapping[i].second == target_fd)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char PlatformChannelPair::kMojoPlatformChannelHandleSwitch[] =
|
||||
"mojo-platform-channel-handle";
|
||||
|
||||
PlatformChannelPair::PlatformChannelPair() {
|
||||
// Create the Unix domain socket and set the ends to nonblocking.
|
||||
int fds[2];
|
||||
// TODO(vtl): Maybe fail gracefully if |socketpair()| fails.
|
||||
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
|
||||
PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
|
||||
PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// This turns off |SIGPIPE| when writing to a closed socket (causing it to
|
||||
// fail with |EPIPE| instead). On Linux, we have to use |send...()| with
|
||||
// |MSG_NOSIGNAL| -- which is not supported on Mac -- instead.
|
||||
int no_sigpipe = 1;
|
||||
PCHECK(setsockopt(fds[0], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
|
||||
sizeof(no_sigpipe)) == 0);
|
||||
PCHECK(setsockopt(fds[1], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
|
||||
sizeof(no_sigpipe)) == 0);
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
server_handle_.reset(PlatformHandle(fds[0]));
|
||||
DCHECK(server_handle_.is_valid());
|
||||
client_handle_.reset(PlatformHandle(fds[1]));
|
||||
DCHECK(client_handle_.is_valid());
|
||||
}
|
||||
|
||||
PlatformChannelPair::~PlatformChannelPair() {
|
||||
}
|
||||
|
||||
@ -23,6 +72,55 @@ ScopedPlatformHandle PlatformChannelPair::PassClientHandle() {
|
||||
return client_handle_.Pass();
|
||||
}
|
||||
|
||||
// static
|
||||
ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess(
|
||||
const base::CommandLine& command_line) {
|
||||
std::string client_fd_string =
|
||||
command_line.GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
|
||||
int client_fd = -1;
|
||||
if (client_fd_string.empty() ||
|
||||
!base::StringToInt(client_fd_string, &client_fd) ||
|
||||
client_fd < base::GlobalDescriptors::kBaseDescriptor) {
|
||||
LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
|
||||
return ScopedPlatformHandle();
|
||||
}
|
||||
|
||||
return ScopedPlatformHandle(PlatformHandle(client_fd));
|
||||
}
|
||||
|
||||
void PlatformChannelPair::PrepareToPassClientHandleToChildProcess(
|
||||
base::CommandLine* command_line,
|
||||
base::FileHandleMappingVector* handle_passing_info) const {
|
||||
DCHECK(command_line);
|
||||
DCHECK(handle_passing_info);
|
||||
// This is an arbitrary sanity check. (Note that this guarantees that the loop
|
||||
// below will terminate sanely.)
|
||||
CHECK_LT(handle_passing_info->size(), 1000u);
|
||||
|
||||
DCHECK(client_handle_.is_valid());
|
||||
|
||||
// Find a suitable FD to map our client handle to in the child process.
|
||||
// This has quadratic time complexity in the size of |*handle_passing_info|,
|
||||
// but |*handle_passing_info| should be very small (usually/often empty).
|
||||
int target_fd = base::GlobalDescriptors::kBaseDescriptor;
|
||||
while (IsTargetDescriptorUsed(*handle_passing_info, target_fd))
|
||||
target_fd++;
|
||||
|
||||
handle_passing_info->push_back(
|
||||
std::pair<int, int>(client_handle_.get().fd, target_fd));
|
||||
// Log a warning if the command line already has the switch, but "clobber" it
|
||||
// anyway, since it's reasonably likely that all the switches were just copied
|
||||
// from the parent.
|
||||
LOG_IF(WARNING, command_line->HasSwitch(kMojoPlatformChannelHandleSwitch))
|
||||
<< "Child command line already has switch --"
|
||||
<< kMojoPlatformChannelHandleSwitch << "="
|
||||
<< command_line->GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
|
||||
// (Any existing switch won't actually be removed from the command line, but
|
||||
// the last one appended takes precedence.)
|
||||
command_line->AppendSwitchASCII(kMojoPlatformChannelHandleSwitch,
|
||||
base::IntToString(target_fd));
|
||||
}
|
||||
|
||||
void PlatformChannelPair::ChildProcessLaunched() {
|
||||
DCHECK(client_handle_.is_valid());
|
||||
client_handle_.reset();
|
||||
|
||||
@ -37,9 +37,9 @@ using HandlePassingInformation = base::FileHandleMappingVector;
|
||||
// implementations.
|
||||
//
|
||||
// Note: On POSIX platforms, to write to the "pipe", use
|
||||
// |PlatformChannel{Write,Writev}()| (from platform_channel_utils_posix.h)
|
||||
// instead of |write()|, |writev()|, etc. Otherwise, you have to worry about
|
||||
// platform differences in suppressing |SIGPIPE|.
|
||||
// |PlatformChannel{Write,Writev}()| (from platform_channel_utils.h) instead of
|
||||
// |write()|, |writev()|, etc. Otherwise, you have to worry about platform
|
||||
// differences in suppressing |SIGPIPE|.
|
||||
class PlatformChannelPair {
|
||||
public:
|
||||
PlatformChannelPair();
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#include "mojo/edk/embedder/platform_channel_pair.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/global_descriptors.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/edk/embedder/platform_handle.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsTargetDescriptorUsed(
|
||||
const base::FileHandleMappingVector& file_handle_mapping,
|
||||
int target_fd) {
|
||||
for (size_t i = 0; i < file_handle_mapping.size(); i++) {
|
||||
if (file_handle_mapping[i].second == target_fd)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PlatformChannelPair::PlatformChannelPair() {
|
||||
// Create the Unix domain socket and set the ends to nonblocking.
|
||||
int fds[2];
|
||||
// TODO(vtl): Maybe fail gracefully if |socketpair()| fails.
|
||||
PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
|
||||
PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
|
||||
PCHECK(fcntl(fds[1], F_SETFL, O_NONBLOCK) == 0);
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// This turns off |SIGPIPE| when writing to a closed socket (causing it to
|
||||
// fail with |EPIPE| instead). On Linux, we have to use |send...()| with
|
||||
// |MSG_NOSIGNAL| -- which is not supported on Mac -- instead.
|
||||
int no_sigpipe = 1;
|
||||
PCHECK(setsockopt(fds[0], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
|
||||
sizeof(no_sigpipe)) == 0);
|
||||
PCHECK(setsockopt(fds[1], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
|
||||
sizeof(no_sigpipe)) == 0);
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
server_handle_.reset(PlatformHandle(fds[0]));
|
||||
DCHECK(server_handle_.is_valid());
|
||||
client_handle_.reset(PlatformHandle(fds[1]));
|
||||
DCHECK(client_handle_.is_valid());
|
||||
}
|
||||
|
||||
// static
|
||||
ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess(
|
||||
const base::CommandLine& command_line) {
|
||||
std::string client_fd_string =
|
||||
command_line.GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
|
||||
int client_fd = -1;
|
||||
if (client_fd_string.empty() ||
|
||||
!base::StringToInt(client_fd_string, &client_fd) ||
|
||||
client_fd < base::GlobalDescriptors::kBaseDescriptor) {
|
||||
LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
|
||||
return ScopedPlatformHandle();
|
||||
}
|
||||
|
||||
return ScopedPlatformHandle(PlatformHandle(client_fd));
|
||||
}
|
||||
|
||||
void PlatformChannelPair::PrepareToPassClientHandleToChildProcess(
|
||||
base::CommandLine* command_line,
|
||||
base::FileHandleMappingVector* handle_passing_info) const {
|
||||
DCHECK(command_line);
|
||||
DCHECK(handle_passing_info);
|
||||
// This is an arbitrary sanity check. (Note that this guarantees that the loop
|
||||
// below will terminate sanely.)
|
||||
CHECK_LT(handle_passing_info->size(), 1000u);
|
||||
|
||||
DCHECK(client_handle_.is_valid());
|
||||
|
||||
// Find a suitable FD to map our client handle to in the child process.
|
||||
// This has quadratic time complexity in the size of |*handle_passing_info|,
|
||||
// but |*handle_passing_info| should be very small (usually/often empty).
|
||||
int target_fd = base::GlobalDescriptors::kBaseDescriptor;
|
||||
while (IsTargetDescriptorUsed(*handle_passing_info, target_fd))
|
||||
target_fd++;
|
||||
|
||||
handle_passing_info->push_back(
|
||||
std::pair<int, int>(client_handle_.get().fd, target_fd));
|
||||
// Log a warning if the command line already has the switch, but "clobber" it
|
||||
// anyway, since it's reasonably likely that all the switches were just copied
|
||||
// from the parent.
|
||||
LOG_IF(WARNING, command_line->HasSwitch(kMojoPlatformChannelHandleSwitch))
|
||||
<< "Child command line already has switch --"
|
||||
<< kMojoPlatformChannelHandleSwitch << "="
|
||||
<< command_line->GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
|
||||
// (Any existing switch won't actually be removed from the command line, but
|
||||
// the last one appended takes precedence.)
|
||||
command_line->AppendSwitchASCII(kMojoPlatformChannelHandleSwitch,
|
||||
base::IntToString(target_fd));
|
||||
}
|
||||
|
||||
} // namespace embedder
|
||||
} // namespace mojo
|
||||
@ -14,14 +14,15 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/edk/embedder/platform_channel_utils_posix.h"
|
||||
#include "mojo/edk/embedder/platform_channel_utils.h"
|
||||
#include "mojo/edk/embedder/platform_handle.h"
|
||||
#include "mojo/edk/embedder/platform_handle_vector.h"
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/test/scoped_test_dir.h"
|
||||
#include "mojo/edk/system/test/scoped_test_dir.h"
|
||||
#include "mojo/edk/test/test_utils.h"
|
||||
#include "mojo/edk/util/scoped_file.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
@ -38,10 +39,10 @@ void WaitReadable(PlatformHandle h) {
|
||||
CHECK_EQ(poll(&pfds, 1, -1), 1);
|
||||
}
|
||||
|
||||
class PlatformChannelPairPosixTest : public testing::Test {
|
||||
class PlatformChannelPairTest : public testing::Test {
|
||||
public:
|
||||
PlatformChannelPairPosixTest() {}
|
||||
~PlatformChannelPairPosixTest() override {}
|
||||
PlatformChannelPairTest() {}
|
||||
~PlatformChannelPairTest() override {}
|
||||
|
||||
void SetUp() override {
|
||||
// Make sure |SIGPIPE| isn't being ignored.
|
||||
@ -58,13 +59,13 @@ class PlatformChannelPairPosixTest : public testing::Test {
|
||||
private:
|
||||
struct sigaction old_action_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairPosixTest);
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairTest);
|
||||
};
|
||||
|
||||
TEST_F(PlatformChannelPairPosixTest, NoSigPipe) {
|
||||
TEST_F(PlatformChannelPairTest, NoSigPipe) {
|
||||
PlatformChannelPair channel_pair;
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle();
|
||||
|
||||
// Write to the client.
|
||||
static const char kHello[] = "hello";
|
||||
@ -102,10 +103,10 @@ TEST_F(PlatformChannelPairPosixTest, NoSigPipe) {
|
||||
PLOG(WARNING) << "write (expected EPIPE)";
|
||||
}
|
||||
|
||||
TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
|
||||
TEST_F(PlatformChannelPairTest, SendReceiveData) {
|
||||
PlatformChannelPair channel_pair;
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle();
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
std::string send_string(1 << i, 'A' + i);
|
||||
@ -126,14 +127,14 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
|
||||
mojo::test::ScopedTestDir test_dir;
|
||||
TEST_F(PlatformChannelPairTest, SendReceiveFDs) {
|
||||
mojo::system::test::ScopedTestDir test_dir;
|
||||
|
||||
static const char kHello[] = "hello";
|
||||
|
||||
PlatformChannelPair channel_pair;
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle();
|
||||
|
||||
// Reduce the number of FDs opened on OS X to avoid test flake.
|
||||
#if defined(OS_MACOSX)
|
||||
@ -152,7 +153,7 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
|
||||
ASSERT_TRUE(fp);
|
||||
ASSERT_EQ(j, fwrite(std::string(j, c).data(), 1, j, fp.get()));
|
||||
platform_handles->push_back(
|
||||
test::PlatformHandleFromFILE(fp.Pass()).release());
|
||||
test::PlatformHandleFromFILE(std::move(fp)).release());
|
||||
ASSERT_TRUE(platform_handles->back().is_valid());
|
||||
}
|
||||
|
||||
@ -189,14 +190,14 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
|
||||
mojo::test::ScopedTestDir test_dir;
|
||||
TEST_F(PlatformChannelPairTest, AppendReceivedFDs) {
|
||||
mojo::system::test::ScopedTestDir test_dir;
|
||||
|
||||
static const char kHello[] = "hello";
|
||||
|
||||
PlatformChannelPair channel_pair;
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle().Pass();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle().Pass();
|
||||
ScopedPlatformHandle server_handle = channel_pair.PassServerHandle();
|
||||
ScopedPlatformHandle client_handle = channel_pair.PassClientHandle();
|
||||
|
||||
const std::string file_contents("hello world");
|
||||
|
||||
@ -207,7 +208,7 @@ TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
|
||||
fwrite(file_contents.data(), 1, file_contents.size(), fp.get()));
|
||||
ScopedPlatformHandleVectorPtr platform_handles(new PlatformHandleVector);
|
||||
platform_handles->push_back(
|
||||
test::PlatformHandleFromFILE(fp.Pass()).release());
|
||||
test::PlatformHandleFromFILE(std::move(fp)).release());
|
||||
ASSERT_TRUE(platform_handles->back().is_valid());
|
||||
|
||||
// Send the FD (+ "hello").
|
||||
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "mojo/edk/embedder/platform_channel_utils_posix.h"
|
||||
#include "mojo/edk/embedder/platform_channel_utils.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_POSIX_H_
|
||||
#define MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_POSIX_H_
|
||||
#ifndef MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_H_
|
||||
#define MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h> // For |ssize_t|.
|
||||
@ -71,4 +71,4 @@ ssize_t PlatformChannelRecvmsg(PlatformHandle h,
|
||||
} // namespace embedder
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_POSIX_H_
|
||||
#endif // MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_H_
|
||||
@ -9,8 +9,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/util/ref_counted.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -34,7 +34,7 @@ class PlatformSharedBufferMapping;
|
||||
//
|
||||
// TODO(vtl): Rectify this with |base::SharedMemory|.
|
||||
class PlatformSharedBuffer
|
||||
: public base::RefCountedThreadSafe<PlatformSharedBuffer> {
|
||||
: public util::RefCountedThreadSafe<PlatformSharedBuffer> {
|
||||
public:
|
||||
// Gets the size of shared buffer (in number of bytes).
|
||||
virtual size_t GetNumBytes() const = 0;
|
||||
@ -65,7 +65,7 @@ class PlatformSharedBuffer
|
||||
virtual ScopedPlatformHandle PassPlatformHandle() = 0;
|
||||
|
||||
protected:
|
||||
friend class base::RefCountedThreadSafe<PlatformSharedBuffer>;
|
||||
friend class util::RefCountedThreadSafe<PlatformSharedBuffer>;
|
||||
|
||||
PlatformSharedBuffer() {}
|
||||
virtual ~PlatformSharedBuffer() {}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
@ -42,8 +43,9 @@ class PlatformSupport {
|
||||
// Gets cryptographically-secure (pseudo)random bytes.
|
||||
virtual void GetCryptoRandomBytes(void* bytes, size_t num_bytes) = 0;
|
||||
|
||||
virtual PlatformSharedBuffer* CreateSharedBuffer(size_t num_bytes) = 0;
|
||||
virtual PlatformSharedBuffer* CreateSharedBufferFromHandle(
|
||||
virtual util::RefPtr<PlatformSharedBuffer> CreateSharedBuffer(
|
||||
size_t num_bytes) = 0;
|
||||
virtual util::RefPtr<PlatformSharedBuffer> CreateSharedBufferFromHandle(
|
||||
size_t num_bytes,
|
||||
ScopedPlatformHandle platform_handle) = 0;
|
||||
|
||||
|
||||
@ -4,44 +4,62 @@
|
||||
|
||||
#include "mojo/edk/embedder/simple_platform_shared_buffer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> // For |fileno()|.
|
||||
#include <sys/mman.h> // For |mmap()|/|munmap()|.
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h> // For |off_t|.
|
||||
#include <unistd.h>
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/sys_info.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/edk/embedder/platform_handle_utils.h"
|
||||
#include "mojo/edk/util/scoped_file.h"
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
#include "third_party/ashmem/ashmem.h"
|
||||
#endif // defined(OS_ANDROID)
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
// We assume that |size_t| and |off_t| (type for |ftruncate()|) fits in a
|
||||
// |uint64_t|.
|
||||
static_assert(sizeof(size_t) <= sizeof(uint64_t), "size_t too big");
|
||||
static_assert(sizeof(off_t) <= sizeof(uint64_t), "off_t too big");
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
|
||||
// SimplePlatformSharedBuffer --------------------------------------------------
|
||||
|
||||
// static
|
||||
SimplePlatformSharedBuffer* SimplePlatformSharedBuffer::Create(
|
||||
RefPtr<SimplePlatformSharedBuffer> SimplePlatformSharedBuffer::Create(
|
||||
size_t num_bytes) {
|
||||
DCHECK_GT(num_bytes, 0u);
|
||||
|
||||
SimplePlatformSharedBuffer* rv = new SimplePlatformSharedBuffer(num_bytes);
|
||||
if (!rv->Init()) {
|
||||
// We can't just delete it directly, due to the "in destructor" (debug)
|
||||
// check.
|
||||
scoped_refptr<SimplePlatformSharedBuffer> deleter(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rv;
|
||||
RefPtr<SimplePlatformSharedBuffer> rv(
|
||||
AdoptRef(new SimplePlatformSharedBuffer(num_bytes)));
|
||||
return rv->Init() ? rv : nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
SimplePlatformSharedBuffer*
|
||||
RefPtr<SimplePlatformSharedBuffer>
|
||||
SimplePlatformSharedBuffer::CreateFromPlatformHandle(
|
||||
size_t num_bytes,
|
||||
ScopedPlatformHandle platform_handle) {
|
||||
DCHECK_GT(num_bytes, 0u);
|
||||
|
||||
SimplePlatformSharedBuffer* rv = new SimplePlatformSharedBuffer(num_bytes);
|
||||
if (!rv->InitFromPlatformHandle(platform_handle.Pass())) {
|
||||
// We can't just delete it directly, due to the "in destructor" (debug)
|
||||
// check.
|
||||
scoped_refptr<SimplePlatformSharedBuffer> deleter(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rv;
|
||||
RefPtr<SimplePlatformSharedBuffer> rv(
|
||||
AdoptRef(new SimplePlatformSharedBuffer(num_bytes)));
|
||||
return rv->InitFromPlatformHandle(std::move(platform_handle)) ? rv : nullptr;
|
||||
}
|
||||
|
||||
size_t SimplePlatformSharedBuffer::GetNumBytes() const {
|
||||
@ -72,7 +90,32 @@ bool SimplePlatformSharedBuffer::IsValidMap(size_t offset, size_t length) {
|
||||
std::unique_ptr<PlatformSharedBufferMapping>
|
||||
SimplePlatformSharedBuffer::MapNoCheck(size_t offset, size_t length) {
|
||||
DCHECK(IsValidMap(offset, length));
|
||||
return MapImpl(offset, length);
|
||||
|
||||
size_t offset_rounding = offset % base::SysInfo::VMAllocationGranularity();
|
||||
size_t real_offset = offset - offset_rounding;
|
||||
size_t real_length = length + offset_rounding;
|
||||
|
||||
// This should hold (since we checked |num_bytes| versus the maximum value of
|
||||
// |off_t| on creation, but it never hurts to be paranoid.
|
||||
DCHECK_LE(static_cast<uint64_t>(real_offset),
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max()));
|
||||
|
||||
void* real_base =
|
||||
mmap(nullptr, real_length, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
handle_.get().fd, static_cast<off_t>(real_offset));
|
||||
// |mmap()| should return |MAP_FAILED| (a.k.a. -1) on error. But it shouldn't
|
||||
// return null either.
|
||||
if (real_base == MAP_FAILED || !real_base) {
|
||||
PLOG(ERROR) << "mmap";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* base = static_cast<char*>(real_base) + offset_rounding;
|
||||
// Note: We can't use |MakeUnique| here, since it's not a friend of
|
||||
// |SimplePlatformSharedBufferMapping| (only we are).
|
||||
return std::unique_ptr<SimplePlatformSharedBufferMapping>(
|
||||
new SimplePlatformSharedBufferMapping(base, length, real_base,
|
||||
real_length));
|
||||
}
|
||||
|
||||
ScopedPlatformHandle SimplePlatformSharedBuffer::DuplicatePlatformHandle() {
|
||||
@ -81,7 +124,7 @@ ScopedPlatformHandle SimplePlatformSharedBuffer::DuplicatePlatformHandle() {
|
||||
|
||||
ScopedPlatformHandle SimplePlatformSharedBuffer::PassPlatformHandle() {
|
||||
DCHECK(HasOneRef());
|
||||
return handle_.Pass();
|
||||
return std::move(handle_);
|
||||
}
|
||||
|
||||
SimplePlatformSharedBuffer::SimplePlatformSharedBuffer(size_t num_bytes)
|
||||
@ -103,5 +146,125 @@ size_t SimplePlatformSharedBufferMapping::GetLength() const {
|
||||
return length_;
|
||||
}
|
||||
|
||||
bool SimplePlatformSharedBuffer::Init() {
|
||||
DCHECK(!handle_.is_valid());
|
||||
|
||||
if (static_cast<uint64_t>(num_bytes_) >
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedPlatformHandle handle;
|
||||
|
||||
// Use ashmem on Android.
|
||||
#if defined(OS_ANDROID)
|
||||
handle.reset(PlatformHandle(ashmem_create_region(nullptr, num_bytes_)));
|
||||
if (!handle.is_valid()) {
|
||||
DPLOG(ERROR) << "ashmem_create_region()";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ashmem_set_prot_region(handle.get().fd, PROT_READ | PROT_WRITE) < 0) {
|
||||
DPLOG(ERROR) << "ashmem_set_prot_region()";
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
|
||||
// TODO(vtl): This is stupid. The implementation of
|
||||
// |CreateAndOpenTemporaryFileInDir()| starts with an FD, |fdopen()|s to get a
|
||||
// |FILE*|, and then we have to |dup(fileno(fp))| to get back to an FD that we
|
||||
// can own. (base/memory/shared_memory_posix.cc does this too, with more
|
||||
// |fstat()|s thrown in for good measure.)
|
||||
base::FilePath shared_buffer_dir;
|
||||
if (!base::GetShmemTempDir(false, &shared_buffer_dir)) {
|
||||
LOG(ERROR) << "Failed to get temporary directory for shared memory";
|
||||
return false;
|
||||
}
|
||||
base::FilePath shared_buffer_file;
|
||||
util::ScopedFILE fp(base::CreateAndOpenTemporaryFileInDir(
|
||||
shared_buffer_dir, &shared_buffer_file));
|
||||
if (!fp) {
|
||||
LOG(ERROR) << "Failed to create/open temporary file for shared memory";
|
||||
return false;
|
||||
}
|
||||
// Note: |unlink()| is not interruptible.
|
||||
if (unlink(shared_buffer_file.value().c_str()) != 0) {
|
||||
PLOG(WARNING) << "unlink";
|
||||
// This isn't "fatal" (e.g., someone else may have unlinked the file first),
|
||||
// so we may as well continue.
|
||||
}
|
||||
|
||||
// Note: |dup()| is not interruptible (but |dup2()|/|dup3()| are).
|
||||
handle.reset(PlatformHandle(dup(fileno(fp.get()))));
|
||||
if (!handle.is_valid()) {
|
||||
PLOG(ERROR) << "dup";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HANDLE_EINTR(
|
||||
ftruncate(handle.get().fd, static_cast<off_t>(num_bytes_))) != 0) {
|
||||
PLOG(ERROR) << "ftruncate";
|
||||
return false;
|
||||
}
|
||||
#endif // defined(OS_ANDROID)
|
||||
|
||||
handle_ = std::move(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimplePlatformSharedBuffer::InitFromPlatformHandle(
|
||||
ScopedPlatformHandle platform_handle) {
|
||||
DCHECK(!handle_.is_valid());
|
||||
|
||||
if (static_cast<uint64_t>(num_bytes_) >
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use ashmem on Android.
|
||||
#if defined(OS_ANDROID)
|
||||
int size = ashmem_get_size_region(platform_handle.get().fd);
|
||||
if (size < 0) {
|
||||
DPLOG(ERROR) << "ashmem_get_size_region()";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(size) != num_bytes_) {
|
||||
LOG(ERROR) << "Shared memory region has the wrong size";
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
struct stat sb = {};
|
||||
// Note: |fstat()| isn't interruptible.
|
||||
if (fstat(platform_handle.get().fd, &sb) != 0) {
|
||||
PLOG(ERROR) << "fstat";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
LOG(ERROR) << "Platform handle not to a regular file";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sb.st_size != static_cast<off_t>(num_bytes_)) {
|
||||
LOG(ERROR) << "Shared memory file has the wrong size";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(vtl): More checks?
|
||||
#endif // defined(OS_ANDROID)
|
||||
|
||||
handle_ = platform_handle.Pass();
|
||||
return true;
|
||||
}
|
||||
|
||||
// SimplePlatformSharedBufferMapping -------------------------------------------
|
||||
|
||||
void SimplePlatformSharedBufferMapping::Unmap() {
|
||||
int result = munmap(real_base_, real_length_);
|
||||
PLOG_IF(ERROR, result != 0) << "munmap";
|
||||
}
|
||||
|
||||
} // namespace embedder
|
||||
} // namespace mojo
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#include "mojo/edk/embedder/platform_shared_buffer.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -18,9 +19,9 @@ class SimplePlatformSharedBuffer final : public PlatformSharedBuffer {
|
||||
public:
|
||||
// Creates a shared buffer of size |num_bytes| bytes (initially zero-filled).
|
||||
// |num_bytes| must be nonzero. Returns null on failure.
|
||||
static SimplePlatformSharedBuffer* Create(size_t num_bytes);
|
||||
static util::RefPtr<SimplePlatformSharedBuffer> Create(size_t num_bytes);
|
||||
|
||||
static SimplePlatformSharedBuffer* CreateFromPlatformHandle(
|
||||
static util::RefPtr<SimplePlatformSharedBuffer> CreateFromPlatformHandle(
|
||||
size_t num_bytes,
|
||||
ScopedPlatformHandle platform_handle);
|
||||
|
||||
@ -39,8 +40,6 @@ class SimplePlatformSharedBuffer final : public PlatformSharedBuffer {
|
||||
explicit SimplePlatformSharedBuffer(size_t num_bytes);
|
||||
~SimplePlatformSharedBuffer() override;
|
||||
|
||||
// Implemented in simple_platform_shared_buffer_{posix,win}.cc:
|
||||
|
||||
// This is called by |Create()| before this object is given to anyone.
|
||||
bool Init();
|
||||
|
||||
@ -49,10 +48,6 @@ class SimplePlatformSharedBuffer final : public PlatformSharedBuffer {
|
||||
// claimed |num_bytes_|.)
|
||||
bool InitFromPlatformHandle(ScopedPlatformHandle platform_handle);
|
||||
|
||||
// The platform-dependent part of |Map()|; doesn't check arguments.
|
||||
std::unique_ptr<PlatformSharedBufferMapping> MapImpl(size_t offset,
|
||||
size_t length);
|
||||
|
||||
const size_t num_bytes_;
|
||||
|
||||
// This is set in |Init()|/|InitFromPlatformHandle()| and never modified
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#include "mojo/edk/embedder/simple_platform_shared_buffer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/mman.h> // For |PROT_...|.
|
||||
#include <sys/types.h> // For |off_t|.
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "third_party/ashmem/ashmem.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
|
||||
// SimplePlatformSharedBuffer --------------------------------------------------
|
||||
|
||||
bool SimplePlatformSharedBuffer::Init() {
|
||||
DCHECK(!handle_.is_valid());
|
||||
|
||||
if (static_cast<uint64_t>(num_bytes_) >
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedPlatformHandle handle(
|
||||
PlatformHandle(ashmem_create_region(nullptr, num_bytes_)));
|
||||
if (!handle.is_valid()) {
|
||||
DPLOG(ERROR) << "ashmem_create_region()";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ashmem_set_prot_region(handle.get().fd, PROT_READ | PROT_WRITE) < 0) {
|
||||
DPLOG(ERROR) << "ashmem_set_prot_region()";
|
||||
return false;
|
||||
}
|
||||
|
||||
handle_ = handle.Pass();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimplePlatformSharedBuffer::InitFromPlatformHandle(
|
||||
ScopedPlatformHandle platform_handle) {
|
||||
DCHECK(!handle_.is_valid());
|
||||
|
||||
if (static_cast<uint64_t>(num_bytes_) >
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int size = ashmem_get_size_region(platform_handle.get().fd);
|
||||
|
||||
if (size < 0) {
|
||||
DPLOG(ERROR) << "ashmem_get_size_region()";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(size) != num_bytes_) {
|
||||
LOG(ERROR) << "Shared memory region has the wrong size";
|
||||
return false;
|
||||
}
|
||||
|
||||
handle_ = platform_handle.Pass();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace embedder
|
||||
} // namespace mojo
|
||||
@ -1,160 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#include "mojo/edk/embedder/simple_platform_shared_buffer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> // For |fileno()|.
|
||||
#include <sys/mman.h> // For |mmap()|/|munmap()|.
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h> // For |off_t|.
|
||||
#include <unistd.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "base/sys_info.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "mojo/edk/util/scoped_file.h"
|
||||
|
||||
// We assume that |size_t| and |off_t| (type for |ftruncate()|) fits in a
|
||||
// |uint64_t|.
|
||||
static_assert(sizeof(size_t) <= sizeof(uint64_t), "size_t too big");
|
||||
static_assert(sizeof(off_t) <= sizeof(uint64_t), "off_t too big");
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
|
||||
// SimplePlatformSharedBuffer --------------------------------------------------
|
||||
|
||||
// The implementation for android uses ashmem to generate the file descriptor
|
||||
// for the shared memory. See simple_platform_shared_buffer_android.cc
|
||||
#if !defined(OS_ANDROID)
|
||||
|
||||
bool SimplePlatformSharedBuffer::Init() {
|
||||
DCHECK(!handle_.is_valid());
|
||||
|
||||
base::ThreadRestrictions::ScopedAllowIO allow_io;
|
||||
|
||||
if (static_cast<uint64_t>(num_bytes_) >
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(vtl): This is stupid. The implementation of
|
||||
// |CreateAndOpenTemporaryFileInDir()| starts with an FD, |fdopen()|s to get a
|
||||
// |FILE*|, and then we have to |dup(fileno(fp))| to get back to an FD that we
|
||||
// can own. (base/memory/shared_memory_posix.cc does this too, with more
|
||||
// |fstat()|s thrown in for good measure.)
|
||||
base::FilePath shared_buffer_dir;
|
||||
if (!base::GetShmemTempDir(false, &shared_buffer_dir)) {
|
||||
LOG(ERROR) << "Failed to get temporary directory for shared memory";
|
||||
return false;
|
||||
}
|
||||
base::FilePath shared_buffer_file;
|
||||
util::ScopedFILE fp(base::CreateAndOpenTemporaryFileInDir(
|
||||
shared_buffer_dir, &shared_buffer_file));
|
||||
if (!fp) {
|
||||
LOG(ERROR) << "Failed to create/open temporary file for shared memory";
|
||||
return false;
|
||||
}
|
||||
// Note: |unlink()| is not interruptible.
|
||||
if (unlink(shared_buffer_file.value().c_str()) != 0) {
|
||||
PLOG(WARNING) << "unlink";
|
||||
// This isn't "fatal" (e.g., someone else may have unlinked the file first),
|
||||
// so we may as well continue.
|
||||
}
|
||||
|
||||
// Note: |dup()| is not interruptible (but |dup2()|/|dup3()| are).
|
||||
ScopedPlatformHandle handle(PlatformHandle(dup(fileno(fp.get()))));
|
||||
if (!handle.is_valid()) {
|
||||
PLOG(ERROR) << "dup";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HANDLE_EINTR(
|
||||
ftruncate(handle.get().fd, static_cast<off_t>(num_bytes_))) != 0) {
|
||||
PLOG(ERROR) << "ftruncate";
|
||||
return false;
|
||||
}
|
||||
|
||||
handle_ = handle.Pass();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimplePlatformSharedBuffer::InitFromPlatformHandle(
|
||||
ScopedPlatformHandle platform_handle) {
|
||||
DCHECK(!handle_.is_valid());
|
||||
|
||||
if (static_cast<uint64_t>(num_bytes_) >
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat sb = {};
|
||||
// Note: |fstat()| isn't interruptible.
|
||||
if (fstat(platform_handle.get().fd, &sb) != 0) {
|
||||
PLOG(ERROR) << "fstat";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
LOG(ERROR) << "Platform handle not to a regular file";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sb.st_size != static_cast<off_t>(num_bytes_)) {
|
||||
LOG(ERROR) << "Shared memory file has the wrong size";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(vtl): More checks?
|
||||
|
||||
handle_ = platform_handle.Pass();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !defined(OS_ANDROID)
|
||||
|
||||
std::unique_ptr<PlatformSharedBufferMapping>
|
||||
SimplePlatformSharedBuffer::MapImpl(size_t offset, size_t length) {
|
||||
size_t offset_rounding = offset % base::SysInfo::VMAllocationGranularity();
|
||||
size_t real_offset = offset - offset_rounding;
|
||||
size_t real_length = length + offset_rounding;
|
||||
|
||||
// This should hold (since we checked |num_bytes| versus the maximum value of
|
||||
// |off_t| on creation, but it never hurts to be paranoid.
|
||||
DCHECK_LE(static_cast<uint64_t>(real_offset),
|
||||
static_cast<uint64_t>(std::numeric_limits<off_t>::max()));
|
||||
|
||||
void* real_base =
|
||||
mmap(nullptr, real_length, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
handle_.get().fd, static_cast<off_t>(real_offset));
|
||||
// |mmap()| should return |MAP_FAILED| (a.k.a. -1) on error. But it shouldn't
|
||||
// return null either.
|
||||
if (real_base == MAP_FAILED || !real_base) {
|
||||
PLOG(ERROR) << "mmap";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* base = static_cast<char*>(real_base) + offset_rounding;
|
||||
// Note: We can't use |MakeUnique| here, since it's not a friend of
|
||||
// |SimplePlatformSharedBufferMapping| (only we are).
|
||||
return std::unique_ptr<SimplePlatformSharedBufferMapping>(
|
||||
new SimplePlatformSharedBufferMapping(base, length, real_base,
|
||||
real_length));
|
||||
}
|
||||
|
||||
// SimplePlatformSharedBufferMapping -------------------------------------------
|
||||
|
||||
void SimplePlatformSharedBufferMapping::Unmap() {
|
||||
int result = munmap(real_base_, real_length_);
|
||||
PLOG_IF(ERROR, result != 0) << "munmap";
|
||||
}
|
||||
|
||||
} // namespace embedder
|
||||
} // namespace mojo
|
||||
@ -6,7 +6,6 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
@ -21,8 +20,7 @@ TEST(SimplePlatformSharedBufferTest, Basic) {
|
||||
const int kFudge = 1234567890;
|
||||
|
||||
// Make some memory.
|
||||
scoped_refptr<SimplePlatformSharedBuffer> buffer(
|
||||
SimplePlatformSharedBuffer::Create(kNumBytes));
|
||||
auto buffer = SimplePlatformSharedBuffer::Create(kNumBytes);
|
||||
ASSERT_TRUE(buffer);
|
||||
|
||||
// Map it all, scribble some stuff, and then unmap it.
|
||||
@ -98,8 +96,7 @@ TEST(SimplePlatformSharedBufferTest, Basic) {
|
||||
// TODO(vtl): Bigger buffers.
|
||||
|
||||
TEST(SimplePlatformSharedBufferTest, InvalidMappings) {
|
||||
scoped_refptr<SimplePlatformSharedBuffer> buffer(
|
||||
SimplePlatformSharedBuffer::Create(100));
|
||||
auto buffer = SimplePlatformSharedBuffer::Create(100);
|
||||
ASSERT_TRUE(buffer);
|
||||
|
||||
// Zero length not allowed.
|
||||
@ -129,8 +126,7 @@ TEST(SimplePlatformSharedBufferTest, TooBig) {
|
||||
// If |size_t| is 32-bit, it's quite possible/likely that |Create()| succeeds
|
||||
// (since it only involves creating a 4 GB file).
|
||||
const size_t kMaxSizeT = std::numeric_limits<size_t>::max();
|
||||
scoped_refptr<SimplePlatformSharedBuffer> buffer(
|
||||
SimplePlatformSharedBuffer::Create(kMaxSizeT));
|
||||
auto buffer = SimplePlatformSharedBuffer::Create(kMaxSizeT);
|
||||
// But, assuming |sizeof(size_t) == sizeof(void*)|, mapping all of it should
|
||||
// always fail.
|
||||
if (buffer)
|
||||
@ -142,8 +138,7 @@ TEST(SimplePlatformSharedBufferTest, TooBig) {
|
||||
// and reuse the same address, in which case we'd have to be more careful about
|
||||
// using the address as the key for unmapping.
|
||||
TEST(SimplePlatformSharedBufferTest, MappingsDistinct) {
|
||||
scoped_refptr<SimplePlatformSharedBuffer> buffer(
|
||||
SimplePlatformSharedBuffer::Create(100));
|
||||
auto buffer = SimplePlatformSharedBuffer::Create(100);
|
||||
std::unique_ptr<PlatformSharedBufferMapping> mapping1(buffer->Map(0, 100));
|
||||
std::unique_ptr<PlatformSharedBufferMapping> mapping2(buffer->Map(0, 100));
|
||||
EXPECT_NE(mapping1->GetBase(), mapping2->GetBase());
|
||||
@ -152,8 +147,7 @@ TEST(SimplePlatformSharedBufferTest, MappingsDistinct) {
|
||||
TEST(SimplePlatformSharedBufferTest, BufferZeroInitialized) {
|
||||
static const size_t kSizes[] = {10, 100, 1000, 10000, 100000};
|
||||
for (size_t i = 0; i < MOJO_ARRAYSIZE(kSizes); i++) {
|
||||
scoped_refptr<SimplePlatformSharedBuffer> buffer(
|
||||
SimplePlatformSharedBuffer::Create(kSizes[i]));
|
||||
auto buffer = SimplePlatformSharedBuffer::Create(kSizes[i]);
|
||||
std::unique_ptr<PlatformSharedBufferMapping> mapping(
|
||||
buffer->Map(0, kSizes[i]));
|
||||
for (size_t j = 0; j < kSizes[i]; j++) {
|
||||
@ -170,8 +164,7 @@ TEST(SimplePlatformSharedBufferTest, MappingsOutliveBuffer) {
|
||||
std::unique_ptr<PlatformSharedBufferMapping> mapping2;
|
||||
|
||||
{
|
||||
scoped_refptr<SimplePlatformSharedBuffer> buffer(
|
||||
SimplePlatformSharedBuffer::Create(100));
|
||||
auto buffer = SimplePlatformSharedBuffer::Create(100);
|
||||
mapping1 = buffer->Map(0, 100);
|
||||
mapping2 = buffer->Map(50, 50);
|
||||
static_cast<char*>(mapping1->GetBase())[50] = 'x';
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include "base/time/time.h"
|
||||
#include "mojo/edk/embedder/simple_platform_shared_buffer.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace embedder {
|
||||
|
||||
@ -20,12 +22,13 @@ void SimplePlatformSupport::GetCryptoRandomBytes(void* bytes,
|
||||
base::RandBytes(bytes, num_bytes);
|
||||
}
|
||||
|
||||
PlatformSharedBuffer* SimplePlatformSupport::CreateSharedBuffer(
|
||||
RefPtr<PlatformSharedBuffer> SimplePlatformSupport::CreateSharedBuffer(
|
||||
size_t num_bytes) {
|
||||
return SimplePlatformSharedBuffer::Create(num_bytes);
|
||||
}
|
||||
|
||||
PlatformSharedBuffer* SimplePlatformSupport::CreateSharedBufferFromHandle(
|
||||
RefPtr<PlatformSharedBuffer>
|
||||
SimplePlatformSupport::CreateSharedBufferFromHandle(
|
||||
size_t num_bytes,
|
||||
ScopedPlatformHandle platform_handle) {
|
||||
return SimplePlatformSharedBuffer::CreateFromPlatformHandle(
|
||||
|
||||
@ -23,8 +23,9 @@ class SimplePlatformSupport final : public PlatformSupport {
|
||||
|
||||
MojoTimeTicks GetTimeTicksNow() override;
|
||||
void GetCryptoRandomBytes(void* bytes, size_t num_bytes) override;
|
||||
PlatformSharedBuffer* CreateSharedBuffer(size_t num_bytes) override;
|
||||
PlatformSharedBuffer* CreateSharedBufferFromHandle(
|
||||
util::RefPtr<PlatformSharedBuffer> CreateSharedBuffer(
|
||||
size_t num_bytes) override;
|
||||
util::RefPtr<PlatformSharedBuffer> CreateSharedBufferFromHandle(
|
||||
size_t num_bytes,
|
||||
ScopedPlatformHandle platform_handle) override;
|
||||
|
||||
|
||||
@ -2,10 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "mojo/edk/embedder/embedder_internal.h"
|
||||
#include "mojo/edk/system/core.h"
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/c/system/buffer.h"
|
||||
#include "mojo/public/c/system/data_pipe.h"
|
||||
#include "mojo/public/c/system/functions.h"
|
||||
@ -16,7 +17,7 @@ using mojo::embedder::internal::g_core;
|
||||
using mojo::system::Core;
|
||||
using mojo::system::Dispatcher;
|
||||
using mojo::system::MakeUserPointer;
|
||||
using mojo::system::RefPtr;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
// Definitions of the system functions, but with an explicit parameter for the
|
||||
// core object rather than using the default singleton. Also includes functions
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("../public/mojo_sdk.gni")
|
||||
import("//testing/test.gni")
|
||||
|
||||
# A mojo_edk_source_set is a mojo_sdk_source_set that does not restrict
|
||||
# external dependencies and understands the following additional variables, all
|
||||
@ -96,6 +97,78 @@ template("mojo_edk_source_set") {
|
||||
}
|
||||
}
|
||||
|
||||
template("mojo_edk_unittests") {
|
||||
test(target_name) {
|
||||
deps = [
|
||||
rebase_path("mojo/edk/system/test:run_all_unittests", ".", mojo_root),
|
||||
]
|
||||
if (defined(invoker.sources)) {
|
||||
sources = invoker.sources
|
||||
}
|
||||
if (defined(invoker.deps)) {
|
||||
foreach(dep, invoker.deps) {
|
||||
# The only deps that are not specified relative to the location of the
|
||||
# Mojo EDK should be on targets within the same file or on a whitelisted
|
||||
# set of external dependencies.
|
||||
# TODO(vtl): Get rid of //base dependencies (and stop allowing it).
|
||||
assert(get_path_info(dep, "dir") == "." || dep == "//testing/gtest" ||
|
||||
dep == "//base")
|
||||
deps += [ dep ]
|
||||
}
|
||||
}
|
||||
if (defined(invoker.mojo_sdk_deps)) {
|
||||
foreach(sdk_dep, invoker.mojo_sdk_deps) {
|
||||
# Check that the SDK dep was not mistakenly given as an absolute path.
|
||||
assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
|
||||
deps += [ rebase_path(sdk_dep, ".", mojo_root) ]
|
||||
}
|
||||
}
|
||||
if (defined(invoker.mojo_edk_deps)) {
|
||||
foreach(edk_dep, invoker.mojo_edk_deps) {
|
||||
# Check that the EDK dep was not mistakenly given as an absolute path.
|
||||
assert(get_path_info(edk_dep, "abspath") != edk_dep)
|
||||
deps += [ rebase_path(edk_dep, ".", mojo_root) ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template("mojo_edk_perftests") {
|
||||
test(target_name) {
|
||||
deps = [
|
||||
rebase_path("mojo/edk/system/test:run_all_perftests", ".", mojo_root),
|
||||
]
|
||||
if (defined(invoker.sources)) {
|
||||
sources = invoker.sources
|
||||
}
|
||||
if (defined(invoker.deps)) {
|
||||
foreach(dep, invoker.deps) {
|
||||
# The only deps that are not specified relative to the location of the
|
||||
# Mojo EDK should be on targets within the same file or on a whitelisted
|
||||
# set of external dependencies.
|
||||
# TODO(vtl): Get rid of //base dependencies (and stop allowing it).
|
||||
assert(get_path_info(dep, "dir") == "." || dep == "//testing/gtest" ||
|
||||
dep == "//base")
|
||||
deps += [ dep ]
|
||||
}
|
||||
}
|
||||
if (defined(invoker.mojo_sdk_deps)) {
|
||||
foreach(sdk_dep, invoker.mojo_sdk_deps) {
|
||||
# Check that the SDK dep was not mistakenly given as an absolute path.
|
||||
assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
|
||||
deps += [ rebase_path(sdk_dep, ".", mojo_root) ]
|
||||
}
|
||||
}
|
||||
if (defined(invoker.mojo_edk_deps)) {
|
||||
foreach(edk_dep, invoker.mojo_edk_deps) {
|
||||
# Check that the EDK dep was not mistakenly given as an absolute path.
|
||||
assert(get_path_info(edk_dep, "abspath") != edk_dep)
|
||||
deps += [ rebase_path(edk_dep, ".", mojo_root) ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Build EDK things with static thread annotation analysis enabled.
|
||||
# TODO(vtl): Should we set this at a higher level?
|
||||
if (is_clang) {
|
||||
|
||||
@ -10,11 +10,8 @@ if (is_android) {
|
||||
import("//build/config/android/rules.gni")
|
||||
}
|
||||
|
||||
# TODO(vtl): Should we get rid of this?
|
||||
config("system_config") {
|
||||
defines = [
|
||||
# Ensures that dependent projects import the core functions on Windows.
|
||||
"MOJO_USE_SYSTEM_IMPL",
|
||||
]
|
||||
}
|
||||
|
||||
component("system") {
|
||||
@ -83,8 +80,6 @@ component("system") {
|
||||
"message_pipe_dispatcher.h",
|
||||
"message_pipe_endpoint.cc",
|
||||
"message_pipe_endpoint.h",
|
||||
"mutex.cc",
|
||||
"mutex.h",
|
||||
"options_validation.h",
|
||||
"platform_handle_dispatcher.cc",
|
||||
"platform_handle_dispatcher.h",
|
||||
@ -94,10 +89,6 @@ component("system") {
|
||||
"raw_channel.cc",
|
||||
"raw_channel.h",
|
||||
"raw_channel_posix.cc",
|
||||
"ref_counted.h",
|
||||
"ref_counted_internal.h",
|
||||
"ref_ptr.h",
|
||||
"ref_ptr_internal.h",
|
||||
"remote_consumer_data_pipe_impl.cc",
|
||||
"remote_consumer_data_pipe_impl.h",
|
||||
"remote_data_pipe_ack.h",
|
||||
@ -109,17 +100,16 @@ component("system") {
|
||||
"simple_dispatcher.h",
|
||||
"slave_connection_manager.cc",
|
||||
"slave_connection_manager.h",
|
||||
"thread_annotations.h",
|
||||
"transport_data.cc",
|
||||
"transport_data.h",
|
||||
"unique_identifier.cc",
|
||||
"unique_identifier.h",
|
||||
"waitable_event.cc",
|
||||
"waitable_event.h",
|
||||
"waiter.cc",
|
||||
"waiter.h",
|
||||
]
|
||||
|
||||
defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
|
||||
|
||||
all_dependent_configs = [ ":system_config" ]
|
||||
|
||||
public_deps = [
|
||||
@ -147,29 +137,9 @@ group("tests") {
|
||||
]
|
||||
}
|
||||
|
||||
mojo_edk_source_set("test_utils") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"test_utils.cc",
|
||||
"test_utils.h",
|
||||
]
|
||||
|
||||
mojo_sdk_public_deps = [
|
||||
"mojo/public/c/system",
|
||||
"mojo/public/cpp/system",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
]
|
||||
|
||||
mojo_edk_deps = [ "mojo/edk/embedder:platform" ]
|
||||
}
|
||||
|
||||
test("mojo_system_unittests") {
|
||||
mojo_edk_unittests("mojo_system_unittests") {
|
||||
sources = [
|
||||
# TODO(vtl): This should be in its own mojo_edk_unittests target.
|
||||
"../test/multiprocess_test_helper_unittest.cc",
|
||||
"awakable_list_unittest.cc",
|
||||
"channel_endpoint_id_unittest.cc",
|
||||
@ -196,21 +166,17 @@ test("mojo_system_unittests") {
|
||||
"message_pipe_test_utils.h",
|
||||
"message_pipe_unittest.cc",
|
||||
"multiprocess_message_pipe_unittest.cc",
|
||||
"mutex_unittest.cc",
|
||||
"options_validation_unittest.cc",
|
||||
"platform_handle_dispatcher_unittest.cc",
|
||||
"raw_channel_unittest.cc",
|
||||
"ref_counted_unittest.cc",
|
||||
"remote_data_pipe_impl_unittest.cc",
|
||||
"remote_message_pipe_unittest.cc",
|
||||
"run_all_unittests.cc",
|
||||
"shared_buffer_dispatcher_unittest.cc",
|
||||
"simple_dispatcher_unittest.cc",
|
||||
"test_channel_endpoint_client.cc",
|
||||
"test_channel_endpoint_client.h",
|
||||
"test_utils_unittest.cc",
|
||||
"thread_annotations_unittest.cc",
|
||||
"unique_identifier_unittest.cc",
|
||||
"waitable_event_unittest.cc",
|
||||
"waiter_test_utils.cc",
|
||||
"waiter_test_utils.h",
|
||||
"waiter_unittest.cc",
|
||||
@ -218,33 +184,41 @@ test("mojo_system_unittests") {
|
||||
|
||||
deps = [
|
||||
":system",
|
||||
":test_utils",
|
||||
"../embedder:embedder_unittests",
|
||||
"../test:test_support",
|
||||
"../util",
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//testing/gtest",
|
||||
]
|
||||
|
||||
allow_circular_includes_from = [ "../embedder:embedder_unittests" ]
|
||||
mojo_edk_deps = [
|
||||
# TODO(vtl): Add separate mojo_edk_unittests targets for these.
|
||||
"mojo/edk/embedder:unittests",
|
||||
"mojo/edk/system/test:unittests",
|
||||
"mojo/edk/util:unittests",
|
||||
|
||||
"mojo/edk/system/test",
|
||||
"mojo/edk/test:test_support",
|
||||
"mojo/edk/util",
|
||||
]
|
||||
}
|
||||
|
||||
test("mojo_system_perftests") {
|
||||
mojo_edk_perftests("mojo_system_perftests") {
|
||||
sources = [
|
||||
"message_pipe_perftest.cc",
|
||||
"message_pipe_test_utils.cc",
|
||||
"message_pipe_test_utils.h",
|
||||
"ref_counted_perftest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":system",
|
||||
":test_utils",
|
||||
"../test:test_support",
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//base/test:test_support_perf",
|
||||
"//testing/gtest",
|
||||
]
|
||||
|
||||
mojo_edk_deps = [
|
||||
# TODO(vtl): Add separate test targets for this.
|
||||
"mojo/edk/util:perftests",
|
||||
|
||||
"mojo/edk/system/test",
|
||||
"mojo/edk/system/test:perf",
|
||||
"mojo/edk/test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
@ -3,14 +3,15 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
// NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a
|
||||
// heavily-loaded system). Sorry. |test::EpsilonDeadline()| may be increased to
|
||||
// heavily-loaded system). Sorry. |test::EpsilonTimeout()| may be increased to
|
||||
// increase tolerance and reduce observed flakiness (though doing so reduces the
|
||||
// meaningfulness of the test).
|
||||
|
||||
#include "mojo/edk/system/awakable_list.h"
|
||||
|
||||
#include "mojo/edk/system/handle_signals_state.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/sleep.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
#include "mojo/edk/system/waiter_test_utils.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
@ -53,7 +54,7 @@ TEST(AwakableListTest, BasicCancel) {
|
||||
test::SimpleWaiterThread thread(&result, &context);
|
||||
awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
|
||||
thread.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
awakable_list.CancelAll();
|
||||
} // Join |thread|.
|
||||
EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
|
||||
@ -100,7 +101,7 @@ TEST(AwakableListTest, BasicAwakeSatisfied) {
|
||||
test::SimpleWaiterThread thread(&result, &context);
|
||||
awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
|
||||
thread.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
MOJO_HANDLE_SIGNAL_READABLE,
|
||||
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
|
||||
@ -146,7 +147,7 @@ TEST(AwakableListTest, BasicAwakeUnsatisfiable) {
|
||||
test::SimpleWaiterThread thread(&result, &context);
|
||||
awakable_list.Add(thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3);
|
||||
thread.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_WRITABLE));
|
||||
awakable_list.Remove(thread.waiter());
|
||||
@ -176,7 +177,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
test::SimpleWaiterThread thread2(&result2, &context2);
|
||||
awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 2);
|
||||
thread2.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
awakable_list.CancelAll();
|
||||
} // Join threads.
|
||||
EXPECT_EQ(MOJO_RESULT_CANCELLED, result1);
|
||||
@ -193,7 +194,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
test::SimpleWaiterThread thread2(&result2, &context2);
|
||||
awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 4);
|
||||
thread2.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
MOJO_HANDLE_SIGNAL_READABLE,
|
||||
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
|
||||
@ -214,7 +215,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
test::SimpleWaiterThread thread2(&result2, &context2);
|
||||
awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 6);
|
||||
thread2.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
MOJO_HANDLE_SIGNAL_NONE, MOJO_HANDLE_SIGNAL_READABLE));
|
||||
awakable_list.Remove(thread2.waiter());
|
||||
@ -232,7 +233,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
awakable_list.Add(thread1.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 7);
|
||||
thread1.Start();
|
||||
|
||||
test::Sleep(1 * test::EpsilonDeadline());
|
||||
test::Sleep(1 * test::EpsilonTimeout());
|
||||
|
||||
// Should do nothing.
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
@ -243,7 +244,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
awakable_list.Add(thread2.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 8);
|
||||
thread2.Start();
|
||||
|
||||
test::Sleep(1 * test::EpsilonDeadline());
|
||||
test::Sleep(1 * test::EpsilonTimeout());
|
||||
|
||||
// Awake #1.
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
@ -251,7 +252,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE));
|
||||
awakable_list.Remove(thread1.waiter());
|
||||
|
||||
test::Sleep(1 * test::EpsilonDeadline());
|
||||
test::Sleep(1 * test::EpsilonTimeout());
|
||||
|
||||
test::SimpleWaiterThread thread3(&result3, &context3);
|
||||
awakable_list.Add(thread3.waiter(), MOJO_HANDLE_SIGNAL_WRITABLE, 9);
|
||||
@ -261,7 +262,7 @@ TEST(AwakableListTest, MultipleAwakables) {
|
||||
awakable_list.Add(thread4.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 10);
|
||||
thread4.Start();
|
||||
|
||||
test::Sleep(1 * test::EpsilonDeadline());
|
||||
test::Sleep(1 * test::EpsilonTimeout());
|
||||
|
||||
// Awake #2 and #3 for unsatisfiability.
|
||||
awakable_list.AwakeForStateChange(HandleSignalsState(
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
#include "mojo/edk/system/endpoint_relayer.h"
|
||||
#include "mojo/edk/system/transport_data.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -16,10 +16,11 @@
|
||||
#include "mojo/edk/system/channel_endpoint_id.h"
|
||||
#include "mojo/edk/system/incoming_endpoint.h"
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
#include "mojo/edk/system/ref_counted.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_counted.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
@ -50,10 +51,10 @@ class MessageInTransitQueue;
|
||||
// |ChannelEndpointClient| (e.g., |MessagePipe|), |ChannelEndpoint|, |Channel|.
|
||||
// Thus |Channel| may not call into |ChannelEndpoint| with |Channel|'s lock
|
||||
// held.
|
||||
class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
class Channel final : public util::RefCountedThreadSafe<Channel>,
|
||||
public RawChannel::Delegate {
|
||||
public:
|
||||
// Note: Use |MakeRefCounted<Channel>()|.
|
||||
// Note: Use |util::MakeRefCounted<Channel>()|.
|
||||
|
||||
// This must be called on the creation thread before any other methods are
|
||||
// called, and before references to this object are given to any other
|
||||
@ -85,7 +86,7 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
//
|
||||
// (Bootstrapping is symmetric: Both sides call this, which will establish the
|
||||
// first connection across a channel.)
|
||||
void SetBootstrapEndpoint(RefPtr<ChannelEndpoint>&& endpoint);
|
||||
void SetBootstrapEndpoint(util::RefPtr<ChannelEndpoint>&& endpoint);
|
||||
|
||||
// Like |SetBootstrapEndpoint()|, but with explicitly-specified local and
|
||||
// remote IDs.
|
||||
@ -93,7 +94,7 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
// (Bootstrapping is still symmetric, though the sides should obviously
|
||||
// interchange local and remote IDs. This can be used to allow multiple
|
||||
// "bootstrap" endpoints, though this is really most useful for testing.)
|
||||
void SetBootstrapEndpointWithIds(RefPtr<ChannelEndpoint>&& endpoint,
|
||||
void SetBootstrapEndpointWithIds(util::RefPtr<ChannelEndpoint>&& endpoint,
|
||||
ChannelEndpointId local_id,
|
||||
ChannelEndpointId remote_id);
|
||||
|
||||
@ -149,14 +150,15 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
MessageInTransitQueue* message_queue);
|
||||
// This one returns the |ChannelEndpoint| for the serialized endpoint (which
|
||||
// can be used by, e.g., a |ProxyMessagePipeEndpoint|.
|
||||
RefPtr<ChannelEndpoint> SerializeEndpointWithLocalPeer(
|
||||
util::RefPtr<ChannelEndpoint> SerializeEndpointWithLocalPeer(
|
||||
void* destination,
|
||||
MessageInTransitQueue* message_queue,
|
||||
RefPtr<ChannelEndpointClient>&& endpoint_client,
|
||||
util::RefPtr<ChannelEndpointClient>&& endpoint_client,
|
||||
unsigned endpoint_client_port);
|
||||
void SerializeEndpointWithRemotePeer(void* destination,
|
||||
MessageInTransitQueue* message_queue,
|
||||
RefPtr<ChannelEndpoint>&& peer_endpoint);
|
||||
void SerializeEndpointWithRemotePeer(
|
||||
void* destination,
|
||||
MessageInTransitQueue* message_queue,
|
||||
util::RefPtr<ChannelEndpoint>&& peer_endpoint);
|
||||
|
||||
// Deserializes an endpoint that was sent from the peer |Channel| (using
|
||||
// |SerializeEndpoint...()|. |source| should be (a copy of) the data that
|
||||
@ -164,7 +166,7 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
// |GetSerializedEndpointSize()| bytes. This returns the deserialized
|
||||
// |IncomingEndpoint| (which can be converted into a |MessagePipe|) or null on
|
||||
// error.
|
||||
RefPtr<IncomingEndpoint> DeserializeEndpoint(const void* source);
|
||||
util::RefPtr<IncomingEndpoint> DeserializeEndpoint(const void* source);
|
||||
|
||||
// See |RawChannel::GetSerializedPlatformHandleSize()|.
|
||||
size_t GetSerializedPlatformHandleSize() const;
|
||||
@ -224,7 +226,8 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
// for which |is_remote()| returns true).
|
||||
//
|
||||
// TODO(vtl): Maybe limit the number of attached message pipes.
|
||||
ChannelEndpointId AttachAndRunEndpoint(RefPtr<ChannelEndpoint>&& endpoint);
|
||||
ChannelEndpointId AttachAndRunEndpoint(
|
||||
util::RefPtr<ChannelEndpoint>&& endpoint);
|
||||
|
||||
// Helper to send channel control messages. Returns true on success. Callable
|
||||
// from any thread.
|
||||
@ -246,7 +249,7 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
// TODO(vtl): Annotate the above rule using |MOJO_ACQUIRED_{BEFORE,AFTER}()|,
|
||||
// once clang actually checks such annotations.
|
||||
// https://github.com/domokit/mojo/issues/313
|
||||
mutable Mutex mutex_;
|
||||
mutable util::Mutex mutex_;
|
||||
|
||||
std::unique_ptr<RawChannel> raw_channel_ MOJO_GUARDED_BY(mutex_);
|
||||
bool is_running_ MOJO_GUARDED_BY(mutex_);
|
||||
@ -257,7 +260,7 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
ChannelManager* channel_manager_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
using IdToEndpointMap =
|
||||
std::unordered_map<ChannelEndpointId, RefPtr<ChannelEndpoint>>;
|
||||
std::unordered_map<ChannelEndpointId, util::RefPtr<ChannelEndpoint>>;
|
||||
// Map from local IDs to endpoints. If the endpoint is null, this means that
|
||||
// we're just waiting for the remove ack before removing the entry.
|
||||
IdToEndpointMap local_id_to_endpoint_map_ MOJO_GUARDED_BY(mutex_);
|
||||
@ -265,7 +268,7 @@ class Channel final : public RefCountedThreadSafe<Channel>,
|
||||
LocalChannelEndpointIdGenerator local_id_generator_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
using IdToIncomingEndpointMap =
|
||||
std::unordered_map<ChannelEndpointId, RefPtr<IncomingEndpoint>>;
|
||||
std::unordered_map<ChannelEndpointId, util::RefPtr<IncomingEndpoint>>;
|
||||
// Map from local IDs to incoming endpoints (i.e., those received inside other
|
||||
// messages, but not yet claimed via |DeserializeEndpoint()|).
|
||||
IdToIncomingEndpointMap incoming_endpoints_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
#include "mojo/edk/system/channel_endpoint_client.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -9,9 +9,10 @@
|
||||
|
||||
#include "mojo/edk/system/channel_endpoint_id.h"
|
||||
#include "mojo/edk/system/message_in_transit_queue.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_counted.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_counted.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -109,9 +110,10 @@ class MessageInTransit;
|
||||
// simultaneously, and both sides send "remove" messages). In that
|
||||
// case, it must still remain alive until it receives the "remove
|
||||
// ack" (and it must ack the "remove" message that it received).
|
||||
class ChannelEndpoint final : public RefCountedThreadSafe<ChannelEndpoint> {
|
||||
class ChannelEndpoint final
|
||||
: public util::RefCountedThreadSafe<ChannelEndpoint> {
|
||||
public:
|
||||
// Note: Use |MakeRefCounted<ChannelEndpoint>()|.
|
||||
// Note: Use |util::MakeRefCounted<ChannelEndpoint>()|.
|
||||
|
||||
// Methods called by |ChannelEndpointClient|:
|
||||
|
||||
@ -127,7 +129,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe<ChannelEndpoint> {
|
||||
// This returns true in the typical case, and false if this endpoint has been
|
||||
// detached from the channel, in which case the caller should probably call
|
||||
// its (new) client's |OnDetachFromChannel()|.
|
||||
bool ReplaceClient(RefPtr<ChannelEndpointClient>&& client,
|
||||
bool ReplaceClient(util::RefPtr<ChannelEndpointClient>&& client,
|
||||
unsigned client_port);
|
||||
|
||||
// Called before the |ChannelEndpointClient| gives up its reference to this
|
||||
@ -161,7 +163,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe<ChannelEndpoint> {
|
||||
// in which case |message_queue| should not be null. In that case, this
|
||||
// endpoint will simply send queued messages upon being attached to a
|
||||
// |Channel| and immediately detach itself.
|
||||
ChannelEndpoint(RefPtr<ChannelEndpointClient>&& client,
|
||||
ChannelEndpoint(util::RefPtr<ChannelEndpointClient>&& client,
|
||||
unsigned client_port,
|
||||
MessageInTransitQueue* message_queue = nullptr);
|
||||
|
||||
@ -177,7 +179,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe<ChannelEndpoint> {
|
||||
// this does not call |channel_->DetachEndpoint()|.
|
||||
void DieNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
Mutex mutex_;
|
||||
util::Mutex mutex_;
|
||||
|
||||
enum class State {
|
||||
// |AttachAndRun()| has not been called yet (|channel_| is null).
|
||||
@ -192,9 +194,9 @@ class ChannelEndpoint final : public RefCountedThreadSafe<ChannelEndpoint> {
|
||||
|
||||
// |client_| must be valid whenever it is non-null. Before |*client_| gives up
|
||||
// its reference to this object, it must call |DetachFromClient()|.
|
||||
// NOTE: This is a |RefPtr<>|, rather than a raw pointer, since the |Channel|
|
||||
// needs to keep the client (e.g., |MessagePipe|) alive for the "proxy-proxy"
|
||||
// case.
|
||||
// NOTE: This is a |util:RefPtr<>|, rather than a raw pointer, since the
|
||||
// |Channel| needs to keep the client (e.g., |MessagePipe|) alive for the
|
||||
// "proxy-proxy" case.
|
||||
// WARNING: |ChannelEndpointClient| methods must not be called under |mutex_|.
|
||||
// Thus to make such a call, a reference must first be taken under |mutex_|
|
||||
// and the lock released.
|
||||
@ -204,7 +206,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe<ChannelEndpoint> {
|
||||
// WARNING: Beware of interactions with |ReplaceClient()|. By the time the
|
||||
// call is made, the client may have changed. This must be detected and dealt
|
||||
// with.
|
||||
RefPtr<ChannelEndpointClient> client_ MOJO_GUARDED_BY(mutex_);
|
||||
util::RefPtr<ChannelEndpointClient> client_ MOJO_GUARDED_BY(mutex_);
|
||||
unsigned client_port_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
// |channel_| must be valid whenever it is non-null. Before |*channel_| gives
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#ifndef MOJO_EDK_SYSTEM_CHANNEL_ENDPOINT_CLIENT_H_
|
||||
#define MOJO_EDK_SYSTEM_CHANNEL_ENDPOINT_CLIENT_H_
|
||||
|
||||
#include "mojo/edk/system/ref_counted.h"
|
||||
#include "mojo/edk/util/ref_counted.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -30,7 +30,7 @@ class MessageInTransit;
|
||||
// |ChannelEndpoint| has apparently relinquished its pointer to the
|
||||
// |ChannelEndpointClient|).
|
||||
class ChannelEndpointClient
|
||||
: public RefCountedThreadSafe<ChannelEndpointClient> {
|
||||
: public util::RefCountedThreadSafe<ChannelEndpointClient> {
|
||||
public:
|
||||
// Called by |ChannelEndpoint| in response to its |OnReadMessage()|, which is
|
||||
// called by |Channel| when it receives a message for the |ChannelEndpoint|.
|
||||
|
||||
@ -7,15 +7,17 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "mojo/edk/system/channel_test_base.h"
|
||||
#include "mojo/edk/system/message_in_transit_queue.h"
|
||||
#include "mojo/edk/system/message_in_transit_test_utils.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/test_channel_endpoint_client.h"
|
||||
#include "mojo/edk/system/waitable_event.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -59,7 +61,7 @@ TEST_F(ChannelEndpointTest, Basic) {
|
||||
channel(1)->SetBootstrapEndpoint(endpoint1.Clone());
|
||||
|
||||
// We'll receive a message on channel/client 0.
|
||||
base::WaitableEvent read_event(true, false);
|
||||
ManualResetWaitableEvent read_event;
|
||||
client0->SetReadEvent(&read_event);
|
||||
|
||||
// Make a test message.
|
||||
@ -69,14 +71,14 @@ TEST_F(ChannelEndpointTest, Basic) {
|
||||
// Check that our test utility works (at least in one direction).
|
||||
test::VerifyTestMessage(send_message.get(), message_id);
|
||||
|
||||
// Event shouldn't be signalled yet.
|
||||
EXPECT_FALSE(read_event.IsSignaled());
|
||||
// Event shouldn't be signaled yet.
|
||||
EXPECT_FALSE(read_event.IsSignaledForTest());
|
||||
|
||||
// Send it through channel/endpoint 1.
|
||||
EXPECT_TRUE(endpoint1->EnqueueMessage(std::move(send_message)));
|
||||
|
||||
// Wait to receive it.
|
||||
EXPECT_TRUE(read_event.TimedWait(TestTimeouts::tiny_timeout()));
|
||||
EXPECT_FALSE(read_event.WaitWithTimeout(test::TinyTimeout()));
|
||||
client0->SetReadEvent(nullptr);
|
||||
|
||||
// Check the received message.
|
||||
@ -113,10 +115,10 @@ TEST_F(ChannelEndpointTest, Prequeued) {
|
||||
EXPECT_TRUE(endpoint1->EnqueueMessage(test::MakeTestMessage(6)));
|
||||
|
||||
// Wait for the messages.
|
||||
base::WaitableEvent read_event(true, false);
|
||||
ManualResetWaitableEvent read_event;
|
||||
client0->SetReadEvent(&read_event);
|
||||
for (size_t i = 0; client0->NumMessages() < 6 && i < 6; i++) {
|
||||
EXPECT_TRUE(read_event.TimedWait(TestTimeouts::tiny_timeout()));
|
||||
EXPECT_FALSE(read_event.WaitWithTimeout(test::TinyTimeout()));
|
||||
read_event.Reset();
|
||||
}
|
||||
client0->SetReadEvent(nullptr);
|
||||
|
||||
@ -12,6 +12,10 @@
|
||||
#include "mojo/edk/system/channel_endpoint.h"
|
||||
#include "mojo/edk/system/message_pipe_dispatcher.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -10,12 +10,12 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/edk/embedder/platform_task_runner.h"
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/system/channel_id.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace base {
|
||||
@ -71,7 +71,7 @@ class ChannelManager {
|
||||
// constructor). |channel_id| should be a valid |ChannelId| (i.e., nonzero)
|
||||
// not "assigned" to any other |Channel| being managed by this
|
||||
// |ChannelManager|.
|
||||
RefPtr<MessagePipeDispatcher> CreateChannelOnIOThread(
|
||||
util::RefPtr<MessagePipeDispatcher> CreateChannelOnIOThread(
|
||||
ChannelId channel_id,
|
||||
embedder::ScopedPlatformHandle platform_handle);
|
||||
|
||||
@ -79,7 +79,7 @@ class ChannelManager {
|
||||
// pipe. Returns the newly-created |Channel|.
|
||||
// TODO(vtl): Maybe get rid of the others (and bootstrap message pipes in
|
||||
// general).
|
||||
RefPtr<Channel> CreateChannelWithoutBootstrapOnIOThread(
|
||||
util::RefPtr<Channel> CreateChannelWithoutBootstrapOnIOThread(
|
||||
ChannelId channel_id,
|
||||
embedder::ScopedPlatformHandle platform_handle);
|
||||
|
||||
@ -87,14 +87,14 @@ class ChannelManager {
|
||||
// completion, will call |callback| (using |callback_thread_task_runner| if it
|
||||
// is non-null, else on the I/O thread). Note: This will always post a task to
|
||||
// the I/O thread, even if called from that thread.
|
||||
RefPtr<MessagePipeDispatcher> CreateChannel(
|
||||
util::RefPtr<MessagePipeDispatcher> CreateChannel(
|
||||
ChannelId channel_id,
|
||||
embedder::ScopedPlatformHandle platform_handle,
|
||||
const base::Closure& callback,
|
||||
embedder::PlatformTaskRunnerRefPtr callback_thread_task_runner);
|
||||
|
||||
// Gets the |Channel| with the given ID (which must exist).
|
||||
RefPtr<Channel> GetChannel(ChannelId channel_id) const;
|
||||
util::RefPtr<Channel> GetChannel(ChannelId channel_id) const;
|
||||
|
||||
// Informs the channel manager (and thus channel) that it will be shutdown
|
||||
// soon (by calling |ShutdownChannel()|). Calling this is optional (and may in
|
||||
@ -129,10 +129,10 @@ class ChannelManager {
|
||||
// Used by |CreateChannelOnIOThread()| and |CreateChannelHelper()|. Called on
|
||||
// the I/O thread. |bootstrap_channel_endpoint| is optional and may be null.
|
||||
// Returns the newly-created |Channel|.
|
||||
RefPtr<Channel> CreateChannelOnIOThreadHelper(
|
||||
util::RefPtr<Channel> CreateChannelOnIOThreadHelper(
|
||||
ChannelId channel_id,
|
||||
embedder::ScopedPlatformHandle platform_handle,
|
||||
RefPtr<ChannelEndpoint>&& bootstrap_channel_endpoint);
|
||||
util::RefPtr<ChannelEndpoint>&& bootstrap_channel_endpoint);
|
||||
|
||||
// Used by |CreateChannel()|. Called on the I/O thread.
|
||||
// TODO(vtl): |bootstrap_channel_endpoint| should be an rvalue reference, but
|
||||
@ -140,7 +140,7 @@ class ChannelManager {
|
||||
void CreateChannelHelper(
|
||||
ChannelId channel_id,
|
||||
embedder::ScopedPlatformHandle platform_handle,
|
||||
RefPtr<ChannelEndpoint> bootstrap_channel_endpoint,
|
||||
util::RefPtr<ChannelEndpoint> bootstrap_channel_endpoint,
|
||||
const base::Closure& callback,
|
||||
embedder::PlatformTaskRunnerRefPtr callback_thread_task_runner);
|
||||
|
||||
@ -153,9 +153,10 @@ class ChannelManager {
|
||||
// TODO(vtl): Annotate the above rule using |MOJO_ACQUIRED_{BEFORE,AFTER}()|,
|
||||
// once clang actually checks such annotations.
|
||||
// https://github.com/domokit/mojo/issues/313
|
||||
mutable Mutex mutex_;
|
||||
mutable util::Mutex mutex_;
|
||||
|
||||
using ChannelIdToChannelMap = std::unordered_map<ChannelId, RefPtr<Channel>>;
|
||||
using ChannelIdToChannelMap =
|
||||
std::unordered_map<ChannelId, util::RefPtr<Channel>>;
|
||||
ChannelIdToChannelMap channels_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(ChannelManager);
|
||||
|
||||
@ -14,10 +14,12 @@
|
||||
#include "mojo/edk/system/channel.h"
|
||||
#include "mojo/edk/system/channel_endpoint.h"
|
||||
#include "mojo/edk/system/message_pipe_dispatcher.h"
|
||||
#include "mojo/edk/test/simple_test_thread.h"
|
||||
#include "mojo/edk/system/test/simple_test_thread.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -53,12 +55,16 @@ TEST_F(ChannelManagerTest, Basic) {
|
||||
|
||||
RefPtr<Channel> ch = channel_manager().GetChannel(id);
|
||||
EXPECT_TRUE(ch);
|
||||
// |ChannelManager| should have a ref.
|
||||
EXPECT_FALSE(ch->HasOneRef());
|
||||
|
||||
channel_manager().WillShutdownChannel(id);
|
||||
// |ChannelManager| should still have a ref.
|
||||
EXPECT_FALSE(ch->HasOneRef());
|
||||
|
||||
channel_manager().ShutdownChannelOnIOThread(id);
|
||||
// |ChannelManager| should have given up its ref.
|
||||
ch->AssertHasOneRef();
|
||||
EXPECT_TRUE(ch->HasOneRef());
|
||||
|
||||
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
|
||||
}
|
||||
@ -83,18 +89,19 @@ TEST_F(ChannelManagerTest, TwoChannels) {
|
||||
// Calling |WillShutdownChannel()| multiple times (on |id1|) is okay.
|
||||
channel_manager().WillShutdownChannel(id1);
|
||||
channel_manager().WillShutdownChannel(id1);
|
||||
EXPECT_FALSE(ch1->HasOneRef());
|
||||
// Not calling |WillShutdownChannel()| (on |id2|) is okay too.
|
||||
|
||||
channel_manager().ShutdownChannelOnIOThread(id1);
|
||||
ch1->AssertHasOneRef();
|
||||
EXPECT_TRUE(ch1->HasOneRef());
|
||||
channel_manager().ShutdownChannelOnIOThread(id2);
|
||||
ch2->AssertHasOneRef();
|
||||
EXPECT_TRUE(ch2->HasOneRef());
|
||||
|
||||
EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
|
||||
EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
|
||||
}
|
||||
|
||||
class OtherThread : public mojo::test::SimpleTestThread {
|
||||
class OtherThread : public test::SimpleTestThread {
|
||||
public:
|
||||
// Note: There should be no other refs to the channel identified by
|
||||
// |channel_id| outside the channel manager.
|
||||
@ -115,8 +122,12 @@ class OtherThread : public mojo::test::SimpleTestThread {
|
||||
|
||||
// You can use any unique, nonzero value as the ID.
|
||||
RefPtr<Channel> ch = channel_manager_->GetChannel(channel_id_);
|
||||
// |ChannelManager| should have a ref.
|
||||
EXPECT_FALSE(ch->HasOneRef());
|
||||
|
||||
channel_manager_->WillShutdownChannel(channel_id_);
|
||||
// |ChannelManager| should still have a ref.
|
||||
EXPECT_FALSE(ch->HasOneRef());
|
||||
|
||||
{
|
||||
base::MessageLoop message_loop;
|
||||
|
||||
@ -11,12 +11,14 @@
|
||||
#include "mojo/edk/embedder/platform_channel_pair.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace test {
|
||||
|
||||
ChannelTestBase::ChannelTestBase()
|
||||
: io_thread_(mojo::test::TestIOThread::StartMode::AUTO) {}
|
||||
: io_thread_(TestIOThread::StartMode::AUTO) {}
|
||||
|
||||
ChannelTestBase::~ChannelTestBase() {
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
#include "base/bind.h"
|
||||
#include "mojo/edk/embedder/simple_platform_support.h"
|
||||
#include "mojo/edk/system/channel.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/test/test_io_thread.h"
|
||||
#include "mojo/edk/system/test/test_io_thread.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
@ -43,17 +43,17 @@ class ChannelTestBase : public testing::Test {
|
||||
void ShutdownChannelOnIOThread(unsigned i);
|
||||
void ShutdownAndReleaseChannelOnIOThread(unsigned i);
|
||||
|
||||
mojo::test::TestIOThread* io_thread() { return &io_thread_; }
|
||||
TestIOThread* io_thread() { return &io_thread_; }
|
||||
Channel* channel(unsigned i) { return channels_[i].get(); }
|
||||
RefPtr<Channel>* mutable_channel(unsigned i) { return &channels_[i]; }
|
||||
util::RefPtr<Channel>* mutable_channel(unsigned i) { return &channels_[i]; }
|
||||
|
||||
private:
|
||||
void SetUpOnIOThread();
|
||||
|
||||
embedder::SimplePlatformSupport platform_support_;
|
||||
mojo::test::TestIOThread io_thread_;
|
||||
TestIOThread io_thread_;
|
||||
std::unique_ptr<RawChannel> raw_channels_[2];
|
||||
RefPtr<Channel> channels_[2];
|
||||
util::RefPtr<Channel> channels_[2];
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(ChannelTestBase);
|
||||
};
|
||||
|
||||
@ -10,9 +10,10 @@
|
||||
#include "mojo/edk/system/channel_endpoint_id.h"
|
||||
#include "mojo/edk/system/channel_test_base.h"
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
@ -29,7 +30,7 @@ TEST_F(ChannelTest, InitShutdown) {
|
||||
PostMethodToIOThreadAndWait(&ChannelTest::ShutdownChannelOnIOThread, 0);
|
||||
|
||||
// Okay to destroy |Channel| on not-the-I/O-thread.
|
||||
channel(0)->AssertHasOneRef();
|
||||
EXPECT_TRUE(channel(0)->HasOneRef());
|
||||
*mutable_channel(0) = nullptr;
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@ TEST_F(ChannelTest, CloseBeforeRun) {
|
||||
|
||||
PostMethodToIOThreadAndWait(&ChannelTest::ShutdownChannelOnIOThread, 0);
|
||||
|
||||
channel(0)->AssertHasOneRef();
|
||||
EXPECT_TRUE(channel(0)->HasOneRef());
|
||||
}
|
||||
|
||||
// ChannelTest.ShutdownAfterAttachAndRun ---------------------------------------
|
||||
@ -79,7 +80,7 @@ TEST_F(ChannelTest, ShutdownAfterAttach) {
|
||||
|
||||
mp->Close(0);
|
||||
|
||||
channel(0)->AssertHasOneRef();
|
||||
EXPECT_TRUE(channel(0)->HasOneRef());
|
||||
}
|
||||
|
||||
// ChannelTest.WaitAfterAttachRunAndShutdown -----------------------------------
|
||||
@ -105,7 +106,7 @@ TEST_F(ChannelTest, WaitAfterAttachRunAndShutdown) {
|
||||
|
||||
mp->Close(0);
|
||||
|
||||
channel(0)->AssertHasOneRef();
|
||||
EXPECT_TRUE(channel(0)->HasOneRef());
|
||||
}
|
||||
|
||||
// ChannelTest.EndpointChannelShutdownRace -------------------------------------
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
#include "mojo/edk/system/connection_identifier.h"
|
||||
#include "mojo/edk/system/process_identifier.h"
|
||||
#include "mojo/edk/system/thread_annotations.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
@ -26,6 +26,9 @@
|
||||
#include "mojo/public/c/system/macros.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -11,8 +11,9 @@
|
||||
#include "mojo/edk/system/handle_table.h"
|
||||
#include "mojo/edk/system/mapping_table.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/buffer.h"
|
||||
#include "mojo/public/c/system/data_pipe.h"
|
||||
#include "mojo/public/c/system/message_pipe.h"
|
||||
@ -48,7 +49,7 @@ class Core {
|
||||
|
||||
// Looks up the dispatcher for the given handle. Returns null if the handle is
|
||||
// invalid.
|
||||
RefPtr<Dispatcher> GetDispatcher(MojoHandle handle);
|
||||
util::RefPtr<Dispatcher> GetDispatcher(MojoHandle handle);
|
||||
|
||||
// Like |GetDispatcher()|, but also removes the handle from the handle table.
|
||||
// On success, gets the dispatcher for a given handle (which should not be
|
||||
@ -57,7 +58,7 @@ class Core {
|
||||
// |MOJO_RESULT_INVALID_ARGUMENT| if there's no dispatcher for the given
|
||||
// handle or |MOJO_RESULT_BUSY| if the handle is marked as busy.)
|
||||
MojoResult GetAndRemoveDispatcher(MojoHandle handle,
|
||||
RefPtr<Dispatcher>* dispatcher);
|
||||
util::RefPtr<Dispatcher>* dispatcher);
|
||||
|
||||
// Watches on the given handle for the given signals, calling |callback| when
|
||||
// a signal is satisfied or when all signals become unsatisfiable. |callback|
|
||||
@ -175,10 +176,10 @@ class Core {
|
||||
|
||||
// TODO(vtl): |handle_table_mutex_| should be a reader-writer lock (if only we
|
||||
// had them).
|
||||
Mutex handle_table_mutex_;
|
||||
util::Mutex handle_table_mutex_;
|
||||
HandleTable handle_table_ MOJO_GUARDED_BY(handle_table_mutex_);
|
||||
|
||||
Mutex mapping_table_mutex_;
|
||||
util::Mutex mapping_table_mutex_;
|
||||
MappingTable mapping_table_ MOJO_GUARDED_BY(mapping_table_mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(Core);
|
||||
|
||||
@ -11,9 +11,12 @@
|
||||
#include "mojo/edk/system/core.h"
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace test {
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
#define MOJO_EDK_SYSTEM_CORE_TEST_BASE_H_
|
||||
|
||||
#include "mojo/edk/embedder/simple_platform_support.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
@ -88,7 +89,7 @@ class CoreTestBase_MockHandleInfo {
|
||||
void AwakableWasAdded(Awakable*);
|
||||
|
||||
private:
|
||||
mutable Mutex mutex_;
|
||||
mutable util::Mutex mutex_;
|
||||
unsigned ctor_call_count_ MOJO_GUARDED_BY(mutex_);
|
||||
unsigned dtor_call_count_ MOJO_GUARDED_BY(mutex_);
|
||||
unsigned close_call_count_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
#include "base/bind.h"
|
||||
#include "mojo/edk/system/awakable.h"
|
||||
#include "mojo/edk/system/core_test_base.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/sleep.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -30,7 +30,7 @@ TEST_F(CoreTest, GetTimeTicksNow) {
|
||||
const MojoTimeTicks start = core()->GetTimeTicksNow();
|
||||
EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
|
||||
<< "GetTimeTicksNow should return nonzero value";
|
||||
test::Sleep(test::DeadlineFromMilliseconds(15));
|
||||
test::SleepMilliseconds(15u);
|
||||
const MojoTimeTicks finish = core()->GetTimeTicksNow();
|
||||
// Allow for some fuzz in sleep.
|
||||
EXPECT_GE((finish - start), static_cast<MojoTimeTicks>(8000))
|
||||
|
||||
@ -25,6 +25,9 @@
|
||||
#include "mojo/edk/system/remote_producer_data_pipe_impl.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -14,9 +14,9 @@
|
||||
#include "mojo/edk/system/channel_endpoint_client.h"
|
||||
#include "mojo/edk/system/handle_signals_state.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/thread_annotations.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/data_pipe.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
@ -58,7 +58,7 @@ class DataPipe final : public ChannelEndpointClient {
|
||||
// |ValidateOptions()|. In particular: |struct_size| is ignored (so
|
||||
// |validated_options| must be the current version of the struct) and
|
||||
// |capacity_num_bytes| must be nonzero.
|
||||
static RefPtr<DataPipe> CreateLocal(
|
||||
static util::RefPtr<DataPipe> CreateLocal(
|
||||
const MojoCreateDataPipeOptions& validated_options);
|
||||
|
||||
// Creates a data pipe with a remote producer and a local consumer, using an
|
||||
@ -67,10 +67,10 @@ class DataPipe final : public ChannelEndpointClient {
|
||||
// |channel_endpoint| is null, this will create a "half-open" data pipe (with
|
||||
// only the consumer open). Note that this may fail, in which case it returns
|
||||
// null.
|
||||
static RefPtr<DataPipe> CreateRemoteProducerFromExisting(
|
||||
static util::RefPtr<DataPipe> CreateRemoteProducerFromExisting(
|
||||
const MojoCreateDataPipeOptions& validated_options,
|
||||
MessageInTransitQueue* message_queue,
|
||||
RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
util::RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
|
||||
// Creates a data pipe with a local producer and a remote consumer, using an
|
||||
// existing |ChannelEndpoint| (whose |ReplaceClient()| it'll call) and taking
|
||||
@ -78,11 +78,11 @@ class DataPipe final : public ChannelEndpointClient {
|
||||
// (|message_queue| may be null). If |channel_endpoint| is null, this will
|
||||
// create a "half-open" data pipe (with only the producer open). Note that
|
||||
// this may fail, in which case it returns null.
|
||||
static RefPtr<DataPipe> CreateRemoteConsumerFromExisting(
|
||||
static util::RefPtr<DataPipe> CreateRemoteConsumerFromExisting(
|
||||
const MojoCreateDataPipeOptions& validated_options,
|
||||
size_t consumer_num_bytes,
|
||||
MessageInTransitQueue* message_queue,
|
||||
RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
util::RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
|
||||
// Used by |DataPipeProducerDispatcher::Deserialize()|. Returns true on
|
||||
// success (in which case, |*data_pipe| is set appropriately) and false on
|
||||
@ -90,7 +90,7 @@ class DataPipe final : public ChannelEndpointClient {
|
||||
static bool ProducerDeserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size,
|
||||
RefPtr<DataPipe>* data_pipe);
|
||||
util::RefPtr<DataPipe>* data_pipe);
|
||||
|
||||
// Used by |DataPipeConsumerDispatcher::Deserialize()|. Returns true on
|
||||
// success (in which case, |*data_pipe| is set appropriately) and false on
|
||||
@ -98,7 +98,7 @@ class DataPipe final : public ChannelEndpointClient {
|
||||
static bool ConsumerDeserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size,
|
||||
RefPtr<DataPipe>* data_pipe);
|
||||
util::RefPtr<DataPipe>* data_pipe);
|
||||
|
||||
// These are called by the producer dispatcher to implement its methods of
|
||||
// corresponding names.
|
||||
@ -265,7 +265,7 @@ class DataPipe final : public ChannelEndpointClient {
|
||||
MSVC_SUPPRESS_WARNING(4324)
|
||||
const MojoCreateDataPipeOptions validated_options_;
|
||||
|
||||
mutable Mutex mutex_;
|
||||
mutable util::Mutex mutex_;
|
||||
// *Known* state of producer or consumer.
|
||||
bool producer_open_ MOJO_GUARDED_BY(mutex_);
|
||||
bool consumer_open_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
#include "mojo/edk/system/data_pipe.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
#define MOJO_EDK_SYSTEM_DATA_PIPE_CONSUMER_DISPATCHER_H_
|
||||
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -19,21 +20,20 @@ class DataPipe;
|
||||
// thread-safe.
|
||||
class DataPipeConsumerDispatcher final : public Dispatcher {
|
||||
public:
|
||||
static RefPtr<DataPipeConsumerDispatcher> Create() {
|
||||
static util::RefPtr<DataPipeConsumerDispatcher> Create() {
|
||||
return AdoptRef(new DataPipeConsumerDispatcher());
|
||||
}
|
||||
|
||||
// Must be called before any other methods.
|
||||
void Init(RefPtr<DataPipe>&& data_pipe) MOJO_NOT_THREAD_SAFE;
|
||||
void Init(util::RefPtr<DataPipe>&& data_pipe) MOJO_NOT_THREAD_SAFE;
|
||||
|
||||
// |Dispatcher| public methods:
|
||||
Type GetType() const override;
|
||||
|
||||
// The "opposite" of |SerializeAndClose()|. (Typically this is called by
|
||||
// |Dispatcher::Deserialize()|.)
|
||||
static RefPtr<DataPipeConsumerDispatcher> Deserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size);
|
||||
static util::RefPtr<DataPipeConsumerDispatcher>
|
||||
Deserialize(Channel* channel, const void* source, size_t size);
|
||||
|
||||
// Get access to the |DataPipe| for testing.
|
||||
DataPipe* GetDataPipeForTest();
|
||||
@ -45,7 +45,8 @@ class DataPipeConsumerDispatcher final : public Dispatcher {
|
||||
// |Dispatcher| protected methods:
|
||||
void CancelAllAwakablesNoLock() override;
|
||||
void CloseImplNoLock() override;
|
||||
RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock() override;
|
||||
util::RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock()
|
||||
override;
|
||||
MojoResult ReadDataImplNoLock(UserPointer<void> elements,
|
||||
UserPointer<uint32_t> num_bytes,
|
||||
MojoReadDataFlags flags) override;
|
||||
@ -73,7 +74,7 @@ class DataPipeConsumerDispatcher final : public Dispatcher {
|
||||
bool IsBusyNoLock() const override;
|
||||
|
||||
// This will be null if closed.
|
||||
RefPtr<DataPipe> data_pipe_ MOJO_GUARDED_BY(mutex());
|
||||
util::RefPtr<DataPipe> data_pipe_ MOJO_GUARDED_BY(mutex());
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(DataPipeConsumerDispatcher);
|
||||
};
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include "mojo/edk/system/data_pipe.h"
|
||||
#include "mojo/edk/system/handle_signals_state.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/thread_annotations.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/data_pipe.h"
|
||||
#include "mojo/public/c/system/macros.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
|
||||
@ -25,13 +25,17 @@
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/sleep.h"
|
||||
#include "mojo/edk/system/test/test_io_thread.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
#include "mojo/edk/test/test_io_thread.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -223,7 +227,7 @@ class LocalDataPipeImplTestHelper : public DataPipeImplTestHelper {
|
||||
class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper {
|
||||
public:
|
||||
RemoteDataPipeImplTestHelper()
|
||||
: io_thread_(mojo::test::TestIOThread::StartMode::AUTO) {}
|
||||
: io_thread_(test::TestIOThread::StartMode::AUTO) {}
|
||||
~RemoteDataPipeImplTestHelper() override {}
|
||||
|
||||
void SetUp() override {
|
||||
@ -279,7 +283,7 @@ class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper {
|
||||
transport.End();
|
||||
}
|
||||
uint32_t context = 0;
|
||||
ASSERT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context));
|
||||
ASSERT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionTimeout(), &context));
|
||||
EXPECT_EQ(987u, context);
|
||||
HandleSignalsState hss = HandleSignalsState();
|
||||
message_pipe(dest_i)->RemoveAwakable(0, &waiter, &hss);
|
||||
@ -299,7 +303,7 @@ class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper {
|
||||
ASSERT_EQ(1u, read_dispatchers.size());
|
||||
ASSERT_EQ(1u, read_num_dispatchers);
|
||||
ASSERT_TRUE(read_dispatchers[0]);
|
||||
read_dispatchers[0]->AssertHasOneRef();
|
||||
EXPECT_TRUE(read_dispatchers[0]->HasOneRef());
|
||||
|
||||
*to_receive = read_dispatchers[0];
|
||||
}
|
||||
@ -344,7 +348,7 @@ class RemoteDataPipeImplTestHelper : public DataPipeImplTestHelper {
|
||||
}
|
||||
|
||||
embedder::SimplePlatformSupport platform_support_;
|
||||
mojo::test::TestIOThread io_thread_;
|
||||
test::TestIOThread io_thread_;
|
||||
RefPtr<Channel> channels_[2];
|
||||
RefPtr<MessagePipe> message_pipes_[2];
|
||||
|
||||
@ -372,7 +376,7 @@ class RemoteProducerDataPipeImplTestHelper
|
||||
SendDispatcher(0, to_send, &to_receive);
|
||||
// |to_send| should have been closed. This is |DCHECK()|ed when it is
|
||||
// destroyed.
|
||||
to_send->AssertHasOneRef();
|
||||
EXPECT_TRUE(to_send->HasOneRef());
|
||||
to_send = nullptr;
|
||||
|
||||
ASSERT_EQ(Dispatcher::Type::DATA_PIPE_PRODUCER, to_receive->GetType());
|
||||
@ -421,7 +425,7 @@ class RemoteConsumerDataPipeImplTestHelper
|
||||
SendDispatcher(0, to_send, &to_receive);
|
||||
// |to_send| should have been closed. This is |DCHECK()|ed when it is
|
||||
// destroyed.
|
||||
to_send->AssertHasOneRef();
|
||||
EXPECT_TRUE(to_send->HasOneRef());
|
||||
to_send = nullptr;
|
||||
|
||||
ASSERT_EQ(Dispatcher::Type::DATA_PIPE_CONSUMER, to_receive->GetType());
|
||||
@ -475,7 +479,7 @@ class RemoteProducerDataPipeImplTestHelper2
|
||||
SendDispatcher(0, to_send, &to_receive);
|
||||
// |to_send| should have been closed. This is |DCHECK()|ed when it is
|
||||
// destroyed.
|
||||
to_send->AssertHasOneRef();
|
||||
EXPECT_TRUE(to_send->HasOneRef());
|
||||
to_send = nullptr;
|
||||
ASSERT_EQ(Dispatcher::Type::DATA_PIPE_PRODUCER, to_receive->GetType());
|
||||
to_send = RefPtr<DataPipeProducerDispatcher>(
|
||||
@ -486,7 +490,7 @@ class RemoteProducerDataPipeImplTestHelper2
|
||||
SendDispatcher(1, to_send, &to_receive);
|
||||
// |producer_dispatcher_| should have been closed. This is |DCHECK()|ed when
|
||||
// it is destroyed.
|
||||
to_send->AssertHasOneRef();
|
||||
EXPECT_TRUE(to_send->HasOneRef());
|
||||
to_send = nullptr;
|
||||
|
||||
ASSERT_EQ(Dispatcher::Type::DATA_PIPE_PRODUCER, to_receive->GetType());
|
||||
@ -522,7 +526,7 @@ class RemoteConsumerDataPipeImplTestHelper2
|
||||
SendDispatcher(0, to_send, &to_receive);
|
||||
// |to_send| should have been closed. This is |DCHECK()|ed when it is
|
||||
// destroyed.
|
||||
to_send->AssertHasOneRef();
|
||||
EXPECT_TRUE(to_send->HasOneRef());
|
||||
to_send = nullptr;
|
||||
ASSERT_EQ(Dispatcher::Type::DATA_PIPE_CONSUMER, to_receive->GetType());
|
||||
to_send = RefPtr<DataPipeConsumerDispatcher>(
|
||||
@ -533,7 +537,7 @@ class RemoteConsumerDataPipeImplTestHelper2
|
||||
SendDispatcher(1, to_send, &to_receive);
|
||||
// |consumer_dispatcher_| should have been closed. This is |DCHECK()|ed when
|
||||
// it is destroyed.
|
||||
to_send->AssertHasOneRef();
|
||||
EXPECT_TRUE(to_send->HasOneRef());
|
||||
to_send = nullptr;
|
||||
|
||||
ASSERT_EQ(Dispatcher::Type::DATA_PIPE_CONSUMER, to_receive->GetType());
|
||||
@ -652,7 +656,7 @@ TYPED_TEST(DataPipeImplTest, SimpleReadWrite) {
|
||||
|
||||
// Wait.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionTimeout(), &context));
|
||||
EXPECT_EQ(123u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -805,7 +809,7 @@ TYPED_TEST(DataPipeImplTest, BasicProducerWaiting) {
|
||||
|
||||
// Wait for data to become available to the consumer.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, cwaiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, cwaiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(1234u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&cwaiter, &hss);
|
||||
@ -856,7 +860,7 @@ TYPED_TEST(DataPipeImplTest, BasicProducerWaiting) {
|
||||
|
||||
// Waiting should now succeed.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, pwaiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, pwaiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(78u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&pwaiter, &hss);
|
||||
@ -900,7 +904,7 @@ TYPED_TEST(DataPipeImplTest, BasicProducerWaiting) {
|
||||
|
||||
// Waiting should succeed.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, pwaiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, pwaiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(90u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&pwaiter, &hss);
|
||||
@ -928,7 +932,7 @@ TYPED_TEST(DataPipeImplTest, BasicProducerWaiting) {
|
||||
// It should now be never-writable.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
||||
pwaiter.Wait(test::TinyDeadline(), &context));
|
||||
pwaiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(12u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&pwaiter, &hss);
|
||||
@ -963,7 +967,7 @@ TYPED_TEST(DataPipeImplTest, PeerClosedProducerWaiting) {
|
||||
|
||||
// It should be signaled.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(12u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&waiter, &hss);
|
||||
@ -998,7 +1002,7 @@ TYPED_TEST(DataPipeImplTest, PeerClosedConsumerWaiting) {
|
||||
|
||||
// It should be signaled.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(12u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -1048,7 +1052,7 @@ TYPED_TEST(DataPipeImplTest, BasicConsumerWaiting) {
|
||||
|
||||
// Wait for readability (needed for remote cases).
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(34u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -1120,7 +1124,7 @@ TYPED_TEST(DataPipeImplTest, BasicConsumerWaiting) {
|
||||
|
||||
// Waiting should now succeed.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(90u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -1152,7 +1156,7 @@ TYPED_TEST(DataPipeImplTest, BasicConsumerWaiting) {
|
||||
|
||||
// Wait for the peer closed signal.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(12u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -1223,7 +1227,7 @@ TYPED_TEST(DataPipeImplTest, ConsumerWaitingTwoPhase) {
|
||||
|
||||
// Wait for readability (needed for remote cases).
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(12u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -1280,7 +1284,7 @@ TYPED_TEST(DataPipeImplTest, ConsumerWaitingTwoPhase) {
|
||||
// Should be never-readable.
|
||||
context = 0;
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
||||
waiter.Wait(test::TinyDeadline(), &context));
|
||||
waiter.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(56u, context);
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
@ -1356,7 +1360,7 @@ TYPED_TEST(DataPipeImplTest, BasicTwoPhaseWaiting) {
|
||||
hss.satisfiable_signals);
|
||||
|
||||
// It should become readable.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, cwaiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, cwaiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&cwaiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -1485,7 +1489,7 @@ TYPED_TEST(DataPipeImplTest, AllOrNone) {
|
||||
// available at once (except that in current implementations, with reasonable
|
||||
// limits, it will). Eventually, we'll be able to wait for a specified amount
|
||||
// of data to become available.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -1545,7 +1549,7 @@ TYPED_TEST(DataPipeImplTest, AllOrNone) {
|
||||
if (num_bytes >= 10u * sizeof(int32_t))
|
||||
break;
|
||||
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
}
|
||||
EXPECT_EQ(10u * sizeof(int32_t), num_bytes);
|
||||
|
||||
@ -1596,7 +1600,7 @@ TYPED_TEST(DataPipeImplTest, AllOrNone) {
|
||||
this->ProducerClose();
|
||||
|
||||
// Wait.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
|
||||
@ -1686,7 +1690,7 @@ TYPED_TEST(DataPipeImplTest, WrapAround) {
|
||||
|
||||
// Wait for data.
|
||||
// TODO(vtl): (See corresponding TODO in AllOrNone.)
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -1732,7 +1736,7 @@ TYPED_TEST(DataPipeImplTest, WrapAround) {
|
||||
EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, result);
|
||||
}
|
||||
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
}
|
||||
EXPECT_EQ(90u, total_num_bytes);
|
||||
|
||||
@ -1745,7 +1749,7 @@ TYPED_TEST(DataPipeImplTest, WrapAround) {
|
||||
if (num_bytes >= 100u)
|
||||
break;
|
||||
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
}
|
||||
EXPECT_EQ(100u, num_bytes);
|
||||
|
||||
@ -1823,7 +1827,7 @@ TYPED_TEST(DataPipeImplTest, WriteCloseProducerRead) {
|
||||
if (num_bytes >= 2u * kTestDataSize)
|
||||
break;
|
||||
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
}
|
||||
EXPECT_EQ(2u * kTestDataSize, num_bytes);
|
||||
|
||||
@ -1898,7 +1902,7 @@ TYPED_TEST(DataPipeImplTest, TwoPhaseWriteReadCloseConsumer) {
|
||||
|
||||
// Wait for data.
|
||||
// TODO(vtl): (See corresponding TODO in AllOrNone.)
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -1924,7 +1928,7 @@ TYPED_TEST(DataPipeImplTest, TwoPhaseWriteReadCloseConsumer) {
|
||||
this->ConsumerClose();
|
||||
|
||||
// Wait for producer to know that the consumer is closed.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
||||
@ -2016,7 +2020,7 @@ TYPED_TEST(DataPipeImplTest, WriteCloseProducerReadNoData) {
|
||||
|
||||
// Wait. (Note that once the consumer knows that the producer is closed, it
|
||||
// must also know about all the data that was sent.)
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
|
||||
@ -2095,7 +2099,7 @@ TYPED_TEST(DataPipeImplTest, WriteReadCloseProducerWaitNoData) {
|
||||
EXPECT_EQ(kTestDataSize, num_bytes);
|
||||
|
||||
// Wait.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -2122,7 +2126,7 @@ TYPED_TEST(DataPipeImplTest, WriteReadCloseProducerWaitNoData) {
|
||||
|
||||
// Wait.
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
||||
waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
||||
@ -2164,7 +2168,7 @@ TYPED_TEST(DataPipeImplTest, BeginReadCloseProducerWaitEndReadNoData) {
|
||||
EXPECT_EQ(kTestDataSize, num_bytes);
|
||||
|
||||
// Wait.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -2190,7 +2194,7 @@ TYPED_TEST(DataPipeImplTest, BeginReadCloseProducerWaitEndReadNoData) {
|
||||
this->ProducerClose();
|
||||
|
||||
// Wait for producer close to be detected.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
||||
@ -2208,7 +2212,7 @@ TYPED_TEST(DataPipeImplTest, BeginReadCloseProducerWaitEndReadNoData) {
|
||||
|
||||
// Wait.
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
||||
waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
||||
@ -2260,7 +2264,7 @@ TYPED_TEST(DataPipeImplTest, BeginWriteCloseConsumerWaitEndWrite) {
|
||||
// Note: If we didn't wait for the consumer close to be detected before
|
||||
// completing the two-phase write, wait might succeed (in the remote cases).
|
||||
// This is because the first |Awake()| "wins".
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter1.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter1.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&waiter1, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
||||
@ -2271,7 +2275,7 @@ TYPED_TEST(DataPipeImplTest, BeginWriteCloseConsumerWaitEndWrite) {
|
||||
|
||||
// Wait.
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
|
||||
waiter2.Wait(test::TinyDeadline(), nullptr));
|
||||
waiter2.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ProducerRemoveAwakable(&waiter2, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
|
||||
@ -2307,7 +2311,7 @@ TYPED_TEST(DataPipeImplTest, TwoPhaseMoreInvalidArguments) {
|
||||
|
||||
// Wait a bit, to make sure that if a signal were (incorrectly) sent, it'd
|
||||
// have time to propagate.
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
|
||||
// Still no data.
|
||||
num_bytes = 1000u;
|
||||
@ -2329,7 +2333,7 @@ TYPED_TEST(DataPipeImplTest, TwoPhaseMoreInvalidArguments) {
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, this->ProducerEndWriteData(0u));
|
||||
|
||||
// Wait a bit (as above).
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
|
||||
// Still no data.
|
||||
num_bytes = 1000u;
|
||||
@ -2351,7 +2355,7 @@ TYPED_TEST(DataPipeImplTest, TwoPhaseMoreInvalidArguments) {
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, this->ProducerEndWriteData(0u));
|
||||
|
||||
// Wait a bit (as above).
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
|
||||
// Still no data.
|
||||
num_bytes = 1000u;
|
||||
@ -2374,7 +2378,7 @@ TYPED_TEST(DataPipeImplTest, TwoPhaseMoreInvalidArguments) {
|
||||
|
||||
// Wait for data.
|
||||
// TODO(vtl): (See corresponding TODO in AllOrNone.)
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::TinyTimeout(), nullptr));
|
||||
hss = HandleSignalsState();
|
||||
this->ConsumerRemoveAwakable(&waiter, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
|
||||
@ -2467,7 +2471,7 @@ TYPED_TEST(DataPipeImplTest, WriteCloseProducerTwoPhaseReadAllData) {
|
||||
if (num_bytes >= kTestDataSize)
|
||||
break;
|
||||
|
||||
test::Sleep(test::EpsilonDeadline());
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
}
|
||||
EXPECT_EQ(kTestDataSize, num_bytes);
|
||||
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
#include "mojo/edk/system/data_pipe.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
#define MOJO_EDK_SYSTEM_DATA_PIPE_PRODUCER_DISPATCHER_H_
|
||||
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -19,21 +20,20 @@ class DataPipe;
|
||||
// thread-safe.
|
||||
class DataPipeProducerDispatcher final : public Dispatcher {
|
||||
public:
|
||||
static RefPtr<DataPipeProducerDispatcher> Create() {
|
||||
static util::RefPtr<DataPipeProducerDispatcher> Create() {
|
||||
return AdoptRef(new DataPipeProducerDispatcher());
|
||||
}
|
||||
|
||||
// Must be called before any other methods.
|
||||
void Init(RefPtr<DataPipe>&& data_pipe) MOJO_NOT_THREAD_SAFE;
|
||||
void Init(util::RefPtr<DataPipe>&& data_pipe) MOJO_NOT_THREAD_SAFE;
|
||||
|
||||
// |Dispatcher| public methods:
|
||||
Type GetType() const override;
|
||||
|
||||
// The "opposite" of |SerializeAndClose()|. (Typically this is called by
|
||||
// |Dispatcher::Deserialize()|.)
|
||||
static RefPtr<DataPipeProducerDispatcher> Deserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size);
|
||||
static util::RefPtr<DataPipeProducerDispatcher>
|
||||
Deserialize(Channel* channel, const void* source, size_t size);
|
||||
|
||||
// Get access to the |DataPipe| for testing.
|
||||
DataPipe* GetDataPipeForTest();
|
||||
@ -45,7 +45,8 @@ class DataPipeProducerDispatcher final : public Dispatcher {
|
||||
// |Dispatcher| protected methods:
|
||||
void CancelAllAwakablesNoLock() override;
|
||||
void CloseImplNoLock() override;
|
||||
RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock() override;
|
||||
util::RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock()
|
||||
override;
|
||||
MojoResult WriteDataImplNoLock(UserPointer<const void> elements,
|
||||
UserPointer<uint32_t> num_bytes,
|
||||
MojoWriteDataFlags flags) override;
|
||||
@ -73,7 +74,7 @@ class DataPipeProducerDispatcher final : public Dispatcher {
|
||||
bool IsBusyNoLock() const override;
|
||||
|
||||
// This will be null if closed.
|
||||
RefPtr<DataPipe> data_pipe_ MOJO_GUARDED_BY(mutex());
|
||||
util::RefPtr<DataPipe> data_pipe_ MOJO_GUARDED_BY(mutex());
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(DataPipeProducerDispatcher);
|
||||
};
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
#include "mojo/edk/system/platform_handle_dispatcher.h"
|
||||
#include "mojo/edk/system/shared_buffer_dispatcher.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -15,9 +15,10 @@
|
||||
#include "mojo/edk/embedder/platform_handle_vector.h"
|
||||
#include "mojo/edk/system/handle_signals_state.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_counted.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_counted.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/buffer.h"
|
||||
#include "mojo/public/c/system/data_pipe.h"
|
||||
#include "mojo/public/c/system/message_pipe.h"
|
||||
@ -42,7 +43,7 @@ class ProxyMessagePipeEndpoint;
|
||||
class TransportData;
|
||||
class Awakable;
|
||||
|
||||
using DispatcherVector = std::vector<RefPtr<Dispatcher>>;
|
||||
using DispatcherVector = std::vector<util::RefPtr<Dispatcher>>;
|
||||
|
||||
namespace test {
|
||||
|
||||
@ -56,7 +57,7 @@ DispatcherTransport DispatcherTryStartTransport(Dispatcher* dispatcher);
|
||||
// object is thread-safe, with its state being protected by a single mutex
|
||||
// |mutex_|, which is also made available to implementation subclasses (via the
|
||||
// |mutex()| method).
|
||||
class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
class Dispatcher : public util::RefCountedThreadSafe<Dispatcher> {
|
||||
public:
|
||||
enum class Type {
|
||||
UNKNOWN = 0,
|
||||
@ -114,7 +115,7 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
// new handle on success).
|
||||
MojoResult DuplicateBufferHandle(
|
||||
UserPointer<const MojoDuplicateBufferHandleOptions> options,
|
||||
RefPtr<Dispatcher>* new_dispatcher);
|
||||
util::RefPtr<Dispatcher>* new_dispatcher);
|
||||
MojoResult MapBuffer(
|
||||
uint64_t offset,
|
||||
uint64_t num_bytes,
|
||||
@ -204,7 +205,7 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
// Deserialization API.
|
||||
// Note: This "clears" (i.e., reset to the invalid handle) any platform
|
||||
// handles that it takes ownership of.
|
||||
static RefPtr<Dispatcher> Deserialize(
|
||||
static util::RefPtr<Dispatcher> Deserialize(
|
||||
Channel* channel,
|
||||
int32_t type,
|
||||
const void* source,
|
||||
@ -222,7 +223,8 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
virtual void CancelAllAwakablesNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
virtual void CloseImplNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
virtual RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock()
|
||||
virtual util::RefPtr<Dispatcher>
|
||||
CreateEquivalentDispatcherAndCloseImplNoLock()
|
||||
MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_) = 0;
|
||||
|
||||
// These are to be overridden by subclasses (if necessary). They are never
|
||||
@ -261,7 +263,8 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
virtual MojoResult DuplicateBufferHandleImplNoLock(
|
||||
UserPointer<const MojoDuplicateBufferHandleOptions> options,
|
||||
RefPtr<Dispatcher>* new_dispatcher) MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
util::RefPtr<Dispatcher>* new_dispatcher)
|
||||
MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
virtual MojoResult MapBufferImplNoLock(
|
||||
uint64_t offset,
|
||||
uint64_t num_bytes,
|
||||
@ -308,7 +311,7 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
// handle from being sent over a message pipe (with status "busy").
|
||||
virtual bool IsBusyNoLock() const MOJO_SHARED_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
Mutex& mutex() const MOJO_LOCK_RETURNED(mutex_) { return mutex_; }
|
||||
util::Mutex& mutex() const MOJO_LOCK_RETURNED(mutex_) { return mutex_; }
|
||||
|
||||
private:
|
||||
FRIEND_REF_COUNTED_THREAD_SAFE(Dispatcher);
|
||||
@ -325,7 +328,7 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
// dispatcher will look as though it was closed, but the resource it
|
||||
// represents will be assigned to the new dispatcher. This must be called
|
||||
// under the dispatcher's lock.
|
||||
RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseNoLock()
|
||||
util::RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseNoLock()
|
||||
MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// API to serialize dispatchers to a |Channel|, exposed to only
|
||||
@ -373,7 +376,7 @@ class Dispatcher : public RefCountedThreadSafe<Dispatcher> {
|
||||
|
||||
// This protects the following members as well as any state added by
|
||||
// subclasses.
|
||||
mutable Mutex mutex_;
|
||||
mutable util::Mutex mutex_;
|
||||
bool is_closed_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(Dispatcher);
|
||||
@ -396,7 +399,8 @@ class DispatcherTransport {
|
||||
return dispatcher_->IsBusyNoLock();
|
||||
}
|
||||
void Close() MOJO_NOT_THREAD_SAFE { dispatcher_->CloseNoLock(); }
|
||||
RefPtr<Dispatcher> CreateEquivalentDispatcherAndClose() MOJO_NOT_THREAD_SAFE {
|
||||
util::RefPtr<Dispatcher> CreateEquivalentDispatcherAndClose()
|
||||
MOJO_NOT_THREAD_SAFE {
|
||||
return dispatcher_->CreateEquivalentDispatcherAndCloseNoLock();
|
||||
}
|
||||
|
||||
|
||||
@ -7,16 +7,20 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/logging.h"
|
||||
#include "mojo/edk/embedder/platform_shared_buffer.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test/simple_test_thread.h"
|
||||
#include "mojo/edk/system/waitable_event.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
#include "mojo/edk/test/simple_test_thread.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -117,7 +121,7 @@ TEST(DispatcherTest, Basic) {
|
||||
EXPECT_EQ(0u, hss.satisfiable_signals);
|
||||
}
|
||||
|
||||
class ThreadSafetyStressThread : public mojo::test::SimpleTestThread {
|
||||
class ThreadSafetyStressThread : public test::SimpleTestThread {
|
||||
public:
|
||||
enum DispatcherOp {
|
||||
CLOSE = 0,
|
||||
@ -136,7 +140,7 @@ class ThreadSafetyStressThread : public mojo::test::SimpleTestThread {
|
||||
DISPATCHER_OP_COUNT
|
||||
};
|
||||
|
||||
ThreadSafetyStressThread(base::WaitableEvent* event,
|
||||
ThreadSafetyStressThread(ManualResetWaitableEvent* event,
|
||||
RefPtr<Dispatcher> dispatcher,
|
||||
DispatcherOp op)
|
||||
: event_(event), dispatcher_(dispatcher), op_(op) {
|
||||
@ -240,7 +244,7 @@ class ThreadSafetyStressThread : public mojo::test::SimpleTestThread {
|
||||
EXPECT_EQ(0u, hss.satisfiable_signals);
|
||||
}
|
||||
|
||||
base::WaitableEvent* const event_;
|
||||
ManualResetWaitableEvent* const event_;
|
||||
const RefPtr<Dispatcher> dispatcher_;
|
||||
const DispatcherOp op_;
|
||||
|
||||
@ -254,8 +258,8 @@ TEST(DispatcherTest, ThreadSafetyStress) {
|
||||
static const size_t kNumThreads = 100;
|
||||
|
||||
for (size_t i = 0; i < kRepeatCount; i++) {
|
||||
// Manual reset, not initially signalled.
|
||||
base::WaitableEvent event(true, false);
|
||||
// Manual reset, not initially signaled.
|
||||
ManualResetWaitableEvent event;
|
||||
auto d = MakeRefCounted<TrivialDispatcher>();
|
||||
|
||||
{
|
||||
@ -282,8 +286,8 @@ TEST(DispatcherTest, ThreadSafetyStressNoClose) {
|
||||
static const size_t kNumThreads = 100;
|
||||
|
||||
for (size_t i = 0; i < kRepeatCount; i++) {
|
||||
// Manual reset, not initially signalled.
|
||||
base::WaitableEvent event(true, false);
|
||||
// Manual reset, not initially signaled.
|
||||
ManualResetWaitableEvent event;
|
||||
auto d = MakeRefCounted<TrivialDispatcher>();
|
||||
|
||||
{
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
#include "mojo/edk/system/channel_endpoint.h"
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -8,8 +8,9 @@
|
||||
#include <memory>
|
||||
|
||||
#include "mojo/edk/system/channel_endpoint_client.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -61,14 +62,14 @@ class EndpointRelayer final : public ChannelEndpointClient {
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(Filter);
|
||||
};
|
||||
|
||||
// Note: Use |MakeRefCounted<EndpointRelayer>()|.
|
||||
// Note: Use |util::MakeRefCounted<EndpointRelayer>()|.
|
||||
|
||||
// Gets the other port number (i.e., 0 -> 1, 1 -> 0).
|
||||
static unsigned GetPeerPort(unsigned port);
|
||||
|
||||
// Initialize this object. This must be called before any other method.
|
||||
void Init(RefPtr<ChannelEndpoint>&& endpoint0,
|
||||
RefPtr<ChannelEndpoint>&& endpoint1) MOJO_NOT_THREAD_SAFE;
|
||||
void Init(util::RefPtr<ChannelEndpoint>&& endpoint0,
|
||||
util::RefPtr<ChannelEndpoint>&& endpoint1) MOJO_NOT_THREAD_SAFE;
|
||||
|
||||
// Sets (or resets) the filter, which can (optionally) handle/filter
|
||||
// |Type::ENDPOINT_CLIENT| messages (see |Filter| above).
|
||||
@ -84,8 +85,8 @@ class EndpointRelayer final : public ChannelEndpointClient {
|
||||
EndpointRelayer();
|
||||
~EndpointRelayer() override;
|
||||
|
||||
Mutex mutex_;
|
||||
RefPtr<ChannelEndpoint> endpoints_[2] MOJO_GUARDED_BY(mutex_);
|
||||
util::Mutex mutex_;
|
||||
util::RefPtr<ChannelEndpoint> endpoints_[2] MOJO_GUARDED_BY(mutex_);
|
||||
std::unique_ptr<Filter> filter_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(EndpointRelayer);
|
||||
|
||||
@ -5,17 +5,20 @@
|
||||
#include "mojo/edk/system/endpoint_relayer.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "mojo/edk/system/channel_endpoint_id.h"
|
||||
#include "mojo/edk/system/channel_test_base.h"
|
||||
#include "mojo/edk/system/message_in_transit_queue.h"
|
||||
#include "mojo/edk/system/message_in_transit_test_utils.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/test_channel_endpoint_client.h"
|
||||
#include "mojo/edk/system/waitable_event.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -90,13 +93,13 @@ class EndpointRelayerTest : public test::ChannelTestBase {
|
||||
};
|
||||
|
||||
TEST_F(EndpointRelayerTest, Basic) {
|
||||
base::WaitableEvent read_event(true, false);
|
||||
ManualResetWaitableEvent read_event;
|
||||
client1b()->SetReadEvent(&read_event);
|
||||
EXPECT_EQ(0u, client1b()->NumMessages());
|
||||
|
||||
EXPECT_TRUE(endpoint1a()->EnqueueMessage(test::MakeTestMessage(12345)));
|
||||
|
||||
EXPECT_TRUE(read_event.TimedWait(TestTimeouts::tiny_timeout()));
|
||||
EXPECT_FALSE(read_event.WaitWithTimeout(test::TinyTimeout()));
|
||||
client1b()->SetReadEvent(nullptr);
|
||||
|
||||
ASSERT_EQ(1u, client1b()->NumMessages());
|
||||
@ -111,7 +114,7 @@ TEST_F(EndpointRelayerTest, Basic) {
|
||||
|
||||
EXPECT_TRUE(endpoint1b()->EnqueueMessage(test::MakeTestMessage(67890)));
|
||||
|
||||
EXPECT_TRUE(read_event.TimedWait(TestTimeouts::tiny_timeout()));
|
||||
EXPECT_FALSE(read_event.WaitWithTimeout(test::TinyTimeout()));
|
||||
client1a()->SetReadEvent(nullptr);
|
||||
|
||||
ASSERT_EQ(1u, client1a()->NumMessages());
|
||||
@ -127,10 +130,10 @@ TEST_F(EndpointRelayerTest, MultipleMessages) {
|
||||
EXPECT_TRUE(endpoint1a()->EnqueueMessage(test::MakeTestMessage(4)));
|
||||
EXPECT_TRUE(endpoint1a()->EnqueueMessage(test::MakeTestMessage(5)));
|
||||
|
||||
base::WaitableEvent read_event(true, false);
|
||||
ManualResetWaitableEvent read_event;
|
||||
client1b()->SetReadEvent(&read_event);
|
||||
for (size_t i = 0; client1b()->NumMessages() < 5 && i < 5; i++) {
|
||||
EXPECT_TRUE(read_event.TimedWait(TestTimeouts::tiny_timeout()));
|
||||
EXPECT_FALSE(read_event.WaitWithTimeout(test::TinyTimeout()));
|
||||
read_event.Reset();
|
||||
}
|
||||
client1b()->SetReadEvent(nullptr);
|
||||
@ -198,10 +201,10 @@ TEST_F(EndpointRelayerTest, Filter) {
|
||||
EXPECT_TRUE(endpoint1a()->EnqueueMessage(test::MakeTestMessage(1003)));
|
||||
EXPECT_TRUE(endpoint1a()->EnqueueMessage(test::MakeTestMessage(5)));
|
||||
|
||||
base::WaitableEvent read_event(true, false);
|
||||
ManualResetWaitableEvent read_event;
|
||||
client1b()->SetReadEvent(&read_event);
|
||||
for (size_t i = 0; client1b()->NumMessages() < 5 && i < 5; i++) {
|
||||
EXPECT_TRUE(read_event.TimedWait(TestTimeouts::tiny_timeout()));
|
||||
EXPECT_FALSE(read_event.WaitWithTimeout(test::TinyTimeout()));
|
||||
read_event.Reset();
|
||||
}
|
||||
client1b()->SetReadEvent(nullptr);
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
#include "mojo/edk/system/configuration.h"
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
@ -20,7 +20,7 @@ class Core;
|
||||
class Dispatcher;
|
||||
class DispatcherTransport;
|
||||
|
||||
using DispatcherVector = std::vector<RefPtr<Dispatcher>>;
|
||||
using DispatcherVector = std::vector<util::RefPtr<Dispatcher>>;
|
||||
|
||||
// Test-only function (defined/used in embedder/test_embedder.cc). Declared here
|
||||
// so it can be friended.
|
||||
@ -46,7 +46,7 @@ class HandleTable {
|
||||
// handle.
|
||||
// WARNING: For efficiency, this returns a dumb pointer. If you're going to
|
||||
// use the result outside |Core|'s lock, you MUST take a reference (e.g., by
|
||||
// storing the result inside a |RefPtr|).
|
||||
// storing the result inside a |util::RefPtr|).
|
||||
Dispatcher* GetDispatcher(MojoHandle handle);
|
||||
|
||||
// On success, gets the dispatcher for a given handle (which should not be
|
||||
@ -55,7 +55,7 @@ class HandleTable {
|
||||
// |MOJO_RESULT_INVALID_ARGUMENT| if there's no dispatcher for the given
|
||||
// handle or |MOJO_RESULT_BUSY| if the handle is marked as busy.)
|
||||
MojoResult GetAndRemoveDispatcher(MojoHandle handle,
|
||||
RefPtr<Dispatcher>* dispatcher);
|
||||
util::RefPtr<Dispatcher>* dispatcher);
|
||||
|
||||
// Adds a dispatcher (which must be valid), returning the handle for it.
|
||||
// Returns |MOJO_HANDLE_INVALID| on failure (if the handle table is full).
|
||||
@ -118,16 +118,16 @@ class HandleTable {
|
||||
// closed (or learning about this too late).
|
||||
struct Entry {
|
||||
Entry();
|
||||
explicit Entry(RefPtr<Dispatcher>&& dispatcher);
|
||||
explicit Entry(util::RefPtr<Dispatcher>&& dispatcher);
|
||||
~Entry();
|
||||
|
||||
RefPtr<Dispatcher> dispatcher;
|
||||
util::RefPtr<Dispatcher> dispatcher;
|
||||
bool busy;
|
||||
};
|
||||
using HandleToEntryMap = std::unordered_map<MojoHandle, Entry>;
|
||||
|
||||
// Adds the given dispatcher to the handle table, not doing any size checks.
|
||||
MojoHandle AddDispatcherNoSizeCheck(RefPtr<Dispatcher>&& dispatcher);
|
||||
MojoHandle AddDispatcherNoSizeCheck(util::RefPtr<Dispatcher>&& dispatcher);
|
||||
|
||||
HandleToEntryMap handle_to_entry_map_;
|
||||
MojoHandle next_handle_; // Invariant: never |MOJO_HANDLE_INVALID|.
|
||||
|
||||
@ -13,6 +13,10 @@
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/remote_producer_data_pipe_impl.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -9,8 +9,9 @@
|
||||
|
||||
#include "mojo/edk/system/channel_endpoint_client.h"
|
||||
#include "mojo/edk/system/message_in_transit_queue.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
struct MojoCreateDataPipeOptions;
|
||||
@ -27,16 +28,16 @@ class MessagePipe;
|
||||
// |MessagePipe|s or |DataPipe|s.
|
||||
class IncomingEndpoint final : public ChannelEndpointClient {
|
||||
public:
|
||||
// Note: Use |MakeRefCounted<IncomingEndpoint>()|.
|
||||
// Note: Use |util::MakeRefCounted<IncomingEndpoint>()|.
|
||||
|
||||
// Must be called before any other method.
|
||||
RefPtr<ChannelEndpoint> Init() MOJO_NOT_THREAD_SAFE;
|
||||
util::RefPtr<ChannelEndpoint> Init() MOJO_NOT_THREAD_SAFE;
|
||||
|
||||
RefPtr<MessagePipe> ConvertToMessagePipe();
|
||||
RefPtr<DataPipe> ConvertToDataPipeProducer(
|
||||
util::RefPtr<MessagePipe> ConvertToMessagePipe();
|
||||
util::RefPtr<DataPipe> ConvertToDataPipeProducer(
|
||||
const MojoCreateDataPipeOptions& validated_options,
|
||||
size_t consumer_num_bytes);
|
||||
RefPtr<DataPipe> ConvertToDataPipeConsumer(
|
||||
util::RefPtr<DataPipe> ConvertToDataPipeConsumer(
|
||||
const MojoCreateDataPipeOptions& validated_options);
|
||||
|
||||
// Must be called before destroying this object if |ConvertToMessagePipe()|
|
||||
@ -53,8 +54,8 @@ class IncomingEndpoint final : public ChannelEndpointClient {
|
||||
IncomingEndpoint();
|
||||
~IncomingEndpoint() override;
|
||||
|
||||
Mutex mutex_;
|
||||
RefPtr<ChannelEndpoint> endpoint_ MOJO_GUARDED_BY(mutex_);
|
||||
util::Mutex mutex_;
|
||||
util::RefPtr<ChannelEndpoint> endpoint_ MOJO_GUARDED_BY(mutex_);
|
||||
MessageInTransitQueue message_queue_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(IncomingEndpoint);
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
#include "mojo/edk/system/message_pipe_dispatcher.h"
|
||||
#include "mojo/edk/system/slave_connection_manager.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/edk/embedder/platform_task_runner.h"
|
||||
#include "mojo/edk/embedder/process_type.h"
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
@ -17,7 +16,7 @@
|
||||
#include "mojo/edk/system/channel_id.h"
|
||||
#include "mojo/edk/system/connection_identifier.h"
|
||||
#include "mojo/edk/system/process_identifier.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -100,7 +99,7 @@ class IPCSupport {
|
||||
//
|
||||
// TODO(vtl): Add some more channel management functionality to this class.
|
||||
// Maybe make this callback interface more sane.
|
||||
RefPtr<MessagePipeDispatcher> ConnectToSlave(
|
||||
util::RefPtr<MessagePipeDispatcher> ConnectToSlave(
|
||||
const ConnectionIdentifier& connection_id,
|
||||
embedder::SlaveInfo slave_info,
|
||||
embedder::ScopedPlatformHandle platform_handle,
|
||||
@ -116,7 +115,7 @@ class IPCSupport {
|
||||
// |ConnectToSlave()|.
|
||||
//
|
||||
// TODO(vtl): |ConnectToSlave()|'s channel management TODO also applies here.
|
||||
RefPtr<MessagePipeDispatcher> ConnectToMaster(
|
||||
util::RefPtr<MessagePipeDispatcher> ConnectToMaster(
|
||||
const ConnectionIdentifier& connection_id,
|
||||
const base::Closure& callback,
|
||||
embedder::PlatformTaskRunnerRefPtr callback_thread_task_runner,
|
||||
|
||||
@ -9,10 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "mojo/edk/embedder/master_process_delegate.h"
|
||||
#include "mojo/edk/embedder/platform_channel_pair.h"
|
||||
#include "mojo/edk/embedder/simple_platform_support.h"
|
||||
@ -23,18 +20,20 @@
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/message_pipe_dispatcher.h"
|
||||
#include "mojo/edk/system/process_identifier.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/test_command_line.h"
|
||||
#include "mojo/edk/system/test/test_io_thread.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/waitable_event.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
#include "mojo/edk/test/multiprocess_test_helper.h"
|
||||
#include "mojo/edk/test/test_io_thread.h"
|
||||
#include "mojo/edk/test/test_utils.h"
|
||||
#include "mojo/edk/util/command_line.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
|
||||
using test::TestIOThread;
|
||||
|
||||
namespace system {
|
||||
namespace {
|
||||
|
||||
@ -58,7 +57,7 @@ void TestWriteReadMessage(MessagePipeDispatcher* write_mp,
|
||||
MOJO_WRITE_MESSAGE_FLAG_NONE));
|
||||
|
||||
// Wait for it to arrive.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), nullptr));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionTimeout(), nullptr));
|
||||
read_mp->RemoveAwakable(&waiter, nullptr);
|
||||
|
||||
// Read the message from the read end.
|
||||
@ -102,7 +101,7 @@ RefPtr<MessagePipeDispatcher> SendMessagePipeDispatcher(
|
||||
mp_to_send = nullptr;
|
||||
|
||||
// Wait for it to arrive.
|
||||
CHECK_EQ(waiter.Wait(test::ActionDeadline(), nullptr), MOJO_RESULT_OK);
|
||||
CHECK_EQ(waiter.Wait(test::ActionTimeout(), nullptr), MOJO_RESULT_OK);
|
||||
read_mp->RemoveAwakable(&waiter, nullptr);
|
||||
|
||||
// Read the message from the read end.
|
||||
@ -121,14 +120,13 @@ RefPtr<MessagePipeDispatcher> SendMessagePipeDispatcher(
|
||||
|
||||
class TestMasterProcessDelegate : public embedder::MasterProcessDelegate {
|
||||
public:
|
||||
TestMasterProcessDelegate()
|
||||
: on_slave_disconnect_event_(false, false) {} // Auto reset.
|
||||
TestMasterProcessDelegate() {}
|
||||
~TestMasterProcessDelegate() override {}
|
||||
|
||||
// Warning: There's only one slave disconnect event (which resets
|
||||
// automatically).
|
||||
bool TryWaitForOnSlaveDisconnect() {
|
||||
return on_slave_disconnect_event_.TimedWait(TestTimeouts::action_timeout());
|
||||
return !on_slave_disconnect_event_.WaitWithTimeout(test::ActionTimeout());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -139,7 +137,7 @@ class TestMasterProcessDelegate : public embedder::MasterProcessDelegate {
|
||||
on_slave_disconnect_event_.Signal();
|
||||
}
|
||||
|
||||
base::WaitableEvent on_slave_disconnect_event_;
|
||||
AutoResetWaitableEvent on_slave_disconnect_event_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(TestMasterProcessDelegate);
|
||||
};
|
||||
@ -161,13 +159,12 @@ class TestSlaveProcessDelegate : public embedder::SlaveProcessDelegate {
|
||||
// Represents the master's side of its connection to a slave.
|
||||
class TestSlaveConnection {
|
||||
public:
|
||||
TestSlaveConnection(TestIOThread* test_io_thread,
|
||||
TestSlaveConnection(test::TestIOThread* test_io_thread,
|
||||
IPCSupport* master_ipc_support)
|
||||
: test_io_thread_(test_io_thread),
|
||||
master_ipc_support_(master_ipc_support),
|
||||
connection_id_(master_ipc_support_->GenerateConnectionIdentifier()),
|
||||
slave_id_(kInvalidProcessIdentifier),
|
||||
event_(true, false) {}
|
||||
slave_id_(kInvalidProcessIdentifier) {}
|
||||
~TestSlaveConnection() {}
|
||||
|
||||
// After this is called, |ShutdownChannelToSlave()| must be called (possibly
|
||||
@ -177,7 +174,8 @@ class TestSlaveConnection {
|
||||
// Note: |ChannelId|s and |ProcessIdentifier|s are interchangeable.
|
||||
RefPtr<MessagePipeDispatcher> mp = master_ipc_support_->ConnectToSlave(
|
||||
connection_id_, nullptr, channel_pair.PassServerHandle(),
|
||||
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event_)),
|
||||
base::Bind(&ManualResetWaitableEvent::Signal,
|
||||
base::Unretained(&event_)),
|
||||
nullptr, &slave_id_);
|
||||
EXPECT_TRUE(mp);
|
||||
EXPECT_NE(slave_id_, kInvalidProcessIdentifier);
|
||||
@ -187,7 +185,7 @@ class TestSlaveConnection {
|
||||
}
|
||||
|
||||
void WaitForChannelToSlave() {
|
||||
EXPECT_TRUE(event_.TimedWait(TestTimeouts::action_timeout()));
|
||||
EXPECT_FALSE(event_.WaitWithTimeout(test::ActionTimeout()));
|
||||
}
|
||||
|
||||
void ShutdownChannelToSlave() {
|
||||
@ -207,13 +205,13 @@ class TestSlaveConnection {
|
||||
const ConnectionIdentifier& connection_id() const { return connection_id_; }
|
||||
|
||||
private:
|
||||
TestIOThread* const test_io_thread_;
|
||||
test::TestIOThread* const test_io_thread_;
|
||||
IPCSupport* const master_ipc_support_;
|
||||
const ConnectionIdentifier connection_id_;
|
||||
// The master's message pipe dispatcher.
|
||||
RefPtr<MessagePipeDispatcher> message_pipe_;
|
||||
ProcessIdentifier slave_id_;
|
||||
base::WaitableEvent event_;
|
||||
ManualResetWaitableEvent event_;
|
||||
embedder::ScopedPlatformHandle slave_platform_handle_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(TestSlaveConnection);
|
||||
@ -225,7 +223,7 @@ class TestSlave {
|
||||
public:
|
||||
// Note: Before destruction, |ShutdownIPCSupport()| must be called.
|
||||
TestSlave(embedder::PlatformSupport* platform_support,
|
||||
TestIOThread* test_io_thread,
|
||||
test::TestIOThread* test_io_thread,
|
||||
embedder::ScopedPlatformHandle platform_handle)
|
||||
: test_io_thread_(test_io_thread),
|
||||
slave_ipc_support_(platform_support,
|
||||
@ -233,8 +231,7 @@ class TestSlave {
|
||||
test_io_thread->task_runner(),
|
||||
&slave_process_delegate_,
|
||||
test_io_thread->task_runner(),
|
||||
platform_handle.Pass()),
|
||||
event_(true, false) {}
|
||||
platform_handle.Pass()) {}
|
||||
~TestSlave() {}
|
||||
|
||||
// After this is called, |ShutdownChannelToMaster()| must be called (possibly
|
||||
@ -243,8 +240,8 @@ class TestSlave {
|
||||
const ConnectionIdentifier& connection_id) {
|
||||
ProcessIdentifier master_id = kInvalidProcessIdentifier;
|
||||
RefPtr<MessagePipeDispatcher> mp = slave_ipc_support_.ConnectToMaster(
|
||||
connection_id,
|
||||
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event_)),
|
||||
connection_id, base::Bind(&ManualResetWaitableEvent::Signal,
|
||||
base::Unretained(&event_)),
|
||||
nullptr, &master_id);
|
||||
EXPECT_TRUE(mp);
|
||||
EXPECT_EQ(kMasterProcessIdentifier, master_id);
|
||||
@ -252,7 +249,7 @@ class TestSlave {
|
||||
}
|
||||
|
||||
void WaitForChannelToMaster() {
|
||||
EXPECT_TRUE(event_.TimedWait(TestTimeouts::action_timeout()));
|
||||
EXPECT_FALSE(event_.WaitWithTimeout(test::ActionTimeout()));
|
||||
}
|
||||
|
||||
void ShutdownChannelToMaster() {
|
||||
@ -273,10 +270,10 @@ class TestSlave {
|
||||
}
|
||||
|
||||
private:
|
||||
TestIOThread* const test_io_thread_;
|
||||
test::TestIOThread* const test_io_thread_;
|
||||
TestSlaveProcessDelegate slave_process_delegate_;
|
||||
IPCSupport slave_ipc_support_;
|
||||
base::WaitableEvent event_;
|
||||
ManualResetWaitableEvent event_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(TestSlave);
|
||||
};
|
||||
@ -285,7 +282,7 @@ class TestSlave {
|
||||
class TestSlaveSetup {
|
||||
public:
|
||||
TestSlaveSetup(embedder::SimplePlatformSupport* platform_support,
|
||||
TestIOThread* test_io_thread,
|
||||
test::TestIOThread* test_io_thread,
|
||||
TestMasterProcessDelegate* master_process_delegate,
|
||||
IPCSupport* master_ipc_support)
|
||||
: platform_support_(platform_support),
|
||||
@ -351,7 +348,7 @@ class TestSlaveSetup {
|
||||
|
||||
private:
|
||||
embedder::SimplePlatformSupport* const platform_support_;
|
||||
TestIOThread* const test_io_thread_;
|
||||
test::TestIOThread* const test_io_thread_;
|
||||
TestMasterProcessDelegate* const master_process_delegate_;
|
||||
IPCSupport* const master_ipc_support_;
|
||||
|
||||
@ -368,7 +365,7 @@ class IPCSupportTest : public testing::Test {
|
||||
public:
|
||||
// Note: Run master process delegate methods on the I/O thread.
|
||||
IPCSupportTest()
|
||||
: test_io_thread_(TestIOThread::StartMode::AUTO),
|
||||
: test_io_thread_(test::TestIOThread::StartMode::AUTO),
|
||||
master_ipc_support_(&platform_support_,
|
||||
embedder::ProcessType::MASTER,
|
||||
test_io_thread_.task_runner(),
|
||||
@ -394,7 +391,7 @@ class IPCSupportTest : public testing::Test {
|
||||
embedder::SimplePlatformSupport& platform_support() {
|
||||
return platform_support_;
|
||||
}
|
||||
TestIOThread& test_io_thread() { return test_io_thread_; }
|
||||
test::TestIOThread& test_io_thread() { return test_io_thread_; }
|
||||
TestMasterProcessDelegate& master_process_delegate() {
|
||||
return master_process_delegate_;
|
||||
}
|
||||
@ -402,7 +399,7 @@ class IPCSupportTest : public testing::Test {
|
||||
|
||||
private:
|
||||
embedder::SimplePlatformSupport platform_support_;
|
||||
TestIOThread test_io_thread_;
|
||||
test::TestIOThread test_io_thread_;
|
||||
|
||||
// All tests require a master.
|
||||
TestMasterProcessDelegate master_process_delegate_;
|
||||
@ -436,7 +433,7 @@ TEST_F(IPCSupportTest, MasterSlave) {
|
||||
|
||||
// A message was sent through the message pipe, |Channel|s must have been
|
||||
// established on both sides. The events have thus almost certainly been
|
||||
// signalled, but we'll wait just to be sure.
|
||||
// signaled, but we'll wait just to be sure.
|
||||
s->slave_connection()->WaitForChannelToSlave();
|
||||
s->slave()->WaitForChannelToMaster();
|
||||
|
||||
@ -675,7 +672,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlaveInternal) {
|
||||
ASSERT_TRUE(client_platform_handle.is_valid());
|
||||
|
||||
embedder::SimplePlatformSupport platform_support;
|
||||
TestIOThread test_io_thread(TestIOThread::StartMode::AUTO);
|
||||
test::TestIOThread test_io_thread(test::TestIOThread::StartMode::AUTO);
|
||||
TestSlaveProcessDelegate slave_process_delegate;
|
||||
// Note: Run process delegate methods on the I/O thread.
|
||||
IPCSupport ipc_support(&platform_support, embedder::ProcessType::SLAVE,
|
||||
@ -683,12 +680,12 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlaveInternal) {
|
||||
test_io_thread.task_runner(),
|
||||
client_platform_handle.Pass());
|
||||
|
||||
const base::CommandLine& command_line =
|
||||
*base::CommandLine::ForCurrentProcess();
|
||||
ASSERT_TRUE(command_line.HasSwitch(kConnectionIdFlag));
|
||||
std::string connection_id_string;
|
||||
ASSERT_TRUE(test::GetTestCommandLine()->GetOptionValue(
|
||||
kConnectionIdFlag, &connection_id_string));
|
||||
bool ok = false;
|
||||
ConnectionIdentifier connection_id = ConnectionIdentifier::FromString(
|
||||
command_line.GetSwitchValueASCII(kConnectionIdFlag), &ok);
|
||||
ConnectionIdentifier connection_id =
|
||||
ConnectionIdentifier::FromString(connection_id_string, &ok);
|
||||
ASSERT_TRUE(ok);
|
||||
|
||||
embedder::ScopedPlatformHandle second_platform_handle =
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
#include "mojo/edk/system/remote_producer_data_pipe_impl.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#include "base/location.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "mojo/edk/embedder/master_process_delegate.h"
|
||||
#include "mojo/edk/embedder/platform_channel_pair.h"
|
||||
#include "mojo/edk/embedder/platform_handle.h"
|
||||
@ -22,9 +21,12 @@
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
#include "mojo/edk/system/transport_data.h"
|
||||
#include "mojo/edk/system/waitable_event.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
@ -371,7 +373,7 @@ ProcessIdentifier MasterConnectionManager::AddSlave(
|
||||
|
||||
// We have to wait for the task to be executed, in case someone calls
|
||||
// |AddSlave()| followed immediately by |Shutdown()|.
|
||||
base::WaitableEvent event(false, false);
|
||||
AutoResetWaitableEvent event;
|
||||
private_thread_.message_loop()->PostTask(
|
||||
FROM_HERE,
|
||||
base::Bind(&MasterConnectionManager::AddSlaveOnPrivateThread,
|
||||
@ -671,7 +673,7 @@ void MasterConnectionManager::AddSlaveOnPrivateThread(
|
||||
embedder::SlaveInfo slave_info,
|
||||
embedder::ScopedPlatformHandle platform_handle,
|
||||
ProcessIdentifier slave_process_identifier,
|
||||
base::WaitableEvent* event) {
|
||||
AutoResetWaitableEvent* event) {
|
||||
DCHECK(platform_handle.is_valid());
|
||||
DCHECK(event);
|
||||
AssertOnPrivateThread();
|
||||
|
||||
@ -9,17 +9,16 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "mojo/edk/embedder/platform_task_runner.h"
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/system/connection_manager.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace base {
|
||||
class TaskRunner;
|
||||
class WaitableEvent;
|
||||
}
|
||||
|
||||
namespace mojo {
|
||||
@ -31,6 +30,8 @@ using SlaveInfo = void*;
|
||||
|
||||
namespace system {
|
||||
|
||||
class AutoResetWaitableEvent;
|
||||
|
||||
// The |ConnectionManager| implementation for the master process.
|
||||
//
|
||||
// This class is thread-safe (except that no public methods may be called from
|
||||
@ -115,7 +116,7 @@ class MasterConnectionManager final : public ConnectionManager {
|
||||
void AddSlaveOnPrivateThread(embedder::SlaveInfo slave_info,
|
||||
embedder::ScopedPlatformHandle platform_handle,
|
||||
ProcessIdentifier slave_process_identifier,
|
||||
base::WaitableEvent* event);
|
||||
AutoResetWaitableEvent* event);
|
||||
// Called by |Helper::OnError()|.
|
||||
void OnError(ProcessIdentifier process_identifier);
|
||||
// Posts a call to |master_process_delegate_->OnSlaveDisconnect()|.
|
||||
@ -147,7 +148,7 @@ class MasterConnectionManager final : public ConnectionManager {
|
||||
|
||||
// Note: |mutex_| is not needed in the constructor, |Init()|,
|
||||
// |Shutdown()|/|ShutdownOnPrivateThread()|, or the destructor
|
||||
Mutex mutex_;
|
||||
util::Mutex mutex_;
|
||||
|
||||
ProcessIdentifier next_process_identifier_ MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
|
||||
@ -58,8 +58,8 @@ template <typename Type>
|
||||
class UserPointerWriter;
|
||||
template <typename Type>
|
||||
class UserPointerReaderWriter;
|
||||
template <class Options>
|
||||
class UserOptionsReader;
|
||||
template <typename Type>
|
||||
class UserPointerPartialReader;
|
||||
|
||||
// Provides a convenient way to implicitly get null |UserPointer<Type>|s.
|
||||
struct NullUserPointer {};
|
||||
@ -75,6 +75,8 @@ class UserPointer {
|
||||
using NonVoidType = typename internal::VoidToChar<Type>::type;
|
||||
|
||||
public:
|
||||
static_assert(!std::is_volatile<Type>::value, "Type must not be volatile");
|
||||
|
||||
// Instead of explicitly using these constructors, you can often use
|
||||
// |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common
|
||||
// exception is when you have, e.g., a |char*| and want to get a
|
||||
@ -235,13 +237,25 @@ class UserPointer {
|
||||
using Writer = UserPointerWriter<Type>;
|
||||
using ReaderWriter = UserPointerReaderWriter<Type>;
|
||||
|
||||
// This is like |Reader| above, but for partially reading the memory of a
|
||||
// single object (usually a struct). The pointer it provides will be to a full
|
||||
// |Type| (no more, no less), with unavailable bytes set to zero.
|
||||
//
|
||||
// Note: It isn't safe to just use |UserPointer<const char>::Reader| and
|
||||
// reinterpret cast the pointer to a struct pointer. Even if before accessing
|
||||
// a field you check that it's within the available size, the compiler may
|
||||
// read beyond the extent of the field itself, so long as the read is still
|
||||
// within the struct.
|
||||
//
|
||||
// TODO(vtl): Add writer and reader-writer versions of this if/when necessary.
|
||||
using PartialReader = UserPointerPartialReader<Type>;
|
||||
|
||||
private:
|
||||
friend class UserPointerReader<Type>;
|
||||
friend class UserPointerReader<const Type>;
|
||||
friend class UserPointerWriter<Type>;
|
||||
friend class UserPointerReaderWriter<Type>;
|
||||
template <class Options>
|
||||
friend class UserOptionsReader;
|
||||
friend class UserPointerPartialReader<Type>;
|
||||
|
||||
Type* pointer_;
|
||||
// Allow copy and assignment.
|
||||
@ -260,37 +274,29 @@ class UserPointerReader {
|
||||
using TypeNoConst = typename std::remove_const<Type>::type;
|
||||
|
||||
public:
|
||||
static_assert(!std::is_volatile<Type>::value, "Type must not be volatile");
|
||||
|
||||
// Note: If |count| is zero, |GetPointer()| will always return null.
|
||||
UserPointerReader(UserPointer<const Type> user_pointer, size_t count) {
|
||||
Init(user_pointer.pointer_, count, true);
|
||||
UserPointerReader(UserPointer<const TypeNoConst> user_pointer, size_t count) {
|
||||
Init(user_pointer.pointer_, count);
|
||||
}
|
||||
UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) {
|
||||
Init(user_pointer.pointer_, count, true);
|
||||
Init(user_pointer.pointer_, count);
|
||||
}
|
||||
|
||||
const Type* GetPointer() const { return buffer_.get(); }
|
||||
const TypeNoConst* GetPointer() const { return buffer_.get(); }
|
||||
|
||||
private:
|
||||
template <class Options>
|
||||
friend class UserOptionsReader;
|
||||
|
||||
struct NoCheck {};
|
||||
UserPointerReader(NoCheck,
|
||||
UserPointer<const Type> user_pointer,
|
||||
size_t count) {
|
||||
Init(user_pointer.pointer_, count, false);
|
||||
}
|
||||
|
||||
void Init(const Type* user_pointer, size_t count, bool check) {
|
||||
void Init(const TypeNoConst* user_pointer, size_t count) {
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
if (check) {
|
||||
internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>(
|
||||
user_pointer, count);
|
||||
}
|
||||
internal::CheckUserPointerWithCount<sizeof(TypeNoConst),
|
||||
MOJO_ALIGNOF(TypeNoConst)>(user_pointer,
|
||||
count);
|
||||
|
||||
buffer_.reset(new TypeNoConst[count]);
|
||||
memcpy(buffer_.get(), user_pointer, count * sizeof(Type));
|
||||
memcpy(buffer_.get(), user_pointer, count * sizeof(TypeNoConst));
|
||||
}
|
||||
|
||||
std::unique_ptr<TypeNoConst[]> buffer_;
|
||||
@ -302,6 +308,9 @@ class UserPointerReader {
|
||||
template <typename Type>
|
||||
class UserPointerWriter {
|
||||
public:
|
||||
static_assert(!std::is_volatile<Type>::value, "Type must not be volatile");
|
||||
static_assert(!std::is_const<Type>::value, "Type must not be const");
|
||||
|
||||
// Note: If |count| is zero, |GetPointer()| will always return null.
|
||||
UserPointerWriter(UserPointer<Type> user_pointer, size_t count)
|
||||
: user_pointer_(user_pointer), count_(count) {
|
||||
@ -331,6 +340,9 @@ class UserPointerWriter {
|
||||
template <typename Type>
|
||||
class UserPointerReaderWriter {
|
||||
public:
|
||||
static_assert(!std::is_volatile<Type>::value, "Type must not be volatile");
|
||||
static_assert(!std::is_const<Type>::value, "Type must not be const");
|
||||
|
||||
// Note: If |count| is zero, |GetPointer()| will always return null.
|
||||
UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count)
|
||||
: user_pointer_(user_pointer), count_(count) {
|
||||
@ -359,6 +371,47 @@ class UserPointerReaderWriter {
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter);
|
||||
};
|
||||
|
||||
// Implementation of |UserPointer<Type>::PartialReader|.
|
||||
template <typename Type>
|
||||
class UserPointerPartialReader {
|
||||
private:
|
||||
using TypeNoConst = typename std::remove_cv<Type>::type;
|
||||
|
||||
public:
|
||||
static_assert(!std::is_volatile<Type>::value, "Type must not be volatile");
|
||||
|
||||
// Note: If |count| is zero, |GetPointer()| will always return null.
|
||||
UserPointerPartialReader(UserPointer<const TypeNoConst> user_pointer,
|
||||
size_t num_bytes) {
|
||||
Init(user_pointer.pointer_, num_bytes);
|
||||
}
|
||||
UserPointerPartialReader(UserPointer<TypeNoConst> user_pointer,
|
||||
size_t num_bytes) {
|
||||
Init(user_pointer.pointer_, num_bytes);
|
||||
}
|
||||
|
||||
const TypeNoConst* GetPointer() const { return &storage_; }
|
||||
|
||||
private:
|
||||
void Init(const TypeNoConst* user_pointer, size_t num_bytes) {
|
||||
// Check that all |num_bytes| are valid.
|
||||
internal::CheckUserPointerWithSize<MOJO_ALIGNOF(TypeNoConst)>(user_pointer,
|
||||
num_bytes);
|
||||
|
||||
// But only copy up to |num_bytes|.
|
||||
if (num_bytes >= sizeof(TypeNoConst))
|
||||
num_bytes = sizeof(TypeNoConst);
|
||||
|
||||
memcpy(&storage_, user_pointer, num_bytes);
|
||||
memset(reinterpret_cast<char*>(&storage_) + num_bytes, 0,
|
||||
sizeof(TypeNoConst) - num_bytes);
|
||||
}
|
||||
|
||||
TypeNoConst storage_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(UserPointerPartialReader);
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace mojo
|
||||
|
||||
|
||||
@ -19,6 +19,10 @@
|
||||
#include "mojo/edk/system/proxy_message_pipe_endpoint.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/edk/embedder/platform_handle_vector.h"
|
||||
#include "mojo/edk/system/channel_endpoint_client.h"
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
@ -19,8 +18,9 @@
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
#include "mojo/edk/system/message_pipe_endpoint.h"
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/mutex.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/c/system/message_pipe.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
@ -39,21 +39,21 @@ class MessageInTransitQueue;
|
||||
class MessagePipe final : public ChannelEndpointClient {
|
||||
public:
|
||||
// Creates a |MessagePipe| with two new |LocalMessagePipeEndpoint|s.
|
||||
static RefPtr<MessagePipe> CreateLocalLocal();
|
||||
static util::RefPtr<MessagePipe> CreateLocalLocal();
|
||||
|
||||
// Creates a |MessagePipe| with a |LocalMessagePipeEndpoint| on port 0 and a
|
||||
// |ProxyMessagePipeEndpoint| on port 1. |*channel_endpoint| is set to the
|
||||
// (newly-created) |ChannelEndpoint| for the latter.
|
||||
static RefPtr<MessagePipe> CreateLocalProxy(
|
||||
RefPtr<ChannelEndpoint>* channel_endpoint);
|
||||
static util::RefPtr<MessagePipe> CreateLocalProxy(
|
||||
util::RefPtr<ChannelEndpoint>* channel_endpoint);
|
||||
|
||||
// Similar to |CreateLocalProxy()|, except that it'll do so from an existing
|
||||
// |ChannelEndpoint| (whose |ReplaceClient()| it'll call) and take
|
||||
// |message_queue|'s contents as already-received incoming messages. If
|
||||
// |channel_endpoint| is null, this will create a "half-open" message pipe.
|
||||
static RefPtr<MessagePipe> CreateLocalProxyFromExisting(
|
||||
static util::RefPtr<MessagePipe> CreateLocalProxyFromExisting(
|
||||
MessageInTransitQueue* message_queue,
|
||||
RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
util::RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
|
||||
// Creates a |MessagePipe| with a |ProxyMessagePipeEndpoint| on port 0 and a
|
||||
// |LocalMessagePipeEndpoint| on port 1. |*channel_endpoint| is set to the
|
||||
@ -61,8 +61,8 @@ class MessagePipe final : public ChannelEndpointClient {
|
||||
// Note: This is really only needed in tests (outside of tests, this
|
||||
// configuration arises from a local message pipe having its port 0
|
||||
// "converted" using |ConvertLocalToProxy()|).
|
||||
static RefPtr<MessagePipe> CreateProxyLocal(
|
||||
RefPtr<ChannelEndpoint>* channel_endpoint);
|
||||
static util::RefPtr<MessagePipe> CreateProxyLocal(
|
||||
util::RefPtr<ChannelEndpoint>* channel_endpoint);
|
||||
|
||||
// Gets the other port number (i.e., 0 -> 1, 1 -> 0).
|
||||
static unsigned GetPeerPort(unsigned port);
|
||||
@ -73,7 +73,7 @@ class MessagePipe final : public ChannelEndpointClient {
|
||||
static bool Deserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size,
|
||||
RefPtr<MessagePipe>* message_pipe,
|
||||
util::RefPtr<MessagePipe>* message_pipe,
|
||||
unsigned* port);
|
||||
|
||||
// Gets the type of the endpoint (used for assertions, etc.).
|
||||
@ -138,7 +138,7 @@ class MessagePipe final : public ChannelEndpointClient {
|
||||
std::vector<DispatcherTransport>* transports)
|
||||
MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
mutable Mutex mutex_;
|
||||
mutable util::Mutex mutex_;
|
||||
std::unique_ptr<MessagePipeEndpoint> endpoints_[2] MOJO_GUARDED_BY(mutex_);
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipe);
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
#include "mojo/edk/system/options_validation.h"
|
||||
#include "mojo/edk/system/proxy_message_pipe_endpoint.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -26,7 +27,7 @@ class MessagePipeDispatcher final : public Dispatcher {
|
||||
// this is exposed directly for testing convenience.)
|
||||
static const MojoCreateMessagePipeOptions kDefaultCreateOptions;
|
||||
|
||||
static RefPtr<MessagePipeDispatcher> Create(
|
||||
static util::RefPtr<MessagePipeDispatcher> Create(
|
||||
const MojoCreateMessagePipeOptions& /*validated_options*/) {
|
||||
return AdoptRef(new MessagePipeDispatcher());
|
||||
}
|
||||
@ -41,7 +42,7 @@ class MessagePipeDispatcher final : public Dispatcher {
|
||||
MojoCreateMessagePipeOptions* out_options);
|
||||
|
||||
// Must be called before any other methods. (This method is not thread-safe.)
|
||||
void Init(RefPtr<MessagePipe>&& message_pipe,
|
||||
void Init(util::RefPtr<MessagePipe>&& message_pipe,
|
||||
unsigned port) MOJO_NOT_THREAD_SAFE;
|
||||
|
||||
// |Dispatcher| public methods:
|
||||
@ -52,14 +53,14 @@ class MessagePipeDispatcher final : public Dispatcher {
|
||||
// the message pipe, port 0).
|
||||
// TODO(vtl): This currently uses |kDefaultCreateOptions|, which is okay since
|
||||
// there aren't any options, but eventually options should be plumbed through.
|
||||
static RefPtr<MessagePipeDispatcher> CreateRemoteMessagePipe(
|
||||
RefPtr<ChannelEndpoint>* channel_endpoint);
|
||||
static util::RefPtr<MessagePipeDispatcher> CreateRemoteMessagePipe(
|
||||
util::RefPtr<ChannelEndpoint>* channel_endpoint);
|
||||
|
||||
// The "opposite" of |SerializeAndClose()|. (Typically this is called by
|
||||
// |Dispatcher::Deserialize()|.)
|
||||
static RefPtr<MessagePipeDispatcher> Deserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size);
|
||||
static util::RefPtr<MessagePipeDispatcher> Deserialize(Channel* channel,
|
||||
const void* source,
|
||||
size_t size);
|
||||
|
||||
private:
|
||||
friend class MessagePipeDispatcherTransport;
|
||||
@ -78,7 +79,8 @@ class MessagePipeDispatcher final : public Dispatcher {
|
||||
// |Dispatcher| protected methods:
|
||||
void CancelAllAwakablesNoLock() override;
|
||||
void CloseImplNoLock() override;
|
||||
RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock() override;
|
||||
util::RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock()
|
||||
override;
|
||||
MojoResult WriteMessageImplNoLock(
|
||||
UserPointer<const void> bytes,
|
||||
uint32_t num_bytes,
|
||||
@ -108,7 +110,7 @@ class MessagePipeDispatcher final : public Dispatcher {
|
||||
MOJO_NOT_THREAD_SAFE;
|
||||
|
||||
// This will be null if closed.
|
||||
RefPtr<MessagePipe> message_pipe_ MOJO_GUARDED_BY(mutex());
|
||||
util::RefPtr<MessagePipe> message_pipe_ MOJO_GUARDED_BY(mutex());
|
||||
unsigned port_ MOJO_GUARDED_BY(mutex());
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher);
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
// NOTE(vtl): Some of these tests are inherently flaky (e.g., if run on a
|
||||
// heavily-loaded system). Sorry. |test::EpsilonDeadline()| may be increased to
|
||||
// heavily-loaded system). Sorry. |test::EpsilonTimeout()| may be increased to
|
||||
// increase tolerance and reduce observed flakiness (though doing so reduces the
|
||||
// meaningfulness of the test).
|
||||
|
||||
@ -17,15 +17,20 @@
|
||||
#include <vector>
|
||||
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/random.h"
|
||||
#include "mojo/edk/system/test/simple_test_thread.h"
|
||||
#include "mojo/edk/system/test/sleep.h"
|
||||
#include "mojo/edk/system/test/stopwatch.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
#include "mojo/edk/system/waiter_test_utils.h"
|
||||
#include "mojo/edk/test/simple_test_thread.h"
|
||||
#include "mojo/edk/util/make_unique.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -77,7 +82,7 @@ TEST(MessagePipeDispatcherTest, Basic) {
|
||||
stopwatch.Start();
|
||||
EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, &context));
|
||||
EXPECT_EQ(1u, context);
|
||||
EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline());
|
||||
EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout());
|
||||
hss = HandleSignalsState();
|
||||
d0->RemoveAwakable(&w, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
|
||||
@ -110,7 +115,7 @@ TEST(MessagePipeDispatcherTest, Basic) {
|
||||
d0->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, nullptr));
|
||||
stopwatch.Start();
|
||||
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, w.Wait(0, nullptr));
|
||||
EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline());
|
||||
EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout());
|
||||
hss = HandleSignalsState();
|
||||
d0->RemoveAwakable(&w, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
|
||||
@ -122,10 +127,10 @@ TEST(MessagePipeDispatcherTest, Basic) {
|
||||
d0->AddAwakable(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, nullptr));
|
||||
stopwatch.Start();
|
||||
EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
|
||||
w.Wait(2 * test::EpsilonDeadline(), nullptr));
|
||||
w.Wait(2 * test::EpsilonTimeout(), nullptr));
|
||||
MojoDeadline elapsed = stopwatch.Elapsed();
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline());
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout());
|
||||
hss = HandleSignalsState();
|
||||
d0->RemoveAwakable(&w, &hss);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
|
||||
@ -140,7 +145,7 @@ TEST(MessagePipeDispatcherTest, Basic) {
|
||||
EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
|
||||
|
||||
// It should be signaled.
|
||||
EXPECT_EQ(MOJO_RESULT_OK, w.Wait(test::TinyDeadline(), &context));
|
||||
EXPECT_EQ(MOJO_RESULT_OK, w.Wait(test::TinyTimeout(), &context));
|
||||
EXPECT_EQ(12u, context);
|
||||
hss = HandleSignalsState();
|
||||
d0->RemoveAwakable(&w, &hss);
|
||||
@ -371,7 +376,7 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) {
|
||||
&context, &hss);
|
||||
stopwatch.Start();
|
||||
thread.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
// Wake it up by writing to |d0|.
|
||||
buffer[0] = 123456789;
|
||||
EXPECT_EQ(MOJO_RESULT_OK,
|
||||
@ -379,8 +384,8 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) {
|
||||
nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE));
|
||||
} // Joins the thread.
|
||||
elapsed = stopwatch.Elapsed();
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline());
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout());
|
||||
EXPECT_TRUE(did_wait);
|
||||
EXPECT_EQ(MOJO_RESULT_OK, result);
|
||||
EXPECT_EQ(1u, context);
|
||||
@ -396,7 +401,7 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) {
|
||||
stopwatch.Start();
|
||||
thread.Start();
|
||||
} // Joins the thread.
|
||||
EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline());
|
||||
EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout());
|
||||
EXPECT_FALSE(did_wait);
|
||||
EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result);
|
||||
EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
|
||||
@ -421,12 +426,12 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) {
|
||||
&context, &hss);
|
||||
stopwatch.Start();
|
||||
thread.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
EXPECT_EQ(MOJO_RESULT_OK, d0->Close());
|
||||
} // Joins the thread.
|
||||
elapsed = stopwatch.Elapsed();
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline());
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout());
|
||||
EXPECT_TRUE(did_wait);
|
||||
EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
|
||||
EXPECT_EQ(3u, context);
|
||||
@ -455,12 +460,12 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) {
|
||||
&context, &hss);
|
||||
stopwatch.Start();
|
||||
thread.Start();
|
||||
test::Sleep(2 * test::EpsilonDeadline());
|
||||
test::Sleep(2 * test::EpsilonTimeout());
|
||||
EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
|
||||
} // Joins the thread.
|
||||
elapsed = stopwatch.Elapsed();
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonDeadline());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonDeadline());
|
||||
EXPECT_GT(elapsed, (2 - 1) * test::EpsilonTimeout());
|
||||
EXPECT_LT(elapsed, (2 + 1) * test::EpsilonTimeout());
|
||||
EXPECT_TRUE(did_wait);
|
||||
EXPECT_EQ(MOJO_RESULT_CANCELLED, result);
|
||||
EXPECT_EQ(4u, context);
|
||||
@ -475,7 +480,7 @@ TEST(MessagePipeDispatcherTest, BasicThreaded) {
|
||||
|
||||
const size_t kMaxMessageSize = 2000;
|
||||
|
||||
class WriterThread : public mojo::test::SimpleTestThread {
|
||||
class WriterThread : public test::SimpleTestThread {
|
||||
public:
|
||||
// |*messages_written| and |*bytes_written| belong to the thread while it's
|
||||
// alive.
|
||||
@ -525,7 +530,7 @@ class WriterThread : public mojo::test::SimpleTestThread {
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(WriterThread);
|
||||
};
|
||||
|
||||
class ReaderThread : public mojo::test::SimpleTestThread {
|
||||
class ReaderThread : public test::SimpleTestThread {
|
||||
public:
|
||||
// |*messages_read| and |*bytes_read| belong to the thread while it's alive.
|
||||
ReaderThread(RefPtr<Dispatcher> read_dispatcher,
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/edk/system/dispatcher.h"
|
||||
#include "mojo/edk/system/memory.h"
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
|
||||
@ -3,30 +3,27 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/test/perf_time_logger.h"
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/system/channel.h"
|
||||
#include "mojo/edk/system/local_message_pipe_endpoint.h"
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/message_pipe_test_utils.h"
|
||||
#include "mojo/edk/system/proxy_message_pipe_endpoint.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/perf_log.h"
|
||||
#include "mojo/edk/system/test/stopwatch.h"
|
||||
#include "mojo/edk/test/test_utils.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -73,12 +70,12 @@ class MultiprocessMessagePipePerfTest
|
||||
std::string test_name =
|
||||
base::StringPrintf("IPC_Perf_%dx_%u", message_count_,
|
||||
static_cast<unsigned>(message_size_));
|
||||
base::PerfTimeLogger logger(test_name.c_str());
|
||||
test::Stopwatch stopwatch;
|
||||
|
||||
stopwatch.Start();
|
||||
for (int i = 0; i < message_count_; ++i)
|
||||
WriteWaitThenRead(mp);
|
||||
|
||||
logger.Done();
|
||||
test::LogPerfResult(test_name.c_str(), stopwatch.Elapsed() / 1000.0, "ms");
|
||||
}
|
||||
|
||||
private:
|
||||
@ -86,7 +83,8 @@ class MultiprocessMessagePipePerfTest
|
||||
size_t message_size_;
|
||||
std::string payload_;
|
||||
std::string read_buffer_;
|
||||
std::unique_ptr<base::PerfTimeLogger> perf_logger_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipePerfTest);
|
||||
};
|
||||
|
||||
// For each message received, sends a reply message with the same contents
|
||||
|
||||
@ -10,9 +10,13 @@
|
||||
#include "mojo/edk/system/channel.h"
|
||||
#include "mojo/edk/system/channel_endpoint.h"
|
||||
#include "mojo/edk/system/message_pipe.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/sleep.h"
|
||||
#include "mojo/edk/system/test/timeouts.h"
|
||||
#include "mojo/edk/system/waiter.h"
|
||||
|
||||
using mojo::util::MakeRefCounted;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace test {
|
||||
@ -37,7 +41,7 @@ MojoResult WaitIfNecessary(MessagePipe* mp,
|
||||
|
||||
ChannelThread::ChannelThread(embedder::PlatformSupport* platform_support)
|
||||
: platform_support_(platform_support),
|
||||
test_io_thread_(mojo::test::TestIOThread::StartMode::MANUAL) {}
|
||||
test_io_thread_(TestIOThread::StartMode::MANUAL) {}
|
||||
|
||||
ChannelThread::~ChannelThread() {
|
||||
Stop();
|
||||
@ -58,7 +62,7 @@ void ChannelThread::Stop() {
|
||||
// TODO(vtl): Remove this once |Channel| has a
|
||||
// |FlushWriteBufferAndShutdown()| (or whatever).
|
||||
while (!channel_->IsWriteBufferEmpty())
|
||||
test::Sleep(test::DeadlineFromMilliseconds(20));
|
||||
test::Sleep(test::EpsilonTimeout());
|
||||
|
||||
test_io_thread_.PostTaskAndWait(base::Bind(
|
||||
&ChannelThread::ShutdownChannelOnIOThread, base::Unretained(this)));
|
||||
|
||||
@ -7,10 +7,9 @@
|
||||
|
||||
#include "mojo/edk/embedder/simple_platform_support.h"
|
||||
#include "mojo/edk/system/channel.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/system/test/test_io_thread.h"
|
||||
#include "mojo/edk/test/multiprocess_test_helper.h"
|
||||
#include "mojo/edk/test/test_io_thread.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -32,19 +31,19 @@ class ChannelThread {
|
||||
~ChannelThread();
|
||||
|
||||
void Start(embedder::ScopedPlatformHandle platform_handle,
|
||||
RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
util::RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
// TODO(vtl): |channel_endpoint| should be an rvalue reference, but that
|
||||
// doesn't currently work correctly with base::Bind.
|
||||
void InitChannelOnIOThread(embedder::ScopedPlatformHandle platform_handle,
|
||||
RefPtr<ChannelEndpoint> channel_endpoint);
|
||||
util::RefPtr<ChannelEndpoint> channel_endpoint);
|
||||
void ShutdownChannelOnIOThread();
|
||||
|
||||
embedder::PlatformSupport* const platform_support_;
|
||||
mojo::test::TestIOThread test_io_thread_;
|
||||
RefPtr<Channel> channel_;
|
||||
TestIOThread test_io_thread_;
|
||||
util::RefPtr<Channel> channel_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(ChannelThread);
|
||||
};
|
||||
@ -56,7 +55,7 @@ class MultiprocessMessagePipeTestBase : public testing::Test {
|
||||
~MultiprocessMessagePipeTestBase() override;
|
||||
|
||||
protected:
|
||||
void Init(RefPtr<ChannelEndpoint>&& ep);
|
||||
void Init(util::RefPtr<ChannelEndpoint>&& ep);
|
||||
|
||||
embedder::PlatformSupport* platform_support() { return &platform_support_; }
|
||||
mojo::test::MultiprocessTestHelper* helper() { return &helper_; }
|
||||
|
||||
@ -22,14 +22,15 @@
|
||||
#include "mojo/edk/system/message_pipe_test_utils.h"
|
||||
#include "mojo/edk/system/platform_handle_dispatcher.h"
|
||||
#include "mojo/edk/system/raw_channel.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/shared_buffer_dispatcher.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/edk/test/scoped_test_dir.h"
|
||||
#include "mojo/edk/system/test/scoped_test_dir.h"
|
||||
#include "mojo/edk/test/test_utils.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/scoped_file.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
@ -338,7 +339,7 @@ TEST_F(MultiprocessMessagePipeTest, MAYBE_SharedBufferPassing) {
|
||||
MOJO_WRITE_MESSAGE_FLAG_NONE));
|
||||
transport.End();
|
||||
|
||||
dispatcher->AssertHasOneRef();
|
||||
EXPECT_TRUE(dispatcher->HasOneRef());
|
||||
dispatcher = nullptr;
|
||||
|
||||
// Wait for a message from the child.
|
||||
@ -426,7 +427,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) {
|
||||
|
||||
RefPtr<PlatformHandleDispatcher> dispatcher(
|
||||
static_cast<PlatformHandleDispatcher*>(dispatchers[i].get()));
|
||||
embedder::ScopedPlatformHandle h = dispatcher->PassPlatformHandle().Pass();
|
||||
embedder::ScopedPlatformHandle h = dispatcher->PassPlatformHandle();
|
||||
CHECK(h.is_valid());
|
||||
dispatcher->Close();
|
||||
|
||||
@ -447,7 +448,7 @@ class MultiprocessMessagePipeTestWithPipeCount
|
||||
public testing::WithParamInterface<size_t> {};
|
||||
|
||||
TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
|
||||
mojo::test::ScopedTestDir test_dir;
|
||||
test::ScopedTestDir test_dir;
|
||||
|
||||
helper()->StartChild("CheckPlatformHandleFile");
|
||||
|
||||
@ -468,7 +469,7 @@ TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
|
||||
|
||||
auto dispatcher =
|
||||
PlatformHandleDispatcher::Create(embedder::ScopedPlatformHandle(
|
||||
mojo::test::PlatformHandleFromFILE(fp.Pass())));
|
||||
mojo::test::PlatformHandleFromFILE(std::move(fp))));
|
||||
dispatchers.push_back(dispatcher);
|
||||
DispatcherTransport transport(
|
||||
test::DispatcherTryStartTransport(dispatcher.get()));
|
||||
@ -485,7 +486,7 @@ TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
|
||||
|
||||
for (size_t i = 0; i < pipe_count; ++i) {
|
||||
transports[i].End();
|
||||
dispatchers[i]->AssertHasOneRef();
|
||||
EXPECT_TRUE(dispatchers[i]->HasOneRef());
|
||||
}
|
||||
|
||||
dispatchers.clear();
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
Mutex::Mutex() : lock_() {
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
DCHECK(owning_thread_ref_.is_null());
|
||||
}
|
||||
|
||||
void Mutex::AssertHeld() const {
|
||||
DCHECK(owning_thread_ref_ == base::PlatformThread::CurrentRef());
|
||||
}
|
||||
|
||||
void Mutex::CheckHeldAndUnmark() {
|
||||
DCHECK(owning_thread_ref_ == base::PlatformThread::CurrentRef());
|
||||
owning_thread_ref_ = base::PlatformThreadRef();
|
||||
}
|
||||
|
||||
void Mutex::CheckUnheldAndMark() {
|
||||
DCHECK(owning_thread_ref_.is_null());
|
||||
owning_thread_ref_ = base::PlatformThread::CurrentRef();
|
||||
}
|
||||
|
||||
} // namespace system
|
||||
} // namespace mojo
|
||||
|
||||
#endif // !NDEBUG || DCHECK_ALWAYS_ON
|
||||
@ -1,92 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// A mutex class, with support for thread annotations.
|
||||
//
|
||||
// TODO(vtl): Currently, this is a fork of Chromium's
|
||||
// base/synchronization/lock.h (with names changed and minor modifications; it
|
||||
// still cheats and uses Chromium's lock_impl.*), but eventually we'll want our
|
||||
// own and, e.g., add support for non-exclusive (reader) locks.
|
||||
|
||||
#ifndef MOJO_EDK_SYSTEM_MUTEX_H_
|
||||
#define MOJO_EDK_SYSTEM_MUTEX_H_
|
||||
|
||||
#include "base/synchronization/lock_impl.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "mojo/edk/system/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
// Mutex -----------------------------------------------------------------------
|
||||
|
||||
class MOJO_LOCKABLE Mutex {
|
||||
public:
|
||||
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
||||
Mutex() : lock_() {}
|
||||
~Mutex() {}
|
||||
|
||||
void Lock() MOJO_EXCLUSIVE_LOCK_FUNCTION() { lock_.Lock(); }
|
||||
void Unlock() MOJO_UNLOCK_FUNCTION() { lock_.Unlock(); }
|
||||
|
||||
bool TryLock() MOJO_EXCLUSIVE_TRYLOCK_FUNCTION(true) { return lock_.Try(); }
|
||||
|
||||
void AssertHeld() const MOJO_ASSERT_EXCLUSIVE_LOCK() {}
|
||||
#else
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void Lock() MOJO_EXCLUSIVE_LOCK_FUNCTION() {
|
||||
lock_.Lock();
|
||||
CheckUnheldAndMark();
|
||||
}
|
||||
void Unlock() MOJO_UNLOCK_FUNCTION() {
|
||||
CheckHeldAndUnmark();
|
||||
lock_.Unlock();
|
||||
}
|
||||
|
||||
bool TryLock() MOJO_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||
bool rv = lock_.Try();
|
||||
if (rv)
|
||||
CheckUnheldAndMark();
|
||||
return rv;
|
||||
}
|
||||
|
||||
void AssertHeld() const MOJO_ASSERT_EXCLUSIVE_LOCK();
|
||||
#endif // NDEBUG && !DCHECK_ALWAYS_ON
|
||||
|
||||
private:
|
||||
#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
|
||||
void CheckHeldAndUnmark();
|
||||
void CheckUnheldAndMark();
|
||||
|
||||
base::PlatformThreadRef owning_thread_ref_;
|
||||
#endif // !NDEBUG || DCHECK_ALWAYS_ON
|
||||
|
||||
base::internal::LockImpl lock_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(Mutex);
|
||||
};
|
||||
|
||||
// MutexLocker -----------------------------------------------------------------
|
||||
|
||||
class MOJO_SCOPED_LOCKABLE MutexLocker {
|
||||
public:
|
||||
explicit MutexLocker(Mutex* mutex) MOJO_EXCLUSIVE_LOCK_FUNCTION(mutex)
|
||||
: mutex_(mutex) {
|
||||
this->mutex_->Lock();
|
||||
}
|
||||
~MutexLocker() MOJO_UNLOCK_FUNCTION() { this->mutex_->Unlock(); }
|
||||
|
||||
private:
|
||||
Mutex* const mutex_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(MutexLocker);
|
||||
};
|
||||
|
||||
} // namespace system
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_EDK_SYSTEM_MUTEX_H_
|
||||
@ -1,250 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
#include "mojo/edk/system/mutex.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "mojo/edk/system/test_utils.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
|
||||
// Sleeps for a "very small" amount of time.
|
||||
void EpsilonRandomSleep() {
|
||||
test::Sleep(test::DeadlineFromMilliseconds(rand() % 20));
|
||||
}
|
||||
|
||||
// Basic test to make sure that Lock()/Unlock()/TryLock() don't crash ----------
|
||||
|
||||
class BasicMutexTestThread : public base::PlatformThread::Delegate {
|
||||
public:
|
||||
explicit BasicMutexTestThread(Mutex* mutex) : mutex_(mutex), acquired_(0) {}
|
||||
|
||||
void ThreadMain() override {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mutex_->Lock();
|
||||
mutex_->AssertHeld();
|
||||
acquired_++;
|
||||
mutex_->Unlock();
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mutex_->Lock();
|
||||
mutex_->AssertHeld();
|
||||
acquired_++;
|
||||
EpsilonRandomSleep();
|
||||
mutex_->Unlock();
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (mutex_->TryLock()) {
|
||||
mutex_->AssertHeld();
|
||||
acquired_++;
|
||||
EpsilonRandomSleep();
|
||||
mutex_->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int acquired() const { return acquired_; }
|
||||
|
||||
private:
|
||||
Mutex* mutex_;
|
||||
int acquired_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(BasicMutexTestThread);
|
||||
};
|
||||
|
||||
TEST(MutexTest, Basic) {
|
||||
Mutex mutex;
|
||||
BasicMutexTestThread thread(&mutex);
|
||||
base::PlatformThreadHandle handle;
|
||||
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle));
|
||||
|
||||
int acquired = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
mutex.Lock();
|
||||
mutex.AssertHeld();
|
||||
acquired++;
|
||||
mutex.Unlock();
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mutex.Lock();
|
||||
mutex.AssertHeld();
|
||||
acquired++;
|
||||
EpsilonRandomSleep();
|
||||
mutex.Unlock();
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (mutex.TryLock()) {
|
||||
mutex.AssertHeld();
|
||||
acquired++;
|
||||
EpsilonRandomSleep();
|
||||
mutex.Unlock();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
mutex.Lock();
|
||||
mutex.AssertHeld();
|
||||
acquired++;
|
||||
EpsilonRandomSleep();
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
base::PlatformThread::Join(handle);
|
||||
|
||||
EXPECT_GE(acquired, 20);
|
||||
EXPECT_GE(thread.acquired(), 20);
|
||||
}
|
||||
|
||||
// Test that TryLock() works as expected ---------------------------------------
|
||||
|
||||
class TryLockTestThread : public base::PlatformThread::Delegate {
|
||||
public:
|
||||
explicit TryLockTestThread(Mutex* mutex) : mutex_(mutex), got_lock_(false) {}
|
||||
|
||||
void ThreadMain() override MOJO_NO_THREAD_SAFETY_ANALYSIS {
|
||||
got_lock_ = mutex_->TryLock();
|
||||
if (got_lock_) {
|
||||
mutex_->AssertHeld();
|
||||
mutex_->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool got_lock() const { return got_lock_; }
|
||||
|
||||
private:
|
||||
Mutex* mutex_;
|
||||
bool got_lock_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
|
||||
};
|
||||
|
||||
TEST(MutexTest, TryLock) MOJO_NO_THREAD_SAFETY_ANALYSIS {
|
||||
Mutex mutex;
|
||||
|
||||
ASSERT_TRUE(mutex.TryLock());
|
||||
// We now have the mutex....
|
||||
|
||||
// This thread will not be able to get the mutex.
|
||||
{
|
||||
TryLockTestThread thread(&mutex);
|
||||
base::PlatformThreadHandle handle;
|
||||
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle));
|
||||
|
||||
base::PlatformThread::Join(handle);
|
||||
|
||||
ASSERT_FALSE(thread.got_lock());
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
|
||||
// This thread will....
|
||||
{
|
||||
TryLockTestThread thread(&mutex);
|
||||
base::PlatformThreadHandle handle;
|
||||
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle));
|
||||
|
||||
base::PlatformThread::Join(handle);
|
||||
|
||||
ASSERT_TRUE(thread.got_lock());
|
||||
// But it released it....
|
||||
ASSERT_TRUE(mutex.TryLock());
|
||||
}
|
||||
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
// Tests that mutexes actually exclude -----------------------------------------
|
||||
|
||||
class MutexLockTestThread : public base::PlatformThread::Delegate {
|
||||
public:
|
||||
MutexLockTestThread(Mutex* mutex, int* value)
|
||||
: mutex_(mutex), value_(value) {}
|
||||
|
||||
// Static helper which can also be called from the main thread.
|
||||
static void DoStuff(Mutex* mutex, int* value) {
|
||||
for (int i = 0; i < 40; i++) {
|
||||
mutex->Lock();
|
||||
int v = *value;
|
||||
EpsilonRandomSleep();
|
||||
*value = v + 1;
|
||||
mutex->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadMain() override { DoStuff(mutex_, value_); }
|
||||
|
||||
private:
|
||||
Mutex* mutex_;
|
||||
int* value_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
|
||||
};
|
||||
|
||||
TEST(MutexTest, MutexTwoThreads) {
|
||||
Mutex mutex;
|
||||
int value = 0;
|
||||
|
||||
MutexLockTestThread thread(&mutex, &value);
|
||||
base::PlatformThreadHandle handle;
|
||||
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle));
|
||||
|
||||
MutexLockTestThread::DoStuff(&mutex, &value);
|
||||
|
||||
base::PlatformThread::Join(handle);
|
||||
|
||||
EXPECT_EQ(2 * 40, value);
|
||||
}
|
||||
|
||||
TEST(MutexTest, MutexFourThreads) {
|
||||
Mutex mutex;
|
||||
int value = 0;
|
||||
|
||||
MutexLockTestThread thread1(&mutex, &value);
|
||||
MutexLockTestThread thread2(&mutex, &value);
|
||||
MutexLockTestThread thread3(&mutex, &value);
|
||||
base::PlatformThreadHandle handle1;
|
||||
base::PlatformThreadHandle handle2;
|
||||
base::PlatformThreadHandle handle3;
|
||||
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread1, &handle1));
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread2, &handle2));
|
||||
ASSERT_TRUE(base::PlatformThread::Create(0, &thread3, &handle3));
|
||||
|
||||
MutexLockTestThread::DoStuff(&mutex, &value);
|
||||
|
||||
base::PlatformThread::Join(handle1);
|
||||
base::PlatformThread::Join(handle2);
|
||||
base::PlatformThread::Join(handle3);
|
||||
|
||||
EXPECT_EQ(4 * 40, value);
|
||||
}
|
||||
|
||||
// MutexLocker -----------------------------------------------------------------
|
||||
|
||||
TEST(MutexTest, MutexLocker) {
|
||||
Mutex mutex;
|
||||
|
||||
{
|
||||
MutexLocker locker(&mutex);
|
||||
mutex.AssertHeld();
|
||||
}
|
||||
|
||||
// The destruction of |locker| should unlock |mutex|.
|
||||
ASSERT_TRUE(mutex.TryLock());
|
||||
mutex.AssertHeld();
|
||||
mutex.Unlock();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace system
|
||||
} // namespace mojo
|
||||
@ -14,7 +14,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/logging.h"
|
||||
@ -38,15 +37,15 @@ class UserOptionsReader {
|
||||
// Note: We initialize |options_reader_| without checking, since we do a check
|
||||
// in |GetSizeForReader()|.
|
||||
explicit UserOptionsReader(UserPointer<const Options> options)
|
||||
: options_reader_(UserPointer<const char>::Reader::NoCheck(),
|
||||
options.template ReinterpretCast<const char>(),
|
||||
GetSizeForReader(options)) {}
|
||||
: options_reader_(options, GetSizeForReader(options)) {}
|
||||
|
||||
bool is_valid() const { return !!options_reader_.GetPointer(); }
|
||||
bool is_valid() const {
|
||||
return options_reader_.GetPointer()->struct_size >= sizeof(uint32_t);
|
||||
}
|
||||
|
||||
const Options& options() const {
|
||||
DCHECK(is_valid());
|
||||
return *reinterpret_cast<const Options*>(options_reader_.GetPointer());
|
||||
return *options_reader_.GetPointer();
|
||||
}
|
||||
|
||||
// Checks that the given (variable-size) |options| passed to the constructor
|
||||
@ -64,20 +63,17 @@ class UserOptionsReader {
|
||||
static inline size_t GetSizeForReader(UserPointer<const Options> options) {
|
||||
uint32_t struct_size =
|
||||
options.template ReinterpretCast<const uint32_t>().Get();
|
||||
// Note: |PartialReader| will clear memory, so |is_valid()| will return
|
||||
// false in this case.
|
||||
if (struct_size < sizeof(uint32_t))
|
||||
return 0;
|
||||
|
||||
// Check the full requested size.
|
||||
// Note: Use |MOJO_ALIGNOF()| here to match the exact macro used in the
|
||||
// declaration of Options structs.
|
||||
internal::CheckUserPointerWithSize<MOJO_ALIGNOF(Options)>(options.pointer_,
|
||||
struct_size);
|
||||
options.template ReinterpretCast<const char>().CheckArray(struct_size);
|
||||
// But we'll never look at more than |sizeof(Options)| bytes.
|
||||
return std::min(static_cast<size_t>(struct_size), sizeof(Options));
|
||||
// |PartialReader|'s constructor will automatically limit the amount copied
|
||||
// to |sizeof(Options)|.
|
||||
return struct_size;
|
||||
}
|
||||
|
||||
UserPointer<const char>::Reader options_reader_;
|
||||
typename UserPointer<const Options>::PartialReader options_reader_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(UserOptionsReader);
|
||||
};
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -6,8 +6,9 @@
|
||||
#define MOJO_EDK_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
|
||||
|
||||
#include "mojo/edk/embedder/scoped_platform_handle.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/system/simple_dispatcher.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/edk/util/thread_annotations.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -17,7 +18,7 @@ namespace system {
|
||||
// the embedder).
|
||||
class PlatformHandleDispatcher final : public SimpleDispatcher {
|
||||
public:
|
||||
static RefPtr<PlatformHandleDispatcher> Create(
|
||||
static util::RefPtr<PlatformHandleDispatcher> Create(
|
||||
embedder::ScopedPlatformHandle platform_handle) {
|
||||
return AdoptRef(new PlatformHandleDispatcher(platform_handle.Pass()));
|
||||
}
|
||||
@ -29,7 +30,7 @@ class PlatformHandleDispatcher final : public SimpleDispatcher {
|
||||
|
||||
// The "opposite" of |SerializeAndClose()|. (Typically this is called by
|
||||
// |Dispatcher::Deserialize()|.)
|
||||
static RefPtr<PlatformHandleDispatcher> Deserialize(
|
||||
static util::RefPtr<PlatformHandleDispatcher> Deserialize(
|
||||
Channel* channel,
|
||||
const void* source,
|
||||
size_t size,
|
||||
@ -42,7 +43,8 @@ class PlatformHandleDispatcher final : public SimpleDispatcher {
|
||||
|
||||
// |Dispatcher| protected methods:
|
||||
void CloseImplNoLock() override;
|
||||
RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock() override;
|
||||
util::RefPtr<Dispatcher> CreateEquivalentDispatcherAndCloseImplNoLock()
|
||||
override;
|
||||
void StartSerializeImplNoLock(Channel* channel,
|
||||
size_t* max_size,
|
||||
size_t* max_platform_handles) override
|
||||
|
||||
@ -6,18 +6,21 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "mojo/edk/test/scoped_test_dir.h"
|
||||
#include <utility>
|
||||
|
||||
#include "mojo/edk/system/test/scoped_test_dir.h"
|
||||
#include "mojo/edk/test/test_utils.h"
|
||||
#include "mojo/edk/util/scoped_file.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
namespace {
|
||||
|
||||
TEST(PlatformHandleDispatcherTest, Basic) {
|
||||
mojo::test::ScopedTestDir test_dir;
|
||||
test::ScopedTestDir test_dir;
|
||||
|
||||
static const char kHelloWorld[] = "hello world";
|
||||
|
||||
@ -27,7 +30,7 @@ TEST(PlatformHandleDispatcherTest, Basic) {
|
||||
fwrite(kHelloWorld, 1, sizeof(kHelloWorld), fp.get()));
|
||||
|
||||
embedder::ScopedPlatformHandle h(
|
||||
mojo::test::PlatformHandleFromFILE(fp.Pass()));
|
||||
mojo::test::PlatformHandleFromFILE(std::move(fp)));
|
||||
EXPECT_FALSE(fp);
|
||||
ASSERT_TRUE(h.is_valid());
|
||||
|
||||
@ -35,10 +38,10 @@ TEST(PlatformHandleDispatcherTest, Basic) {
|
||||
EXPECT_FALSE(h.is_valid());
|
||||
EXPECT_EQ(Dispatcher::Type::PLATFORM_HANDLE, dispatcher->GetType());
|
||||
|
||||
h = dispatcher->PassPlatformHandle().Pass();
|
||||
h = dispatcher->PassPlatformHandle();
|
||||
EXPECT_TRUE(h.is_valid());
|
||||
|
||||
fp = mojo::test::FILEFromPlatformHandle(h.Pass(), "rb").Pass();
|
||||
fp = mojo::test::FILEFromPlatformHandle(h.Pass(), "rb");
|
||||
EXPECT_FALSE(h.is_valid());
|
||||
EXPECT_TRUE(fp);
|
||||
|
||||
@ -49,14 +52,14 @@ TEST(PlatformHandleDispatcherTest, Basic) {
|
||||
EXPECT_STREQ(kHelloWorld, read_buffer);
|
||||
|
||||
// Try getting the handle again. (It should fail cleanly.)
|
||||
h = dispatcher->PassPlatformHandle().Pass();
|
||||
h = dispatcher->PassPlatformHandle();
|
||||
EXPECT_FALSE(h.is_valid());
|
||||
|
||||
EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
|
||||
}
|
||||
|
||||
TEST(PlatformHandleDispatcherTest, CreateEquivalentDispatcherAndClose) {
|
||||
mojo::test::ScopedTestDir test_dir;
|
||||
test::ScopedTestDir test_dir;
|
||||
|
||||
static const char kFooBar[] = "foo bar";
|
||||
|
||||
@ -64,7 +67,7 @@ TEST(PlatformHandleDispatcherTest, CreateEquivalentDispatcherAndClose) {
|
||||
EXPECT_EQ(sizeof(kFooBar), fwrite(kFooBar, 1, sizeof(kFooBar), fp.get()));
|
||||
|
||||
auto dispatcher = PlatformHandleDispatcher::Create(
|
||||
mojo::test::PlatformHandleFromFILE(fp.Pass()));
|
||||
mojo::test::PlatformHandleFromFILE(std::move(fp)));
|
||||
|
||||
DispatcherTransport transport(
|
||||
test::DispatcherTryStartTransport(dispatcher.get()));
|
||||
@ -76,7 +79,7 @@ TEST(PlatformHandleDispatcherTest, CreateEquivalentDispatcherAndClose) {
|
||||
ASSERT_TRUE(generic_dispatcher);
|
||||
|
||||
transport.End();
|
||||
dispatcher->AssertHasOneRef();
|
||||
EXPECT_TRUE(dispatcher->HasOneRef());
|
||||
dispatcher = nullptr;
|
||||
|
||||
ASSERT_EQ(Dispatcher::Type::PLATFORM_HANDLE, generic_dispatcher->GetType());
|
||||
@ -84,7 +87,7 @@ TEST(PlatformHandleDispatcherTest, CreateEquivalentDispatcherAndClose) {
|
||||
static_cast<PlatformHandleDispatcher*>(generic_dispatcher.get()));
|
||||
|
||||
fp = mojo::test::FILEFromPlatformHandle(dispatcher->PassPlatformHandle(),
|
||||
"rb").Pass();
|
||||
"rb");
|
||||
EXPECT_TRUE(fp);
|
||||
|
||||
rewind(fp.get());
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
#include "mojo/edk/system/local_message_pipe_endpoint.h"
|
||||
#include "mojo/edk/system/message_pipe_dispatcher.h"
|
||||
|
||||
using mojo::util::RefPtr;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
#include "mojo/edk/system/message_pipe_endpoint.h"
|
||||
#include "mojo/edk/system/ref_ptr.h"
|
||||
#include "mojo/edk/util/ref_ptr.h"
|
||||
#include "mojo/public/cpp/system/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
@ -28,7 +28,8 @@ class MessagePipe;
|
||||
// a |MessagePipeDispatcher|.
|
||||
class ProxyMessagePipeEndpoint final : public MessagePipeEndpoint {
|
||||
public:
|
||||
explicit ProxyMessagePipeEndpoint(RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
explicit ProxyMessagePipeEndpoint(
|
||||
util::RefPtr<ChannelEndpoint>&& channel_endpoint);
|
||||
~ProxyMessagePipeEndpoint() override;
|
||||
|
||||
// Returns |channel_endpoint_| and resets |channel_endpoint_| to null. This
|
||||
@ -37,7 +38,7 @@ class ProxyMessagePipeEndpoint final : public MessagePipeEndpoint {
|
||||
// Note: The returned |ChannelEndpoint| must have its client changed while
|
||||
// still under |MessagePipe|'s lock (which this must have also been called
|
||||
// under).
|
||||
RefPtr<ChannelEndpoint> ReleaseChannelEndpoint();
|
||||
util::RefPtr<ChannelEndpoint> ReleaseChannelEndpoint();
|
||||
|
||||
// |MessagePipeEndpoint| implementation:
|
||||
Type GetType() const override;
|
||||
@ -48,7 +49,7 @@ class ProxyMessagePipeEndpoint final : public MessagePipeEndpoint {
|
||||
private:
|
||||
void DetachIfNecessary();
|
||||
|
||||
RefPtr<ChannelEndpoint> channel_endpoint_;
|
||||
util::RefPtr<ChannelEndpoint> channel_endpoint_;
|
||||
|
||||
MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyMessagePipeEndpoint);
|
||||
};
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
#include "mojo/edk/system/message_in_transit.h"
|
||||
#include "mojo/edk/system/transport_data.h"
|
||||
|
||||
using mojo::util::MutexLocker;
|
||||
|
||||
namespace mojo {
|
||||
namespace system {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user