From 0847bbc2d08e9e18d30f5cacee02bb3054ff6da0 Mon Sep 17 00:00:00 2001 From: Collin Jackson Date: Fri, 6 Nov 2015 14:15:04 -0800 Subject: [PATCH] Update to mojo dd010e1297c09b351dc82f7def154cfa63d795b1 --- mojo/android/BUILD.gn | 1 - mojo/common/BUILD.gn | 29 +- mojo/common/binding_set.h | 7 +- mojo/common/strong_binding_set.h | 65 +++ mojo/common/strong_binding_set_unittest.cc | 115 +++++ mojo/common/task_tracker.cc | 102 ---- mojo/common/task_tracker.h | 26 -- mojo/common/task_tracker_unittest.cc | 54 --- .../array_string_type_converters.cc | 2 +- .../geometry/geometry_type_converters.cc | 12 +- .../input_events_type_converters.cc | 3 +- .../input_events_type_converters.h | 20 +- .../ozone_drm_gpu_type_converters.cc | 4 +- .../surfaces/surfaces_type_converters.cc | 32 +- mojo/edk/embedder/BUILD.gn | 21 +- mojo/edk/embedder/embedder.cc | 15 +- mojo/edk/embedder/embedder.h | 3 +- mojo/edk/embedder/embedder_unittest.cc | 68 +-- mojo/edk/embedder/platform_channel_pair.cc | 98 ++++ mojo/edk/embedder/platform_channel_pair.h | 6 +- .../embedder/platform_channel_pair_posix.cc | 111 ----- ...t.cc => platform_channel_pair_unittest.cc} | 45 +- ...ils_posix.cc => platform_channel_utils.cc} | 2 +- ...utils_posix.h => platform_channel_utils.h} | 6 +- mojo/edk/embedder/platform_shared_buffer.h | 6 +- mojo/edk/embedder/platform_support.h | 6 +- .../embedder/simple_platform_shared_buffer.cc | 207 +++++++- .../embedder/simple_platform_shared_buffer.h | 11 +- .../simple_platform_shared_buffer_android.cc | 71 --- .../simple_platform_shared_buffer_posix.cc | 160 ------- .../simple_platform_shared_buffer_unittest.cc | 19 +- mojo/edk/embedder/simple_platform_support.cc | 7 +- mojo/edk/embedder/simple_platform_support.h | 5 +- .../system_impl_private_entrypoints.cc | 5 +- mojo/edk/mojo_edk.gni | 73 +++ mojo/edk/system/BUILD.gn | 78 ++-- mojo/edk/system/awakable_list_unittest.cc | 25 +- mojo/edk/system/channel.cc | 4 + mojo/edk/system/channel.h | 37 +- mojo/edk/system/channel_endpoint.cc | 3 + mojo/edk/system/channel_endpoint.h | 26 +- mojo/edk/system/channel_endpoint_client.h | 4 +- mojo/edk/system/channel_endpoint_unittest.cc | 20 +- mojo/edk/system/channel_manager.cc | 4 + mojo/edk/system/channel_manager.h | 25 +- mojo/edk/system/channel_manager_unittest.cc | 21 +- mojo/edk/system/channel_test_base.cc | 4 +- mojo/edk/system/channel_test_base.h | 12 +- mojo/edk/system/channel_unittest.cc | 13 +- mojo/edk/system/connection_manager.h | 2 +- mojo/edk/system/core.cc | 3 + mojo/edk/system/core.h | 13 +- mojo/edk/system/core_test_base.cc | 5 +- mojo/edk/system/core_test_base.h | 5 +- mojo/edk/system/core_unittest.cc | 4 +- mojo/edk/system/data_pipe.cc | 3 + mojo/edk/system/data_pipe.h | 22 +- .../system/data_pipe_consumer_dispatcher.cc | 3 + .../system/data_pipe_consumer_dispatcher.h | 17 +- mojo/edk/system/data_pipe_impl.h | 2 +- mojo/edk/system/data_pipe_impl_unittest.cc | 100 ++-- .../system/data_pipe_producer_dispatcher.cc | 3 + .../system/data_pipe_producer_dispatcher.h | 17 +- mojo/edk/system/dispatcher.cc | 3 + mojo/edk/system/dispatcher.h | 30 +- mojo/edk/system/dispatcher_unittest.cc | 24 +- mojo/edk/system/endpoint_relayer.cc | 3 + mojo/edk/system/endpoint_relayer.h | 15 +- mojo/edk/system/endpoint_relayer_unittest.cc | 23 +- mojo/edk/system/handle_table.cc | 2 + mojo/edk/system/handle_table.h | 14 +- mojo/edk/system/incoming_endpoint.cc | 4 + mojo/edk/system/incoming_endpoint.h | 19 +- mojo/edk/system/ipc_support.cc | 2 + mojo/edk/system/ipc_support.h | 7 +- mojo/edk/system/ipc_support_unittest.cc | 79 ++-- mojo/edk/system/local_data_pipe_impl.cc | 2 + mojo/edk/system/master_connection_manager.cc | 8 +- mojo/edk/system/master_connection_manager.h | 11 +- mojo/edk/system/memory.h | 101 +++- mojo/edk/system/message_pipe.cc | 4 + mojo/edk/system/message_pipe.h | 24 +- mojo/edk/system/message_pipe_dispatcher.cc | 2 + mojo/edk/system/message_pipe_dispatcher.h | 22 +- .../message_pipe_dispatcher_unittest.cc | 49 +- mojo/edk/system/message_pipe_endpoint.h | 1 - mojo/edk/system/message_pipe_perftest.cc | 24 +- mojo/edk/system/message_pipe_test_utils.cc | 10 +- mojo/edk/system/message_pipe_test_utils.h | 15 +- .../multiprocess_message_pipe_unittest.cc | 17 +- mojo/edk/system/mutex.cc | 38 -- mojo/edk/system/mutex.h | 92 ---- mojo/edk/system/mutex_unittest.cc | 250 ---------- mojo/edk/system/options_validation.h | 26 +- mojo/edk/system/platform_handle_dispatcher.cc | 3 + mojo/edk/system/platform_handle_dispatcher.h | 10 +- .../platform_handle_dispatcher_unittest.cc | 25 +- .../edk/system/proxy_message_pipe_endpoint.cc | 2 + mojo/edk/system/proxy_message_pipe_endpoint.h | 9 +- mojo/edk/system/raw_channel.cc | 2 + mojo/edk/system/raw_channel.h | 10 +- mojo/edk/system/raw_channel_posix.cc | 4 +- mojo/edk/system/raw_channel_unittest.cc | 60 +-- .../system/remote_consumer_data_pipe_impl.cc | 2 + .../system/remote_consumer_data_pipe_impl.h | 6 +- .../system/remote_data_pipe_impl_unittest.cc | 42 +- .../system/remote_message_pipe_unittest.cc | 53 ++- .../system/remote_producer_data_pipe_impl.cc | 2 + .../system/remote_producer_data_pipe_impl.h | 8 +- mojo/edk/system/shared_buffer_dispatcher.cc | 23 +- mojo/edk/system/shared_buffer_dispatcher.h | 24 +- .../shared_buffer_dispatcher_unittest.cc | 3 +- mojo/edk/system/simple_dispatcher.h | 5 +- mojo/edk/system/simple_dispatcher_unittest.cc | 88 ++-- mojo/edk/system/slave_connection_manager.cc | 6 +- mojo/edk/system/slave_connection_manager.h | 8 +- mojo/edk/system/test/BUILD.gn | 106 +++++ mojo/edk/system/test/perf_log.cc | 19 + mojo/edk/system/test/perf_log.h | 29 ++ mojo/edk/system/test/random.cc | 36 ++ mojo/edk/system/test/random.h | 23 + .../random_unittest.cc} | 6 +- mojo/edk/system/test/run_all_perftests.cc | 11 + .../system/{ => test}/run_all_unittests.cc | 5 + mojo/edk/{ => system}/test/scoped_test_dir.cc | 4 +- mojo/edk/{ => system}/test/scoped_test_dir.h | 8 +- .../{ => system}/test/simple_test_thread.cc | 18 +- .../{ => system}/test/simple_test_thread.h | 27 +- mojo/edk/system/test/sleep.cc | 31 ++ mojo/edk/system/test/sleep.h | 24 + mojo/edk/system/test/stopwatch.cc | 32 ++ mojo/edk/system/test/stopwatch.h | 43 ++ mojo/edk/system/test/test_command_line.cc | 29 ++ mojo/edk/system/test/test_command_line.h | 34 ++ mojo/edk/{ => system}/test/test_io_thread.cc | 4 +- mojo/edk/{ => system}/test/test_io_thread.h | 8 +- mojo/edk/system/test/timeouts.cc | 42 ++ mojo/edk/system/test/timeouts.h | 36 ++ .../system/test_channel_endpoint_client.cc | 8 +- .../edk/system/test_channel_endpoint_client.h | 24 +- mojo/edk/system/test_utils.cc | 90 ---- mojo/edk/system/test_utils.h | 71 --- mojo/edk/system/waitable_event.cc | 168 +++++++ mojo/edk/system/waitable_event.h | 127 +++++ mojo/edk/system/waitable_event_unittest.cc | 257 ++++++++++ mojo/edk/system/waiter.cc | 54 ++- mojo/edk/system/waiter.h | 19 +- mojo/edk/system/waiter_test_utils.cc | 2 + mojo/edk/system/waiter_test_utils.h | 12 +- mojo/edk/system/waiter_unittest.cc | 95 ++-- mojo/edk/test/BUILD.gn | 94 +--- mojo/edk/test/multiprocess_test_helper.cc | 1 + mojo/edk/test/multiprocess_test_helper.h | 1 - mojo/edk/test/run_all_perftests.cc | 3 - mojo/edk/test/run_all_unittests.cc | 3 - mojo/edk/test/test_support_impl.cc | 36 +- mojo/edk/test/test_support_impl.h | 36 -- .../{test_utils_posix.cc => test_utils.cc} | 2 +- mojo/edk/util/BUILD.gn | 56 ++- mojo/edk/util/command_line.cc | 158 +++++++ mojo/edk/util/command_line.h | 224 +++++++++ mojo/edk/util/command_line_unittest.cc | 442 ++++++++++++++++++ mojo/edk/util/cond_var.cc | 147 ++++++ mojo/edk/util/cond_var.h | 66 +++ mojo/edk/util/cond_var_unittest.cc | 173 +++++++ mojo/edk/util/logging_internal.cc | 33 ++ mojo/edk/util/logging_internal.h | 61 +++ mojo/edk/util/mutex.cc | 57 +++ mojo/edk/util/mutex.h | 83 ++++ mojo/edk/util/mutex_unittest.cc | 201 ++++++++ mojo/edk/{system => util}/ref_counted.h | 36 +- .../{system => util}/ref_counted_internal.h | 17 +- .../{system => util}/ref_counted_perftest.cc | 27 +- .../{system => util}/ref_counted_unittest.cc | 13 +- mojo/edk/{system => util}/ref_ptr.h | 12 +- mojo/edk/{system => util}/ref_ptr_internal.h | 10 +- mojo/edk/util/scoped_file.h | 4 +- .../edk/{system => util}/thread_annotations.h | 6 +- .../thread_annotations_unittest.cc | 8 +- mojo/environment/BUILD.gn | 4 - mojo/environment/default_task_tracker.cc | 48 -- mojo/environment/default_task_tracker.h | 19 - mojo/environment/environment.cc | 6 - mojo/message_pump/handle_watcher_unittest.cc | 2 +- mojo/services/files/c/tests/test_utils.cc | 2 +- mojo/services/files/interfaces/file.mojom | 2 +- .../http_server/cpp/lib/http_server_util.cc | 2 +- mojo/services/mojo_services.gni | 1 + mojo/services/surfaces/cpp/surfaces_utils.cc | 6 +- mojo/services/ui/views/interfaces/BUILD.gn | 21 + .../ui/views/interfaces/layouts.mojom | 73 +++ .../ui/views/interfaces/view_manager.mojom | 49 ++ .../ui/views/interfaces/view_provider.mojom | 30 ++ .../ui/views/interfaces/view_trees.mojom | 92 ++++ mojo/services/ui/views/interfaces/views.mojom | 167 +++++++ .../security/interfaces/principal.mojom | 92 ++-- mojo/services/view_manager/cpp/lib/view.cc | 4 +- 197 files changed, 4999 insertions(+), 2341 deletions(-) create mode 100644 mojo/common/strong_binding_set.h create mode 100644 mojo/common/strong_binding_set_unittest.cc delete mode 100644 mojo/common/task_tracker.cc delete mode 100644 mojo/common/task_tracker.h delete mode 100644 mojo/common/task_tracker_unittest.cc delete mode 100644 mojo/edk/embedder/platform_channel_pair_posix.cc rename mojo/edk/embedder/{platform_channel_pair_posix_unittest.cc => platform_channel_pair_unittest.cc} (90%) rename mojo/edk/embedder/{platform_channel_utils_posix.cc => platform_channel_utils.cc} (99%) rename mojo/edk/embedder/{platform_channel_utils_posix.h => platform_channel_utils.h} (94%) delete mode 100644 mojo/edk/embedder/simple_platform_shared_buffer_android.cc delete mode 100644 mojo/edk/embedder/simple_platform_shared_buffer_posix.cc delete mode 100644 mojo/edk/system/mutex.cc delete mode 100644 mojo/edk/system/mutex.h delete mode 100644 mojo/edk/system/mutex_unittest.cc create mode 100644 mojo/edk/system/test/BUILD.gn create mode 100644 mojo/edk/system/test/perf_log.cc create mode 100644 mojo/edk/system/test/perf_log.h create mode 100644 mojo/edk/system/test/random.cc create mode 100644 mojo/edk/system/test/random.h rename mojo/edk/system/{test_utils_unittest.cc => test/random_unittest.cc} (92%) create mode 100644 mojo/edk/system/test/run_all_perftests.cc rename mojo/edk/system/{ => test}/run_all_unittests.cc (81%) rename mojo/edk/{ => system}/test/scoped_test_dir.cc (87%) rename mojo/edk/{ => system}/test/scoped_test_dir.h (79%) rename mojo/edk/{ => system}/test/simple_test_thread.cc (50%) rename mojo/edk/{ => system}/test/simple_test_thread.h (53%) create mode 100644 mojo/edk/system/test/sleep.cc create mode 100644 mojo/edk/system/test/sleep.h create mode 100644 mojo/edk/system/test/stopwatch.cc create mode 100644 mojo/edk/system/test/stopwatch.h create mode 100644 mojo/edk/system/test/test_command_line.cc create mode 100644 mojo/edk/system/test/test_command_line.h rename mojo/edk/{ => system}/test/test_io_thread.cc (94%) rename mojo/edk/{ => system}/test/test_io_thread.h (89%) create mode 100644 mojo/edk/system/test/timeouts.cc create mode 100644 mojo/edk/system/test/timeouts.h delete mode 100644 mojo/edk/system/test_utils.cc delete mode 100644 mojo/edk/system/test_utils.h create mode 100644 mojo/edk/system/waitable_event.cc create mode 100644 mojo/edk/system/waitable_event.h create mode 100644 mojo/edk/system/waitable_event_unittest.cc delete mode 100644 mojo/edk/test/test_support_impl.h rename mojo/edk/test/{test_utils_posix.cc => test_utils.cc} (99%) create mode 100644 mojo/edk/util/command_line.cc create mode 100644 mojo/edk/util/command_line.h create mode 100644 mojo/edk/util/command_line_unittest.cc create mode 100644 mojo/edk/util/cond_var.cc create mode 100644 mojo/edk/util/cond_var.h create mode 100644 mojo/edk/util/cond_var_unittest.cc create mode 100644 mojo/edk/util/logging_internal.cc create mode 100644 mojo/edk/util/logging_internal.h create mode 100644 mojo/edk/util/mutex.cc create mode 100644 mojo/edk/util/mutex.h create mode 100644 mojo/edk/util/mutex_unittest.cc rename mojo/edk/{system => util}/ref_counted.h (77%) rename mojo/edk/{system => util}/ref_counted_internal.h (86%) rename mojo/edk/{system => util}/ref_counted_perftest.cc (63%) rename mojo/edk/{system => util}/ref_counted_unittest.cc (97%) rename mojo/edk/{system => util}/ref_ptr.h (97%) rename mojo/edk/{system => util}/ref_ptr_internal.h (83%) rename mojo/edk/{system => util}/thread_annotations.h (95%) rename mojo/edk/{system => util}/thread_annotations_unittest.cc (95%) delete mode 100644 mojo/environment/default_task_tracker.cc delete mode 100644 mojo/environment/default_task_tracker.h create mode 100644 mojo/services/ui/views/interfaces/BUILD.gn create mode 100644 mojo/services/ui/views/interfaces/layouts.mojom create mode 100644 mojo/services/ui/views/interfaces/view_manager.mojom create mode 100644 mojo/services/ui/views/interfaces/view_provider.mojom create mode 100644 mojo/services/ui/views/interfaces/view_trees.mojom create mode 100644 mojo/services/ui/views/interfaces/views.mojom diff --git a/mojo/android/BUILD.gn b/mojo/android/BUILD.gn index ccb482324f5..5c8381d1d3f 100644 --- a/mojo/android/BUILD.gn +++ b/mojo/android/BUILD.gn @@ -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" ] } diff --git a/mojo/common/BUILD.gn b/mojo/common/BUILD.gn index cdc4b64ea9c..adac15897f8 100644 --- a/mojo/common/BUILD.gn +++ b/mojo/common/BUILD.gn @@ -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", ] } diff --git a/mojo/common/binding_set.h b/mojo/common/binding_set.h index 6e81e766217..4439f32e764 100644 --- a/mojo/common/binding_set.h +++ b/mojo/common/binding_set.h @@ -6,9 +6,11 @@ #define MOJO_COMMON_BINDING_SET_H_ #include +#include #include -#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 request) { bindings_.emplace_back(new Binding(impl, request.Pass())); auto* binding = bindings_.back().get(); diff --git a/mojo/common/strong_binding_set.h b/mojo/common/strong_binding_set.h new file mode 100644 index 00000000000..95467d892c0 --- /dev/null +++ b/mojo/common/strong_binding_set.h @@ -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 +#include +#include + +#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 +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 request) { + bindings_.emplace_back(new Binding(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>& 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>> bindings_; + + DISALLOW_COPY_AND_ASSIGN(StrongBindingSet); +}; + +} // namespace mojo + +#endif // MOJO_COMMON_STRONG_BINDING_SET_H_ diff --git a/mojo/common/strong_binding_set_unittest.cc b/mojo/common/strong_binding_set_unittest.cc new file mode 100644 index 00000000000..59a7aa4e65c --- /dev/null +++ b/mojo/common/strong_binding_set_unittest.cc @@ -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 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 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& 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 diff --git a/mojo/common/task_tracker.cc b/mojo/common/task_tracker.cc deleted file mode 100644 index 8665799c7fd..00000000000 --- a/mojo/common/task_tracker.cc +++ /dev/null @@ -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 - -#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(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 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(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(id), g_activation.Get()); - reinterpret_cast(id)->End(); -} - -} // namespace common -} // namespace mojo diff --git a/mojo/common/task_tracker.h b/mojo/common/task_tracker.h deleted file mode 100644 index 788663649bf..00000000000 --- a/mojo/common/task_tracker.h +++ /dev/null @@ -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 - -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_ diff --git a/mojo/common/task_tracker_unittest.cc b/mojo/common/task_tracker_unittest.cc deleted file mode 100644 index 090e58695de..00000000000 --- a/mojo/common/task_tracker_unittest.cc +++ /dev/null @@ -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 diff --git a/mojo/converters/array_string/array_string_type_converters.cc b/mojo/converters/array_string/array_string_type_converters.cc index 84d3c2a20a9..9f99460f3e0 100644 --- a/mojo/converters/array_string/array_string_type_converters.cc +++ b/mojo/converters/array_string/array_string_type_converters.cc @@ -23,7 +23,7 @@ Array TypeConverter, std::string>::Convert( const std::string& input) { auto result = Array::New(input.size()); memcpy(&result.front(), input.c_str(), input.size()); - return result.Pass(); + return result; } } // namespace mojo diff --git a/mojo/converters/geometry/geometry_type_converters.cc b/mojo/converters/geometry/geometry_type_converters.cc index 40d8d89ad5e..ad66c1112a4 100644 --- a/mojo/converters/geometry/geometry_type_converters.cc +++ b/mojo/converters/geometry/geometry_type_converters.cc @@ -11,7 +11,7 @@ PointPtr TypeConverter::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::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::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::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::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::Convert( matrix.Swap(&storage); TransformPtr transform(Transform::New()); transform->matrix = matrix.Pass(); - return transform.Pass(); + return transform; } // static diff --git a/mojo/converters/input_events/input_events_type_converters.cc b/mojo/converters/input_events/input_events_type_converters.cc index e7b0f1536d2..7635930fb12 100644 --- a/mojo/converters/input_events/input_events_type_converters.cc +++ b/mojo/converters/input_events/input_events_type_converters.cc @@ -225,7 +225,7 @@ EventPtr TypeConverter::Convert(const ui::Event& input) { } event->key_data = key_data.Pass(); } - return event.Pass(); + return event; } // static @@ -283,6 +283,7 @@ scoped_ptr TypeConverter, EventPtr>::Convert( // TODO: last flags isn't right. Need to send changed_flags. scoped_ptr 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 diff --git a/mojo/converters/input_events/input_events_type_converters.h b/mojo/converters/input_events/input_events_type_converters.h index df3d01dacef..7afff26dfab 100644 --- a/mojo/converters/input_events/input_events_type_converters.h +++ b/mojo/converters/input_events/input_events_type_converters.h @@ -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 { - static EventType Convert(ui::EventType type); +struct TypeConverter { + static EventType Convert(::ui::EventType type); }; template <> -struct TypeConverter { - static EventPtr Convert(const ui::Event& input); +struct TypeConverter { + static EventPtr Convert(const ::ui::Event& input); }; template <> -struct TypeConverter { - static EventPtr Convert(const ui::KeyEvent& input); +struct TypeConverter { + static EventPtr Convert(const ::ui::KeyEvent& input); }; template <> -struct TypeConverter { - static EventPtr Convert(const ui::GestureEvent& input); +struct TypeConverter { + static EventPtr Convert(const ::ui::GestureEvent& input); }; template <> -struct TypeConverter, EventPtr> { - static scoped_ptr Convert(const EventPtr& input); +struct TypeConverter, EventPtr> { + static scoped_ptr<::ui::Event> Convert(const EventPtr& input); }; } // namespace mojo diff --git a/mojo/converters/ozone_drm_gpu/ozone_drm_gpu_type_converters.cc b/mojo/converters/ozone_drm_gpu/ozone_drm_gpu_type_converters.cc index 51639a504cb..3f31e63b31f 100644 --- a/mojo/converters/ozone_drm_gpu/ozone_drm_gpu_type_converters.cc +++ b/mojo/converters/ozone_drm_gpu/ozone_drm_gpu_type_converters.cc @@ -26,7 +26,7 @@ DisplayModePtr TypeConverter::Convert( out->size = Size::From(in.size); out->is_interlaced = in.is_interlaced; out->refresh_rate = in.refresh_rate; - return out.Pass(); + return out; } static_assert(static_cast(ui::DISPLAY_CONNECTION_TYPE_NONE) == @@ -102,7 +102,7 @@ TypeConverter::Convert( out->native_mode = DisplayMode::From(in.native_mode); out->product_id = in.product_id; out->string_representation = in.string_representation; - return out.Pass(); + return out; } } // namespace mojo diff --git a/mojo/converters/surfaces/surfaces_type_converters.cc b/mojo/converters/surfaces/surfaces_type_converters.cc index 2c273dda785..f16dac12ee2 100644 --- a/mojo/converters/surfaces/surfaces_type_converters.cc +++ b/mojo/converters/surfaces/surfaces_type_converters.cc @@ -198,7 +198,7 @@ SurfaceIdPtr TypeConverter::Convert( SurfaceIdPtr id(SurfaceId::New()); id->local = static_cast(input.id); id->id_namespace = cc::SurfaceIdAllocator::NamespaceForId(input); - return id.Pass(); + return id; } // static @@ -214,7 +214,7 @@ cc::SurfaceId TypeConverter::Convert( ColorPtr TypeConverter::Convert(const SkColor& input) { ColorPtr color(Color::New()); color->rgba = input; - return color.Pass(); + return color; } // static @@ -228,7 +228,7 @@ RenderPassIdPtr TypeConverter::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::Convert( default: NOTREACHED() << "Unsupported material " << input.material; } - return quad.Pass(); + return quad; } // static @@ -354,7 +354,7 @@ TypeConverter::Convert( state->opacity = input.opacity; state->blend_mode = static_cast(input.blend_mode); state->sorting_context_id = input.sorting_context_id; - return state.Pass(); + return state; } // static @@ -391,7 +391,7 @@ PassPtr TypeConverter::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, PassPtr>::Convert( ++sqs_iter; } if (!ConvertDrawQuad(quad, *sqs_iter, pass.get())) - return scoped_ptr(); + return nullptr; } - return pass.Pass(); + return pass; } // static @@ -430,7 +430,7 @@ MailboxPtr TypeConverter::Convert( } MailboxPtr mailbox(Mailbox::New()); mailbox->name = name.Pass(); - return mailbox.Pass(); + return mailbox; } // static @@ -449,7 +449,7 @@ MailboxHolderPtr TypeConverter::Convert( holder->mailbox = Mailbox::From(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::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 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::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, 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::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, FramePtr>::Convert( } scoped_ptr frame(new cc::CompositorFrame); frame->delegated_frame_data = frame_data.Pass(); - return frame.Pass(); + return frame; } } // namespace mojo diff --git a/mojo/edk/embedder/BUILD.gn b/mojo/edk/embedder/BUILD.gn index 3916de35ce9..f80f11b06bf 100644 --- a/mojo/edk/embedder/BUILD.gn +++ b/mojo/edk/embedder/BUILD.gn @@ -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", ] } diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc index b6712d3f0fd..9e1e4627b35 100644 --- a/mojo/edk/embedder/embedder.cc +++ b/mojo/edk/embedder/embedder.cc @@ -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(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 dispatcher = + RefPtr 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 dispatcher = + RefPtr 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 dispatcher = + RefPtr 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 channel_info(new ChannelInfo(channel_id)); - system::RefPtr dispatcher = + RefPtr dispatcher = channel_manager->CreateChannel( channel_id, platform_handle.Pass(), base::Bind(did_create_channel_callback, diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h index c7c3dc0189d..8899aea321c 100644 --- a/mojo/edk/embedder/embedder.h +++ b/mojo/edk/embedder/embedder.h @@ -9,7 +9,6 @@ #include #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(); diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc index e1d44218475..415c34f2e40 100644 --- a/mojo/edk/embedder/embedder_unittest.cc +++ b/mojo/edk/embedder/embedder_unittest.cc @@ -9,28 +9,30 @@ #include #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))); } diff --git a/mojo/edk/embedder/platform_channel_pair.cc b/mojo/edk/embedder/platform_channel_pair.cc index 4e88bc9e08a..1eaf30bf52f 100644 --- a/mojo/edk/embedder/platform_channel_pair.cc +++ b/mojo/edk/embedder/platform_channel_pair.cc @@ -4,14 +4,63 @@ #include "mojo/edk/embedder/platform_channel_pair.h" +#include +#include +#include +#include + +#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(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(); diff --git a/mojo/edk/embedder/platform_channel_pair.h b/mojo/edk/embedder/platform_channel_pair.h index 5f44ef42672..8e1771aedd8 100644 --- a/mojo/edk/embedder/platform_channel_pair.h +++ b/mojo/edk/embedder/platform_channel_pair.h @@ -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(); diff --git a/mojo/edk/embedder/platform_channel_pair_posix.cc b/mojo/edk/embedder/platform_channel_pair_posix.cc deleted file mode 100644 index 2242cce61b8..00000000000 --- a/mojo/edk/embedder/platform_channel_pair_posix.cc +++ /dev/null @@ -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 -#include -#include -#include - -#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(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 diff --git a/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc b/mojo/edk/embedder/platform_channel_pair_unittest.cc similarity index 90% rename from mojo/edk/embedder/platform_channel_pair_posix_unittest.cc rename to mojo/edk/embedder/platform_channel_pair_unittest.cc index 5787e532142..20b9a7a79b9 100644 --- a/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc +++ b/mojo/edk/embedder/platform_channel_pair_unittest.cc @@ -14,14 +14,15 @@ #include #include +#include #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"). diff --git a/mojo/edk/embedder/platform_channel_utils_posix.cc b/mojo/edk/embedder/platform_channel_utils.cc similarity index 99% rename from mojo/edk/embedder/platform_channel_utils_posix.cc rename to mojo/edk/embedder/platform_channel_utils.cc index 61b573bda4b..71c11597609 100644 --- a/mojo/edk/embedder/platform_channel_utils_posix.cc +++ b/mojo/edk/embedder/platform_channel_utils.cc @@ -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 #include diff --git a/mojo/edk/embedder/platform_channel_utils_posix.h b/mojo/edk/embedder/platform_channel_utils.h similarity index 94% rename from mojo/edk/embedder/platform_channel_utils_posix.h rename to mojo/edk/embedder/platform_channel_utils.h index 429cffa5ed4..8458b06940a 100644 --- a/mojo/edk/embedder/platform_channel_utils_posix.h +++ b/mojo/edk/embedder/platform_channel_utils.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 #include // 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_ diff --git a/mojo/edk/embedder/platform_shared_buffer.h b/mojo/edk/embedder/platform_shared_buffer.h index 331440f45e8..89073665308 100644 --- a/mojo/edk/embedder/platform_shared_buffer.h +++ b/mojo/edk/embedder/platform_shared_buffer.h @@ -9,8 +9,8 @@ #include -#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 { + : public util::RefCountedThreadSafe { 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; + friend class util::RefCountedThreadSafe; PlatformSharedBuffer() {} virtual ~PlatformSharedBuffer() {} diff --git a/mojo/edk/embedder/platform_support.h b/mojo/edk/embedder/platform_support.h index 40b404c74e4..ae02504344f 100644 --- a/mojo/edk/embedder/platform_support.h +++ b/mojo/edk/embedder/platform_support.h @@ -8,6 +8,7 @@ #include #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 CreateSharedBuffer( + size_t num_bytes) = 0; + virtual util::RefPtr CreateSharedBufferFromHandle( size_t num_bytes, ScopedPlatformHandle platform_handle) = 0; diff --git a/mojo/edk/embedder/simple_platform_shared_buffer.cc b/mojo/edk/embedder/simple_platform_shared_buffer.cc index cb4ae3d61d1..d23e1eeb083 100644 --- a/mojo/edk/embedder/simple_platform_shared_buffer.cc +++ b/mojo/edk/embedder/simple_platform_shared_buffer.cc @@ -4,44 +4,62 @@ #include "mojo/edk/embedder/simple_platform_shared_buffer.h" +#include +#include // For |fileno()|. +#include // For |mmap()|/|munmap()|. +#include +#include // For |off_t|. +#include + +#include +#include + +#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::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 deleter(rv); - return nullptr; - } - - return rv; + RefPtr rv( + AdoptRef(new SimplePlatformSharedBuffer(num_bytes))); + return rv->Init() ? rv : nullptr; } // static -SimplePlatformSharedBuffer* +RefPtr 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 deleter(rv); - return nullptr; - } - - return rv; + RefPtr 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 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(real_offset), + static_cast(std::numeric_limits::max())); + + void* real_base = + mmap(nullptr, real_length, PROT_READ | PROT_WRITE, MAP_SHARED, + handle_.get().fd, static_cast(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(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( + 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(num_bytes_) > + static_cast(std::numeric_limits::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(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(num_bytes_) > + static_cast(std::numeric_limits::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) != 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(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 diff --git a/mojo/edk/embedder/simple_platform_shared_buffer.h b/mojo/edk/embedder/simple_platform_shared_buffer.h index 199826df521..75dfa82ced1 100644 --- a/mojo/edk/embedder/simple_platform_shared_buffer.h +++ b/mojo/edk/embedder/simple_platform_shared_buffer.h @@ -8,6 +8,7 @@ #include #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 Create(size_t num_bytes); - static SimplePlatformSharedBuffer* CreateFromPlatformHandle( + static util::RefPtr 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 MapImpl(size_t offset, - size_t length); - const size_t num_bytes_; // This is set in |Init()|/|InitFromPlatformHandle()| and never modified diff --git a/mojo/edk/embedder/simple_platform_shared_buffer_android.cc b/mojo/edk/embedder/simple_platform_shared_buffer_android.cc deleted file mode 100644 index 6ee24e70304..00000000000 --- a/mojo/edk/embedder/simple_platform_shared_buffer_android.cc +++ /dev/null @@ -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 -#include // For |PROT_...|. -#include // For |off_t|. - -#include - -#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(num_bytes_) > - static_cast(std::numeric_limits::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(num_bytes_) > - static_cast(std::numeric_limits::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) != num_bytes_) { - LOG(ERROR) << "Shared memory region has the wrong size"; - return false; - } - - handle_ = platform_handle.Pass(); - return true; -} - -} // namespace embedder -} // namespace mojo diff --git a/mojo/edk/embedder/simple_platform_shared_buffer_posix.cc b/mojo/edk/embedder/simple_platform_shared_buffer_posix.cc deleted file mode 100644 index ca3f01303d1..00000000000 --- a/mojo/edk/embedder/simple_platform_shared_buffer_posix.cc +++ /dev/null @@ -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 -#include // For |fileno()|. -#include // For |mmap()|/|munmap()|. -#include -#include // For |off_t|. -#include - -#include - -#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(num_bytes_) > - static_cast(std::numeric_limits::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(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(num_bytes_) > - static_cast(std::numeric_limits::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(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 -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(real_offset), - static_cast(std::numeric_limits::max())); - - void* real_base = - mmap(nullptr, real_length, PROT_READ | PROT_WRITE, MAP_SHARED, - handle_.get().fd, static_cast(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(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( - 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 diff --git a/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc b/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc index 368604fafb8..bb71d9894b3 100644 --- a/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc +++ b/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc @@ -6,7 +6,6 @@ #include -#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 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 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::max(); - scoped_refptr 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 buffer( - SimplePlatformSharedBuffer::Create(100)); + auto buffer = SimplePlatformSharedBuffer::Create(100); std::unique_ptr mapping1(buffer->Map(0, 100)); std::unique_ptr 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 buffer( - SimplePlatformSharedBuffer::Create(kSizes[i])); + auto buffer = SimplePlatformSharedBuffer::Create(kSizes[i]); std::unique_ptr 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 mapping2; { - scoped_refptr buffer( - SimplePlatformSharedBuffer::Create(100)); + auto buffer = SimplePlatformSharedBuffer::Create(100); mapping1 = buffer->Map(0, 100); mapping2 = buffer->Map(50, 50); static_cast(mapping1->GetBase())[50] = 'x'; diff --git a/mojo/edk/embedder/simple_platform_support.cc b/mojo/edk/embedder/simple_platform_support.cc index f3143239b2a..d0b31106e3f 100644 --- a/mojo/edk/embedder/simple_platform_support.cc +++ b/mojo/edk/embedder/simple_platform_support.cc @@ -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 SimplePlatformSupport::CreateSharedBuffer( size_t num_bytes) { return SimplePlatformSharedBuffer::Create(num_bytes); } -PlatformSharedBuffer* SimplePlatformSupport::CreateSharedBufferFromHandle( +RefPtr +SimplePlatformSupport::CreateSharedBufferFromHandle( size_t num_bytes, ScopedPlatformHandle platform_handle) { return SimplePlatformSharedBuffer::CreateFromPlatformHandle( diff --git a/mojo/edk/embedder/simple_platform_support.h b/mojo/edk/embedder/simple_platform_support.h index 19c56a3a65a..41c16024167 100644 --- a/mojo/edk/embedder/simple_platform_support.h +++ b/mojo/edk/embedder/simple_platform_support.h @@ -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 CreateSharedBuffer( + size_t num_bytes) override; + util::RefPtr CreateSharedBufferFromHandle( size_t num_bytes, ScopedPlatformHandle platform_handle) override; diff --git a/mojo/edk/embedder/system_impl_private_entrypoints.cc b/mojo/edk/embedder/system_impl_private_entrypoints.cc index e2a369b4657..e772165eb3e 100644 --- a/mojo/edk/embedder/system_impl_private_entrypoints.cc +++ b/mojo/edk/embedder/system_impl_private_entrypoints.cc @@ -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 diff --git a/mojo/edk/mojo_edk.gni b/mojo/edk/mojo_edk.gni index 21ad315a96a..6fbaafc9773 100644 --- a/mojo/edk/mojo_edk.gni +++ b/mojo/edk/mojo_edk.gni @@ -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) { diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn index 7800a59b901..01393464dbb 100644 --- a/mojo/edk/system/BUILD.gn +++ b/mojo/edk/system/BUILD.gn @@ -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", + ] } diff --git a/mojo/edk/system/awakable_list_unittest.cc b/mojo/edk/system/awakable_list_unittest.cc index 728dbc33ee1..c2a1fb1cdcf 100644 --- a/mojo/edk/system/awakable_list_unittest.cc +++ b/mojo/edk/system/awakable_list_unittest.cc @@ -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( diff --git a/mojo/edk/system/channel.cc b/mojo/edk/system/channel.cc index ae8b1c45e84..61fd80f8c4c 100644 --- a/mojo/edk/system/channel.cc +++ b/mojo/edk/system/channel.cc @@ -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 { diff --git a/mojo/edk/system/channel.h b/mojo/edk/system/channel.h index 3857a14f06d..1828d4338ce 100644 --- a/mojo/edk/system/channel.h +++ b/mojo/edk/system/channel.h @@ -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, +class Channel final : public util::RefCountedThreadSafe, public RawChannel::Delegate { public: - // Note: Use |MakeRefCounted()|. + // Note: Use |util::MakeRefCounted()|. // 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, // // (Bootstrapping is symmetric: Both sides call this, which will establish the // first connection across a channel.) - void SetBootstrapEndpoint(RefPtr&& endpoint); + void SetBootstrapEndpoint(util::RefPtr&& endpoint); // Like |SetBootstrapEndpoint()|, but with explicitly-specified local and // remote IDs. @@ -93,7 +94,7 @@ class Channel final : public RefCountedThreadSafe, // (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&& endpoint, + void SetBootstrapEndpointWithIds(util::RefPtr&& endpoint, ChannelEndpointId local_id, ChannelEndpointId remote_id); @@ -149,14 +150,15 @@ class Channel final : public RefCountedThreadSafe, MessageInTransitQueue* message_queue); // This one returns the |ChannelEndpoint| for the serialized endpoint (which // can be used by, e.g., a |ProxyMessagePipeEndpoint|. - RefPtr SerializeEndpointWithLocalPeer( + util::RefPtr SerializeEndpointWithLocalPeer( void* destination, MessageInTransitQueue* message_queue, - RefPtr&& endpoint_client, + util::RefPtr&& endpoint_client, unsigned endpoint_client_port); - void SerializeEndpointWithRemotePeer(void* destination, - MessageInTransitQueue* message_queue, - RefPtr&& peer_endpoint); + void SerializeEndpointWithRemotePeer( + void* destination, + MessageInTransitQueue* message_queue, + util::RefPtr&& 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, // |GetSerializedEndpointSize()| bytes. This returns the deserialized // |IncomingEndpoint| (which can be converted into a |MessagePipe|) or null on // error. - RefPtr DeserializeEndpoint(const void* source); + util::RefPtr DeserializeEndpoint(const void* source); // See |RawChannel::GetSerializedPlatformHandleSize()|. size_t GetSerializedPlatformHandleSize() const; @@ -224,7 +226,8 @@ class Channel final : public RefCountedThreadSafe, // for which |is_remote()| returns true). // // TODO(vtl): Maybe limit the number of attached message pipes. - ChannelEndpointId AttachAndRunEndpoint(RefPtr&& endpoint); + ChannelEndpointId AttachAndRunEndpoint( + util::RefPtr&& endpoint); // Helper to send channel control messages. Returns true on success. Callable // from any thread. @@ -246,7 +249,7 @@ class Channel final : public RefCountedThreadSafe, // 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 raw_channel_ MOJO_GUARDED_BY(mutex_); bool is_running_ MOJO_GUARDED_BY(mutex_); @@ -257,7 +260,7 @@ class Channel final : public RefCountedThreadSafe, ChannelManager* channel_manager_ MOJO_GUARDED_BY(mutex_); using IdToEndpointMap = - std::unordered_map>; + std::unordered_map>; // 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, LocalChannelEndpointIdGenerator local_id_generator_ MOJO_GUARDED_BY(mutex_); using IdToIncomingEndpointMap = - std::unordered_map>; + std::unordered_map>; // 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_); diff --git a/mojo/edk/system/channel_endpoint.cc b/mojo/edk/system/channel_endpoint.cc index b2ced62cf52..8d8ecc1558b 100644 --- a/mojo/edk/system/channel_endpoint.cc +++ b/mojo/edk/system/channel_endpoint.cc @@ -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 { diff --git a/mojo/edk/system/channel_endpoint.h b/mojo/edk/system/channel_endpoint.h index af537e58901..fca0e9e7792 100644 --- a/mojo/edk/system/channel_endpoint.h +++ b/mojo/edk/system/channel_endpoint.h @@ -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 { +class ChannelEndpoint final + : public util::RefCountedThreadSafe { public: - // Note: Use |MakeRefCounted()|. + // Note: Use |util::MakeRefCounted()|. // Methods called by |ChannelEndpointClient|: @@ -127,7 +129,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe { // 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&& client, + bool ReplaceClient(util::RefPtr&& client, unsigned client_port); // Called before the |ChannelEndpointClient| gives up its reference to this @@ -161,7 +163,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe { // 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&& client, + ChannelEndpoint(util::RefPtr&& client, unsigned client_port, MessageInTransitQueue* message_queue = nullptr); @@ -177,7 +179,7 @@ class ChannelEndpoint final : public RefCountedThreadSafe { // 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 { // |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 { // 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 client_ MOJO_GUARDED_BY(mutex_); + util::RefPtr client_ MOJO_GUARDED_BY(mutex_); unsigned client_port_ MOJO_GUARDED_BY(mutex_); // |channel_| must be valid whenever it is non-null. Before |*channel_| gives diff --git a/mojo/edk/system/channel_endpoint_client.h b/mojo/edk/system/channel_endpoint_client.h index fea942d2d40..5b4a21beb13 100644 --- a/mojo/edk/system/channel_endpoint_client.h +++ b/mojo/edk/system/channel_endpoint_client.h @@ -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 { + : public util::RefCountedThreadSafe { public: // Called by |ChannelEndpoint| in response to its |OnReadMessage()|, which is // called by |Channel| when it receives a message for the |ChannelEndpoint|. diff --git a/mojo/edk/system/channel_endpoint_unittest.cc b/mojo/edk/system/channel_endpoint_unittest.cc index 19cc237415e..5c93fb25347 100644 --- a/mojo/edk/system/channel_endpoint_unittest.cc +++ b/mojo/edk/system/channel_endpoint_unittest.cc @@ -7,15 +7,17 @@ #include #include -#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); diff --git a/mojo/edk/system/channel_manager.cc b/mojo/edk/system/channel_manager.cc index b2f73887a62..ca0c2702896 100644 --- a/mojo/edk/system/channel_manager.cc +++ b/mojo/edk/system/channel_manager.cc @@ -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 { diff --git a/mojo/edk/system/channel_manager.h b/mojo/edk/system/channel_manager.h index af2e28e24ee..1ef217b8e5d 100644 --- a/mojo/edk/system/channel_manager.h +++ b/mojo/edk/system/channel_manager.h @@ -10,12 +10,12 @@ #include #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 CreateChannelOnIOThread( + util::RefPtr 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 CreateChannelWithoutBootstrapOnIOThread( + util::RefPtr 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 CreateChannel( + util::RefPtr 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 GetChannel(ChannelId channel_id) const; + util::RefPtr 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 CreateChannelOnIOThreadHelper( + util::RefPtr CreateChannelOnIOThreadHelper( ChannelId channel_id, embedder::ScopedPlatformHandle platform_handle, - RefPtr&& bootstrap_channel_endpoint); + util::RefPtr&& 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 bootstrap_channel_endpoint, + util::RefPtr 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>; + using ChannelIdToChannelMap = + std::unordered_map>; ChannelIdToChannelMap channels_ MOJO_GUARDED_BY(mutex_); MOJO_DISALLOW_COPY_AND_ASSIGN(ChannelManager); diff --git a/mojo/edk/system/channel_manager_unittest.cc b/mojo/edk/system/channel_manager_unittest.cc index b5467e7c1d6..9b9e6ac8299 100644 --- a/mojo/edk/system/channel_manager_unittest.cc +++ b/mojo/edk/system/channel_manager_unittest.cc @@ -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 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 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; diff --git a/mojo/edk/system/channel_test_base.cc b/mojo/edk/system/channel_test_base.cc index 1069e79cf9e..ecb7d1b202b 100644 --- a/mojo/edk/system/channel_test_base.cc +++ b/mojo/edk/system/channel_test_base.cc @@ -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() { } diff --git a/mojo/edk/system/channel_test_base.h b/mojo/edk/system/channel_test_base.h index 8b1b9326b48..4ca931cd267 100644 --- a/mojo/edk/system/channel_test_base.h +++ b/mojo/edk/system/channel_test_base.h @@ -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* mutable_channel(unsigned i) { return &channels_[i]; } + util::RefPtr* 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 raw_channels_[2]; - RefPtr channels_[2]; + util::RefPtr channels_[2]; MOJO_DISALLOW_COPY_AND_ASSIGN(ChannelTestBase); }; diff --git a/mojo/edk/system/channel_unittest.cc b/mojo/edk/system/channel_unittest.cc index b90c8847fa1..d4894fe4a35 100644 --- a/mojo/edk/system/channel_unittest.cc +++ b/mojo/edk/system/channel_unittest.cc @@ -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 ------------------------------------- diff --git a/mojo/edk/system/connection_manager.h b/mojo/edk/system/connection_manager.h index 7cc0801fd98..13d7584a29b 100644 --- a/mojo/edk/system/connection_manager.h +++ b/mojo/edk/system/connection_manager.h @@ -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 { diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc index ae729a95bad..8e1340f68da 100644 --- a/mojo/edk/system/core.cc +++ b/mojo/edk/system/core.cc @@ -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 { diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h index 8c794219138..c8a47e0f8af 100644 --- a/mojo/edk/system/core.h +++ b/mojo/edk/system/core.h @@ -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 GetDispatcher(MojoHandle handle); + util::RefPtr 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); + util::RefPtr* 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); diff --git a/mojo/edk/system/core_test_base.cc b/mojo/edk/system/core_test_base.cc index 29b569e8b52..90480709c90 100644 --- a/mojo/edk/system/core_test_base.cc +++ b/mojo/edk/system/core_test_base.cc @@ -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 { diff --git a/mojo/edk/system/core_test_base.h b/mojo/edk/system/core_test_base.h index e2375cde3d7..0e9c14c2657 100644 --- a/mojo/edk/system/core_test_base.h +++ b/mojo/edk/system/core_test_base.h @@ -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_); diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc index 57495d8b83e..89f9856a3b6 100644 --- a/mojo/edk/system/core_unittest.cc +++ b/mojo/edk/system/core_unittest.cc @@ -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(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(8000)) diff --git a/mojo/edk/system/data_pipe.cc b/mojo/edk/system/data_pipe.cc index ffe34694889..7cfd2a58066 100644 --- a/mojo/edk/system/data_pipe.cc +++ b/mojo/edk/system/data_pipe.cc @@ -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 { diff --git a/mojo/edk/system/data_pipe.h b/mojo/edk/system/data_pipe.h index 9eb567a7b68..62fe5aa85bb 100644 --- a/mojo/edk/system/data_pipe.h +++ b/mojo/edk/system/data_pipe.h @@ -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 CreateLocal( + static util::RefPtr 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 CreateRemoteProducerFromExisting( + static util::RefPtr CreateRemoteProducerFromExisting( const MojoCreateDataPipeOptions& validated_options, MessageInTransitQueue* message_queue, - RefPtr&& channel_endpoint); + util::RefPtr&& 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 CreateRemoteConsumerFromExisting( + static util::RefPtr CreateRemoteConsumerFromExisting( const MojoCreateDataPipeOptions& validated_options, size_t consumer_num_bytes, MessageInTransitQueue* message_queue, - RefPtr&& channel_endpoint); + util::RefPtr&& 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* data_pipe); + util::RefPtr* 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* data_pipe); + util::RefPtr* 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_); diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/mojo/edk/system/data_pipe_consumer_dispatcher.cc index 74121dc1792..490b91788c2 100644 --- a/mojo/edk/system/data_pipe_consumer_dispatcher.cc +++ b/mojo/edk/system/data_pipe_consumer_dispatcher.cc @@ -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 { diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.h b/mojo/edk/system/data_pipe_consumer_dispatcher.h index 6c7b2ea2c01..9f2389df00b 100644 --- a/mojo/edk/system/data_pipe_consumer_dispatcher.h +++ b/mojo/edk/system/data_pipe_consumer_dispatcher.h @@ -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 Create() { + static util::RefPtr Create() { return AdoptRef(new DataPipeConsumerDispatcher()); } // Must be called before any other methods. - void Init(RefPtr&& data_pipe) MOJO_NOT_THREAD_SAFE; + void Init(util::RefPtr&& 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 Deserialize(Channel* channel, - const void* source, - size_t size); + static util::RefPtr + 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 CreateEquivalentDispatcherAndCloseImplNoLock() override; + util::RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() + override; MojoResult ReadDataImplNoLock(UserPointer elements, UserPointer 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 data_pipe_ MOJO_GUARDED_BY(mutex()); + util::RefPtr data_pipe_ MOJO_GUARDED_BY(mutex()); MOJO_DISALLOW_COPY_AND_ASSIGN(DataPipeConsumerDispatcher); }; diff --git a/mojo/edk/system/data_pipe_impl.h b/mojo/edk/system/data_pipe_impl.h index 6dfddc70cfe..87464c89533 100644 --- a/mojo/edk/system/data_pipe_impl.h +++ b/mojo/edk/system/data_pipe_impl.h @@ -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" diff --git a/mojo/edk/system/data_pipe_impl_unittest.cc b/mojo/edk/system/data_pipe_impl_unittest.cc index cbacf0e34c2..46e6a187f94 100644 --- a/mojo/edk/system/data_pipe_impl_unittest.cc +++ b/mojo/edk/system/data_pipe_impl_unittest.cc @@ -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 channels_[2]; RefPtr 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( @@ -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( @@ -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); diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.cc b/mojo/edk/system/data_pipe_producer_dispatcher.cc index 55ee7359631..814fa598c29 100644 --- a/mojo/edk/system/data_pipe_producer_dispatcher.cc +++ b/mojo/edk/system/data_pipe_producer_dispatcher.cc @@ -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 { diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.h b/mojo/edk/system/data_pipe_producer_dispatcher.h index 77c09aac88c..9251ce13382 100644 --- a/mojo/edk/system/data_pipe_producer_dispatcher.h +++ b/mojo/edk/system/data_pipe_producer_dispatcher.h @@ -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 Create() { + static util::RefPtr Create() { return AdoptRef(new DataPipeProducerDispatcher()); } // Must be called before any other methods. - void Init(RefPtr&& data_pipe) MOJO_NOT_THREAD_SAFE; + void Init(util::RefPtr&& 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 Deserialize(Channel* channel, - const void* source, - size_t size); + static util::RefPtr + 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 CreateEquivalentDispatcherAndCloseImplNoLock() override; + util::RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() + override; MojoResult WriteDataImplNoLock(UserPointer elements, UserPointer 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 data_pipe_ MOJO_GUARDED_BY(mutex()); + util::RefPtr data_pipe_ MOJO_GUARDED_BY(mutex()); MOJO_DISALLOW_COPY_AND_ASSIGN(DataPipeProducerDispatcher); }; diff --git a/mojo/edk/system/dispatcher.cc b/mojo/edk/system/dispatcher.cc index a39647df39d..ea88870b138 100644 --- a/mojo/edk/system/dispatcher.cc +++ b/mojo/edk/system/dispatcher.cc @@ -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 { diff --git a/mojo/edk/system/dispatcher.h b/mojo/edk/system/dispatcher.h index 9b8dafde7fb..e425bb33371 100644 --- a/mojo/edk/system/dispatcher.h +++ b/mojo/edk/system/dispatcher.h @@ -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>; +using DispatcherVector = std::vector>; 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 { +class Dispatcher : public util::RefCountedThreadSafe { public: enum class Type { UNKNOWN = 0, @@ -114,7 +115,7 @@ class Dispatcher : public RefCountedThreadSafe { // new handle on success). MojoResult DuplicateBufferHandle( UserPointer options, - RefPtr* new_dispatcher); + util::RefPtr* new_dispatcher); MojoResult MapBuffer( uint64_t offset, uint64_t num_bytes, @@ -204,7 +205,7 @@ class Dispatcher : public RefCountedThreadSafe { // Deserialization API. // Note: This "clears" (i.e., reset to the invalid handle) any platform // handles that it takes ownership of. - static RefPtr Deserialize( + static util::RefPtr Deserialize( Channel* channel, int32_t type, const void* source, @@ -222,7 +223,8 @@ class Dispatcher : public RefCountedThreadSafe { virtual void CancelAllAwakablesNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); virtual void CloseImplNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - virtual RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() + virtual util::RefPtr + 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 { MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); virtual MojoResult DuplicateBufferHandleImplNoLock( UserPointer options, - RefPtr* new_dispatcher) MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + util::RefPtr* 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 { // 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 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 CreateEquivalentDispatcherAndCloseNoLock() + util::RefPtr CreateEquivalentDispatcherAndCloseNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // API to serialize dispatchers to a |Channel|, exposed to only @@ -373,7 +376,7 @@ class Dispatcher : public RefCountedThreadSafe { // 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 CreateEquivalentDispatcherAndClose() MOJO_NOT_THREAD_SAFE { + util::RefPtr CreateEquivalentDispatcherAndClose() + MOJO_NOT_THREAD_SAFE { return dispatcher_->CreateEquivalentDispatcherAndCloseNoLock(); } diff --git a/mojo/edk/system/dispatcher_unittest.cc b/mojo/edk/system/dispatcher_unittest.cc index 827b1f41ab8..43a83761730 100644 --- a/mojo/edk/system/dispatcher_unittest.cc +++ b/mojo/edk/system/dispatcher_unittest.cc @@ -7,16 +7,20 @@ #include #include -#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, 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_; 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(); { @@ -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(); { diff --git a/mojo/edk/system/endpoint_relayer.cc b/mojo/edk/system/endpoint_relayer.cc index 0cf4efa8603..3d7b8d1908d 100644 --- a/mojo/edk/system/endpoint_relayer.cc +++ b/mojo/edk/system/endpoint_relayer.cc @@ -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 { diff --git a/mojo/edk/system/endpoint_relayer.h b/mojo/edk/system/endpoint_relayer.h index f41de9680cd..bb06894149d 100644 --- a/mojo/edk/system/endpoint_relayer.h +++ b/mojo/edk/system/endpoint_relayer.h @@ -8,8 +8,9 @@ #include #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()|. + // Note: Use |util::MakeRefCounted()|. // 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&& endpoint0, - RefPtr&& endpoint1) MOJO_NOT_THREAD_SAFE; + void Init(util::RefPtr&& endpoint0, + util::RefPtr&& 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 endpoints_[2] MOJO_GUARDED_BY(mutex_); + util::Mutex mutex_; + util::RefPtr endpoints_[2] MOJO_GUARDED_BY(mutex_); std::unique_ptr filter_ MOJO_GUARDED_BY(mutex_); MOJO_DISALLOW_COPY_AND_ASSIGN(EndpointRelayer); diff --git a/mojo/edk/system/endpoint_relayer_unittest.cc b/mojo/edk/system/endpoint_relayer_unittest.cc index 1b8b4402961..3ebdaf3e020 100644 --- a/mojo/edk/system/endpoint_relayer_unittest.cc +++ b/mojo/edk/system/endpoint_relayer_unittest.cc @@ -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); diff --git a/mojo/edk/system/handle_table.cc b/mojo/edk/system/handle_table.cc index 19d076313cb..19d80876e53 100644 --- a/mojo/edk/system/handle_table.cc +++ b/mojo/edk/system/handle_table.cc @@ -11,6 +11,8 @@ #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/dispatcher.h" +using mojo::util::RefPtr; + namespace mojo { namespace system { diff --git a/mojo/edk/system/handle_table.h b/mojo/edk/system/handle_table.h index 91d3669a3f7..26c9c998c99 100644 --- a/mojo/edk/system/handle_table.h +++ b/mojo/edk/system/handle_table.h @@ -9,7 +9,7 @@ #include #include -#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>; +using DispatcherVector = std::vector>; // 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); + util::RefPtr* 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); + explicit Entry(util::RefPtr&& dispatcher); ~Entry(); - RefPtr dispatcher; + util::RefPtr dispatcher; bool busy; }; using HandleToEntryMap = std::unordered_map; // Adds the given dispatcher to the handle table, not doing any size checks. - MojoHandle AddDispatcherNoSizeCheck(RefPtr&& dispatcher); + MojoHandle AddDispatcherNoSizeCheck(util::RefPtr&& dispatcher); HandleToEntryMap handle_to_entry_map_; MojoHandle next_handle_; // Invariant: never |MOJO_HANDLE_INVALID|. diff --git a/mojo/edk/system/incoming_endpoint.cc b/mojo/edk/system/incoming_endpoint.cc index 4fd8789ffe1..d1d57153aaf 100644 --- a/mojo/edk/system/incoming_endpoint.cc +++ b/mojo/edk/system/incoming_endpoint.cc @@ -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 { diff --git a/mojo/edk/system/incoming_endpoint.h b/mojo/edk/system/incoming_endpoint.h index 6dbf9a0270d..1ad708e4146 100644 --- a/mojo/edk/system/incoming_endpoint.h +++ b/mojo/edk/system/incoming_endpoint.h @@ -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()|. + // Note: Use |util::MakeRefCounted()|. // Must be called before any other method. - RefPtr Init() MOJO_NOT_THREAD_SAFE; + util::RefPtr Init() MOJO_NOT_THREAD_SAFE; - RefPtr ConvertToMessagePipe(); - RefPtr ConvertToDataPipeProducer( + util::RefPtr ConvertToMessagePipe(); + util::RefPtr ConvertToDataPipeProducer( const MojoCreateDataPipeOptions& validated_options, size_t consumer_num_bytes); - RefPtr ConvertToDataPipeConsumer( + util::RefPtr 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 endpoint_ MOJO_GUARDED_BY(mutex_); + util::Mutex mutex_; + util::RefPtr endpoint_ MOJO_GUARDED_BY(mutex_); MessageInTransitQueue message_queue_ MOJO_GUARDED_BY(mutex_); MOJO_DISALLOW_COPY_AND_ASSIGN(IncomingEndpoint); diff --git a/mojo/edk/system/ipc_support.cc b/mojo/edk/system/ipc_support.cc index fbd81368831..c3778de7212 100644 --- a/mojo/edk/system/ipc_support.cc +++ b/mojo/edk/system/ipc_support.cc @@ -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 { diff --git a/mojo/edk/system/ipc_support.h b/mojo/edk/system/ipc_support.h index ed5ab02e17d..26b70e53ef1 100644 --- a/mojo/edk/system/ipc_support.h +++ b/mojo/edk/system/ipc_support.h @@ -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 ConnectToSlave( + util::RefPtr 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 ConnectToMaster( + util::RefPtr ConnectToMaster( const ConnectionIdentifier& connection_id, const base::Closure& callback, embedder::PlatformTaskRunnerRefPtr callback_thread_task_runner, diff --git a/mojo/edk/system/ipc_support_unittest.cc b/mojo/edk/system/ipc_support_unittest.cc index 2fb34188da8..5c8316edd79 100644 --- a/mojo/edk/system/ipc_support_unittest.cc +++ b/mojo/edk/system/ipc_support_unittest.cc @@ -9,10 +9,7 @@ #include #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 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 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 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 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 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 = diff --git a/mojo/edk/system/local_data_pipe_impl.cc b/mojo/edk/system/local_data_pipe_impl.cc index 1d1f205f26e..d4330aeadaa 100644 --- a/mojo/edk/system/local_data_pipe_impl.cc +++ b/mojo/edk/system/local_data_pipe_impl.cc @@ -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 { diff --git a/mojo/edk/system/master_connection_manager.cc b/mojo/edk/system/master_connection_manager.cc index 0976a5d4024..84f838a50f2 100644 --- a/mojo/edk/system/master_connection_manager.cc +++ b/mojo/edk/system/master_connection_manager.cc @@ -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(); diff --git a/mojo/edk/system/master_connection_manager.h b/mojo/edk/system/master_connection_manager.h index efbe43c2500..e751e4decf9 100644 --- a/mojo/edk/system/master_connection_manager.h +++ b/mojo/edk/system/master_connection_manager.h @@ -9,17 +9,16 @@ #include -#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_); diff --git a/mojo/edk/system/memory.h b/mojo/edk/system/memory.h index 427dbb3becc..b996e9c503b 100644 --- a/mojo/edk/system/memory.h +++ b/mojo/edk/system/memory.h @@ -58,8 +58,8 @@ template class UserPointerWriter; template class UserPointerReaderWriter; -template -class UserOptionsReader; +template +class UserPointerPartialReader; // Provides a convenient way to implicitly get null |UserPointer|s. struct NullUserPointer {}; @@ -75,6 +75,8 @@ class UserPointer { using NonVoidType = typename internal::VoidToChar::type; public: + static_assert(!std::is_volatile::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; using ReaderWriter = UserPointerReaderWriter; + // 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::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; + private: friend class UserPointerReader; friend class UserPointerReader; friend class UserPointerWriter; friend class UserPointerReaderWriter; - template - friend class UserOptionsReader; + friend class UserPointerPartialReader; Type* pointer_; // Allow copy and assignment. @@ -260,37 +274,29 @@ class UserPointerReader { using TypeNoConst = typename std::remove_const::type; public: + static_assert(!std::is_volatile::value, "Type must not be volatile"); + // Note: If |count| is zero, |GetPointer()| will always return null. - UserPointerReader(UserPointer user_pointer, size_t count) { - Init(user_pointer.pointer_, count, true); + UserPointerReader(UserPointer user_pointer, size_t count) { + Init(user_pointer.pointer_, count); } UserPointerReader(UserPointer 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 - friend class UserOptionsReader; - - struct NoCheck {}; - UserPointerReader(NoCheck, - UserPointer 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( - user_pointer, count); - } + internal::CheckUserPointerWithCount(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 buffer_; @@ -302,6 +308,9 @@ class UserPointerReader { template class UserPointerWriter { public: + static_assert(!std::is_volatile::value, "Type must not be volatile"); + static_assert(!std::is_const::value, "Type must not be const"); + // Note: If |count| is zero, |GetPointer()| will always return null. UserPointerWriter(UserPointer user_pointer, size_t count) : user_pointer_(user_pointer), count_(count) { @@ -331,6 +340,9 @@ class UserPointerWriter { template class UserPointerReaderWriter { public: + static_assert(!std::is_volatile::value, "Type must not be volatile"); + static_assert(!std::is_const::value, "Type must not be const"); + // Note: If |count| is zero, |GetPointer()| will always return null. UserPointerReaderWriter(UserPointer 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::PartialReader|. +template +class UserPointerPartialReader { + private: + using TypeNoConst = typename std::remove_cv::type; + + public: + static_assert(!std::is_volatile::value, "Type must not be volatile"); + + // Note: If |count| is zero, |GetPointer()| will always return null. + UserPointerPartialReader(UserPointer user_pointer, + size_t num_bytes) { + Init(user_pointer.pointer_, num_bytes); + } + UserPointerPartialReader(UserPointer 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(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(&storage_) + num_bytes, 0, + sizeof(TypeNoConst) - num_bytes); + } + + TypeNoConst storage_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(UserPointerPartialReader); +}; + } // namespace system } // namespace mojo diff --git a/mojo/edk/system/message_pipe.cc b/mojo/edk/system/message_pipe.cc index 49fd5a01754..5256bd3c844 100644 --- a/mojo/edk/system/message_pipe.cc +++ b/mojo/edk/system/message_pipe.cc @@ -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 { diff --git a/mojo/edk/system/message_pipe.h b/mojo/edk/system/message_pipe.h index d7eefc6eb6e..99b12008617 100644 --- a/mojo/edk/system/message_pipe.h +++ b/mojo/edk/system/message_pipe.h @@ -11,7 +11,6 @@ #include #include -#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 CreateLocalLocal(); + static util::RefPtr 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 CreateLocalProxy( - RefPtr* channel_endpoint); + static util::RefPtr CreateLocalProxy( + util::RefPtr* 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 CreateLocalProxyFromExisting( + static util::RefPtr CreateLocalProxyFromExisting( MessageInTransitQueue* message_queue, - RefPtr&& channel_endpoint); + util::RefPtr&& 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 CreateProxyLocal( - RefPtr* channel_endpoint); + static util::RefPtr CreateProxyLocal( + util::RefPtr* 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* message_pipe, + util::RefPtr* 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* transports) MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - mutable Mutex mutex_; + mutable util::Mutex mutex_; std::unique_ptr endpoints_[2] MOJO_GUARDED_BY(mutex_); MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipe); diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc index 8ba09279448..704fd13e29c 100644 --- a/mojo/edk/system/message_pipe_dispatcher.cc +++ b/mojo/edk/system/message_pipe_dispatcher.cc @@ -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 { diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h index 24b262f1dd2..da6464928f8 100644 --- a/mojo/edk/system/message_pipe_dispatcher.h +++ b/mojo/edk/system/message_pipe_dispatcher.h @@ -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 Create( + static util::RefPtr 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&& message_pipe, + void Init(util::RefPtr&& 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 CreateRemoteMessagePipe( - RefPtr* channel_endpoint); + static util::RefPtr CreateRemoteMessagePipe( + util::RefPtr* channel_endpoint); // The "opposite" of |SerializeAndClose()|. (Typically this is called by // |Dispatcher::Deserialize()|.) - static RefPtr Deserialize(Channel* channel, - const void* source, - size_t size); + static util::RefPtr 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 CreateEquivalentDispatcherAndCloseImplNoLock() override; + util::RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() + override; MojoResult WriteMessageImplNoLock( UserPointer 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 message_pipe_ MOJO_GUARDED_BY(mutex()); + util::RefPtr message_pipe_ MOJO_GUARDED_BY(mutex()); unsigned port_ MOJO_GUARDED_BY(mutex()); MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher); diff --git a/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/mojo/edk/system/message_pipe_dispatcher_unittest.cc index b51899b086b..3d852c202d9 100644 --- a/mojo/edk/system/message_pipe_dispatcher_unittest.cc +++ b/mojo/edk/system/message_pipe_dispatcher_unittest.cc @@ -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 #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 read_dispatcher, diff --git a/mojo/edk/system/message_pipe_endpoint.h b/mojo/edk/system/message_pipe_endpoint.h index c488ca3a43f..560ad628077 100644 --- a/mojo/edk/system/message_pipe_endpoint.h +++ b/mojo/edk/system/message_pipe_endpoint.h @@ -10,7 +10,6 @@ #include #include -#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" diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc index 9a5d569b368..77169385386 100644 --- a/mojo/edk/system/message_pipe_perftest.cc +++ b/mojo/edk/system/message_pipe_perftest.cc @@ -3,30 +3,27 @@ // found in the LICENSE file. #include -#include -#include -#include #include #include -#include #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(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 perf_logger_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipePerfTest); }; // For each message received, sends a reply message with the same contents diff --git a/mojo/edk/system/message_pipe_test_utils.cc b/mojo/edk/system/message_pipe_test_utils.cc index 18bdf5dbec9..45215757efc 100644 --- a/mojo/edk/system/message_pipe_test_utils.cc +++ b/mojo/edk/system/message_pipe_test_utils.cc @@ -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))); diff --git a/mojo/edk/system/message_pipe_test_utils.h b/mojo/edk/system/message_pipe_test_utils.h index 9982dca14a2..29bf70985fb 100644 --- a/mojo/edk/system/message_pipe_test_utils.h +++ b/mojo/edk/system/message_pipe_test_utils.h @@ -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&& channel_endpoint); + util::RefPtr&& 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 channel_endpoint); + util::RefPtr channel_endpoint); void ShutdownChannelOnIOThread(); embedder::PlatformSupport* const platform_support_; - mojo::test::TestIOThread test_io_thread_; - RefPtr channel_; + TestIOThread test_io_thread_; + util::RefPtr channel_; MOJO_DISALLOW_COPY_AND_ASSIGN(ChannelThread); }; @@ -56,7 +55,7 @@ class MultiprocessMessagePipeTestBase : public testing::Test { ~MultiprocessMessagePipeTestBase() override; protected: - void Init(RefPtr&& ep); + void Init(util::RefPtr&& ep); embedder::PlatformSupport* platform_support() { return &platform_support_; } mojo::test::MultiprocessTestHelper* helper() { return &helper_; } diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc index 88e73edbeb7..0e4de3ace86 100644 --- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc @@ -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 dispatcher( static_cast(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 {}; 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(); diff --git a/mojo/edk/system/mutex.cc b/mojo/edk/system/mutex.cc deleted file mode 100644 index 216b35a0388..00000000000 --- a/mojo/edk/system/mutex.cc +++ /dev/null @@ -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 diff --git a/mojo/edk/system/mutex.h b/mojo/edk/system/mutex.h deleted file mode 100644 index 859f6a31a63..00000000000 --- a/mojo/edk/system/mutex.h +++ /dev/null @@ -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_ diff --git a/mojo/edk/system/mutex_unittest.cc b/mojo/edk/system/mutex_unittest.cc deleted file mode 100644 index 9b516536560..00000000000 --- a/mojo/edk/system/mutex_unittest.cc +++ /dev/null @@ -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 - -#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 diff --git a/mojo/edk/system/options_validation.h b/mojo/edk/system/options_validation.h index 35d81f9884c..bd904f5bc32 100644 --- a/mojo/edk/system/options_validation.h +++ b/mojo/edk/system/options_validation.h @@ -14,7 +14,6 @@ #include #include -#include #include #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 options) - : options_reader_(UserPointer::Reader::NoCheck(), - options.template ReinterpretCast(), - 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(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 options) { uint32_t struct_size = options.template ReinterpretCast().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(options.pointer_, - struct_size); - options.template ReinterpretCast().CheckArray(struct_size); - // But we'll never look at more than |sizeof(Options)| bytes. - return std::min(static_cast(struct_size), sizeof(Options)); + // |PartialReader|'s constructor will automatically limit the amount copied + // to |sizeof(Options)|. + return struct_size; } - UserPointer::Reader options_reader_; + typename UserPointer::PartialReader options_reader_; MOJO_DISALLOW_COPY_AND_ASSIGN(UserOptionsReader); }; diff --git a/mojo/edk/system/platform_handle_dispatcher.cc b/mojo/edk/system/platform_handle_dispatcher.cc index f9a9f96244b..91c64fd8956 100644 --- a/mojo/edk/system/platform_handle_dispatcher.cc +++ b/mojo/edk/system/platform_handle_dispatcher.cc @@ -8,6 +8,9 @@ #include "base/logging.h" +using mojo::util::MutexLocker; +using mojo::util::RefPtr; + namespace mojo { namespace system { diff --git a/mojo/edk/system/platform_handle_dispatcher.h b/mojo/edk/system/platform_handle_dispatcher.h index db2f0cfa543..d9b809ff097 100644 --- a/mojo/edk/system/platform_handle_dispatcher.h +++ b/mojo/edk/system/platform_handle_dispatcher.h @@ -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 Create( + static util::RefPtr 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 Deserialize( + static util::RefPtr 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 CreateEquivalentDispatcherAndCloseImplNoLock() override; + util::RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() + override; void StartSerializeImplNoLock(Channel* channel, size_t* max_size, size_t* max_platform_handles) override diff --git a/mojo/edk/system/platform_handle_dispatcher_unittest.cc b/mojo/edk/system/platform_handle_dispatcher_unittest.cc index 7d70d75fe90..6564e7c2d93 100644 --- a/mojo/edk/system/platform_handle_dispatcher_unittest.cc +++ b/mojo/edk/system/platform_handle_dispatcher_unittest.cc @@ -6,18 +6,21 @@ #include -#include "base/memory/ref_counted.h" -#include "mojo/edk/test/scoped_test_dir.h" +#include + +#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(generic_dispatcher.get())); fp = mojo::test::FILEFromPlatformHandle(dispatcher->PassPlatformHandle(), - "rb").Pass(); + "rb"); EXPECT_TRUE(fp); rewind(fp.get()); diff --git a/mojo/edk/system/proxy_message_pipe_endpoint.cc b/mojo/edk/system/proxy_message_pipe_endpoint.cc index c8a69617e9a..00937a7b33f 100644 --- a/mojo/edk/system/proxy_message_pipe_endpoint.cc +++ b/mojo/edk/system/proxy_message_pipe_endpoint.cc @@ -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 { diff --git a/mojo/edk/system/proxy_message_pipe_endpoint.h b/mojo/edk/system/proxy_message_pipe_endpoint.h index ac760cd6904..24d06e36242 100644 --- a/mojo/edk/system/proxy_message_pipe_endpoint.h +++ b/mojo/edk/system/proxy_message_pipe_endpoint.h @@ -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&& channel_endpoint); + explicit ProxyMessagePipeEndpoint( + util::RefPtr&& 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 ReleaseChannelEndpoint(); + util::RefPtr ReleaseChannelEndpoint(); // |MessagePipeEndpoint| implementation: Type GetType() const override; @@ -48,7 +49,7 @@ class ProxyMessagePipeEndpoint final : public MessagePipeEndpoint { private: void DetachIfNecessary(); - RefPtr channel_endpoint_; + util::RefPtr channel_endpoint_; MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyMessagePipeEndpoint); }; diff --git a/mojo/edk/system/raw_channel.cc b/mojo/edk/system/raw_channel.cc index 9c1aa247bd2..16f924d7a97 100644 --- a/mojo/edk/system/raw_channel.cc +++ b/mojo/edk/system/raw_channel.cc @@ -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 { diff --git a/mojo/edk/system/raw_channel.h b/mojo/edk/system/raw_channel.h index 6a783955514..beb0194e9d6 100644 --- a/mojo/edk/system/raw_channel.h +++ b/mojo/edk/system/raw_channel.h @@ -13,8 +13,8 @@ #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/message_in_transit.h" #include "mojo/edk/system/message_in_transit_queue.h" -#include "mojo/edk/system/mutex.h" -#include "mojo/edk/system/thread_annotations.h" +#include "mojo/edk/util/mutex.h" +#include "mojo/edk/util/thread_annotations.h" #include "mojo/public/cpp/system/macros.h" namespace base { @@ -211,7 +211,9 @@ class RawChannel { size_t bytes_written) MOJO_LOCKS_EXCLUDED(write_mutex_); base::MessageLoopForIO* message_loop_for_io() { return message_loop_for_io_; } - Mutex& write_mutex() MOJO_LOCK_RETURNED(write_mutex_) { return write_mutex_; } + util::Mutex& write_mutex() MOJO_LOCK_RETURNED(write_mutex_) { + return write_mutex_; + } // Should only be called on the I/O thread. ReadBuffer* read_buffer() { return read_buffer_.get(); } @@ -319,7 +321,7 @@ class RawChannel { bool* set_on_shutdown_; std::unique_ptr read_buffer_; - Mutex write_mutex_; // Protects the following members. + util::Mutex write_mutex_; // Protects the following members. bool write_stopped_ MOJO_GUARDED_BY(write_mutex_); std::unique_ptr write_buffer_ MOJO_GUARDED_BY(write_mutex_); diff --git a/mojo/edk/system/raw_channel_posix.cc b/mojo/edk/system/raw_channel_posix.cc index d740516e7d5..096d0d78c43 100644 --- a/mojo/edk/system/raw_channel_posix.cc +++ b/mojo/edk/system/raw_channel_posix.cc @@ -18,13 +18,15 @@ #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.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/system/transport_data.h" #include "mojo/edk/util/make_unique.h" #include "mojo/public/cpp/system/macros.h" +using mojo::util::MutexLocker; + namespace mojo { namespace system { diff --git a/mojo/edk/system/raw_channel_unittest.cc b/mojo/edk/system/raw_channel_unittest.cc index 53e8688c6a3..0c18226d011 100644 --- a/mojo/edk/system/raw_channel_unittest.cc +++ b/mojo/edk/system/raw_channel_unittest.cc @@ -13,23 +13,27 @@ #include "base/bind.h" #include "base/logging.h" -#include "base/synchronization/waitable_event.h" #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/platform_handle.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/message_in_transit.h" -#include "mojo/edk/system/mutex.h" -#include "mojo/edk/system/test_utils.h" +#include "mojo/edk/system/test/random.h" +#include "mojo/edk/system/test/scoped_test_dir.h" +#include "mojo/edk/system/test/simple_test_thread.h" +#include "mojo/edk/system/test/sleep.h" +#include "mojo/edk/system/test/test_io_thread.h" #include "mojo/edk/system/transport_data.h" -#include "mojo/edk/test/scoped_test_dir.h" -#include "mojo/edk/test/simple_test_thread.h" -#include "mojo/edk/test/test_io_thread.h" +#include "mojo/edk/system/waitable_event.h" #include "mojo/edk/test/test_utils.h" #include "mojo/edk/util/make_unique.h" +#include "mojo/edk/util/mutex.h" #include "mojo/edk/util/scoped_file.h" #include "mojo/public/cpp/system/macros.h" #include "testing/gtest/include/gtest/gtest.h" +using mojo::util::Mutex; +using mojo::util::MutexLocker; + namespace mojo { namespace system { namespace { @@ -71,7 +75,7 @@ bool WriteTestMessageToHandle(const embedder::PlatformHandle& handle, class RawChannelTest : public testing::Test { public: - RawChannelTest() : io_thread_(mojo::test::TestIOThread::StartMode::MANUAL) {} + RawChannelTest() : io_thread_(test::TestIOThread::StartMode::MANUAL) {} ~RawChannelTest() override {} void SetUp() override { @@ -88,12 +92,12 @@ class RawChannelTest : public testing::Test { } protected: - mojo::test::TestIOThread* io_thread() { return &io_thread_; } + test::TestIOThread* io_thread() { return &io_thread_; } embedder::ScopedPlatformHandle handles[2]; private: - mojo::test::TestIOThread io_thread_; + test::TestIOThread io_thread_; MOJO_DISALLOW_COPY_AND_ASSIGN(RawChannelTest); }; @@ -170,7 +174,7 @@ class TestMessageReaderAndChecker { if (static_cast(read_size) < sizeof(buffer)) { i++; - test::Sleep(test::DeadlineFromMilliseconds(kMessageReaderSleepMs)); + test::SleepMilliseconds(kMessageReaderSleepMs); } } @@ -215,7 +219,7 @@ TEST_F(RawChannelTest, WriteMessage) { class ReadCheckerRawChannelDelegate : public RawChannel::Delegate { public: - ReadCheckerRawChannelDelegate() : done_event_(false, false), position_(0) {} + ReadCheckerRawChannelDelegate() : position_(0) {} ~ReadCheckerRawChannelDelegate() override {} // |RawChannel::Delegate| implementation (called on the I/O thread): @@ -263,7 +267,7 @@ class ReadCheckerRawChannelDelegate : public RawChannel::Delegate { } private: - base::WaitableEvent done_event_; + AutoResetWaitableEvent done_event_; Mutex mutex_; std::vector expected_sizes_ MOJO_GUARDED_BY(mutex_); @@ -304,7 +308,7 @@ TEST_F(RawChannelTest, OnReadMessage) { // RawChannelTest.WriteMessageAndOnReadMessage --------------------------------- -class RawChannelWriterThread : public mojo::test::SimpleTestThread { +class RawChannelWriterThread : public test::SimpleTestThread { public: RawChannelWriterThread(RawChannel* raw_channel, size_t write_count) : raw_channel_(raw_channel), left_to_write_(write_count) {} @@ -330,7 +334,7 @@ class RawChannelWriterThread : public mojo::test::SimpleTestThread { class ReadCountdownRawChannelDelegate : public RawChannel::Delegate { public: explicit ReadCountdownRawChannelDelegate(size_t expected_count) - : done_event_(false, false), expected_count_(expected_count), count_(0) {} + : expected_count_(expected_count), count_(0) {} ~ReadCountdownRawChannelDelegate() override {} // |RawChannel::Delegate| implementation (called on the I/O thread): @@ -357,7 +361,7 @@ class ReadCountdownRawChannelDelegate : public RawChannel::Delegate { void Wait() { done_event_.Wait(); } private: - base::WaitableEvent done_event_; + AutoResetWaitableEvent done_event_; size_t expected_count_; size_t count_; @@ -391,7 +395,7 @@ TEST_F(RawChannelTest, WriteMessageAndOnReadMessage) { // Sleep a bit, to let any extraneous reads be processed. (There shouldn't be // any, but we want to know about them.) - test::Sleep(test::DeadlineFromMilliseconds(100)); + test::SleepMilliseconds(100u); // Wait for reading to finish. reader_delegate.Wait(); @@ -412,8 +416,6 @@ class ErrorRecordingRawChannelDelegate bool expect_read_error, bool expect_write_error) : ReadCountdownRawChannelDelegate(expected_read_count), - got_read_error_event_(false, false), - got_write_error_event_(false, false), expecting_read_error_(expect_read_error), expecting_write_error_(expect_write_error) {} @@ -450,8 +452,8 @@ class ErrorRecordingRawChannelDelegate void WaitForWriteError() { got_write_error_event_.Wait(); } private: - base::WaitableEvent got_read_error_event_; - base::WaitableEvent got_write_error_event_; + AutoResetWaitableEvent got_read_error_event_; + AutoResetWaitableEvent got_write_error_event_; bool expecting_read_error_; bool expecting_write_error_; @@ -481,7 +483,7 @@ TEST_F(RawChannelTest, OnError) { // Sleep a bit, to make sure we don't get another |OnError()| // notification. (If we actually get another one, |OnError()| crashes.) - test::Sleep(test::DeadlineFromMilliseconds(20)); + test::SleepMilliseconds(20u); io_thread()->PostTaskAndWait( base::Bind(&RawChannel::Shutdown, base::Unretained(rc.get()))); @@ -546,7 +548,6 @@ class ShutdownOnReadMessageRawChannelDelegate : public RawChannel::Delegate { bool should_destroy) : raw_channel_(raw_channel), should_destroy_(should_destroy), - done_event_(false, false), did_shutdown_(false) {} ~ShutdownOnReadMessageRawChannelDelegate() override {} @@ -577,7 +578,7 @@ class ShutdownOnReadMessageRawChannelDelegate : public RawChannel::Delegate { private: RawChannel* const raw_channel_; const bool should_destroy_; - base::WaitableEvent done_event_; + AutoResetWaitableEvent done_event_; bool did_shutdown_; MOJO_DISALLOW_COPY_AND_ASSIGN(ShutdownOnReadMessageRawChannelDelegate); @@ -621,7 +622,6 @@ class ShutdownOnErrorRawChannelDelegate : public RawChannel::Delegate { : raw_channel_(raw_channel), should_destroy_(should_destroy), shutdown_on_error_type_(shutdown_on_error_type), - done_event_(false, false), did_shutdown_(false) {} ~ShutdownOnErrorRawChannelDelegate() override {} @@ -652,7 +652,7 @@ class ShutdownOnErrorRawChannelDelegate : public RawChannel::Delegate { RawChannel* const raw_channel_; const bool should_destroy_; const Error shutdown_on_error_type_; - base::WaitableEvent done_event_; + AutoResetWaitableEvent done_event_; bool did_shutdown_; MOJO_DISALLOW_COPY_AND_ASSIGN(ShutdownOnErrorRawChannelDelegate); @@ -723,7 +723,7 @@ TEST_F(RawChannelTest, ShutdownAndDestroyOnErrorWrite) { class ReadPlatformHandlesCheckerRawChannelDelegate : public RawChannel::Delegate { public: - ReadPlatformHandlesCheckerRawChannelDelegate() : done_event_(false, false) {} + ReadPlatformHandlesCheckerRawChannelDelegate() {} ~ReadPlatformHandlesCheckerRawChannelDelegate() override {} // |RawChannel::Delegate| implementation (called on the I/O thread): @@ -772,13 +772,13 @@ class ReadPlatformHandlesCheckerRawChannelDelegate void Wait() { done_event_.Wait(); } private: - base::WaitableEvent done_event_; + AutoResetWaitableEvent done_event_; MOJO_DISALLOW_COPY_AND_ASSIGN(ReadPlatformHandlesCheckerRawChannelDelegate); }; TEST_F(RawChannelTest, ReadWritePlatformHandles) { - mojo::test::ScopedTestDir test_dir; + test::ScopedTestDir test_dir; WriteOnlyRawChannelDelegate write_delegate; std::unique_ptr rc_write(RawChannel::Create(handles[0].Pass())); @@ -800,9 +800,9 @@ TEST_F(RawChannelTest, ReadWritePlatformHandles) { embedder::ScopedPlatformHandleVectorPtr platform_handles( new embedder::PlatformHandleVector()); platform_handles->push_back( - mojo::test::PlatformHandleFromFILE(fp1.Pass()).release()); + mojo::test::PlatformHandleFromFILE(std::move(fp1)).release()); platform_handles->push_back( - mojo::test::PlatformHandleFromFILE(fp2.Pass()).release()); + mojo::test::PlatformHandleFromFILE(std::move(fp2)).release()); std::unique_ptr message( new MessageInTransit(MessageInTransit::Type::ENDPOINT_CLIENT, diff --git a/mojo/edk/system/remote_consumer_data_pipe_impl.cc b/mojo/edk/system/remote_consumer_data_pipe_impl.cc index d71a3de84e2..b54b0fad626 100644 --- a/mojo/edk/system/remote_consumer_data_pipe_impl.cc +++ b/mojo/edk/system/remote_consumer_data_pipe_impl.cc @@ -18,6 +18,8 @@ #include "mojo/edk/system/message_in_transit.h" #include "mojo/edk/system/remote_data_pipe_ack.h" +using mojo::util::RefPtr; + namespace mojo { namespace system { diff --git a/mojo/edk/system/remote_consumer_data_pipe_impl.h b/mojo/edk/system/remote_consumer_data_pipe_impl.h index f05de1bc7a2..20a3f045fb2 100644 --- a/mojo/edk/system/remote_consumer_data_pipe_impl.h +++ b/mojo/edk/system/remote_consumer_data_pipe_impl.h @@ -10,7 +10,7 @@ #include "base/memory/aligned_memory.h" #include "mojo/edk/system/channel_endpoint.h" #include "mojo/edk/system/data_pipe_impl.h" -#include "mojo/edk/system/ref_ptr.h" +#include "mojo/edk/util/ref_ptr.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { @@ -25,7 +25,7 @@ class RemoteConsumerDataPipeImpl final : public DataPipeImpl { // is nonzero (i.e., if we're in the middle of a two-phase write when the // consumer handle is transferred); |start_index| is ignored if it is zero. RemoteConsumerDataPipeImpl( - RefPtr&& channel_endpoint, + util::RefPtr&& channel_endpoint, size_t consumer_num_bytes, std::unique_ptr buffer, size_t start_index); @@ -95,7 +95,7 @@ class RemoteConsumerDataPipeImpl final : public DataPipeImpl { void Disconnect(); // Should be valid if and only if |consumer_open()| returns true. - RefPtr channel_endpoint_; + util::RefPtr channel_endpoint_; // The number of bytes we've sent the consumer, but don't *know* have been // consumed. diff --git a/mojo/edk/system/remote_data_pipe_impl_unittest.cc b/mojo/edk/system/remote_data_pipe_impl_unittest.cc index 60ceb45c511..242bf0ee064 100644 --- a/mojo/edk/system/remote_data_pipe_impl_unittest.cc +++ b/mojo/edk/system/remote_data_pipe_impl_unittest.cc @@ -22,13 +22,16 @@ #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/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 { @@ -39,8 +42,7 @@ const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | class RemoteDataPipeImplTest : public testing::Test { public: - RemoteDataPipeImplTest() - : io_thread_(mojo::test::TestIOThread::StartMode::AUTO) {} + RemoteDataPipeImplTest() : io_thread_(test::TestIOThread::StartMode::AUTO) {} ~RemoteDataPipeImplTest() override {} void SetUp() override { @@ -114,7 +116,7 @@ class RemoteDataPipeImplTest : public testing::Test { } embedder::SimplePlatformSupport platform_support_; - mojo::test::TestIOThread io_thread_; + test::TestIOThread io_thread_; RefPtr channels_[2]; RefPtr message_pipes_[2]; @@ -145,7 +147,7 @@ TEST_F(RemoteDataPipeImplTest, Sanity) { message_pipe(0)->WriteMessage(0, UserPointer(kHello), sizeof(kHello), nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE)); - 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(); message_pipe(1)->RemoveAwakable(0, &waiter, &hss); @@ -204,10 +206,10 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerWithClosedProducer) { // |consumer| should have been closed. This is |DCHECK()|ed when it is // destroyed. - consumer->AssertHasOneRef(); + EXPECT_TRUE(consumer->HasOneRef()); consumer = nullptr; } - 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(); message_pipe(1)->RemoveAwakable(0, &waiter, &hss); @@ -223,7 +225,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerWithClosedProducer) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::DATA_PIPE_CONSUMER, read_dispatchers[0]->GetType()); @@ -237,7 +239,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerWithClosedProducer) { consumer->AddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 456, &hss); if (result == MOJO_RESULT_OK) { context = 0; - EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionTimeout(), &context)); EXPECT_EQ(456u, context); consumer->RemoveAwakable(&waiter, &hss); } else { @@ -265,7 +267,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerWithClosedProducer) { if (result == MOJO_RESULT_OK) { context = 0; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - waiter.Wait(test::ActionDeadline(), &context)); + waiter.Wait(test::ActionTimeout(), &context)); EXPECT_EQ(789u, context); consumer->RemoveAwakable(&waiter, &hss); } else { @@ -319,10 +321,10 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerDuringTwoPhaseWrite) { // |consumer| should have been closed. This is |DCHECK()|ed when it is // destroyed. - consumer->AssertHasOneRef(); + EXPECT_TRUE(consumer->HasOneRef()); consumer = nullptr; } - 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(); message_pipe(1)->RemoveAwakable(0, &waiter, &hss); @@ -338,7 +340,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerDuringTwoPhaseWrite) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::DATA_PIPE_CONSUMER, read_dispatchers[0]->GetType()); @@ -360,7 +362,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerDuringTwoPhaseWrite) { consumer->AddAwakable(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 456, &hss); if (result == MOJO_RESULT_OK) { context = 0; - EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionTimeout(), &context)); EXPECT_EQ(456u, context); consumer->RemoveAwakable(&waiter, &hss); } else { @@ -438,10 +440,10 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerDuringSecondTwoPhaseWrite) { // |consumer| should have been closed. This is |DCHECK()|ed when it is // destroyed. - consumer->AssertHasOneRef(); + EXPECT_TRUE(consumer->HasOneRef()); consumer = nullptr; } - 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(); message_pipe(1)->RemoveAwakable(0, &waiter, &hss); @@ -457,7 +459,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerDuringSecondTwoPhaseWrite) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::DATA_PIPE_CONSUMER, read_dispatchers[0]->GetType()); @@ -479,7 +481,7 @@ TEST_F(RemoteDataPipeImplTest, SendConsumerDuringSecondTwoPhaseWrite) { consumer->AddAwakable(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 456, &hss); if (result == MOJO_RESULT_OK) { context = 0; - EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionDeadline(), &context)); + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(test::ActionTimeout(), &context)); EXPECT_EQ(456u, context); consumer->RemoveAwakable(&waiter, &hss); } else { diff --git a/mojo/edk/system/remote_message_pipe_unittest.cc b/mojo/edk/system/remote_message_pipe_unittest.cc index 32043ff73b4..a29e38249ff 100644 --- a/mojo/edk/system/remote_message_pipe_unittest.cc +++ b/mojo/edk/system/remote_message_pipe_unittest.cc @@ -25,17 +25,21 @@ #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/system/shared_buffer_dispatcher.h" -#include "mojo/edk/system/test_utils.h" +#include "mojo/edk/system/test/scoped_test_dir.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/scoped_test_dir.h" -#include "mojo/edk/test/test_io_thread.h" #include "mojo/edk/test/test_utils.h" +#include "mojo/edk/util/ref_ptr.h" #include "mojo/edk/util/scoped_file.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 { @@ -46,8 +50,7 @@ const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | class RemoteMessagePipeTest : public testing::Test { public: - RemoteMessagePipeTest() - : io_thread_(mojo::test::TestIOThread::StartMode::AUTO) {} + RemoteMessagePipeTest() : io_thread_(test::TestIOThread::StartMode::AUTO) {} ~RemoteMessagePipeTest() override {} void SetUp() override { @@ -89,7 +92,7 @@ class RemoteMessagePipeTest : public testing::Test { } embedder::PlatformSupport* platform_support() { return &platform_support_; } - mojo::test::TestIOThread* io_thread() { return &io_thread_; } + test::TestIOThread* io_thread() { return &io_thread_; } // Warning: It's up to the caller to ensure that the returned channel // is/remains valid. Channel* channels(size_t i) { return channels_[i].get(); } @@ -160,7 +163,7 @@ class RemoteMessagePipeTest : public testing::Test { } embedder::SimplePlatformSupport platform_support_; - mojo::test::TestIOThread io_thread_; + test::TestIOThread io_thread_; embedder::ScopedPlatformHandle platform_handles_[2]; RefPtr channels_[2]; @@ -643,7 +646,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { // |dispatcher| should have been closed. This is |DCHECK()|ed when the // |dispatcher| is destroyed. - dispatcher->AssertHasOneRef(); + EXPECT_TRUE(dispatcher->HasOneRef()); dispatcher = nullptr; } @@ -671,7 +674,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::MESSAGE_PIPE, read_dispatchers[0]->GetType()); dispatcher = RefPtr( @@ -818,7 +821,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { // |dispatcher| should have been closed. This is |DCHECK()|ed when the // |dispatcher| is destroyed. - dispatcher->AssertHasOneRef(); + EXPECT_TRUE(dispatcher->HasOneRef()); dispatcher = nullptr; } @@ -846,7 +849,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::MESSAGE_PIPE, read_dispatchers[0]->GetType()); dispatcher = RefPtr( @@ -947,7 +950,7 @@ TEST_F(RemoteMessagePipeTest, SharedBufferPassing) { // |dispatcher| should have been closed. This is |DCHECK()|ed when the // |dispatcher| is destroyed. - dispatcher->AssertHasOneRef(); + EXPECT_TRUE(dispatcher->HasOneRef()); dispatcher = nullptr; } @@ -975,7 +978,7 @@ TEST_F(RemoteMessagePipeTest, SharedBufferPassing) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, read_dispatchers[0]->GetType()); dispatcher = RefPtr( @@ -1013,7 +1016,7 @@ TEST_F(RemoteMessagePipeTest, SharedBufferPassing) { } TEST_F(RemoteMessagePipeTest, PlatformHandlePassing) { - mojo::test::ScopedTestDir test_dir; + test::ScopedTestDir test_dir; static const char kHello[] = "hello"; static const char kWorld[] = "world"; @@ -1032,7 +1035,7 @@ TEST_F(RemoteMessagePipeTest, PlatformHandlePassing) { // We'll try to pass this dispatcher, which will cause a |PlatformHandle| to // be passed. auto dispatcher = PlatformHandleDispatcher::Create( - mojo::test::PlatformHandleFromFILE(fp.Pass())); + mojo::test::PlatformHandleFromFILE(std::move(fp))); // Prepare to wait on MP 1, port 1. (Add the waiter now. Otherwise, if we do // it later, it might already be readable.) @@ -1057,7 +1060,7 @@ TEST_F(RemoteMessagePipeTest, PlatformHandlePassing) { // |dispatcher| should have been closed. This is |DCHECK()|ed when the // |dispatcher| is destroyed. - dispatcher->AssertHasOneRef(); + EXPECT_TRUE(dispatcher->HasOneRef()); dispatcher = nullptr; } @@ -1085,16 +1088,16 @@ TEST_F(RemoteMessagePipeTest, PlatformHandlePassing) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::PLATFORM_HANDLE, read_dispatchers[0]->GetType()); dispatcher = RefPtr( static_cast(read_dispatchers[0].get())); - embedder::ScopedPlatformHandle h = dispatcher->PassPlatformHandle().Pass(); + embedder::ScopedPlatformHandle 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); @@ -1115,7 +1118,7 @@ TEST_F(RemoteMessagePipeTest, PlatformHandlePassing) { // itself (not in the test). Also, any logged warnings/errors would also // probably be indicative of bugs. TEST_F(RemoteMessagePipeTest, RacingClosesStress) { - MojoDeadline delay = test::DeadlineFromMilliseconds(5); + MojoDeadline delay = test::DeadlineFromMilliseconds(5u); for (unsigned i = 0; i < 256; i++) { DVLOG(2) << "---------------------------------------- " << i; @@ -1192,7 +1195,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { // |dispatcher| should have been closed. This is |DCHECK()|ed when the // |dispatcher| is destroyed. - dispatcher->AssertHasOneRef(); + EXPECT_TRUE(dispatcher->HasOneRef()); dispatcher = nullptr; } @@ -1220,7 +1223,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::MESSAGE_PIPE, read_dispatchers[0]->GetType()); dispatcher = RefPtr( @@ -1252,7 +1255,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { // |dispatcher| should have been closed. This is |DCHECK()|ed when the // |dispatcher| is destroyed. - dispatcher->AssertHasOneRef(); + EXPECT_TRUE(dispatcher->HasOneRef()); dispatcher = nullptr; } @@ -1278,7 +1281,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { EXPECT_EQ(1u, read_dispatchers.size()); EXPECT_EQ(1u, read_num_dispatchers); ASSERT_TRUE(read_dispatchers[0]); - read_dispatchers[0]->AssertHasOneRef(); + EXPECT_TRUE(read_dispatchers[0]->HasOneRef()); EXPECT_EQ(Dispatcher::Type::MESSAGE_PIPE, read_dispatchers[0]->GetType()); dispatcher = RefPtr( diff --git a/mojo/edk/system/remote_producer_data_pipe_impl.cc b/mojo/edk/system/remote_producer_data_pipe_impl.cc index 6cd9b2dcfd4..772277bcca5 100644 --- a/mojo/edk/system/remote_producer_data_pipe_impl.cc +++ b/mojo/edk/system/remote_producer_data_pipe_impl.cc @@ -20,6 +20,8 @@ #include "mojo/edk/system/remote_consumer_data_pipe_impl.h" #include "mojo/edk/system/remote_data_pipe_ack.h" +using mojo::util::RefPtr; + namespace mojo { namespace system { diff --git a/mojo/edk/system/remote_producer_data_pipe_impl.h b/mojo/edk/system/remote_producer_data_pipe_impl.h index 2f0a3a97837..1210b73c0fe 100644 --- a/mojo/edk/system/remote_producer_data_pipe_impl.h +++ b/mojo/edk/system/remote_producer_data_pipe_impl.h @@ -10,7 +10,7 @@ #include "base/memory/aligned_memory.h" #include "mojo/edk/system/channel_endpoint.h" #include "mojo/edk/system/data_pipe_impl.h" -#include "mojo/edk/system/ref_ptr.h" +#include "mojo/edk/util/ref_ptr.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { @@ -24,9 +24,9 @@ class MessageInTransitQueue; class RemoteProducerDataPipeImpl final : public DataPipeImpl { public: explicit RemoteProducerDataPipeImpl( - RefPtr&& channel_endpoint); + util::RefPtr&& channel_endpoint); RemoteProducerDataPipeImpl( - RefPtr&& channel_endpoint, + util::RefPtr&& channel_endpoint, std::unique_ptr buffer, size_t start_index, size_t current_num_bytes); @@ -106,7 +106,7 @@ class RemoteProducerDataPipeImpl final : public DataPipeImpl { void Disconnect(); // Should be valid if and only if |producer_open()| returns true. - RefPtr channel_endpoint_; + util::RefPtr channel_endpoint_; std::unique_ptr buffer_; // Circular buffer. diff --git a/mojo/edk/system/shared_buffer_dispatcher.cc b/mojo/edk/system/shared_buffer_dispatcher.cc index 38d7faa43a7..8b86d0a46fb 100644 --- a/mojo/edk/system/shared_buffer_dispatcher.cc +++ b/mojo/edk/system/shared_buffer_dispatcher.cc @@ -5,6 +5,7 @@ #include "mojo/edk/system/shared_buffer_dispatcher.h" #include +#include #include "base/logging.h" #include "mojo/edk/embedder/platform_support.h" @@ -14,6 +15,8 @@ #include "mojo/edk/system/options_validation.h" #include "mojo/public/c/system/macros.h" +using mojo::util::RefPtr; + namespace mojo { namespace system { @@ -75,15 +78,15 @@ RefPtr SharedBufferDispatcher::Create( return nullptr; } - scoped_refptr shared_buffer( - platform_support->CreateSharedBuffer(static_cast(num_bytes))); + auto shared_buffer = + platform_support->CreateSharedBuffer(static_cast(num_bytes)); if (!shared_buffer) { *result = MOJO_RESULT_RESOURCE_EXHAUSTED; return nullptr; } *result = MOJO_RESULT_OK; - return CreateInternal(shared_buffer.Pass()); + return CreateInternal(std::move(shared_buffer)); } Dispatcher::Type SharedBufferDispatcher::GetType() const { @@ -144,21 +147,21 @@ RefPtr SharedBufferDispatcher::Deserialize( // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be // closed even if creation fails. - scoped_refptr shared_buffer( + auto shared_buffer = channel->platform_support()->CreateSharedBufferFromHandle( - num_bytes, embedder::ScopedPlatformHandle(platform_handle))); + num_bytes, embedder::ScopedPlatformHandle(platform_handle)); if (!shared_buffer) { LOG(ERROR) << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)"; return nullptr; } - return CreateInternal(shared_buffer.Pass()); + return CreateInternal(std::move(shared_buffer)); } SharedBufferDispatcher::SharedBufferDispatcher( - scoped_refptr shared_buffer) - : shared_buffer_(shared_buffer) { + RefPtr&& shared_buffer) + : shared_buffer_(std::move(shared_buffer)) { DCHECK(shared_buffer_); } @@ -207,7 +210,7 @@ RefPtr SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() { mutex().AssertHeld(); DCHECK(shared_buffer_); - return CreateInternal(shared_buffer_.Pass()); + return CreateInternal(std::move(shared_buffer_)); } MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock( @@ -221,7 +224,7 @@ MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock( return result; // Note: Since this is "duplicate", we keep our ref to |shared_buffer_|. - *new_dispatcher = CreateInternal(shared_buffer_); + *new_dispatcher = CreateInternal(shared_buffer_.Clone()); return MOJO_RESULT_OK; } diff --git a/mojo/edk/system/shared_buffer_dispatcher.h b/mojo/edk/system/shared_buffer_dispatcher.h index c61bd5cff54..9f153cf8a3c 100644 --- a/mojo/edk/system/shared_buffer_dispatcher.h +++ b/mojo/edk/system/shared_buffer_dispatcher.h @@ -5,10 +5,13 @@ #ifndef MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_ #define MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_ +#include + #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/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 { @@ -41,7 +44,7 @@ class SharedBufferDispatcher final : public SimpleDispatcher { // Static factory method: |validated_options| must be validated (obviously). // Returns null on error; |*result| will be set to an appropriate result // code). - static RefPtr Create( + static util::RefPtr Create( embedder::PlatformSupport* platform_support, const MojoCreateSharedBufferOptions& validated_options, uint64_t num_bytes, @@ -52,20 +55,20 @@ class SharedBufferDispatcher final : public SimpleDispatcher { // The "opposite" of |SerializeAndClose()|. (Typically this is called by // |Dispatcher::Deserialize()|.) - static RefPtr Deserialize( + static util::RefPtr Deserialize( Channel* channel, const void* source, size_t size, embedder::PlatformHandleVector* platform_handles); private: - static RefPtr CreateInternal( - scoped_refptr shared_buffer) { - return AdoptRef(new SharedBufferDispatcher(shared_buffer.Pass())); + static util::RefPtr CreateInternal( + util::RefPtr&& shared_buffer) { + return AdoptRef(new SharedBufferDispatcher(std::move(shared_buffer))); } explicit SharedBufferDispatcher( - scoped_refptr shared_buffer); + util::RefPtr&& shared_buffer); ~SharedBufferDispatcher() override; // Validates and/or sets default options for @@ -79,10 +82,11 @@ class SharedBufferDispatcher final : public SimpleDispatcher { // |Dispatcher| protected methods: void CloseImplNoLock() override; - RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() override; + util::RefPtr CreateEquivalentDispatcherAndCloseImplNoLock() + override; MojoResult DuplicateBufferHandleImplNoLock( UserPointer options, - RefPtr* new_dispatcher) override; + util::RefPtr* new_dispatcher) override; MojoResult MapBufferImplNoLock( uint64_t offset, uint64_t num_bytes, @@ -99,7 +103,7 @@ class SharedBufferDispatcher final : public SimpleDispatcher { embedder::PlatformHandleVector* platform_handles) override MOJO_NOT_THREAD_SAFE; - scoped_refptr shared_buffer_ + util::RefPtr shared_buffer_ MOJO_GUARDED_BY(mutex()); MOJO_DISALLOW_COPY_AND_ASSIGN(SharedBufferDispatcher); diff --git a/mojo/edk/system/shared_buffer_dispatcher_unittest.cc b/mojo/edk/system/shared_buffer_dispatcher_unittest.cc index 571e4316fd8..f4998bb3a4b 100644 --- a/mojo/edk/system/shared_buffer_dispatcher_unittest.cc +++ b/mojo/edk/system/shared_buffer_dispatcher_unittest.cc @@ -6,13 +6,14 @@ #include -#include "base/memory/ref_counted.h" #include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/embedder/simple_platform_support.h" #include "mojo/edk/system/dispatcher.h" #include "mojo/public/cpp/system/macros.h" #include "testing/gtest/include/gtest/gtest.h" +using mojo::util::RefPtr; + namespace mojo { namespace system { namespace { diff --git a/mojo/edk/system/simple_dispatcher.h b/mojo/edk/system/simple_dispatcher.h index 8a8e83ec8f1..c305d5f5306 100644 --- a/mojo/edk/system/simple_dispatcher.h +++ b/mojo/edk/system/simple_dispatcher.h @@ -9,6 +9,7 @@ #include "mojo/edk/system/awakable_list.h" #include "mojo/edk/system/dispatcher.h" +#include "mojo/edk/util/thread_annotations.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { @@ -16,8 +17,8 @@ namespace system { // A base class for simple dispatchers. "Simple" means that there's a one-to-one // correspondence between handles and dispatchers (see the explanatory comment -// in core.cc). This class implements the standard waiter-signalling mechanism -// in that case. +// in core.cc). This class implements the standard waiter-signaling mechanism in +// that case. class SimpleDispatcher : public Dispatcher { protected: SimpleDispatcher(); diff --git a/mojo/edk/system/simple_dispatcher_unittest.cc b/mojo/edk/system/simple_dispatcher_unittest.cc index 8b5fb5c1989..998801b820a 100644 --- a/mojo/edk/system/simple_dispatcher_unittest.cc +++ b/mojo/edk/system/simple_dispatcher_unittest.cc @@ -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). @@ -13,15 +13,21 @@ #include #include "base/logging.h" -#include "mojo/edk/system/ref_ptr.h" -#include "mojo/edk/system/test_utils.h" -#include "mojo/edk/system/thread_annotations.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/util/make_unique.h" +#include "mojo/edk/util/ref_ptr.h" +#include "mojo/edk/util/thread_annotations.h" #include "mojo/public/cpp/system/macros.h" #include "testing/gtest/include/gtest/gtest.h" +using mojo::util::MakeRefCounted; +using mojo::util::MutexLocker; +using mojo::util::RefPtr; + namespace mojo { namespace system { namespace { @@ -114,7 +120,7 @@ TEST(SimpleDispatcherTest, Basic) { d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_WRITABLE); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_OK, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(1u, context); hss = HandleSignalsState(); d->RemoveAwakable(&w, &hss); @@ -130,7 +136,7 @@ TEST(SimpleDispatcherTest, Basic) { d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_WRITABLE); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_OK, w.Wait(0, &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(2u, context); hss = HandleSignalsState(); d->RemoveAwakable(&w, &hss); @@ -145,8 +151,8 @@ TEST(SimpleDispatcherTest, Basic) { d->AddAwakable(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 3, nullptr)); d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_WRITABLE); stopwatch.Start(); - EXPECT_EQ(MOJO_RESULT_OK, w.Wait(2 * test::EpsilonDeadline(), &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(2 * test::EpsilonTimeout(), &context)); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(3u, context); hss = HandleSignalsState(); d->RemoveAwakable(&w, &hss); @@ -161,7 +167,7 @@ TEST(SimpleDispatcherTest, Basic) { d->AddAwakable(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 4, 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(); d->RemoveAwakable(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); @@ -176,10 +182,10 @@ TEST(SimpleDispatcherTest, Basic) { d->AddAwakable(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 5, 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(); d->RemoveAwakable(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); @@ -218,7 +224,7 @@ TEST(SimpleDispatcherTest, BasicUnsatisfiable) { stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(2u, context); hss = HandleSignalsState(); d->RemoveAwakable(&w, &hss); @@ -234,7 +240,7 @@ TEST(SimpleDispatcherTest, BasicUnsatisfiable) { d->SetSatisfiableSignals(MOJO_HANDLE_SIGNAL_READABLE); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, w.Wait(0, &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(3u, context); hss = HandleSignalsState(); d->RemoveAwakable(&w, &hss); @@ -251,8 +257,8 @@ TEST(SimpleDispatcherTest, BasicUnsatisfiable) { d->SetSatisfiableSignals(MOJO_HANDLE_SIGNAL_READABLE); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - w.Wait(2 * test::EpsilonDeadline(), &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + w.Wait(2 * test::EpsilonTimeout(), &context)); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(4u, context); hss = HandleSignalsState(); d->RemoveAwakable(&w, &hss); @@ -289,7 +295,7 @@ TEST(SimpleDispatcherTest, BasicClosed) { EXPECT_EQ(MOJO_RESULT_OK, d->Close()); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(MOJO_DEADLINE_INDEFINITE, &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(2u, context); // Don't need to remove waiters from closed dispatchers. @@ -301,7 +307,7 @@ TEST(SimpleDispatcherTest, BasicClosed) { EXPECT_EQ(MOJO_RESULT_OK, d->Close()); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_CANCELLED, w.Wait(0, &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(3u, context); // Don't need to remove waiters from closed dispatchers. @@ -314,8 +320,8 @@ TEST(SimpleDispatcherTest, BasicClosed) { EXPECT_EQ(MOJO_RESULT_OK, d->Close()); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_CANCELLED, - w.Wait(2 * test::EpsilonDeadline(), &context)); - EXPECT_LT(stopwatch.Elapsed(), test::EpsilonDeadline()); + w.Wait(2 * test::EpsilonTimeout(), &context)); + EXPECT_LT(stopwatch.Elapsed(), test::EpsilonTimeout()); EXPECT_EQ(4u, context); // Don't need to remove waiters from closed dispatchers. } @@ -341,7 +347,7 @@ TEST(SimpleDispatcherTest, BasicThreaded) { // If we closed earlier, then probably we'd get a |MOJO_RESULT_CANCELLED|. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } - 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, hss.satisfied_signals); @@ -357,14 +363,14 @@ TEST(SimpleDispatcherTest, BasicThreaded) { &context, &hss); stopwatch.Start(); thread.Start(); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_READABLE); } // Joins the thread. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } 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()); EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_OK, result); EXPECT_EQ(2u, context); @@ -381,14 +387,14 @@ TEST(SimpleDispatcherTest, BasicThreaded) { &context, &hss); stopwatch.Start(); thread.Start(); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); d->SetSatisfiableSignals(MOJO_HANDLE_SIGNAL_NONE); } // Joins the thread. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } 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); @@ -403,12 +409,12 @@ TEST(SimpleDispatcherTest, BasicThreaded) { &context, &hss); stopwatch.Start(); thread.Start(); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); EXPECT_EQ(MOJO_RESULT_OK, d->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); @@ -420,11 +426,11 @@ TEST(SimpleDispatcherTest, BasicThreaded) { auto d = MakeRefCounted(); { test::WaiterThread thread(d, MOJO_HANDLE_SIGNAL_READABLE, - 2 * test::EpsilonDeadline(), 5, &did_wait, + 2 * test::EpsilonTimeout(), 5, &did_wait, &result, &context, &hss); stopwatch.Start(); thread.Start(); - test::Sleep(1 * test::EpsilonDeadline()); + test::Sleep(1 * test::EpsilonTimeout()); // Not what we're waiting for. d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_WRITABLE); } // Joins the thread (after its wait times out). @@ -432,8 +438,8 @@ TEST(SimpleDispatcherTest, BasicThreaded) { EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } 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_DEADLINE_EXCEEDED, result); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); @@ -459,7 +465,7 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { &did_wait[i], &result[i], &context[i], &hss[i])); threads.back()->Start(); } - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_READABLE); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } // Joins the threads. @@ -488,7 +494,7 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { &did_wait[i], &result[i], &context[i], &hss[i])); threads.back()->Start(); } - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_READABLE); // This will wake up the ones waiting to write. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); @@ -525,9 +531,9 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { &did_wait[i], &result[i], &context[i], &hss[i])); threads.back()->Start(); } - test::Sleep(1 * test::EpsilonDeadline()); + test::Sleep(1 * test::EpsilonTimeout()); d->SetSatisfiableSignals(MOJO_HANDLE_SIGNAL_READABLE); - test::Sleep(1 * test::EpsilonDeadline()); + test::Sleep(1 * test::EpsilonTimeout()); d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_READABLE); EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } // Joins the threads. @@ -553,17 +559,17 @@ TEST(SimpleDispatcherTest, MultipleWaiters) { std::vector> threads; for (uint32_t i = 0; i < kNumWaiters / 2; i++) { threads.push_back(util::MakeUnique( - d, MOJO_HANDLE_SIGNAL_READABLE, 3 * test::EpsilonDeadline(), i, + d, MOJO_HANDLE_SIGNAL_READABLE, 3 * test::EpsilonTimeout(), i, &did_wait[i], &result[i], &context[i], &hss[i])); threads.back()->Start(); } for (uint32_t i = kNumWaiters / 2; i < kNumWaiters; i++) { threads.push_back(util::MakeUnique( - d, MOJO_HANDLE_SIGNAL_WRITABLE, 1 * test::EpsilonDeadline(), i, + d, MOJO_HANDLE_SIGNAL_WRITABLE, 1 * test::EpsilonTimeout(), i, &did_wait[i], &result[i], &context[i], &hss[i])); threads.back()->Start(); } - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); d->SetSatisfiedSignals(MOJO_HANDLE_SIGNAL_READABLE); // All those waiting for writable should have timed out. EXPECT_EQ(MOJO_RESULT_OK, d->Close()); diff --git a/mojo/edk/system/slave_connection_manager.cc b/mojo/edk/system/slave_connection_manager.cc index 08aaf9d5dac..749597afe62 100644 --- a/mojo/edk/system/slave_connection_manager.cc +++ b/mojo/edk/system/slave_connection_manager.cc @@ -13,6 +13,8 @@ #include "mojo/edk/system/message_in_transit.h" #include "mojo/edk/util/make_unique.h" +using mojo::util::MutexLocker; + namespace mojo { namespace system { @@ -27,9 +29,7 @@ SlaveConnectionManager::SlaveConnectionManager( ack_result_(nullptr), ack_peer_process_identifier_(nullptr), ack_is_first_(nullptr), - ack_platform_handle_(nullptr), - event_(false, false) { // Auto-reset, not initially signalled. -} + ack_platform_handle_(nullptr) {} SlaveConnectionManager::~SlaveConnectionManager() { DCHECK(!delegate_thread_task_runner_); diff --git a/mojo/edk/system/slave_connection_manager.h b/mojo/edk/system/slave_connection_manager.h index 894f67d2f0c..bd66534c91e 100644 --- a/mojo/edk/system/slave_connection_manager.h +++ b/mojo/edk/system/slave_connection_manager.h @@ -8,14 +8,14 @@ #include #include "base/memory/ref_counted.h" -#include "base/synchronization/waitable_event.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/embedder/slave_process_delegate.h" #include "mojo/edk/system/connection_manager.h" -#include "mojo/edk/system/mutex.h" #include "mojo/edk/system/raw_channel.h" +#include "mojo/edk/system/waitable_event.h" +#include "mojo/edk/util/mutex.h" #include "mojo/public/cpp/system/macros.h" namespace base { @@ -146,8 +146,8 @@ class SlaveConnectionManager final : public ConnectionManager, // // TODO(vtl): This is all a hack. It'd really suffice to have a version of // |RawChannel| with fully synchronous reading and writing. - Mutex mutex_; - base::WaitableEvent event_; + util::Mutex mutex_; + AutoResetWaitableEvent event_; MOJO_DISALLOW_COPY_AND_ASSIGN(SlaveConnectionManager); }; diff --git a/mojo/edk/system/test/BUILD.gn b/mojo/edk/system/test/BUILD.gn new file mode 100644 index 00000000000..dd33b9a46e2 --- /dev/null +++ b/mojo/edk/system/test/BUILD.gn @@ -0,0 +1,106 @@ +# 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. + +import("../../mojo_edk.gni") + +# Utilties for use by EDK internal (unit and perf) tests. +mojo_edk_source_set("test") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/*" ] + + sources = [ + "random.cc", + "random.h", + "scoped_test_dir.cc", + "scoped_test_dir.h", + "simple_test_thread.cc", + "simple_test_thread.h", + "sleep.cc", + "sleep.h", + "stopwatch.cc", + "stopwatch.h", + "test_command_line.cc", + "test_command_line.h", + "test_io_thread.cc", + "test_io_thread.h", + "timeouts.cc", + "timeouts.h", + ] + + mojo_sdk_public_deps = [ + "mojo/public/c/system", + "mojo/public/cpp/system", + ] + + deps = [ + "//base", + "//base/test:test_support", + "//testing/gtest", + ] + + mojo_edk_deps = [ + "mojo/edk/embedder:platform", + "mojo/edk/util", + ] +} + +# Utilities for use by EDK internal perf tests (for use with +# :run_all_perftests). +mojo_edk_source_set("perf") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/*" ] + + sources = [ + "perf_log.cc", + "perf_log.h", + ] + + deps = [ + "//base/test:test_support", + ] +} + +mojo_edk_source_set("run_all_unittests") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/*" ] + + sources = [ + "run_all_unittests.cc", + ] + + deps = [ + ":test", + "//base", + "//base/test:test_support", + "//testing/gtest", + ] +} + +mojo_edk_source_set("run_all_perftests") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/*" ] + + sources = [ + "run_all_perftests.cc", + ] + + deps = [ + ":test", + "//base/test:test_support", + ] +} + +mojo_edk_source_set("unittests") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/system:mojo_system_unittests" ] + + sources = [ + "random_unittest.cc", + ] + + deps = [ + ":test", + "//testing/gtest", + ] +} diff --git a/mojo/edk/system/test/perf_log.cc b/mojo/edk/system/test/perf_log.cc new file mode 100644 index 00000000000..5b9d738688f --- /dev/null +++ b/mojo/edk/system/test/perf_log.cc @@ -0,0 +1,19 @@ +// 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/test/perf_log.h" + +#include "base/test/perf_log.h" + +namespace mojo { +namespace system { +namespace test { + +void LogPerfResult(const char* test_name, double value, const char* units) { + base::LogPerfResult(test_name, value, units); +} + +} // namespace test +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/test/perf_log.h b/mojo/edk/system/test/perf_log.h new file mode 100644 index 00000000000..93affff7c05 --- /dev/null +++ b/mojo/edk/system/test/perf_log.h @@ -0,0 +1,29 @@ +// 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. + +// Functions for logging perf test results. + +#ifndef MOJO_EDK_SYSTEM_TEST_PERF_LOG_H_ +#define MOJO_EDK_SYSTEM_TEST_PERF_LOG_H_ + +//#include "mojo/public/c/system/types.h" +//#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace system { +namespace test { + +// TODO(vtl): Possibly should have our own "InitPerfLog()" and +// "FinalizePerfLog()" functions, but we can't do that until we stop using +// |base::PerfTestSuite()|. Currently, + +// Logs the result of a perf test. You may only call this while running inside a +// perf test suite (using the :run_all_perftests from this directory). +void LogPerfResult(const char* test_name, double value, const char* units); + +} // namespace test +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_TEST_PERF_LOG_H_ diff --git a/mojo/edk/system/test/random.cc b/mojo/edk/system/test/random.cc new file mode 100644 index 00000000000..9463d272f54 --- /dev/null +++ b/mojo/edk/system/test/random.cc @@ -0,0 +1,36 @@ +// Copyright 2013 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/test/random.h" + +#include + +#include + +#include "base/logging.h" + +namespace mojo { +namespace system { +namespace test { + +// TODO(vtl): Replace all of this implementation with suitable use of C++11 +// when we can. +int RandomInt(int min, int max) { + DCHECK_LE(min, max); + DCHECK_LE(static_cast(max) - min, RAND_MAX); + DCHECK_LT(static_cast(max) - min, std::numeric_limits::max()); + + // This is in-range for an |int| due to the above. + int range = max - min + 1; + int max_valid = (RAND_MAX / range) * range - 1; + int value; + do { + value = rand(); + } while (value > max_valid); + return min + (value % range); +} + +} // namespace test +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/test/random.h b/mojo/edk/system/test/random.h new file mode 100644 index 00000000000..cae4b9a7c1c --- /dev/null +++ b/mojo/edk/system/test/random.h @@ -0,0 +1,23 @@ +// Copyright 2013 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. + +// Pseudorandom number generation for tests. + +#ifndef MOJO_EDK_SYSTEM_TEST_RANDOM_H_ +#define MOJO_EDK_SYSTEM_TEST_RANDOM_H_ + +namespace mojo { +namespace system { +namespace test { + +// Returns a (uniformly) (pseudo)random integer in the interval [min, max]. +// Currently, |max - min| must be at most |RAND_MAX| and must also be (strictly) +// less than |INT_MAX|. +int RandomInt(int min, int max); + +} // namespace test +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_TEST_RANDOM_H_ diff --git a/mojo/edk/system/test_utils_unittest.cc b/mojo/edk/system/test/random_unittest.cc similarity index 92% rename from mojo/edk/system/test_utils_unittest.cc rename to mojo/edk/system/test/random_unittest.cc index 5a3eda55ff6..d1743ca5dea 100644 --- a/mojo/edk/system/test_utils_unittest.cc +++ b/mojo/edk/system/test/random_unittest.cc @@ -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/system/test_utils.h" +#include "mojo/edk/system/test/random.h" #include @@ -13,7 +13,7 @@ namespace system { namespace test { namespace { -TEST(TestUtilsTest, RandomInt) { +TEST(RandomTest, RandomInt) { static const int kMin = -3; static const int kMax = 6; static const unsigned kNumBuckets = kMax - kMin + 1; @@ -37,7 +37,7 @@ TEST(TestUtilsTest, RandomInt) { } } -TEST(TestUtilsTest, RandomIntSameValues) { +TEST(RandomTest, RandomIntSameValues) { static const int kIntMin = std::numeric_limits::min(); EXPECT_EQ(kIntMin, RandomInt(kIntMin, kIntMin)); diff --git a/mojo/edk/system/test/run_all_perftests.cc b/mojo/edk/system/test/run_all_perftests.cc new file mode 100644 index 00000000000..aba386d7927 --- /dev/null +++ b/mojo/edk/system/test/run_all_perftests.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 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 "base/test/perf_test_suite.h" +#include "mojo/edk/system/test/test_command_line.h" + +int main(int argc, char** argv) { + mojo::system::test::InitializeTestCommandLine(argc, argv); + return base::PerfTestSuite(argc, argv).Run(); +} diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/test/run_all_unittests.cc similarity index 81% rename from mojo/edk/system/run_all_unittests.cc rename to mojo/edk/system/test/run_all_unittests.cc index cd6133741bb..72a9ca217e5 100644 --- a/mojo/edk/system/run_all_unittests.cc +++ b/mojo/edk/system/test/run_all_unittests.cc @@ -2,12 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// This defines the main() for EDK internal implementation unit test binaries. + #include "base/bind.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" +#include "mojo/edk/system/test/test_command_line.h" #include "testing/gtest/include/gtest/gtest.h" int main(int argc, char** argv) { + mojo::system::test::InitializeTestCommandLine(argc, argv); + // Silence death test thread warnings on Linux. We can afford to run our death // tests a little more slowly (< 10 ms per death test on a Z620). // On android, we need to run in the default mode, as the threadsafe mode diff --git a/mojo/edk/test/scoped_test_dir.cc b/mojo/edk/system/test/scoped_test_dir.cc similarity index 87% rename from mojo/edk/test/scoped_test_dir.cc rename to mojo/edk/system/test/scoped_test_dir.cc index 5bd768b352a..7f7f2bc4dd1 100644 --- a/mojo/edk/test/scoped_test_dir.cc +++ b/mojo/edk/system/test/scoped_test_dir.cc @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "mojo/edk/test/scoped_test_dir.h" +#include "mojo/edk/system/test/scoped_test_dir.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/logging.h" namespace mojo { +namespace system { namespace test { ScopedTestDir::ScopedTestDir() { @@ -24,4 +25,5 @@ util::ScopedFILE ScopedTestDir::CreateFile() { } } // namespace test +} // namespace system } // namespace mojo diff --git a/mojo/edk/test/scoped_test_dir.h b/mojo/edk/system/test/scoped_test_dir.h similarity index 79% rename from mojo/edk/test/scoped_test_dir.h rename to mojo/edk/system/test/scoped_test_dir.h index 4db372ff3e4..9f4db1bb3d2 100644 --- a/mojo/edk/test/scoped_test_dir.h +++ b/mojo/edk/system/test/scoped_test_dir.h @@ -2,14 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MOJO_EDK_TEST_SCOPED_TEST_DIR_H_ -#define MOJO_EDK_TEST_SCOPED_TEST_DIR_H_ +#ifndef MOJO_EDK_SYSTEM_TEST_SCOPED_TEST_DIR_H_ +#define MOJO_EDK_SYSTEM_TEST_SCOPED_TEST_DIR_H_ #include "base/files/scoped_temp_dir.h" #include "mojo/edk/util/scoped_file.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { +namespace system { namespace test { // Creates/destroyes a temporary directory for test purposes. (Unlike @@ -28,6 +29,7 @@ class ScopedTestDir { }; } // namespace test +} // namespace system } // namespace mojo -#endif // MOJO_EDK_TEST_SCOPED_TEST_DIR_H_ +#endif // MOJO_EDK_SYSTEM_TEST_SCOPED_TEST_DIR_H_ diff --git a/mojo/edk/test/simple_test_thread.cc b/mojo/edk/system/test/simple_test_thread.cc similarity index 50% rename from mojo/edk/test/simple_test_thread.cc rename to mojo/edk/system/test/simple_test_thread.cc index 6cf9f11a796..dd4c91aa957 100644 --- a/mojo/edk/test/simple_test_thread.cc +++ b/mojo/edk/system/test/simple_test_thread.cc @@ -2,24 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "mojo/edk/test/simple_test_thread.h" +#include "mojo/edk/system/test/simple_test_thread.h" #include "base/logging.h" namespace mojo { +namespace system { namespace test { -SimpleTestThread::SimpleTestThread() : thread_(this, "SimpleTestThread") {} - -SimpleTestThread::~SimpleTestThread() {} +SimpleTestThread::~SimpleTestThread() { + DCHECK(!thread_.joinable()); +} void SimpleTestThread::Start() { - thread_.Start(); + DCHECK(!thread_.joinable()); + thread_ = std::thread([this]() { Run(); }); } void SimpleTestThread::Join() { - thread_.Join(); + DCHECK(thread_.joinable()); + thread_.join(); } +SimpleTestThread::SimpleTestThread() {} + } // namespace test +} // namespace system } // namespace mojo diff --git a/mojo/edk/test/simple_test_thread.h b/mojo/edk/system/test/simple_test_thread.h similarity index 53% rename from mojo/edk/test/simple_test_thread.h rename to mojo/edk/system/test/simple_test_thread.h index 36ec7cde816..e258d1815a3 100644 --- a/mojo/edk/test/simple_test_thread.h +++ b/mojo/edk/system/test/simple_test_thread.h @@ -2,20 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MOJO_EDK_TEST_SIMPLE_TEST_THREAD_ -#define MOJO_EDK_TEST_SIMPLE_TEST_THREAD_ +#ifndef MOJO_EDK_SYSTEM_TEST_SIMPLE_TEST_THREAD_ +#define MOJO_EDK_SYSTEM_TEST_SIMPLE_TEST_THREAD_ + +#include -#include "base/threading/simple_thread.h" #include "mojo/public/cpp/system/macros.h" namespace mojo { +namespace system { namespace test { // Class to help simple threads (with no message loops) in tests. -class SimpleTestThread : public base::DelegateSimpleThread::Delegate { +class SimpleTestThread { public: - SimpleTestThread(); - ~SimpleTestThread() override; + virtual ~SimpleTestThread(); // Starts the thread. void Start(); @@ -23,18 +24,20 @@ class SimpleTestThread : public base::DelegateSimpleThread::Delegate { // Joins the thread; this must be called if the thread was started. void Join(); - // Note: Subclasses must implement: - // virtual void Run() = 0; - // TODO(vtl): When we stop using |base::DelegateSimpleThread|, this will - // directly become part of our interface. + protected: + SimpleTestThread(); + + // Code to run in the thread. + virtual void Run() = 0; private: - base::DelegateSimpleThread thread_; + std::thread thread_; MOJO_DISALLOW_COPY_AND_ASSIGN(SimpleTestThread); }; } // namespace test +} // namespace system } // namespace mojo -#endif // MOJO_EDK_TEST_SIMPLE_TEST_THREAD_ +#endif // MOJO_EDK_TEST_SYSTEM_SIMPLE_TEST_THREAD_ diff --git a/mojo/edk/system/test/sleep.cc b/mojo/edk/system/test/sleep.cc new file mode 100644 index 00000000000..e909f3d9aee --- /dev/null +++ b/mojo/edk/system/test/sleep.cc @@ -0,0 +1,31 @@ +// Copyright 2013 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/test/sleep.h" + +#include + +#include "base/logging.h" +#include "base/threading/platform_thread.h" // For |Sleep()|. +#include "base/time/time.h" +#include "mojo/edk/system/test/timeouts.h" + +namespace mojo { +namespace system { +namespace test { + +void Sleep(MojoDeadline duration) { + CHECK_LE(duration, + static_cast(std::numeric_limits::max())); + base::PlatformThread::Sleep( + base::TimeDelta::FromMicroseconds(static_cast(duration))); +} + +void SleepMilliseconds(unsigned duration_milliseconds) { + Sleep(DeadlineFromMilliseconds(duration_milliseconds)); +} + +} // namespace test +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/test/sleep.h b/mojo/edk/system/test/sleep.h new file mode 100644 index 00000000000..ff8e4f08da6 --- /dev/null +++ b/mojo/edk/system/test/sleep.h @@ -0,0 +1,24 @@ +// Copyright 2013 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. + +// Function for sleeping in tests. (Please use sparingly.) + +#ifndef MOJO_EDK_SYSTEM_TEST_SLEEP_H_ +#define MOJO_EDK_SYSTEM_TEST_SLEEP_H_ + +#include "mojo/public/c/system/types.h" + +namespace mojo { +namespace system { +namespace test { + +// Sleeps for at least the specified duration. +void Sleep(MojoDeadline duration); +void SleepMilliseconds(unsigned duration_milliseconds); + +} // namespace test +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_TEST_SLEEP_H_ diff --git a/mojo/edk/system/test/stopwatch.cc b/mojo/edk/system/test/stopwatch.cc new file mode 100644 index 00000000000..5aad8fd1fde --- /dev/null +++ b/mojo/edk/system/test/stopwatch.cc @@ -0,0 +1,32 @@ +// Copyright 2013 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/test/stopwatch.h" + +#include + +#include "base/logging.h" + +namespace mojo { +namespace system { +namespace test { + +Stopwatch::Stopwatch() {} + +Stopwatch::~Stopwatch() {} + +void Stopwatch::Start() { + start_time_ = platform_support_.GetTimeTicksNow(); +} + +MojoDeadline Stopwatch::Elapsed() { + int64_t result = platform_support_.GetTimeTicksNow() - start_time_; + // |DCHECK_GE|, not |CHECK_GE|, since this may be performance-important. + DCHECK_GE(result, 0); + return static_cast(result); +} + +} // namespace test +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/test/stopwatch.h b/mojo/edk/system/test/stopwatch.h new file mode 100644 index 00000000000..ed8d1493e83 --- /dev/null +++ b/mojo/edk/system/test/stopwatch.h @@ -0,0 +1,43 @@ +// Copyright 2013 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 simple "stopwatch" for measuring elapsed time. + +#ifndef MOJO_EDK_SYSTEM_TEST_STOPWATCH_H_ +#define MOJO_EDK_SYSTEM_TEST_STOPWATCH_H_ + +#include "mojo/edk/embedder/simple_platform_support.h" +#include "mojo/public/c/system/types.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace system { +namespace test { + +// A simple "stopwatch" for measuring time elapsed from a given starting point. +class Stopwatch { + public: + Stopwatch(); + ~Stopwatch(); + + void Start(); + // Returns the amount of time elapsed since the last call to |Start()| (in + // microseconds). + MojoDeadline Elapsed(); + + private: + // TODO(vtl): We need this for |GetTimeTicksNow()|. Maybe we should have a + // singleton for tests instead? Or maybe it should be injected? + embedder::SimplePlatformSupport platform_support_; + + MojoTimeTicks start_time_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Stopwatch); +}; + +} // namespace test +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_TEST_STOPWATCH_H_ diff --git a/mojo/edk/system/test/test_command_line.cc b/mojo/edk/system/test/test_command_line.cc new file mode 100644 index 00000000000..cf6f3274fef --- /dev/null +++ b/mojo/edk/system/test/test_command_line.cc @@ -0,0 +1,29 @@ +// 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/test/test_command_line.h" + +#include "base/logging.h" +#include "mojo/edk/util/command_line.h" + +namespace mojo { +namespace system { +namespace test { + +static util::CommandLine* g_test_command_line = nullptr; + +void InitializeTestCommandLine(int argc, const char* const* argv) { + CHECK(!g_test_command_line); + // TODO(vtl): May have to annotate the following "leak", if we run with LSan. + g_test_command_line = + new util::CommandLine(util::CommandLineFromArgcArgv(argc, argv)); +} + +const util::CommandLine* GetTestCommandLine() { + return g_test_command_line; +} + +} // namespace test +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/test/test_command_line.h b/mojo/edk/system/test/test_command_line.h new file mode 100644 index 00000000000..0acc1caf4e7 --- /dev/null +++ b/mojo/edk/system/test/test_command_line.h @@ -0,0 +1,34 @@ +// 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. + +// Provides a command line singleton for tests. (This is mainly useful for +// multiprocess tests which start their own binary as a child process. Having +// the singleton makes the command line accessible without lots of plumbing.) + +#ifndef MOJO_EDK_SYSTEM_TEST_TEST_COMMAND_LINE_H_ +#define MOJO_EDK_SYSTEM_TEST_TEST_COMMAND_LINE_H_ + +namespace mojo { + +namespace util { +class CommandLine; +} // namespace util + +namespace system { +namespace test { + +// Initializes the command line singleton (made accessible via +// |GetTestCommandLine()| below. This should be called at most once (typically +// in |main()|). +void InitializeTestCommandLine(int argc, const char* const* argv); + +// Gets the "command line" that the test binary was run with. +const util::CommandLine* GetTestCommandLine(); + +} // namespace test +} // namespace system + +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_TEST_TEST_COMMAND_LINE_H_ diff --git a/mojo/edk/test/test_io_thread.cc b/mojo/edk/system/test/test_io_thread.cc similarity index 94% rename from mojo/edk/test/test_io_thread.cc rename to mojo/edk/system/test/test_io_thread.cc index b8b4745057a..ee11ff3f94f 100644 --- a/mojo/edk/test/test_io_thread.cc +++ b/mojo/edk/system/test/test_io_thread.cc @@ -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/test/test_io_thread.h" +#include "mojo/edk/system/test/test_io_thread.h" #include "base/bind.h" #include "base/callback.h" @@ -10,6 +10,7 @@ #include "base/synchronization/waitable_event.h" namespace mojo { +namespace system { namespace test { namespace { @@ -63,4 +64,5 @@ void TestIOThread::PostTaskAndWait(const base::Closure& task) { } } // namespace test +} // namespace system } // namespace mojo diff --git a/mojo/edk/test/test_io_thread.h b/mojo/edk/system/test/test_io_thread.h similarity index 89% rename from mojo/edk/test/test_io_thread.h rename to mojo/edk/system/test/test_io_thread.h index e85672cf4e7..8b0d6e39e95 100644 --- a/mojo/edk/test/test_io_thread.h +++ b/mojo/edk/system/test/test_io_thread.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_TEST_TEST_IO_THREAD_H_ -#define MOJO_EDK_TEST_TEST_IO_THREAD_H_ +#ifndef MOJO_EDK_SYSTEM_TEST_TEST_IO_THREAD_H_ +#define MOJO_EDK_SYSTEM_TEST_TEST_IO_THREAD_H_ #include "base/callback_forward.h" #include "base/memory/ref_counted.h" @@ -12,6 +12,7 @@ #include "mojo/public/cpp/system/macros.h" namespace mojo { +namespace system { namespace test { // Class to help create/run threads with I/O |MessageLoop|s in tests. @@ -50,6 +51,7 @@ class TestIOThread { }; } // namespace test +} // namespace system } // namespace mojo -#endif // MOJO_EDK_TEST_TEST_IO_THREAD_H_ +#endif // MOJO_EDK_SYSTEM_TEST_TEST_IO_THREAD_H_ diff --git a/mojo/edk/system/test/timeouts.cc b/mojo/edk/system/test/timeouts.cc new file mode 100644 index 00000000000..f23b12da91f --- /dev/null +++ b/mojo/edk/system/test/timeouts.cc @@ -0,0 +1,42 @@ +// Copyright 2013 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/test/timeouts.h" + +#include "base/test/test_timeouts.h" +#include "build/build_config.h" + +namespace mojo { +namespace system { +namespace test { + +MojoDeadline DeadlineFromMilliseconds(unsigned milliseconds) { + return static_cast(milliseconds) * 1000; +} + +MojoDeadline EpsilonTimeout() { +// Currently, |tiny_timeout()| is usually 100 ms (possibly scaled under ASAN, +// etc.). Based on this, set it to (usually be) 30 ms on Android and 20 ms +// elsewhere. (We'd like this to be as small as possible, without making things +// flaky) +#if defined(OS_ANDROID) + return (TinyTimeout() * 3) / 10; +#else + return (TinyTimeout() * 2) / 10; +#endif +} + +MojoDeadline TinyTimeout() { + return static_cast( + TestTimeouts::tiny_timeout().InMicroseconds()); +} + +MojoDeadline ActionTimeout() { + return static_cast( + TestTimeouts::action_timeout().InMicroseconds()); +} + +} // namespace test +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/test/timeouts.h b/mojo/edk/system/test/timeouts.h new file mode 100644 index 00000000000..aa69ec2bced --- /dev/null +++ b/mojo/edk/system/test/timeouts.h @@ -0,0 +1,36 @@ +// Copyright 2013 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. + +// Test timeouts. + +#ifndef MOJO_EDK_SYSTEM_TEST_TIMEOUTS_H_ +#define MOJO_EDK_SYSTEM_TEST_TIMEOUTS_H_ + +#include "mojo/public/c/system/types.h" + +namespace mojo { +namespace system { +namespace test { + +MojoDeadline DeadlineFromMilliseconds(unsigned milliseconds); + +// A timeout smaller than |TestTimeouts::tiny_timeout()|, as a |MojoDeadline|. +// Warning: This may lead to flakiness, but this is unavoidable if, e.g., you're +// trying to ensure that functions with timeouts are reasonably accurate. We +// want this to be as small as possible without causing too much flakiness. +MojoDeadline EpsilonTimeout(); + +// |TestTimeouts::tiny_timeout()|, as a |MojoDeadline|. (Expect this to be on +// the order of 100 ms.) +MojoDeadline TinyTimeout(); + +// |TestTimeouts::action_timeout()|, as a |MojoDeadline|. (Expect this to be on +// the order of 10 s.) +MojoDeadline ActionTimeout(); + +} // namespace test +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_TEST_TIMEOUTS_H_ diff --git a/mojo/edk/system/test_channel_endpoint_client.cc b/mojo/edk/system/test_channel_endpoint_client.cc index 957fa964c6e..cc7b25dbce4 100644 --- a/mojo/edk/system/test_channel_endpoint_client.cc +++ b/mojo/edk/system/test_channel_endpoint_client.cc @@ -6,10 +6,13 @@ #include -#include "base/synchronization/waitable_event.h" #include "mojo/edk/system/message_in_transit.h" +#include "mojo/edk/system/waitable_event.h" #include "testing/gtest/include/gtest/gtest.h" +using mojo::util::MutexLocker; +using mojo::util::RefPtr; + namespace mojo { namespace system { namespace test { @@ -40,7 +43,8 @@ std::unique_ptr TestChannelEndpointClient::PopMessage() { return messages_.GetMessage(); } -void TestChannelEndpointClient::SetReadEvent(base::WaitableEvent* read_event) { +void TestChannelEndpointClient::SetReadEvent( + ManualResetWaitableEvent* read_event) { MutexLocker locker(&mutex_); read_event_ = read_event; } diff --git a/mojo/edk/system/test_channel_endpoint_client.h b/mojo/edk/system/test_channel_endpoint_client.h index 592e8ae4637..420d0b85caf 100644 --- a/mojo/edk/system/test_channel_endpoint_client.h +++ b/mojo/edk/system/test_channel_endpoint_client.h @@ -10,24 +10,24 @@ #include "mojo/edk/system/channel_endpoint.h" #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" -namespace base { -class WaitableEvent; -} - namespace mojo { namespace system { + +class ManualResetWaitableEvent; + namespace test { class TestChannelEndpointClient final : public ChannelEndpointClient { public: - // Note: Use |MakeRefCounted()|. + // Note: Use |util::MakeRefCounted()|. // Initializes with the given port and endpoint. - void Init(unsigned port, RefPtr&& endpoint); + void Init(unsigned port, util::RefPtr&& endpoint); // Returns true if we're detached from the |ChannelEndpoint|. bool IsDetached() const; @@ -41,7 +41,7 @@ class TestChannelEndpointClient final : public ChannelEndpointClient { // Sets an event to signal when we receive a message. (|read_event| must live // until this object is destroyed or the read event is reset to null.) - void SetReadEvent(base::WaitableEvent* read_event); + void SetReadEvent(ManualResetWaitableEvent* read_event); // |ChannelEndpointClient| implementation: bool OnReadMessage(unsigned port, MessageInTransit* message) override; @@ -53,15 +53,15 @@ class TestChannelEndpointClient final : public ChannelEndpointClient { TestChannelEndpointClient(); ~TestChannelEndpointClient() override; - mutable Mutex mutex_; + mutable util::Mutex mutex_; unsigned port_ MOJO_GUARDED_BY(mutex_); - RefPtr endpoint_ MOJO_GUARDED_BY(mutex_); + util::RefPtr endpoint_ MOJO_GUARDED_BY(mutex_); MessageInTransitQueue messages_ MOJO_GUARDED_BY(mutex_); // Event to trigger if we read a message (may be null). - base::WaitableEvent* read_event_ MOJO_GUARDED_BY(mutex_); + ManualResetWaitableEvent* read_event_ MOJO_GUARDED_BY(mutex_); MOJO_DISALLOW_COPY_AND_ASSIGN(TestChannelEndpointClient); }; diff --git a/mojo/edk/system/test_utils.cc b/mojo/edk/system/test_utils.cc deleted file mode 100644 index e25adc9a067..00000000000 --- a/mojo/edk/system/test_utils.cc +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2013 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/test_utils.h" - -#include -#include - -#include - -#include "base/logging.h" -#include "base/test/test_timeouts.h" -#include "base/threading/platform_thread.h" // For |Sleep()|. -#include "build/build_config.h" - -namespace mojo { -namespace system { -namespace test { - -MojoDeadline DeadlineFromMilliseconds(unsigned milliseconds) { - return static_cast(milliseconds) * 1000; -} - -MojoDeadline EpsilonDeadline() { -// Currently, |tiny_timeout()| is usually 100 ms (possibly scaled under ASAN, -// etc.). Based on this, set it to (usually be) 30 ms on Android and 20 ms -// elsewhere. (We'd like this to be as small as possible, without making things -// flaky) -#if defined(OS_ANDROID) - return (TinyDeadline() * 3) / 10; -#else - return (TinyDeadline() * 2) / 10; -#endif -} - -MojoDeadline TinyDeadline() { - return static_cast( - TestTimeouts::tiny_timeout().InMicroseconds()); -} - -MojoDeadline ActionDeadline() { - return static_cast( - TestTimeouts::action_timeout().InMicroseconds()); -} - -void Sleep(MojoDeadline deadline) { - CHECK_LE(deadline, - static_cast(std::numeric_limits::max())); - base::PlatformThread::Sleep( - base::TimeDelta::FromMicroseconds(static_cast(deadline))); -} - -// TODO(vtl): Replace all of this implementation with suitable use of C++11 -// when we can. -int RandomInt(int min, int max) { - DCHECK_LE(min, max); - DCHECK_LE(static_cast(max) - min, RAND_MAX); - DCHECK_LT(static_cast(max) - min, std::numeric_limits::max()); - - // This is in-range for an |int| due to the above. - int range = max - min + 1; - int max_valid = (RAND_MAX / range) * range - 1; - int value; - do { - value = rand(); - } while (value > max_valid); - return min + (value % range); -} - -Stopwatch::Stopwatch() { -} - -Stopwatch::~Stopwatch() { -} - -void Stopwatch::Start() { - start_time_ = platform_support_.GetTimeTicksNow(); -} - -MojoDeadline Stopwatch::Elapsed() { - int64_t result = platform_support_.GetTimeTicksNow() - start_time_; - // |DCHECK_GE|, not |CHECK_GE|, since this may be performance-important. - DCHECK_GE(result, 0); - return static_cast(result); -} - -} // namespace test -} // namespace system -} // namespace mojo diff --git a/mojo/edk/system/test_utils.h b/mojo/edk/system/test_utils.h deleted file mode 100644 index 8d424cc9e90..00000000000 --- a/mojo/edk/system/test_utils.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2013 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_EDK_SYSTEM_TEST_UTILS_H_ -#define MOJO_EDK_SYSTEM_TEST_UTILS_H_ - -#include "mojo/edk/embedder/simple_platform_support.h" -#include "mojo/public/c/system/types.h" -#include "mojo/public/cpp/system/macros.h" - -namespace mojo { -namespace system { -namespace test { - -// Deadlines/timeouts and sleeping --------------------------------------------- - -MojoDeadline DeadlineFromMilliseconds(unsigned milliseconds); - -// A timeout smaller than |TestTimeouts::tiny_timeout()|, as a |MojoDeadline|. -// Warning: This may lead to flakiness, but this is unavoidable if, e.g., you're -// trying to ensure that functions with timeouts are reasonably accurate. We -// want this to be as small as possible without causing too much flakiness. -MojoDeadline EpsilonDeadline(); - -// |TestTimeouts::tiny_timeout()|, as a |MojoDeadline|. (Expect this to be on -// the order of 100 ms.) -MojoDeadline TinyDeadline(); - -// |TestTimeouts::action_timeout()|, as a |MojoDeadline|. (Expect this to be on -// the order of 10 s.) -MojoDeadline ActionDeadline(); - -// Sleeps for at least the specified duration. -void Sleep(MojoDeadline deadline); - -// Pseudorandom numbers for testing -------------------------------------------- - -// Returns a (uniformly) (pseudo)random integer in the interval [min, max]. -// Currently, |max - min| must be at most |RAND_MAX| and must also be (strictly) -// less than |INT_MAX|. -int RandomInt(int min, int max); - -// Stopwatch ------------------------------------------------------------------- - -// A simple "stopwatch" for measuring time elapsed from a given starting point. -class Stopwatch { - public: - Stopwatch(); - ~Stopwatch(); - - void Start(); - // Returns the amount of time elapsed since the last call to |Start()| (in - // microseconds). - MojoDeadline Elapsed(); - - private: - // TODO(vtl): We need this for |GetTimeTicksNow()|. Maybe we should have a - // singleton for tests instead? Or maybe it should be injected? - embedder::SimplePlatformSupport platform_support_; - - MojoTimeTicks start_time_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(Stopwatch); -}; - -} // namespace test -} // namespace system -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_TEST_UTILS_H_ diff --git a/mojo/edk/system/waitable_event.cc b/mojo/edk/system/waitable_event.cc new file mode 100644 index 00000000000..c05d038e0e4 --- /dev/null +++ b/mojo/edk/system/waitable_event.cc @@ -0,0 +1,168 @@ +// 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/waitable_event.h" + +#include "base/logging.h" +#include "base/time/time.h" + +using mojo::util::CondVar; +using mojo::util::Mutex; +using mojo::util::MutexLocker; + +namespace mojo { +namespace system { + +namespace { + +// Waits with a timeout on |condition()|. Returns true on timeout, or false if +// |condition()| ever returns true. |condition()| should have no side effects +// (and will always be called with |*mutex| held). +template +bool WaitWithTimeoutImpl(Mutex* mutex, + CondVar* cv, + ConditionFn condition, + uint64_t timeout_microseconds) + MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex) { + mutex->AssertHeld(); + + if (condition()) + return false; + + // We may get spurious wakeups. + uint64_t wait_remaining = timeout_microseconds; + auto start = base::TimeTicks::Now(); + while (true) { + if (cv->WaitWithTimeout(mutex, wait_remaining)) + return true; // Definitely timed out. + + // We may have been awoken. + if (condition()) + return false; + + // Or the wakeup may have been spurious. + auto now = base::TimeTicks::Now(); + DCHECK_GE(now, start); + uint64_t elapsed = static_cast((now - start).InMicroseconds()); + // It's possible that we may have timed out anyway. + if (elapsed >= timeout_microseconds) + return true; + + // Otherwise, recalculate the amount that we have left to wait. + wait_remaining = timeout_microseconds - elapsed; + } +} + +} // namespace + +// AutoResetWaitableEvent ------------------------------------------------------ + +void AutoResetWaitableEvent::Signal() { + MutexLocker locker(&mutex_); + signaled_ = true; + cv_.Signal(); +} + +void AutoResetWaitableEvent::Reset() { + MutexLocker locker(&mutex_); + signaled_ = false; +} + +void AutoResetWaitableEvent::Wait() { + MutexLocker locker(&mutex_); + while (!signaled_) + cv_.Wait(&mutex_); + signaled_ = false; +} + +bool AutoResetWaitableEvent::WaitWithTimeout(uint64_t timeout_microseconds) { + MutexLocker locker(&mutex_); + + if (signaled_) { + signaled_ = false; + return false; + } + + // We may get spurious wakeups. + uint64_t wait_remaining = timeout_microseconds; + auto start = base::TimeTicks::Now(); + while (true) { + if (cv_.WaitWithTimeout(&mutex_, wait_remaining)) + return true; // Definitely timed out. + + // We may have been awoken. + if (signaled_) + break; + + // Or the wakeup may have been spurious. + auto now = base::TimeTicks::Now(); + DCHECK_GE(now, start); + uint64_t elapsed = static_cast((now - start).InMicroseconds()); + // It's possible that we may have timed out anyway. + if (elapsed >= timeout_microseconds) + return true; + + // Otherwise, recalculate the amount that we have left to wait. + wait_remaining = timeout_microseconds - elapsed; + } + + signaled_ = false; + return false; +} + +bool AutoResetWaitableEvent::IsSignaledForTest() { + MutexLocker locker(&mutex_); + return signaled_; +} + +// ManualResetWaitableEvent ---------------------------------------------------- + +void ManualResetWaitableEvent::Signal() { + MutexLocker locker(&mutex_); + signaled_ = true; + signal_id_++; + cv_.SignalAll(); +} + +void ManualResetWaitableEvent::Reset() { + MutexLocker locker(&mutex_); + signaled_ = false; +} + +void ManualResetWaitableEvent::Wait() { + MutexLocker locker(&mutex_); + + if (signaled_) + return; + + auto last_signal_id = signal_id_; + do { + cv_.Wait(&mutex_); + } while (signal_id_ == last_signal_id); +} + +bool ManualResetWaitableEvent::WaitWithTimeout(uint64_t timeout_microseconds) { + MutexLocker locker(&mutex_); + + auto last_signal_id = signal_id_; + // Disable thread-safety analysis for the lambda: We could annotate it with + // |MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_)|, but then the analyzer currently + // isn't able to figure out that |WaitWithTimeoutImpl()| calls it while + // holding |mutex_|. + bool rv = WaitWithTimeoutImpl( + &mutex_, &cv_, [this, last_signal_id]() MOJO_NO_THREAD_SAFETY_ANALYSIS { + // Also check |signaled_| in case we're already signaled. + return signaled_ || signal_id_ != last_signal_id; + }, timeout_microseconds); + DCHECK(rv || signaled_ || signal_id_ != last_signal_id); + return rv; +} + +bool ManualResetWaitableEvent::IsSignaledForTest() { + MutexLocker locker(&mutex_); + return signaled_; +} + +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/waitable_event.h b/mojo/edk/system/waitable_event.h new file mode 100644 index 00000000000..38c75e06564 --- /dev/null +++ b/mojo/edk/system/waitable_event.h @@ -0,0 +1,127 @@ +// 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. + +// Provides classes with functionality analogous to (but much more limited than) +// Chromium's |base::WaitableEvent|, which in turn provides functionality +// analogous to Windows's Event. (Unlike these two, we have separate types for +// the manual- and auto-reset versions.) + +#ifndef MOJO_EDK_SYSTEM_WAITABLE_EVENT_H_ +#define MOJO_EDK_SYSTEM_WAITABLE_EVENT_H_ + +#include "mojo/edk/util/cond_var.h" +#include "mojo/edk/util/mutex.h" +#include "mojo/edk/util/thread_annotations.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace system { + +// AutoResetWaitableEvent ------------------------------------------------------ + +// An event that can be signaled and waited on. This version automatically +// returns to the unsignaled state after unblocking one waiter. (This is similar +// to Windows's auto-reset Event, which is also imitated by Chromium's +// auto-reset |base::WaitableEvent|. However, there are some limitations -- see +// |Signal()|.) This class is thread-safe. +class AutoResetWaitableEvent { + public: + AutoResetWaitableEvent() {} + ~AutoResetWaitableEvent() {} + + // Put the event in the signaled state. Exactly one |Wait()| will be unblocked + // and the event will be returned to the unsignaled state. + // + // Notes (these are arguably bugs, but not worth working around): + // * That |Wait()| may be one that occurs on the calling thread, *after* the + // call to |Signal()|. + // * A |Signal()|, followed by a |Reset()|, may cause *no* waiting thread to + // be unblocked. + // * We rely on pthreads's queueing for picking which waiting thread to + // unblock, rather than enforcing FIFO ordering. + void Signal(); + + // Put the event into the unsignaled state. Generally, this is not recommended + // on an auto-reset event (see notes above). + void Reset(); + + // Blocks the calling thread until the event is signaled. Upon unblocking, the + // event is returned to the unsignaled state, so that (unless |Reset()| is + // called) each |Signal()| unblocks exactly one |Wait()|. + void Wait(); + + // Like |Wait()|, but with a timeout. Also unblocks if |timeout_microseconds| + // without being signaled in which case it returns true (otherwise, it returns + // false). + bool WaitWithTimeout(uint64_t timeout_microseconds); + + // Returns whether this event is in a signaled state or not. For use in tests + // only (in general, this is racy). Note: Unlike + // |base::WaitableEvent::IsSignaled()|, this doesn't reset the signaled state. + bool IsSignaledForTest(); + + private: + util::CondVar cv_; + util::Mutex mutex_; + + // True if this event is in the signaled state. + bool signaled_ MOJO_GUARDED_BY(mutex_) = false; + + MOJO_DISALLOW_COPY_AND_ASSIGN(AutoResetWaitableEvent); +}; + +// ManualResetWaitableEvent ---------------------------------------------------- + +// An event that can be signaled and waited on. This version remains signaled +// until explicitly reset. (This is similar to Windows's manual-reset Event, +// which is also imitated by Chromium's manual-reset |base::WaitableEvent|.) +// This class is thread-safe. +class ManualResetWaitableEvent { + public: + ManualResetWaitableEvent() {} + ~ManualResetWaitableEvent() {} + + // Put the event into the unsignaled state. + void Reset(); + + // Put the event in the signaled state. If this is a manual-reset event, it + // wakes all waiting threads (blocked on |Wait()| or |WaitWithTimeout()|). + // Otherwise, it wakes a single waiting thread (and returns to the unsignaled + // state), if any; if there are none, it remains signaled. + void Signal(); + + // Blocks the calling thread until the event is signaled. + void Wait(); + + // Like |Wait()|, but with a timeout. Also unblocks if |timeout_microseconds| + // without being signaled in which case it returns true (otherwise, it returns + // false). + bool WaitWithTimeout(uint64_t timeout_microseconds); + + // Returns whether this event is in a signaled state or not. For use in tests + // only (in general, this is racy). + bool IsSignaledForTest(); + + private: + util::CondVar cv_; + util::Mutex mutex_; + + // True if this event is in the signaled state. + bool signaled_ MOJO_GUARDED_BY(mutex_) = false; + + // While |CondVar::SignalAll()| (|pthread_cond_broadcast()|) will wake all + // waiting threads, one has to deal with spurious wake-ups. Checking + // |signaled_| isn't sufficient, since another thread may have been awoken and + // (manually) reset |signaled_|. This is a counter that is incremented in + // |Signal()| before calling |CondVar::SignalAll()|. A waiting thread knows it + // was awoken if |signal_id_| is different from when it started waiting. + unsigned signal_id_ MOJO_GUARDED_BY(mutex_) = 0u; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ManualResetWaitableEvent); +}; + +} // namespace system +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_WAITABLE_EVENT_H_ diff --git a/mojo/edk/system/waitable_event_unittest.cc b/mojo/edk/system/waitable_event_unittest.cc new file mode 100644 index 00000000000..80e4c9b1e52 --- /dev/null +++ b/mojo/edk/system/waitable_event_unittest.cc @@ -0,0 +1,257 @@ +// 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/waitable_event.h" + +#include +#include + +#include +#include +#include +#include + +#include "mojo/edk/system/test/sleep.h" +#include "mojo/edk/system/test/stopwatch.h" +#include "mojo/edk/system/test/timeouts.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::SleepMilliseconds(static_cast(rand()) % 20u); +} + +// We'll use |MojoDeadline| with |uint64_t| (for |WaitWithTimeout()|'s timeout +// argument), though note that |WaitWithTimeout()| doesn't support +// |MOJO_DEADLINE_INDEFINITE|. +static_assert(std::is_same::value, + "MojoDeadline isn't uint64_t!"); + +// AutoResetWaitableEvent ------------------------------------------------------ + +TEST(AutoResetWaitableEventTest, Basic) { + AutoResetWaitableEvent ev; + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Signal(); + EXPECT_TRUE(ev.IsSignaledForTest()); + ev.Wait(); + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Reset(); + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Signal(); + EXPECT_TRUE(ev.IsSignaledForTest()); + ev.Reset(); + EXPECT_FALSE(ev.IsSignaledForTest()); + EXPECT_TRUE(ev.WaitWithTimeout(0)); + EXPECT_FALSE(ev.IsSignaledForTest()); + EXPECT_TRUE(ev.WaitWithTimeout(test::DeadlineFromMilliseconds(1))); + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Signal(); + EXPECT_TRUE(ev.IsSignaledForTest()); + EXPECT_FALSE(ev.WaitWithTimeout(0)); + EXPECT_FALSE(ev.IsSignaledForTest()); + EXPECT_TRUE(ev.WaitWithTimeout(test::DeadlineFromMilliseconds(1))); + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Signal(); + EXPECT_FALSE(ev.WaitWithTimeout(test::DeadlineFromMilliseconds(1))); + EXPECT_FALSE(ev.IsSignaledForTest()); +} + +TEST(AutoResetWaitableEventTest, MultipleWaiters) { + AutoResetWaitableEvent ev; + + for (size_t i = 0u; i < 5u; i++) { + std::atomic_uint wake_count(0u); + std::vector threads; + for (size_t j = 0u; j < 4u; j++) { + threads.push_back(std::thread([&ev, &wake_count]() { + if (rand() % 2 == 0) + ev.Wait(); + else + EXPECT_FALSE(ev.WaitWithTimeout(test::ActionTimeout())); + wake_count.fetch_add(1u); + // Note: We can't say anything about the signaled state of |ev| here, + // since the main thread may have already signaled it again. + })); + } + + // Unfortunately, we can't really wait for the threads to be waiting, so we + // just sleep for a bit, and count on them having started and advanced to + // waiting. + test::Sleep(2 * test::TinyTimeout()); + + for (size_t j = 0u; j < threads.size(); j++) { + unsigned old_wake_count = wake_count.load(); + EXPECT_EQ(j, old_wake_count); + + // Each |Signal()| should wake exactly one thread. + ev.Signal(); + + // Poll for |wake_count| to change. + while (wake_count.load() == old_wake_count) + test::Sleep(test::EpsilonTimeout()); + + EXPECT_FALSE(ev.IsSignaledForTest()); + + // And once it's changed, wait a little longer, to see if any other + // threads are awoken (they shouldn't be). + test::Sleep(test::EpsilonTimeout()); + + EXPECT_EQ(old_wake_count + 1u, wake_count.load()); + + EXPECT_FALSE(ev.IsSignaledForTest()); + } + + // Having done that, if we signal |ev| now, it should stay signaled. + ev.Signal(); + test::Sleep(test::EpsilonTimeout()); + EXPECT_TRUE(ev.IsSignaledForTest()); + + for (auto& thread : threads) + thread.join(); + + ev.Reset(); + } +} + +TEST(AutoResetWaitableEventTest, Timeouts) { + static const unsigned kTestTimeoutsMs[] = {0, 10, 20, 40, 80}; + + test::Stopwatch stopwatch; + + AutoResetWaitableEvent ev; + + for (size_t i = 0u; i < MOJO_ARRAYSIZE(kTestTimeoutsMs); i++) { + uint64_t timeout = test::DeadlineFromMilliseconds(kTestTimeoutsMs[i]); + + stopwatch.Start(); + EXPECT_TRUE(ev.WaitWithTimeout(timeout)); + MojoDeadline elapsed = stopwatch.Elapsed(); + + // It should time out after *at least* the specified amount of time. + EXPECT_GE(elapsed, timeout); + // But we expect that it should time out soon after that amount of time. + EXPECT_LT(elapsed, timeout + test::EpsilonTimeout()); + } +} + +// ManualResetWaitableEvent ---------------------------------------------------- + +TEST(ManualResetWaitableEventTest, Basic) { + ManualResetWaitableEvent ev; + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Signal(); + EXPECT_TRUE(ev.IsSignaledForTest()); + ev.Wait(); + EXPECT_TRUE(ev.IsSignaledForTest()); + ev.Reset(); + EXPECT_FALSE(ev.IsSignaledForTest()); + EXPECT_TRUE(ev.WaitWithTimeout(0)); + EXPECT_FALSE(ev.IsSignaledForTest()); + EXPECT_TRUE(ev.WaitWithTimeout(test::DeadlineFromMilliseconds(1))); + EXPECT_FALSE(ev.IsSignaledForTest()); + ev.Signal(); + EXPECT_TRUE(ev.IsSignaledForTest()); + EXPECT_FALSE(ev.WaitWithTimeout(0)); + EXPECT_TRUE(ev.IsSignaledForTest()); + EXPECT_FALSE(ev.WaitWithTimeout(test::DeadlineFromMilliseconds(1))); + EXPECT_TRUE(ev.IsSignaledForTest()); +} + +TEST(ManualResetWaitableEventTest, SignalMultiple) { + ManualResetWaitableEvent ev; + + for (size_t i = 0u; i < 10u; i++) { + for (size_t num_waiters = 1u; num_waiters < 5u; num_waiters++) { + std::vector threads; + for (size_t j = 0u; j < num_waiters; j++) { + threads.push_back(std::thread([&ev]() { + EpsilonRandomSleep(); + + if (rand() % 2 == 0) + ev.Wait(); + else + EXPECT_FALSE(ev.WaitWithTimeout(test::ActionTimeout())); + })); + } + + EpsilonRandomSleep(); + + ev.Signal(); + + // The threads will only terminate once they've successfully waited (or + // timed out). + for (auto& thread : threads) + thread.join(); + + ev.Reset(); + } + } +} + +// Tries to test that threads that are awoken may immediately call |Reset()| +// without affecting other threads that are awoken. +TEST(ManualResetWaitableEventTest, SignalMultipleWaitReset) { + ManualResetWaitableEvent ev; + + for (size_t i = 0u; i < 5u; i++) { + std::vector threads; + for (size_t j = 0u; j < 4u; j++) { + threads.push_back(std::thread([&ev]() { + if (rand() % 2 == 0) + ev.Wait(); + else + EXPECT_FALSE(ev.WaitWithTimeout(test::ActionTimeout())); + ev.Reset(); + })); + } + + // Unfortunately, we can't really wait for the threads to be waiting, so we + // just sleep for a bit, and count on them having started and advanced to + // waiting. + test::Sleep(2 * test::TinyTimeout()); + + ev.Signal(); + + // In fact, we may ourselves call |Reset()| immediately. + ev.Reset(); + + // The threads will only terminate once they've successfully waited (or + // timed out). + for (auto& thread : threads) + thread.join(); + + ASSERT_FALSE(ev.IsSignaledForTest()); + } +} + +TEST(ManualResetWaitableEventTest, Timeouts) { + static const unsigned kTestTimeoutsMs[] = {0, 10, 20, 40, 80}; + + test::Stopwatch stopwatch; + + ManualResetWaitableEvent ev; + + for (size_t i = 0u; i < MOJO_ARRAYSIZE(kTestTimeoutsMs); i++) { + uint64_t timeout = test::DeadlineFromMilliseconds(kTestTimeoutsMs[i]); + + stopwatch.Start(); + EXPECT_TRUE(ev.WaitWithTimeout(timeout)); + MojoDeadline elapsed = stopwatch.Elapsed(); + + // It should time out after *at least* the specified amount of time. + EXPECT_GE(elapsed, timeout); + // But we expect that it should time out soon after that amount of time. + EXPECT_LT(elapsed, timeout + test::EpsilonTimeout()); + } +} + +} // namespace +} // namespace system +} // namespace mojo diff --git a/mojo/edk/system/waiter.cc b/mojo/edk/system/waiter.cc index f18edc8e815..540dcb62987 100644 --- a/mojo/edk/system/waiter.cc +++ b/mojo/edk/system/waiter.cc @@ -4,16 +4,16 @@ #include "mojo/edk/system/waiter.h" -#include - #include "base/logging.h" #include "base/time/time.h" +using mojo::util::MutexLocker; + namespace mojo { namespace system { Waiter::Waiter() - : cv_(&lock_), + : #ifndef NDEBUG initialized_(false), #endif @@ -37,7 +37,7 @@ void Waiter::Init() { // TODO(vtl): Fast-path the |deadline == 0| case? MojoResult Waiter::Wait(MojoDeadline deadline, uint32_t* context) { - base::AutoLock locker(lock_); + MutexLocker locker(&mutex_); #ifndef NDEBUG DCHECK(initialized_); @@ -53,27 +53,36 @@ MojoResult Waiter::Wait(MojoDeadline deadline, uint32_t* context) { return awake_result_; } - // |MojoDeadline| is actually a |uint64_t|, but we need a signed quantity. - // Treat any out-of-range deadline as "forever" (which is wrong, but okay - // since 2^63 microseconds is ~300000 years). Note that this also takes care - // of the |MOJO_DEADLINE_INDEFINITE| (= 2^64 - 1) case. - if (deadline > static_cast(std::numeric_limits::max())) { + if (deadline == MOJO_DEADLINE_INDEFINITE) { do { - cv_.Wait(); + cv_.Wait(&mutex_); } while (!awoken_); } else { - // NOTE(vtl): This is very inefficient on POSIX, since pthreads condition - // variables take an absolute deadline. - const base::TimeTicks end_time = - base::TimeTicks::Now() + - base::TimeDelta::FromMicroseconds(static_cast(deadline)); - do { - base::TimeTicks now_time = base::TimeTicks::Now(); - if (now_time >= end_time) + // We may get spurious wakeups, so record the start time and track the + // remaining timeout. + uint64_t wait_remaining = deadline; + auto start = base::TimeTicks::Now(); + while (true) { + // NOTE(vtl): Possibly, we should add a version of |WaitWithTimeout()| + // that takes an absolute deadline, since that's what pthreads takes. + if (cv_.WaitWithTimeout(&mutex_, wait_remaining)) + return MOJO_RESULT_DEADLINE_EXCEEDED; // Definitely timed out. + + // Otherwise, we may have been awoken. + if (awoken_) + break; + + // Or the wakeup may have been spurious. + auto now = base::TimeTicks::Now(); + DCHECK_GE(now, start); + uint64_t elapsed = static_cast((now - start).InMicroseconds()); + // It's possible that the deadline has passed anyway. + if (elapsed >= deadline) return MOJO_RESULT_DEADLINE_EXCEEDED; - cv_.TimedWait(end_time - now_time); - } while (!awoken_); + // Otherwise, recalculate the amount that we have left to wait. + wait_remaining = deadline - elapsed; + } } DCHECK_NE(awake_result_, MOJO_RESULT_INTERNAL); @@ -83,7 +92,7 @@ MojoResult Waiter::Wait(MojoDeadline deadline, uint32_t* context) { } bool Waiter::Awake(MojoResult result, uintptr_t context) { - base::AutoLock locker(lock_); + MutexLocker locker(&mutex_); if (awoken_) return true; @@ -92,7 +101,8 @@ bool Waiter::Awake(MojoResult result, uintptr_t context) { awake_result_ = result; awake_context_ = context; cv_.Signal(); - // |cv_.Wait()|/|cv_.TimedWait()| will return after |lock_| is released. + // |cv_.Wait()|/|cv_.WaitWithTimeout()| will return after |mutex_| is + // released. return true; } diff --git a/mojo/edk/system/waiter.h b/mojo/edk/system/waiter.h index d676789f291..0a2f7ee6517 100644 --- a/mojo/edk/system/waiter.h +++ b/mojo/edk/system/waiter.h @@ -7,9 +7,10 @@ #include -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" #include "mojo/edk/system/awakable.h" +#include "mojo/edk/util/cond_var.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" @@ -27,7 +28,7 @@ class Waiter final : public Awakable { // A |Waiter| can be used multiple times; |Init()| should be called before // each time it's used. - void Init(); + void Init() MOJO_NOT_THREAD_SAFE; // Waits until a suitable |Awake()| is called. (|context| may be null, in // which case, obviously no context is ever returned.) @@ -60,14 +61,14 @@ class Waiter final : public Awakable { bool Awake(MojoResult result, uintptr_t context) override; private: - base::ConditionVariable cv_; // Associated to |lock_|. - base::Lock lock_; // Protects the following members. + util::CondVar cv_; // Associated to |mutex_|. + util::Mutex mutex_; #ifndef NDEBUG - bool initialized_; + bool initialized_ MOJO_GUARDED_BY(mutex_); #endif - bool awoken_; - MojoResult awake_result_; - uintptr_t awake_context_; + bool awoken_ MOJO_GUARDED_BY(mutex_); + MojoResult awake_result_ MOJO_GUARDED_BY(mutex_); + uintptr_t awake_context_ MOJO_GUARDED_BY(mutex_); MOJO_DISALLOW_COPY_AND_ASSIGN(Waiter); }; diff --git a/mojo/edk/system/waiter_test_utils.cc b/mojo/edk/system/waiter_test_utils.cc index 9b54909371d..be2e9a3c7b0 100644 --- a/mojo/edk/system/waiter_test_utils.cc +++ b/mojo/edk/system/waiter_test_utils.cc @@ -6,6 +6,8 @@ #include +using mojo::util::RefPtr; + namespace mojo { namespace system { namespace test { diff --git a/mojo/edk/system/waiter_test_utils.h b/mojo/edk/system/waiter_test_utils.h index b45ba09fa25..585cc5bb36c 100644 --- a/mojo/edk/system/waiter_test_utils.h +++ b/mojo/edk/system/waiter_test_utils.h @@ -9,9 +9,9 @@ #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/handle_signals_state.h" -#include "mojo/edk/system/ref_ptr.h" +#include "mojo/edk/system/test/simple_test_thread.h" #include "mojo/edk/system/waiter.h" -#include "mojo/edk/test/simple_test_thread.h" +#include "mojo/edk/util/ref_ptr.h" #include "mojo/public/c/system/types.h" #include "mojo/public/cpp/system/macros.h" @@ -43,7 +43,7 @@ namespace test { // code). (We accept this unrealism for simplicity, since |AwakableList| is // thread-unsafe so making it more realistic would require adding nontrivial // synchronization machinery.) -class SimpleWaiterThread : public mojo::test::SimpleTestThread { +class SimpleWaiterThread : public test::SimpleTestThread { public: // For the duration of the lifetime of this object, |*result| belongs to it // (in the sense that it will write to it whenever it wants). @@ -65,12 +65,12 @@ class SimpleWaiterThread : public mojo::test::SimpleTestThread { // This is a more complex and realistic thread that has a |Waiter|, on which it // waits for the given deadline (with the given flags). Unlike // |SimpleWaiterThread|, it requires the machinery of |Dispatcher|. -class WaiterThread : public mojo::test::SimpleTestThread { +class WaiterThread : public test::SimpleTestThread { public: // Note: |*did_wait_out|, |*result_out|, |*context_out| and // |*signals_state_out| "belong" to this object (i.e., may be modified by, on // some other thread) while it's alive. - WaiterThread(RefPtr&& dispatcher, + WaiterThread(util::RefPtr&& dispatcher, MojoHandleSignals handle_signals, MojoDeadline deadline, uint32_t context, @@ -83,7 +83,7 @@ class WaiterThread : public mojo::test::SimpleTestThread { private: void Run() override; - const RefPtr dispatcher_; + const util::RefPtr dispatcher_; const MojoHandleSignals handle_signals_; const MojoDeadline deadline_; const uint32_t context_; diff --git a/mojo/edk/system/waiter_unittest.cc b/mojo/edk/system/waiter_unittest.cc index 7406e06bb0e..9a344f5a116 100644 --- a/mojo/edk/system/waiter_unittest.cc +++ b/mojo/edk/system/waiter_unittest.cc @@ -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). @@ -11,19 +11,24 @@ #include -#include "mojo/edk/system/mutex.h" -#include "mojo/edk/system/test_utils.h" -#include "mojo/edk/test/simple_test_thread.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/util/mutex.h" #include "mojo/public/cpp/system/macros.h" #include "testing/gtest/include/gtest/gtest.h" +using mojo::util::Mutex; +using mojo::util::MutexLocker; + namespace mojo { namespace system { namespace { const unsigned kPollTimeMs = 10; -class WaitingThread : public mojo::test::SimpleTestThread { +class WaitingThread : public test::SimpleTestThread { public: explicit WaitingThread(MojoDeadline deadline) : deadline_(deadline), @@ -49,7 +54,7 @@ class WaitingThread : public mojo::test::SimpleTestThread { } } - test::Sleep(test::DeadlineFromMilliseconds(kPollTimeMs)); + test::SleepMilliseconds(kPollTimeMs); } } @@ -96,61 +101,61 @@ TEST(WaiterTest, Basic) { // Awake immediately after thread start. { - WaitingThread thread(10 * test::EpsilonDeadline()); + WaitingThread thread(10 * test::EpsilonTimeout()); thread.Start(); thread.waiter()->Awake(MOJO_RESULT_OK, 1); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_OK, result); EXPECT_EQ(1u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } // Awake before after thread start. { - WaitingThread thread(10 * test::EpsilonDeadline()); + WaitingThread thread(10 * test::EpsilonTimeout()); thread.waiter()->Awake(MOJO_RESULT_CANCELLED, 2); thread.Start(); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_CANCELLED, result); EXPECT_EQ(2u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } // Awake some time after thread start. { - WaitingThread thread(10 * test::EpsilonDeadline()); + WaitingThread thread(10 * test::EpsilonTimeout()); thread.Start(); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); thread.waiter()->Awake(1, 3); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(1u, result); EXPECT_EQ(3u, context); - 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()); } // Awake some longer time after thread start. { - WaitingThread thread(10 * test::EpsilonDeadline()); + WaitingThread thread(10 * test::EpsilonTimeout()); thread.Start(); - test::Sleep(5 * test::EpsilonDeadline()); + test::Sleep(5 * test::EpsilonTimeout()); thread.waiter()->Awake(2, 4); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(2u, result); EXPECT_EQ(4u, context); - EXPECT_GT(elapsed, (5 - 1) * test::EpsilonDeadline()); - EXPECT_LT(elapsed, (5 + 1) * test::EpsilonDeadline()); + EXPECT_GT(elapsed, (5 - 1) * test::EpsilonTimeout()); + EXPECT_LT(elapsed, (5 + 1) * test::EpsilonTimeout()); } // Don't awake -- time out (on another thread). { - WaitingThread thread(2 * test::EpsilonDeadline()); + WaitingThread thread(2 * test::EpsilonTimeout()); thread.Start(); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, result); EXPECT_EQ(static_cast(-1), context); - 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()); } // No (indefinite) deadline. @@ -163,7 +168,7 @@ TEST(WaiterTest, Basic) { thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_OK, result); EXPECT_EQ(5u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } // Awake before after thread start. @@ -174,33 +179,33 @@ TEST(WaiterTest, Basic) { thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_CANCELLED, result); EXPECT_EQ(6u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } // Awake some time after thread start. { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); thread.waiter()->Awake(1, 7); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(1u, result); EXPECT_EQ(7u, context); - 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()); } // Awake some longer time after thread start. { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); - test::Sleep(5 * test::EpsilonDeadline()); + test::Sleep(5 * test::EpsilonTimeout()); thread.waiter()->Awake(2, 8); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(2u, result); EXPECT_EQ(8u, context); - EXPECT_GT(elapsed, (5 - 1) * test::EpsilonDeadline()); - EXPECT_LT(elapsed, (5 + 1) * test::EpsilonDeadline()); + EXPECT_GT(elapsed, (5 - 1) * test::EpsilonTimeout()); + EXPECT_LT(elapsed, (5 + 1) * test::EpsilonTimeout()); } } @@ -215,25 +220,25 @@ TEST(WaiterTest, TimeOut) { stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, &context)); elapsed = stopwatch.Elapsed(); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); EXPECT_EQ(123u, context); waiter.Init(); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - waiter.Wait(2 * test::EpsilonDeadline(), &context)); + waiter.Wait(2 * test::EpsilonTimeout(), &context)); 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_EQ(123u, context); waiter.Init(); stopwatch.Start(); EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, - waiter.Wait(5 * test::EpsilonDeadline(), &context)); + waiter.Wait(5 * test::EpsilonTimeout(), &context)); elapsed = stopwatch.Elapsed(); - EXPECT_GT(elapsed, (5 - 1) * test::EpsilonDeadline()); - EXPECT_LT(elapsed, (5 + 1) * test::EpsilonDeadline()); + EXPECT_GT(elapsed, (5 - 1) * test::EpsilonTimeout()); + EXPECT_LT(elapsed, (5 + 1) * test::EpsilonTimeout()); EXPECT_EQ(123u, context); } @@ -251,7 +256,7 @@ TEST(WaiterTest, MultipleAwakes) { thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_OK, result); EXPECT_EQ(1u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } { @@ -262,33 +267,33 @@ TEST(WaiterTest, MultipleAwakes) { thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(1u, result); EXPECT_EQ(3u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } { WaitingThread thread(MOJO_DEADLINE_INDEFINITE); thread.Start(); thread.waiter()->Awake(10, 5); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); thread.waiter()->Awake(20, 6); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(10u, result); EXPECT_EQ(5u, context); - EXPECT_LT(elapsed, test::EpsilonDeadline()); + EXPECT_LT(elapsed, test::EpsilonTimeout()); } { - WaitingThread thread(10 * test::EpsilonDeadline()); + WaitingThread thread(10 * test::EpsilonTimeout()); thread.Start(); - test::Sleep(1 * test::EpsilonDeadline()); + test::Sleep(1 * test::EpsilonTimeout()); thread.waiter()->Awake(MOJO_RESULT_FAILED_PRECONDITION, 7); - test::Sleep(2 * test::EpsilonDeadline()); + test::Sleep(2 * test::EpsilonTimeout()); thread.waiter()->Awake(MOJO_RESULT_OK, 8); thread.WaitUntilDone(&result, &context, &elapsed); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); EXPECT_EQ(7u, context); - EXPECT_GT(elapsed, (1 - 1) * test::EpsilonDeadline()); - EXPECT_LT(elapsed, (1 + 1) * test::EpsilonDeadline()); + EXPECT_GT(elapsed, (1 - 1) * test::EpsilonTimeout()); + EXPECT_LT(elapsed, (1 + 1) * test::EpsilonTimeout()); } } diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn index 6a905ee2bd6..8fab4ee9bed 100644 --- a/mojo/edk/test/BUILD.gn +++ b/mojo/edk/test/BUILD.gn @@ -3,8 +3,6 @@ # found in the LICENSE file. import("../mojo_edk.gni") -import("../../public/mojo.gni") -import("//testing/test.gni") mojo_edk_source_set("test_support") { testonly = true @@ -13,14 +11,8 @@ mojo_edk_source_set("test_support") { "multiprocess_test_helper.h", "scoped_ipc_support.cc", "scoped_ipc_support.h", - "scoped_test_dir.cc", - "scoped_test_dir.h", - "simple_test_thread.cc", - "simple_test_thread.h", - "test_io_thread.cc", - "test_io_thread.h", + "test_utils.cc", "test_utils.h", - "test_utils_posix.cc", ] deps = [ @@ -51,8 +43,6 @@ mojo_edk_source_set("run_all_unittests") { ] mojo_edk_deps = [ "mojo/edk/system" ] - - mojo_sdk_deps = [ "mojo/public/c/test_support" ] } mojo_edk_source_set("run_all_perftests") { @@ -65,8 +55,6 @@ mojo_edk_source_set("run_all_perftests") { mojo_edk_deps = [ "mojo/edk/system" ] - mojo_sdk_deps = [ "mojo/public/c/test_support" ] - sources = [ "run_all_perftests.cc", ] @@ -79,92 +67,16 @@ mojo_edk_source_set("test_support_impl") { "//base/test:test_support", ] - mojo_sdk_deps = [ "mojo/public/c/test_support" ] + mojo_sdk_deps = [ "mojo/public/cpp/test_support" ] mojo_sdk_public_deps = [ "mojo/public/cpp/system" ] sources = [ "test_support_impl.cc", - "test_support_impl.h", - ] -} - -# Public SDK test targets follow. These targets are not defined within the -# public SDK itself as running the unittests requires the EDK. -# TODO(vtl): These don't really belong here. (They should be converted to -# apptests, but even apart from that these targets belong somewhere else.) - -group("public_tests") { - testonly = true - deps = [ - ":mojo_public_bindings_perftests", - ":mojo_public_bindings_unittests", - ":mojo_public_environment_unittests", - ":mojo_public_system_perftests", - ":mojo_public_system_unittests", - ":mojo_public_utility_unittests", - ":mojo_system_impl_private_unittests", ] - if (mojo_use_application_in_sdk) { - deps += [ ":mojo_public_application_unittests" ] - } -} - -if (mojo_use_application_in_sdk) { - test("mojo_public_application_unittests") { - deps = [ - ":run_all_unittests", - "../../public/cpp/application/tests", - ] - } -} - -test("mojo_public_bindings_unittests") { - deps = [ + visibility = [ ":run_all_unittests", - "../../public/cpp/bindings/tests", - ] -} - -test("mojo_public_bindings_perftests") { - deps = [ ":run_all_perftests", - "../../public/cpp/bindings/tests:perftests", - ] -} - -test("mojo_public_environment_unittests") { - deps = [ - ":run_all_unittests", - "../../public/cpp/environment/tests", - ] -} - -test("mojo_public_system_perftests") { - deps = [ - ":run_all_perftests", - "../../public/c/system/tests:perftests", - ] -} - -test("mojo_public_system_unittests") { - deps = [ - ":run_all_unittests", - "../../public/cpp/system/tests", - ] -} - -test("mojo_public_utility_unittests") { - deps = [ - ":run_all_unittests", - "../../public/cpp/utility/tests", - ] -} - -test("mojo_system_impl_private_unittests") { - deps = [ - ":run_all_unittests", - "../../public/platform/native:system_impl_private_tests", ] } diff --git a/mojo/edk/test/multiprocess_test_helper.cc b/mojo/edk/test/multiprocess_test_helper.cc index 81fbdcc1749..65265a3383a 100644 --- a/mojo/edk/test/multiprocess_test_helper.cc +++ b/mojo/edk/test/multiprocess_test_helper.cc @@ -6,6 +6,7 @@ #include "base/command_line.h" #include "base/logging.h" +#include "base/test/test_timeouts.h" #include "mojo/edk/embedder/platform_channel_pair.h" namespace mojo { diff --git a/mojo/edk/test/multiprocess_test_helper.h b/mojo/edk/test/multiprocess_test_helper.h index 2d02796b4b0..952df0414bd 100644 --- a/mojo/edk/test/multiprocess_test_helper.h +++ b/mojo/edk/test/multiprocess_test_helper.h @@ -10,7 +10,6 @@ #include "base/process/process.h" #include "base/test/multiprocess_test.h" -#include "base/test/test_timeouts.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/public/cpp/system/macros.h" #include "testing/multiprocess_func_list.h" diff --git a/mojo/edk/test/run_all_perftests.cc b/mojo/edk/test/run_all_perftests.cc index f0eacc6bd4c..998dffbb098 100644 --- a/mojo/edk/test/run_all_perftests.cc +++ b/mojo/edk/test/run_all_perftests.cc @@ -4,11 +4,8 @@ #include "base/test/perf_test_suite.h" #include "mojo/edk/embedder/test_embedder.h" -#include "mojo/edk/test/test_support_impl.h" -#include "mojo/public/tests/test_support_private.h" int main(int argc, char** argv) { mojo::embedder::test::InitWithSimplePlatformSupport(); - mojo::test::TestSupport::Init(new mojo::test::TestSupportImpl()); return base::PerfTestSuite(argc, argv).Run(); } diff --git a/mojo/edk/test/run_all_unittests.cc b/mojo/edk/test/run_all_unittests.cc index 2059347ea3a..d5cea6f2ab3 100644 --- a/mojo/edk/test/run_all_unittests.cc +++ b/mojo/edk/test/run_all_unittests.cc @@ -8,8 +8,6 @@ #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "mojo/edk/embedder/test_embedder.h" -#include "mojo/edk/test/test_support_impl.h" -#include "mojo/public/tests/test_support_private.h" #include "testing/gtest/include/gtest/gtest.h" int main(int argc, char** argv) { @@ -31,7 +29,6 @@ int main(int argc, char** argv) { base::TestSuite test_suite(argc, argv); mojo::embedder::test::InitWithSimplePlatformSupport(); - mojo::test::TestSupport::Init(new mojo::test::TestSupportImpl()); return base::LaunchUnitTests( argc, argv, diff --git a/mojo/edk/test/test_support_impl.cc b/mojo/edk/test/test_support_impl.cc index 4bf11bde0ce..3f84b8f9081 100644 --- a/mojo/edk/test/test_support_impl.cc +++ b/mojo/edk/test/test_support_impl.cc @@ -2,12 +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/test/test_support_impl.h" - -#include -#include - -#include +#include "mojo/public/cpp/test_support/test_support.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" @@ -20,7 +15,7 @@ namespace mojo { namespace test { namespace { -base::FilePath ResolveSourceRootRelativePath(const char* relative_path) { +base::FilePath ResolveSourceRootRelativePath(const std::string& relative_path) { // TODO(vtl): Have someone inject the source root instead. base::FilePath path; if (!PathService::Get(base::DIR_SOURCE_ROOT, &path)) @@ -30,16 +25,10 @@ base::FilePath ResolveSourceRootRelativePath(const char* relative_path) { } // namespace -TestSupportImpl::TestSupportImpl() { -} - -TestSupportImpl::~TestSupportImpl() { -} - -void TestSupportImpl::LogPerfResult(const char* test_name, - const char* sub_test_name, - double value, - const char* units) { +void LogPerfResult(const char* test_name, + const char* sub_test_name, + double value, + const char* units) { DCHECK(test_name); if (sub_test_name) { std::string name = std::string(test_name) + "/" + sub_test_name; @@ -49,23 +38,18 @@ void TestSupportImpl::LogPerfResult(const char* test_name, } } -FILE* TestSupportImpl::OpenSourceRootRelativeFile(const char* relative_path) { +FILE* OpenSourceRootRelativeFile(const std::string& relative_path) { return base::OpenFile(ResolveSourceRootRelativePath(relative_path), "rb"); } -char** TestSupportImpl::EnumerateSourceRootRelativeDirectory( - const char* relative_path) { +std::vector EnumerateSourceRootRelativeDirectory( + const std::string& relative_path) { std::vector names; base::FileEnumerator e(ResolveSourceRootRelativePath(relative_path), false, base::FileEnumerator::FILES); for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) names.push_back(name.BaseName().AsUTF8Unsafe()); - - // |names.size() + 1| for null terminator. - char** rv = static_cast(calloc(names.size() + 1, sizeof(char*))); - for (size_t i = 0; i < names.size(); ++i) - rv[i] = strdup(names[i].c_str()); - return rv; + return names; } } // namespace test diff --git a/mojo/edk/test/test_support_impl.h b/mojo/edk/test/test_support_impl.h deleted file mode 100644 index 589253a0eb8..00000000000 --- a/mojo/edk/test/test_support_impl.h +++ /dev/null @@ -1,36 +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. - -#ifndef MOJO_EDK_TEST_TEST_SUPPORT_IMPL_H_ -#define MOJO_EDK_TEST_TEST_SUPPORT_IMPL_H_ - -#include - -#include "mojo/public/cpp/system/macros.h" -#include "mojo/public/tests/test_support_private.h" - -namespace mojo { -namespace test { - -class TestSupportImpl : public TestSupport { - public: - TestSupportImpl(); - ~TestSupportImpl() override; - - void LogPerfResult(const char* test_name, - const char* sub_test_name, - double value, - const char* units) override; - FILE* OpenSourceRootRelativeFile(const char* relative_path) override; - char** EnumerateSourceRootRelativeDirectory( - const char* relative_path) override; - - private: - MOJO_DISALLOW_COPY_AND_ASSIGN(TestSupportImpl); -}; - -} // namespace test -} // namespace mojo - -#endif // MOJO_EDK_TEST_TEST_SUPPORT_IMPL_H_ diff --git a/mojo/edk/test/test_utils_posix.cc b/mojo/edk/test/test_utils.cc similarity index 99% rename from mojo/edk/test/test_utils_posix.cc rename to mojo/edk/test/test_utils.cc index 70c1bdee27c..1a0496221a3 100644 --- a/mojo/edk/test/test_utils_posix.cc +++ b/mojo/edk/test/test_utils.cc @@ -86,7 +86,7 @@ util::ScopedFILE FILEFromPlatformHandle(embedder::ScopedPlatformHandle h, CHECK(h.is_valid()); util::ScopedFILE rv(fdopen(h.release().fd, mode)); PCHECK(rv) << "fdopen"; - return rv.Pass(); + return rv; } } // namespace test diff --git a/mojo/edk/util/BUILD.gn b/mojo/edk/util/BUILD.gn index 380255d8a34..1725b619439 100644 --- a/mojo/edk/util/BUILD.gn +++ b/mojo/edk/util/BUILD.gn @@ -6,15 +6,65 @@ import("../mojo_edk.gni") mojo_edk_source_set("util") { sources = [ + "command_line.cc", + "command_line.h", + "cond_var.cc", + "cond_var.h", + "logging_internal.cc", + "logging_internal.h", "make_unique.h", + "mutex.cc", + "mutex.h", + "ref_counted.h", + "ref_counted_internal.h", + "ref_ptr.h", + "ref_ptr_internal.h", "scoped_file.h", + "thread_annotations.h", ] - defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ] - mojo_edk_configs = [ "mojo/edk/system:system_config" ] + mojo_sdk_public_deps = [ "mojo/public/cpp/system" ] +} + +mojo_edk_source_set("unittests") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/system:mojo_system_unittests" ] + + sources = [ + "command_line_unittest.cc", + "cond_var_unittest.cc", + "mutex_unittest.cc", + "ref_counted_unittest.cc", + "thread_annotations_unittest.cc", + ] + deps = [ - "//base", + ":util", + "//testing/gtest", + ] + + mojo_sdk_deps = [ "mojo/public/cpp/system" ] + + mojo_edk_deps = [ "mojo/edk/system/test" ] +} + +mojo_edk_source_set("perftests") { + testonly = true + mojo_edk_visibility = [ "mojo/edk/system:mojo_system_perftests" ] + + sources = [ + "ref_counted_perftest.cc", + ] + + deps = [ + ":util", + "//testing/gtest", + ] + + mojo_edk_deps = [ + "mojo/edk/system/test", + "mojo/edk/system/test:perf", ] } diff --git a/mojo/edk/util/command_line.cc b/mojo/edk/util/command_line.cc new file mode 100644 index 00000000000..3f7701dbf28 --- /dev/null +++ b/mojo/edk/util/command_line.cc @@ -0,0 +1,158 @@ +// 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/util/command_line.h" + +namespace mojo { +namespace util { + +// CommandLine ----------------------------------------------------------------- + +CommandLine::Option::Option(const std::string& name) : name(name) {} + +CommandLine::Option::Option(const std::string& name, const std::string& value) + : name(name), value(value) {} + +CommandLine::CommandLine() = default; + +CommandLine::CommandLine(const CommandLine& from) = default; + +CommandLine::CommandLine(CommandLine&& from) = default; + +CommandLine::CommandLine(const std::string& argv0, + const std::vector