aboutsummaryrefslogtreecommitdiff
path: root/mojo/edk
diff options
context:
space:
mode:
Diffstat (limited to 'mojo/edk')
-rw-r--r--mojo/edk/DEPS14
-rw-r--r--mojo/edk/embedder/BUILD.gn147
-rw-r--r--mojo/edk/embedder/README.md346
-rw-r--r--mojo/edk/embedder/configuration.h65
-rw-r--r--mojo/edk/embedder/connection_params.cc28
-rw-r--r--mojo/edk/embedder/connection_params.h34
-rw-r--r--mojo/edk/embedder/embedder.cc158
-rw-r--r--mojo/edk/embedder/embedder.h173
-rw-r--r--mojo/edk/embedder/embedder_internal.h44
-rw-r--r--mojo/edk/embedder/embedder_unittest.cc603
-rw-r--r--mojo/edk/embedder/entrypoints.cc283
-rw-r--r--mojo/edk/embedder/entrypoints.h22
-rw-r--r--mojo/edk/embedder/named_platform_channel_pair.h73
-rw-r--r--mojo/edk/embedder/named_platform_channel_pair_win.cc89
-rw-r--r--mojo/edk/embedder/named_platform_handle.h51
-rw-r--r--mojo/edk/embedder/named_platform_handle_utils.h56
-rw-r--r--mojo/edk/embedder/named_platform_handle_utils_posix.cc141
-rw-r--r--mojo/edk/embedder/named_platform_handle_utils_win.cc95
-rw-r--r--mojo/edk/embedder/pending_process_connection.cc50
-rw-r--r--mojo/edk/embedder/pending_process_connection.h124
-rw-r--r--mojo/edk/embedder/platform_channel_pair.cc34
-rw-r--r--mojo/edk/embedder/platform_channel_pair.h106
-rw-r--r--mojo/edk/embedder/platform_channel_pair_posix.cc172
-rw-r--r--mojo/edk/embedder/platform_channel_pair_posix_unittest.cc261
-rw-r--r--mojo/edk/embedder/platform_channel_pair_win.cc123
-rw-r--r--mojo/edk/embedder/platform_channel_utils_posix.cc282
-rw-r--r--mojo/edk/embedder/platform_channel_utils_posix.h87
-rw-r--r--mojo/edk/embedder/platform_handle.cc74
-rw-r--r--mojo/edk/embedder/platform_handle.h90
-rw-r--r--mojo/edk/embedder/platform_handle_utils.h33
-rw-r--r--mojo/edk/embedder/platform_handle_utils_posix.cc24
-rw-r--r--mojo/edk/embedder/platform_handle_utils_win.cc28
-rw-r--r--mojo/edk/embedder/platform_handle_vector.h35
-rw-r--r--mojo/edk/embedder/platform_shared_buffer.cc325
-rw-r--r--mojo/edk/embedder/platform_shared_buffer.h178
-rw-r--r--mojo/edk/embedder/platform_shared_buffer_unittest.cc227
-rw-r--r--mojo/edk/embedder/scoped_ipc_support.cc39
-rw-r--r--mojo/edk/embedder/scoped_ipc_support.h118
-rw-r--r--mojo/edk/embedder/scoped_platform_handle.h63
-rw-r--r--mojo/edk/embedder/test_embedder.cc46
-rw-r--r--mojo/edk/embedder/test_embedder.h28
-rw-r--r--mojo/edk/js/BUILD.gn35
-rw-r--r--mojo/edk/js/core.cc454
-rw-r--r--mojo/edk/js/core.h25
-rw-r--r--mojo/edk/js/drain_data.cc129
-rw-r--r--mojo/edk/js/drain_data.h65
-rw-r--r--mojo/edk/js/handle.cc85
-rw-r--r--mojo/edk/js/handle.h107
-rw-r--r--mojo/edk/js/handle_close_observer.h24
-rw-r--r--mojo/edk/js/handle_unittest.cc92
-rw-r--r--mojo/edk/js/js_export.h32
-rw-r--r--mojo/edk/js/mojo_runner_delegate.cc80
-rw-r--r--mojo/edk/js/mojo_runner_delegate.h36
-rw-r--r--mojo/edk/js/support.cc77
-rw-r--r--mojo/edk/js/support.h25
-rw-r--r--mojo/edk/js/tests/BUILD.gn68
-rw-r--r--mojo/edk/js/tests/js_to_cpp.mojom54
-rw-r--r--mojo/edk/js/tests/js_to_cpp_tests.cc455
-rw-r--r--mojo/edk/js/tests/js_to_cpp_tests.js223
-rw-r--r--mojo/edk/js/tests/run_js_unittests.cc61
-rw-r--r--mojo/edk/js/threading.cc49
-rw-r--r--mojo/edk/js/threading.h28
-rw-r--r--mojo/edk/js/waiting_callback.cc95
-rw-r--r--mojo/edk/js/waiting_callback.h67
-rw-r--r--mojo/edk/system/BUILD.gn205
-rw-r--r--mojo/edk/system/atomic_flag.h57
-rw-r--r--mojo/edk/system/broker.h52
-rw-r--r--mojo/edk/system/broker_host.cc153
-rw-r--r--mojo/edk/system/broker_host.h64
-rw-r--r--mojo/edk/system/broker_messages.h80
-rw-r--r--mojo/edk/system/broker_posix.cc125
-rw-r--r--mojo/edk/system/broker_win.cc155
-rw-r--r--mojo/edk/system/channel.cc683
-rw-r--r--mojo/edk/system/channel.h303
-rw-r--r--mojo/edk/system/channel_posix.cc572
-rw-r--r--mojo/edk/system/channel_unittest.cc177
-rw-r--r--mojo/edk/system/channel_win.cc360
-rw-r--r--mojo/edk/system/configuration.cc25
-rw-r--r--mojo/edk/system/configuration.h29
-rw-r--r--mojo/edk/system/core.cc1019
-rw-r--r--mojo/edk/system/core.h297
-rw-r--r--mojo/edk/system/core_test_base.cc272
-rw-r--r--mojo/edk/system/core_test_base.h94
-rw-r--r--mojo/edk/system/core_unittest.cc971
-rw-r--r--mojo/edk/system/data_pipe_consumer_dispatcher.cc562
-rw-r--r--mojo/edk/system/data_pipe_consumer_dispatcher.h123
-rw-r--r--mojo/edk/system/data_pipe_control_message.cc35
-rw-r--r--mojo/edk/system/data_pipe_control_message.h43
-rw-r--r--mojo/edk/system/data_pipe_producer_dispatcher.cc507
-rw-r--r--mojo/edk/system/data_pipe_producer_dispatcher.h123
-rw-r--r--mojo/edk/system/data_pipe_unittest.cc2034
-rw-r--r--mojo/edk/system/dispatcher.cc198
-rw-r--r--mojo/edk/system/dispatcher.h245
-rw-r--r--mojo/edk/system/handle_signals_state.h13
-rw-r--r--mojo/edk/system/handle_table.cc135
-rw-r--r--mojo/edk/system/handle_table.h75
-rw-r--r--mojo/edk/system/mach_port_relay.cc248
-rw-r--r--mojo/edk/system/mach_port_relay.h94
-rw-r--r--mojo/edk/system/mapping_table.cc48
-rw-r--r--mojo/edk/system/mapping_table.h57
-rw-r--r--mojo/edk/system/message_for_transit.cc136
-rw-r--r--mojo/edk/system/message_for_transit.h115
-rw-r--r--mojo/edk/system/message_pipe_dispatcher.cc554
-rw-r--r--mojo/edk/system/message_pipe_dispatcher.h115
-rw-r--r--mojo/edk/system/message_pipe_perftest.cc167
-rw-r--r--mojo/edk/system/message_pipe_unittest.cc699
-rw-r--r--mojo/edk/system/multiprocess_message_pipe_unittest.cc1366
-rw-r--r--mojo/edk/system/node_channel.cc905
-rw-r--r--mojo/edk/system/node_channel.h219
-rw-r--r--mojo/edk/system/node_controller.cc1470
-rw-r--r--mojo/edk/system/node_controller.h378
-rw-r--r--mojo/edk/system/options_validation.h97
-rw-r--r--mojo/edk/system/options_validation_unittest.cc134
-rw-r--r--mojo/edk/system/platform_handle_dispatcher.cc104
-rw-r--r--mojo/edk/system/platform_handle_dispatcher.h61
-rw-r--r--mojo/edk/system/platform_handle_dispatcher_unittest.cc123
-rw-r--r--mojo/edk/system/platform_wrapper_unittest.cc212
-rw-r--r--mojo/edk/system/ports/BUILD.gn46
-rw-r--r--mojo/edk/system/ports/event.cc46
-rw-r--r--mojo/edk/system/ports/event.h111
-rw-r--r--mojo/edk/system/ports/message.cc100
-rw-r--r--mojo/edk/system/ports/message.h93
-rw-r--r--mojo/edk/system/ports/message_filter.h29
-rw-r--r--mojo/edk/system/ports/message_queue.cc87
-rw-r--r--mojo/edk/system/ports/message_queue.h73
-rw-r--r--mojo/edk/system/ports/name.cc26
-rw-r--r--mojo/edk/system/ports/name.h74
-rw-r--r--mojo/edk/system/ports/node.cc1385
-rw-r--r--mojo/edk/system/ports/node.h228
-rw-r--r--mojo/edk/system/ports/node_delegate.h48
-rw-r--r--mojo/edk/system/ports/port.cc24
-rw-r--r--mojo/edk/system/ports/port.h60
-rw-r--r--mojo/edk/system/ports/port_ref.cc36
-rw-r--r--mojo/edk/system/ports/port_ref.h41
-rw-r--r--mojo/edk/system/ports/ports_unittest.cc1478
-rw-r--r--mojo/edk/system/ports/user_data.h25
-rw-r--r--mojo/edk/system/ports_message.cc62
-rw-r--r--mojo/edk/system/ports_message.h69
-rw-r--r--mojo/edk/system/request_context.cc110
-rw-r--r--mojo/edk/system/request_context.h107
-rw-r--r--mojo/edk/system/shared_buffer_dispatcher.cc339
-rw-r--r--mojo/edk/system/shared_buffer_dispatcher.h127
-rw-r--r--mojo/edk/system/shared_buffer_dispatcher_unittest.cc312
-rw-r--r--mojo/edk/system/shared_buffer_unittest.cc318
-rw-r--r--mojo/edk/system/signals_unittest.cc76
-rw-r--r--mojo/edk/system/system_impl_export.h29
-rw-r--r--mojo/edk/system/test_utils.cc76
-rw-r--r--mojo/edk/system/test_utils.h59
-rw-r--r--mojo/edk/system/watch.cc83
-rw-r--r--mojo/edk/system/watch.h124
-rw-r--r--mojo/edk/system/watcher_dispatcher.cc232
-rw-r--r--mojo/edk/system/watcher_dispatcher.h101
-rw-r--r--mojo/edk/system/watcher_set.cc82
-rw-r--r--mojo/edk/system/watcher_set.h71
-rw-r--r--mojo/edk/system/watcher_unittest.cc1637
-rw-r--r--mojo/edk/test/BUILD.gn131
-rw-r--r--mojo/edk/test/mojo_test_base.cc327
-rw-r--r--mojo/edk/test/mojo_test_base.h249
-rw-r--r--mojo/edk/test/multiprocess_test_helper.cc263
-rw-r--r--mojo/edk/test/multiprocess_test_helper.h110
-rw-r--r--mojo/edk/test/multiprocess_test_helper_unittest.cc165
-rw-r--r--mojo/edk/test/run_all_perftests.cc26
-rw-r--r--mojo/edk/test/run_all_unittests.cc49
-rw-r--r--mojo/edk/test/test_support_impl.cc84
-rw-r--r--mojo/edk/test/test_support_impl.h38
-rw-r--r--mojo/edk/test/test_utils.h55
-rw-r--r--mojo/edk/test/test_utils_posix.cc94
-rw-r--r--mojo/edk/test/test_utils_win.cc115
168 files changed, 0 insertions, 34153 deletions
diff --git a/mojo/edk/DEPS b/mojo/edk/DEPS
deleted file mode 100644
index 77abb21..0000000
--- a/mojo/edk/DEPS
+++ /dev/null
@@ -1,14 +0,0 @@
-include_rules = [
- # This code is checked into the chromium repo so it's fine to depend on this.
- "+base",
- "+crypto",
- "+build",
- "+gin",
- "+native_client/src/public",
- "+testing",
- "+third_party/ashmem",
- "+v8",
-
- # internal includes.
- "+mojo",
-]
diff --git a/mojo/edk/embedder/BUILD.gn b/mojo/edk/embedder/BUILD.gn
deleted file mode 100644
index 8105bed..0000000
--- a/mojo/edk/embedder/BUILD.gn
+++ /dev/null
@@ -1,147 +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.
-
-import("//build/config/nacl/config.gni")
-
-source_set("headers") {
- sources = [
- "configuration.h",
- "connection_params.h",
- "embedder.h",
- "embedder_internal.h",
- "named_platform_channel_pair.h",
- "named_platform_handle.h",
- "named_platform_handle_utils.h",
- "pending_process_connection.h",
- "platform_channel_pair.h",
- "platform_handle.h",
- "platform_handle_utils.h",
- "scoped_platform_handle.h",
- ]
-
- public_deps = [
- "//base",
- "//mojo/public/cpp/system",
- ]
-}
-
-source_set("embedder") {
- # This isn't really a standalone target; it must be linked into the
- # mojo_system_impl component.
- visibility = [
- "//mojo/edk/system",
- "//components/nacl:nacl",
- ]
-
- sources = [
- "configuration.h",
- "connection_params.cc",
- "connection_params.h",
- "embedder.cc",
- "embedder.h",
- "embedder_internal.h",
- "entrypoints.cc",
- "entrypoints.h",
- "pending_process_connection.cc",
- "scoped_ipc_support.cc",
- "scoped_ipc_support.h",
-
- # Test-only code:
- # TODO(vtl): It's a little unfortunate that these end up in the same
- # component as non-test-only code. In the static build, this code should
- # hopefully be dead-stripped.
- "test_embedder.cc",
- "test_embedder.h",
- ]
-
- defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
-
- public_deps = [
- ":headers",
- ":platform",
- "//base",
- "//mojo/public/cpp/system",
- ]
-
- if (!is_nacl) {
- deps = [
- "//crypto",
- ]
- }
-}
-
-source_set("platform") {
- # This isn't really a standalone target; it must be linked into the
- # mojo_system_impl component.
- visibility = [
- ":embedder",
- "//mojo/edk/system",
- ]
-
- sources = [
- "named_platform_channel_pair.h",
- "named_platform_channel_pair_win.cc",
- "named_platform_handle.h",
- "named_platform_handle_utils.h",
- "named_platform_handle_utils_win.cc",
- "platform_channel_pair.cc",
- "platform_channel_pair.h",
- "platform_channel_pair_posix.cc",
- "platform_channel_pair_win.cc",
- "platform_channel_utils_posix.cc",
- "platform_channel_utils_posix.h",
- "platform_handle.cc",
- "platform_handle.h",
- "platform_handle_utils.h",
- "platform_handle_utils_posix.cc",
- "platform_handle_utils_win.cc",
- "platform_handle_vector.h",
- "platform_shared_buffer.cc",
- "platform_shared_buffer.h",
- "scoped_platform_handle.h",
- ]
- if (!is_nacl) {
- sources += [ "named_platform_handle_utils_posix.cc" ]
- }
-
- defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
-
- public_deps = [
- "//mojo/public/cpp/system",
- ]
-
- deps = [
- "//base",
- ]
-
- if (is_android) {
- deps += [ "//third_party/ashmem" ]
- }
-
- if (is_nacl && !is_nacl_nonsfi) {
- sources -= [ "platform_channel_utils_posix.cc" ]
- }
-}
-
-source_set("embedder_unittests") {
- testonly = true
-
- # TODO: Figure out why this visibility check fails on Android.
- # visibility = [ "//mojo/edk/system:mojo_system_unittests" ]
-
- sources = [
- "embedder_unittest.cc",
- "platform_channel_pair_posix_unittest.cc",
- "platform_shared_buffer_unittest.cc",
- ]
-
- deps = [
- "//base",
- "//base/test:test_support",
- "//mojo/edk/system",
- "//mojo/edk/system:test_utils",
- "//mojo/edk/test:test_support",
- "//testing/gtest",
- ]
-}
diff --git a/mojo/edk/embedder/README.md b/mojo/edk/embedder/README.md
deleted file mode 100644
index fc53bec..0000000
--- a/mojo/edk/embedder/README.md
+++ /dev/null
@@ -1,346 +0,0 @@
-# ![Mojo Graphic](https://goo.gl/6CdlbH) Mojo Embedder Development Kit (EDK)
-This document is a subset of the [Mojo documentation](/mojo).
-
-[TOC]
-
-## Overview
-
-The Mojo EDK is a (binary-unstable) API which enables a process to use Mojo both
-internally and for IPC to other Mojo-embedding processes.
-
-Using any of the API surface in `//mojo/edk/embedder` requires (somewhat
-confusingly) a direct dependency on the GN `//mojo/edk/system` target. Despite
-this fact, you should never reference any of the headers in `mojo/edk/system`
-directly, as everything there is considered to be an internal detail of the EDK.
-
-**NOTE:** Unless you are introducing a new binary entry point into the system
-(*e.g.,* a new executable with a new `main()` definition), you probably don't
-need to know anything about the EDK API. Most processes defined in the Chrome
-repo today already fully initialize the EDK so that Mojo's other public APIs
-"just work" out of the box.
-
-## Basic Initialization
-
-In order to use Mojo in a given process, it's necessary to call
-`mojo::edk::Init` exactly once:
-
-```
-#include "mojo/edk/embedder/embedder.h"
-
-int main(int argc, char** argv) {
- mojo::edk::Init();
-
- // Now you can create message pipes, write messages, etc
-
- return 0;
-}
-```
-
-As it happens though, Mojo is less useful without some kind of IPC support as
-well, and that's a second initialization step.
-
-## IPC Initialization
-
-You also need to provide the system with a background TaskRunner on which it can
-watch for inbound I/O from any of the various other processes you will later
-connect to it.
-
-Here we'll just create a new background thread for IPC and let Mojo use that.
-Note that in Chromium, we use the existing "IO thread" in the browser process
-and content child processes.
-
-```
-#include "base/threading/thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-
-int main(int argc, char** argv) {
- mojo::edk::Init();
-
- base::Thread ipc_thread("ipc!");
- ipc_thread.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO));
-
- // As long as this object is alive, all EDK API surface relevant to IPC
- // connections is usable and message pipes which span a process boundary will
- // continue to function.
- mojo::edk::ScopedIPCSupport ipc_support(
- ipc_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-
- return 0;
-}
-```
-
-This process is now fully prepared to use Mojo IPC!
-
-Note that all existing process types in Chromium already perform this setup
-very early during startup.
-
-## Connecting Two Processes
-
-Now suppose you're running a process which has initialized Mojo IPC, and you
-want to launch another process which you know will also initialize Mojo IPC.
-You want to be able to connect Mojo interfaces between these two processes.
-Rejoice, because this section was written just for you.
-
-NOTE: For legacy reasons, some API terminology may refer to concepts of "parent"
-and "child" as a relationship between processes being connected by Mojo. This
-relationship is today completely orthogonal to any notion of process hierarchy
-in the OS, and so use of these APIs is not constrained by an adherence to any
-such hierarchy.
-
-Mojo requires you to bring your own OS pipe to the party, and it will do the
-rest. It also provides a convenient mechanism for creating such pipes, known as
-a `PlatformChannelPair`.
-
-You provide one end of this pipe to the EDK in the local process via
-`PendingProcessConnection` - which can also be used to create cross-process
-message pipes (see the next section) - and you're responsible for getting the
-other end into the remote process.
-
-```
-#include "base/process/process_handle.h"
-#include "base/threading/thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/pending_process_connection.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-
-// You write this. It launches a new process, passing the pipe handle
-// encapsulated by |channel| by any means possible (e.g. on Windows or POSIX
-// you may inhert the file descriptor/HANDLE at launch and pass a commandline
-// argument to indicate its numeric value). Returns the handle of the new
-// process.
-base::ProcessHandle LaunchCoolChildProcess(
- mojo::edk::ScopedPlatformHandle channel);
-
-int main(int argc, char** argv) {
- mojo::edk::Init();
-
- base::Thread ipc_thread("ipc!");
- ipc_thread.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO));
-
- mojo::edk::ScopedIPCSupport ipc_support(
- ipc_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-
- // This is essentially always an OS pipe (domain socket pair, Windows named
- // pipe, etc.)
- mojo::edk::PlatformChannelPair channel;
-
- // This is a scoper which encapsulates the intent to connect to another
- // process. It exists because process connection is inherently asynchronous,
- // things may go wrong, and the lifetime of any associated resources is bound
- // by the lifetime of this object regardless of success or failure.
- mojo::edk::PendingProcessConnection child;
-
- base::ProcessHandle child_handle =
- LaunchCoolChildProcess(channel.PassClientHandle());
-
- // At this point it's safe for |child| to go out of scope and nothing will
- // break.
- child.Connect(child_handle, channel.PassServerHandle());
-
- return 0;
-}
-```
-
-The launched process code uses `SetParentPipeHandle` to get connected, and might
-look something like:
-
-```
-#include "base/threading/thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-
-// You write this. It acquires the ScopedPlatformHandle that was passed by
-// whomever launched this process (i.e. LaunchCoolChildProcess above).
-mojo::edk::ScopedPlatformHandle GetChannelHandle();
-
-int main(int argc, char** argv) {
- mojo::edk::Init();
-
- base::Thread ipc_thread("ipc!");
- ipc_thread.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO));
-
- mojo::edk::ScopedIPCSupport ipc_support(
- ipc_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-
- mojo::edk::SetParentPipeHandle(GetChannelHandle());
-
- return 0;
-}
-```
-
-Now you have IPC initialized between two processes. For some practical examples
-of how this is done, you can dig into the various multiprocess tests in the
-`mojo_system_unittests` test suite.
-
-## Bootstrapping Cross-Process Message Pipes
-
-Having internal Mojo IPC support initialized is pretty useless if you don't have
-any message pipes spanning the process boundary. Fortunately, this is made
-trivial by the EDK: `PendingProcessConnection` has a
-`CreateMessagePipe` method which synthesizes a new solitary message pipe
-endpoint for your immediate use, while also generating a magic token string that
-can be exchanged for the other end of the pipe via
-`mojo::edk::CreateChildMessagePipe`.
-
-The token exchange can be done by the same process (which is sometimes useful),
-or by the process that is eventually connected via `Connect()` on that
-`PendingProcessConnection`. This means that you can effectively pass message
-pipes on the commandline by passing a token string.
-
-We can modify our existing sample code as follows:
-
-```
-#include "base/command_line.h"
-#include "base/process/process_handle.h"
-#include "base/threading/thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/pending_process_connection.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "local/foo.mojom.h" // You provide this
-
-base::ProcessHandle LaunchCoolChildProcess(
- const base::CommandLine& command_line,
- mojo::edk::ScopedPlatformHandle channel);
-
-int main(int argc, char** argv) {
- mojo::edk::Init();
-
- base::Thread ipc_thread("ipc!");
- ipc_thread.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO));
-
- mojo::edk::ScopedIPCSupport ipc_support(
- ipc_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-
- mojo::edk::PlatformChannelPair channel;
-
- mojo::edk::PendingProcessConnection child;
-
- base::CommandLine command_line; // Assume this is appropriately initialized
-
- // Create a new message pipe with one end being retrievable in the new
- // process. Note that it doesn't matter whether we call CreateMessagePipe()
- // before or after Connect(), and we can create as many different pipes as
- // we like.
- std::string pipe_token;
- mojo::ScopedMessagePipeHandle my_pipe = child.CreateMessagePipe(&pipe_token);
- command_line.AppendSwitchASCII("primordial-pipe", pipe_token);
-
- base::ProcessHandle child_handle =
- LaunchCoolChildProcess(command_line, channel.PassClientHandle());
-
- child.Connect(child_handle, channel.PassServerHandle());
-
- // We can start using our end of the pipe immediately. Here we assume the
- // other end will eventually be bound to a local::mojom::Foo implementation,
- // so we can start making calls on that interface.
- //
- // Note that this could even be done before the child process is launched and
- // it would still work as expected.
- local::mojom::FooPtr foo;
- foo.Bind(local::mojom::FooPtrInfo(std::move(my_pipe), 0));
- foo->DoSomeStuff(42);
-
- return 0;
-}
-```
-
-and for the launched process:
-
-
-```
-#include "base/command_line.h"
-#include "base/run_loop/run_loop.h"
-#include "base/threading/thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "local/foo.mojom.h" // You provide this
-
-mojo::edk::ScopedPlatformHandle GetChannelHandle();
-
-class FooImpl : local::mojom::Foo {
- public:
- explicit FooImpl(local::mojom::FooRequest request)
- : binding_(this, std::move(request)) {}
- ~FooImpl() override {}
-
- void DoSomeStuff(int32_t n) override {
- // ...
- }
-
- private:
- mojo::Binding<local::mojom::Foo> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(FooImpl);
-};
-
-int main(int argc, char** argv) {
- base::CommandLine::Init(argc, argv);
-
- mojo::edk::Init();
-
- base::Thread ipc_thread("ipc!");
- ipc_thread.StartWithOptions(
- base::Thread::Options(base::MessageLoop::TYPE_IO));
-
- mojo::edk::ScopedIPCSupport ipc_support(
- ipc_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
-
- mojo::edk::SetParentPipeHandle(GetChannelHandle());
-
- mojo::ScopedMessagePipeHandle my_pipe = mojo::edk::CreateChildMessagePipe(
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- "primordial-pipe"));
-
- local::mojom::FooRequest foo_request;
- foo_request.Bind(std::move(my_pipe));
- FooImpl impl(std::move(foo_request));
-
- // Run forever!
- base::RunLoop().Run();
-
- return 0;
-}
-```
-
-Note that the above samples assume an interface definition in
-`//local/test.mojom` which would look something like:
-
-```
-module local.mojom;
-
-interface Foo {
- DoSomeStuff(int32 n);
-};
-```
-
-Once you've bootstrapped your process connection with a real mojom interface,
-you can avoid any further mucking around with EDK APIs or raw message pipe
-handles, as everything beyond this point - including the passing of other
-interface pipes - can be handled eloquently using
-[public bindings APIs](/mojo#High-Level-Bindings-APIs).
-
-## Setting System Properties
-
-The public Mojo C System API exposes a
-[**`MojoGetProperty`**](/mojo/public/c/system#MojoGetProperty) function for
-querying global, embedder-defined property values. These can be set by calling:
-
-```
-mojo::edk::SetProperty(MojoPropertyType type, const void* value)
-```
-
diff --git a/mojo/edk/embedder/configuration.h b/mojo/edk/embedder/configuration.h
deleted file mode 100644
index 1990fb1..0000000
--- a/mojo/edk/embedder/configuration.h
+++ /dev/null
@@ -1,65 +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_EMBEDDER_CONFIGURATION_H_
-#define MOJO_EDK_EMBEDDER_CONFIGURATION_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-namespace mojo {
-namespace edk {
-
-// A set of constants that the Mojo system internally uses. These values should
-// be consistent across all processes on the same system.
-//
-// In general, there should be no need to change these values from their
-// defaults. However, if you do change them, you must do so before
-// initialization.
-struct Configuration {
- // Maximum number of open (Mojo) handles. The default is 1,000,000.
- //
- // TODO(vtl): This doesn't count "live" handles, some of which may live in
- // messages.
- size_t max_handle_table_size;
-
- // Maximum number of active memory mappings. The default is 1,000,000.
- size_t max_mapping_table_sze;
-
- // Maximum data size of messages sent over message pipes, in bytes. The
- // default is 4MB.
- size_t max_message_num_bytes;
-
- // Maximum number of handles that can be attached to messages sent over
- // message pipes. The default is 10,000.
- size_t max_message_num_handles;
-
- // Maximum capacity of a data pipe, in bytes. The default is 256MB. This value
- // must fit into a |uint32_t|. WARNING: If you bump it closer to 2^32, you
- // must audit all the code to check that we don't overflow (2^31 would
- // definitely be risky; up to 2^30 is probably okay).
- size_t max_data_pipe_capacity_bytes;
-
- // Default data pipe capacity, if not specified explicitly in the creation
- // options. The default is 1MB.
- size_t default_data_pipe_capacity_bytes;
-
- // Alignment for the "start" of the data buffer used by data pipes. (The
- // alignment of elements will depend on this and the element size.) The
- // default is 16 bytes.
- size_t data_pipe_buffer_alignment_bytes;
-
- // Maximum size of a single shared memory segment, in bytes. The default is
- // 1GB.
- //
- // TODO(vtl): Set this hard limit appropriately (e.g., higher on 64-bit).
- // (This will also entail some auditing to make sure I'm not messing up my
- // checks anywhere.)
- size_t max_shared_memory_num_bytes;
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_CONFIGURATION_H_
diff --git a/mojo/edk/embedder/connection_params.cc b/mojo/edk/embedder/connection_params.cc
deleted file mode 100644
index 9b7ec54..0000000
--- a/mojo/edk/embedder/connection_params.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 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/connection_params.h"
-
-#include <utility>
-
-namespace mojo {
-namespace edk {
-
-ConnectionParams::ConnectionParams(ScopedPlatformHandle channel)
- : channel_(std::move(channel)) {}
-
-ConnectionParams::ConnectionParams(ConnectionParams&& param)
- : channel_(std::move(param.channel_)) {}
-
-ConnectionParams& ConnectionParams::operator=(ConnectionParams&& param) {
- channel_ = std::move(param.channel_);
- return *this;
-}
-
-ScopedPlatformHandle ConnectionParams::TakeChannelHandle() {
- return std::move(channel_);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/connection_params.h b/mojo/edk/embedder/connection_params.h
deleted file mode 100644
index 25ffdde..0000000
--- a/mojo/edk/embedder/connection_params.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2017 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_EMBEDDER_CONNECTION_PARAMS_H_
-#define MOJO_EDK_EMBEDDER_CONNECTION_PARAMS_H_
-
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-class MOJO_SYSTEM_IMPL_EXPORT ConnectionParams {
- public:
- explicit ConnectionParams(ScopedPlatformHandle channel);
-
- ConnectionParams(ConnectionParams&& param);
- ConnectionParams& operator=(ConnectionParams&& param);
-
- ScopedPlatformHandle TakeChannelHandle();
-
- private:
- ScopedPlatformHandle channel_;
-
- DISALLOW_COPY_AND_ASSIGN(ConnectionParams);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_CONNECTION_PARAMS_H_
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc
deleted file mode 100644
index 0fdda5c..0000000
--- a/mojo/edk/embedder/embedder.cc
+++ /dev/null
@@ -1,158 +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/embedder.h"
-
-#include <stdint.h>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/entrypoints.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/node_controller.h"
-
-#if !defined(OS_NACL)
-#include "crypto/random.h"
-#endif
-
-namespace mojo {
-namespace edk {
-
-class Core;
-class PlatformSupport;
-
-namespace internal {
-
-Core* g_core;
-
-Core* GetCore() { return g_core; }
-
-} // namespace internal
-
-void SetMaxMessageSize(size_t bytes) {
-}
-
-void SetParentPipeHandle(ScopedPlatformHandle pipe) {
- CHECK(internal::g_core);
- internal::g_core->InitChild(ConnectionParams(std::move(pipe)));
-}
-
-void SetParentPipeHandleFromCommandLine() {
- ScopedPlatformHandle platform_channel =
- PlatformChannelPair::PassClientHandleFromParentProcess(
- *base::CommandLine::ForCurrentProcess());
- CHECK(platform_channel.is_valid());
- SetParentPipeHandle(std::move(platform_channel));
-}
-
-ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe) {
- return ConnectToPeerProcess(std::move(pipe), GenerateRandomToken());
-}
-
-ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe,
- const std::string& peer_token) {
- DCHECK(pipe.is_valid());
- DCHECK(!peer_token.empty());
- return internal::g_core->ConnectToPeerProcess(std::move(pipe), peer_token);
-}
-
-void ClosePeerConnection(const std::string& peer_token) {
- return internal::g_core->ClosePeerConnection(peer_token);
-}
-
-void Init() {
- MojoSystemThunks thunks = MakeSystemThunks();
- size_t expected_size = MojoEmbedderSetSystemThunks(&thunks);
- DCHECK_EQ(expected_size, sizeof(thunks));
-
- internal::g_core = new Core();
-}
-
-void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback) {
- internal::g_core->SetDefaultProcessErrorCallback(callback);
-}
-
-MojoResult CreatePlatformHandleWrapper(
- ScopedPlatformHandle platform_handle,
- MojoHandle* platform_handle_wrapper_handle) {
- return internal::g_core->CreatePlatformHandleWrapper(
- std::move(platform_handle), platform_handle_wrapper_handle);
-}
-
-MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
- ScopedPlatformHandle* platform_handle) {
- return internal::g_core->PassWrappedPlatformHandle(
- platform_handle_wrapper_handle, platform_handle);
-}
-
-MojoResult CreateSharedBufferWrapper(
- base::SharedMemoryHandle shared_memory_handle,
- size_t num_bytes,
- bool read_only,
- MojoHandle* mojo_wrapper_handle) {
- return internal::g_core->CreateSharedBufferWrapper(
- shared_memory_handle, num_bytes, read_only, mojo_wrapper_handle);
-}
-
-MojoResult PassSharedMemoryHandle(
- MojoHandle mojo_handle,
- base::SharedMemoryHandle* shared_memory_handle,
- size_t* num_bytes,
- bool* read_only) {
- return internal::g_core->PassSharedMemoryHandle(
- mojo_handle, shared_memory_handle, num_bytes, read_only);
-}
-
-void InitIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner) {
- CHECK(internal::g_core);
- internal::g_core->SetIOTaskRunner(io_thread_task_runner);
-}
-
-scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
- return internal::g_core->GetNodeController()->io_task_runner();
-}
-
-void ShutdownIPCSupport(const base::Closure& callback) {
- CHECK(internal::g_core);
- internal::g_core->RequestShutdown(callback);
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-void SetMachPortProvider(base::PortProvider* port_provider) {
- DCHECK(port_provider);
- internal::g_core->SetMachPortProvider(port_provider);
-}
-#endif
-
-ScopedMessagePipeHandle CreateChildMessagePipe(const std::string& token) {
- return internal::g_core->CreateChildMessagePipe(token);
-}
-
-std::string GenerateRandomToken() {
- char random_bytes[16];
-#if defined(OS_NACL)
- // Not secure. For NaCl only!
- base::RandBytes(random_bytes, 16);
-#else
- crypto::RandBytes(random_bytes, 16);
-#endif
- return base::HexEncode(random_bytes, 16);
-}
-
-MojoResult SetProperty(MojoPropertyType type, const void* value) {
- CHECK(internal::g_core);
- return internal::g_core->SetProperty(type, value);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h
deleted file mode 100644
index 97258e5..0000000
--- a/mojo/edk/embedder/embedder.h
+++ /dev/null
@@ -1,173 +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_EMBEDDER_EMBEDDER_H_
-#define MOJO_EDK_EMBEDDER_EMBEDDER_H_
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory_handle.h"
-#include "base/process/process_handle.h"
-#include "base/task_runner.h"
-#include "mojo/edk/embedder/pending_process_connection.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-
-namespace base {
-class PortProvider;
-}
-
-namespace mojo {
-namespace edk {
-
-// Basic configuration/initialization ------------------------------------------
-
-// |Init()| sets up the basic Mojo system environment, making the |Mojo...()|
-// functions available and functional. This is never shut down (except in tests
-// -- see test_embedder.h).
-
-// Allows changing the default max message size. Must be called before Init.
-MOJO_SYSTEM_IMPL_EXPORT void SetMaxMessageSize(size_t bytes);
-
-// Should be called as early as possible in a child process with a handle to the
-// other end of a pipe provided in the parent to
-// PendingProcessConnection::Connect.
-MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandle(ScopedPlatformHandle pipe);
-
-// Same as above but extracts the pipe handle from the command line. See
-// PlatformChannelPair for details.
-MOJO_SYSTEM_IMPL_EXPORT void SetParentPipeHandleFromCommandLine();
-
-// Called to connect to a peer process. This should be called only if there
-// is no common ancestor for the processes involved within this mojo system.
-// Both processes must call this function, each passing one end of a platform
-// channel. This returns one end of a message pipe to each process.
-MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
-ConnectToPeerProcess(ScopedPlatformHandle pipe);
-
-// Called to connect to a peer process. This should be called only if there
-// is no common ancestor for the processes involved within this mojo system.
-// Both processes must call this function, each passing one end of a platform
-// channel. This returns one end of a message pipe to each process. |peer_token|
-// may be passed to ClosePeerConnection() to close the connection.
-MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
-ConnectToPeerProcess(ScopedPlatformHandle pipe, const std::string& peer_token);
-
-// Closes a connection to a peer process created by ConnectToPeerProcess()
-// where the same |peer_token| was used.
-MOJO_SYSTEM_IMPL_EXPORT void ClosePeerConnection(const std::string& peer_token);
-
-// Must be called first, or just after setting configuration parameters, to
-// initialize the (global, singleton) system.
-MOJO_SYSTEM_IMPL_EXPORT void Init();
-
-// Sets a default callback to invoke when an internal error is reported but
-// cannot be associated with a specific child process.
-MOJO_SYSTEM_IMPL_EXPORT void SetDefaultProcessErrorCallback(
- const ProcessErrorCallback& callback);
-
-// Basic functions -------------------------------------------------------------
-
-// The functions in this section are available once |Init()| has been called.
-
-// Creates a |MojoHandle| that wraps the given |PlatformHandle| (taking
-// ownership of it). This |MojoHandle| can then, e.g., be passed through message
-// pipes. Note: This takes ownership (and thus closes) |platform_handle| even on
-// failure, which is different from what you'd expect from a Mojo API, but it
-// makes for a more convenient embedder API.
-MOJO_SYSTEM_IMPL_EXPORT MojoResult
-CreatePlatformHandleWrapper(ScopedPlatformHandle platform_handle,
- MojoHandle* platform_handle_wrapper_handle);
-
-// Retrieves the |PlatformHandle| that was wrapped into a |MojoHandle| (using
-// |CreatePlatformHandleWrapper()| above). Note that the |MojoHandle| is closed
-// on success.
-MOJO_SYSTEM_IMPL_EXPORT MojoResult
-PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
- ScopedPlatformHandle* platform_handle);
-
-// Creates a |MojoHandle| that wraps the given |SharedMemoryHandle| (taking
-// ownership of it). |num_bytes| is the size of the shared memory object, and
-// |read_only| is whether the handle is a read-only handle to shared memory.
-// This |MojoHandle| is a Mojo shared buffer and can be manipulated using the
-// shared buffer functions and transferred over a message pipe.
-MOJO_SYSTEM_IMPL_EXPORT MojoResult
-CreateSharedBufferWrapper(base::SharedMemoryHandle shared_memory_handle,
- size_t num_bytes,
- bool read_only,
- MojoHandle* mojo_wrapper_handle);
-
-// Retrieves the underlying |SharedMemoryHandle| from a shared buffer
-// |MojoHandle| and closes the handle. If successful, |num_bytes| will contain
-// the size of the shared memory buffer and |read_only| will contain whether the
-// buffer handle is read-only. Both |num_bytes| and |read_only| may be null.
-// Note: The value of |shared_memory_handle| may be
-// base::SharedMemory::NULLHandle(), even if this function returns success.
-// Callers should perform appropriate checks.
-MOJO_SYSTEM_IMPL_EXPORT MojoResult
-PassSharedMemoryHandle(MojoHandle mojo_handle,
- base::SharedMemoryHandle* shared_memory_handle,
- size_t* num_bytes,
- bool* read_only);
-
-// Initialialization/shutdown for interprocess communication (IPC) -------------
-
-// |InitIPCSupport()| sets up the subsystem for interprocess communication,
-// making the IPC functions (in the following section) available and functional.
-// (This may only be done after |Init()|.)
-//
-// This subsystem may be shut down using |ShutdownIPCSupport()|. None of the IPC
-// functions may be called after this is called.
-//
-// |io_thread_task_runner| should live at least until |ShutdownIPCSupport()|'s
-// callback has been run.
-MOJO_SYSTEM_IMPL_EXPORT void InitIPCSupport(
- scoped_refptr<base::TaskRunner> io_thread_task_runner);
-
-// Retrieves the TaskRunner used for IPC I/O, as set by InitIPCSupport.
-MOJO_SYSTEM_IMPL_EXPORT scoped_refptr<base::TaskRunner> GetIOTaskRunner();
-
-// Shuts down the subsystem initialized by |InitIPCSupport()|. It be called from
-// any thread and will attempt to complete shutdown on the I/O thread with which
-// the system was initialized. Upon completion, |callback| is invoked on an
-// arbitrary thread.
-MOJO_SYSTEM_IMPL_EXPORT void ShutdownIPCSupport(const base::Closure& callback);
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// Set the |base::PortProvider| for this process. Can be called on any thread,
-// but must be set in the root process before any Mach ports can be transferred.
-MOJO_SYSTEM_IMPL_EXPORT void SetMachPortProvider(
- base::PortProvider* port_provider);
-#endif
-
-// Creates a message pipe from a token in a child process. This token must have
-// been acquired by a corresponding call to
-// PendingProcessConnection::CreateMessagePipe.
-MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
-CreateChildMessagePipe(const std::string& token);
-
-// Generates a random ASCII token string for use with various APIs that expect
-// a globally unique token string.
-MOJO_SYSTEM_IMPL_EXPORT std::string GenerateRandomToken();
-
-// Sets system properties that can be read by the MojoGetProperty() API. See the
-// documentation for MojoPropertyType for supported property types and their
-// corresponding value type.
-//
-// Default property values:
-// |MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED| - true
-MOJO_SYSTEM_IMPL_EXPORT MojoResult SetProperty(MojoPropertyType type,
- const void* value);
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_EMBEDDER_H_
diff --git a/mojo/edk/embedder/embedder_internal.h b/mojo/edk/embedder/embedder_internal.h
deleted file mode 100644
index 7deeca1..0000000
--- a/mojo/edk/embedder/embedder_internal.h
+++ /dev/null
@@ -1,44 +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.
-
-// This header contains internal details for the *implementation* of the
-// embedder API. It should not be included by any public header (nor by users of
-// the embedder API).
-
-#ifndef MOJO_EDK_EMBEDDER_EMBEDDER_INTERNAL_H_
-#define MOJO_EDK_EMBEDDER_EMBEDDER_INTERNAL_H_
-
-#include <stdint.h>
-
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace base {
-class TaskRunner;
-}
-
-namespace mojo {
-
-namespace edk {
-
-class Broker;
-class Core;
-class ProcessDelegate;
-
-namespace internal {
-
-// Instance of |Broker| to use.
-extern Broker* g_broker;
-
-// Instance of |Core| used by the system functions (|Mojo...()|).
-extern MOJO_SYSTEM_IMPL_EXPORT Core* g_core;
-extern base::TaskRunner* g_delegate_thread_task_runner;
-extern ProcessDelegate* g_process_delegate;
-
-} // namespace internal
-
-} // namepace edk
-
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_EMBEDDER_INTERNAL_H_
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc
deleted file mode 100644
index 388b45c..0000000
--- a/mojo/edk/embedder/embedder_unittest.cc
+++ /dev/null
@@ -1,603 +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/embedder.h"
-
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <utility>
-
-#include "base/base_paths.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/shared_memory.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/process/process_handle.h"
-#include "base/run_loop.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/test/test_timeouts.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-#include "mojo/edk/embedder/named_platform_handle_utils.h"
-#include "mojo/edk/embedder/pending_process_connection.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/test_embedder.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/core.h"
-#include "mojo/public/cpp/system/handle.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "mojo/public/cpp/system/wait.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-// The multiprocess tests that use these don't compile on iOS.
-#if !defined(OS_IOS)
-const char kHelloWorld[] = "hello world";
-const char kByeWorld[] = "bye world";
-#endif
-
-using EmbedderTest = test::MojoTestBase;
-
-TEST_F(EmbedderTest, ChannelBasic) {
- MojoHandle server_mp, client_mp;
- CreateMessagePipe(&server_mp, &client_mp);
-
- const std::string kHello = "hello";
-
- // We can write to a message pipe handle immediately.
- WriteMessage(server_mp, kHello);
- EXPECT_EQ(kHello, ReadMessage(client_mp));
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
-}
-
-// Verifies that a MP with pending messages to be written can be sent and the
-// pending messages aren't dropped.
-TEST_F(EmbedderTest, SendMessagePipeWithWriteQueue) {
- MojoHandle server_mp, client_mp;
- CreateMessagePipe(&server_mp, &client_mp);
-
- MojoHandle server_mp2, client_mp2;
- CreateMessagePipe(&server_mp2, &client_mp2);
-
- static const size_t kNumMessages = 1001;
- for (size_t i = 1; i <= kNumMessages; i++)
- WriteMessage(client_mp2, std::string(i, 'A' + (i % 26)));
-
- // Now send client2.
- WriteMessageWithHandles(server_mp, "hey", &client_mp2, 1);
- client_mp2 = MOJO_HANDLE_INVALID;
-
- // Read client2 just so we can close it later.
- EXPECT_EQ("hey", ReadMessageWithHandles(client_mp, &client_mp2, 1));
- EXPECT_NE(MOJO_HANDLE_INVALID, client_mp2);
-
- // Now verify that all the messages that were written were sent correctly.
- for (size_t i = 1; i <= kNumMessages; i++)
- ASSERT_EQ(std::string(i, 'A' + (i % 26)), ReadMessage(server_mp2));
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
-}
-
-TEST_F(EmbedderTest, ChannelsHandlePassing) {
- MojoHandle server_mp, client_mp;
- CreateMessagePipe(&server_mp, &client_mp);
- EXPECT_NE(server_mp, MOJO_HANDLE_INVALID);
- EXPECT_NE(client_mp, MOJO_HANDLE_INVALID);
-
- MojoHandle h0, h1;
- CreateMessagePipe(&h0, &h1);
-
- // Write a message to |h0| (attaching nothing).
- const std::string kHello = "hello";
- WriteMessage(h0, kHello);
-
- // Write one message to |server_mp|, attaching |h1|.
- const std::string kWorld = "world!!!";
- WriteMessageWithHandles(server_mp, kWorld, &h1, 1);
- h1 = MOJO_HANDLE_INVALID;
-
- // Write another message to |h0|.
- const std::string kFoo = "foo";
- WriteMessage(h0, kFoo);
-
- // Wait for |client_mp| to become readable and read a message from it.
- EXPECT_EQ(kWorld, ReadMessageWithHandles(client_mp, &h1, 1));
- EXPECT_NE(h1, MOJO_HANDLE_INVALID);
-
- // Wait for |h1| to become readable and read a message from it.
- EXPECT_EQ(kHello, ReadMessage(h1));
-
- // Wait for |h1| to become readable (again) and read its second message.
- EXPECT_EQ(kFoo, ReadMessage(h1));
-
- // Write a message to |h1|.
- const std::string kBarBaz = "barbaz";
- WriteMessage(h1, kBarBaz);
-
- // Wait for |h0| to become readable and read a message from it.
- EXPECT_EQ(kBarBaz, ReadMessage(h0));
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h0));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h1));
-}
-
-TEST_F(EmbedderTest, PipeSetup) {
- // Ensures that a pending process connection's message pipe can be claimed by
- // the host process itself.
- PendingProcessConnection process;
- std::string pipe_token;
- ScopedMessagePipeHandle parent_mp = process.CreateMessagePipe(&pipe_token);
- ScopedMessagePipeHandle child_mp = CreateChildMessagePipe(pipe_token);
-
- const std::string kHello = "hello";
- WriteMessage(parent_mp.get().value(), kHello);
-
- EXPECT_EQ(kHello, ReadMessage(child_mp.get().value()));
-}
-
-TEST_F(EmbedderTest, PipeSetup_LaunchDeath) {
- PlatformChannelPair pair;
-
- PendingProcessConnection process;
- std::string pipe_token;
- ScopedMessagePipeHandle parent_mp = process.CreateMessagePipe(&pipe_token);
- process.Connect(base::GetCurrentProcessHandle(),
- ConnectionParams(pair.PassServerHandle()));
-
- // Close the remote end, simulating child death before the child connects to
- // the reserved port.
- ignore_result(pair.PassClientHandle());
-
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(parent_mp.get().value(),
- MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-TEST_F(EmbedderTest, PipeSetup_LaunchFailure) {
- PlatformChannelPair pair;
-
- auto process = base::MakeUnique<PendingProcessConnection>();
- std::string pipe_token;
- ScopedMessagePipeHandle parent_mp = process->CreateMessagePipe(&pipe_token);
-
- // Ensure that if a PendingProcessConnection goes away before Connect() is
- // called, any message pipes associated with it detect peer closure.
- process.reset();
-
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(parent_mp.get().value(),
- MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-// The sequence of messages sent is:
-// server_mp client_mp mp0 mp1 mp2 mp3
-// 1. "hello"
-// 2. "world!"
-// 3. "FOO"
-// 4. "Bar"+mp1
-// 5. (close)
-// 6. (close)
-// 7. "baz"
-// 8. (closed)
-// 9. "quux"+mp2
-// 10. (close)
-// 11. (wait/cl.)
-// 12. (wait/cl.)
-
-#if !defined(OS_IOS)
-
-TEST_F(EmbedderTest, MultiprocessChannels) {
- RUN_CHILD_ON_PIPE(MultiprocessChannelsClient, server_mp)
- // 1. Write a message to |server_mp| (attaching nothing).
- WriteMessage(server_mp, "hello");
-
- // 2. Read a message from |server_mp|.
- EXPECT_EQ("world!", ReadMessage(server_mp));
-
- // 3. Create a new message pipe (endpoints |mp0| and |mp1|).
- MojoHandle mp0, mp1;
- CreateMessagePipe(&mp0, &mp1);
-
- // 4. Write something to |mp0|.
- WriteMessage(mp0, "FOO");
-
- // 5. Write a message to |server_mp|, attaching |mp1|.
- WriteMessageWithHandles(server_mp, "Bar", &mp1, 1);
- mp1 = MOJO_HANDLE_INVALID;
-
- // 6. Read a message from |mp0|, which should have |mp2| attached.
- MojoHandle mp2 = MOJO_HANDLE_INVALID;
- EXPECT_EQ("quux", ReadMessageWithHandles(mp0, &mp2, 1));
-
- // 7. Read a message from |mp2|.
- EXPECT_EQ("baz", ReadMessage(mp2));
-
- // 8. Close |mp0|.
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp0));
-
- // 9. Tell the client to quit.
- WriteMessage(server_mp, "quit");
-
- // 10. Wait on |mp2| (which should eventually fail) and then close it.
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(mp2, MOJO_HANDLE_SIGNAL_READABLE, &state));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp2));
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient, EmbedderTest,
- client_mp) {
- // 1. Read the first message from |client_mp|.
- EXPECT_EQ("hello", ReadMessage(client_mp));
-
- // 2. Write a message to |client_mp| (attaching nothing).
- WriteMessage(client_mp, "world!");
-
- // 4. Read a message from |client_mp|, which should have |mp1| attached.
- MojoHandle mp1;
- EXPECT_EQ("Bar", ReadMessageWithHandles(client_mp, &mp1, 1));
-
- // 5. Create a new message pipe (endpoints |mp2| and |mp3|).
- MojoHandle mp2, mp3;
- CreateMessagePipe(&mp2, &mp3);
-
- // 6. Write a message to |mp3|.
- WriteMessage(mp3, "baz");
-
- // 7. Close |mp3|.
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
-
- // 8. Write a message to |mp1|, attaching |mp2|.
- WriteMessageWithHandles(mp1, "quux", &mp2, 1);
- mp2 = MOJO_HANDLE_INVALID;
-
- // 9. Read a message from |mp1|.
- EXPECT_EQ("FOO", ReadMessage(mp1));
-
- EXPECT_EQ("quit", ReadMessage(client_mp));
-
- // 10. Wait on |mp1| (which should eventually fail) and then close it.
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &state));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1));
-}
-
-TEST_F(EmbedderTest, MultiprocessBaseSharedMemory) {
- RUN_CHILD_ON_PIPE(MultiprocessSharedMemoryClient, server_mp)
- // 1. Create a base::SharedMemory object and create a mojo shared buffer
- // from it.
- base::SharedMemoryCreateOptions options;
- options.size = 123;
- base::SharedMemory shared_memory;
- ASSERT_TRUE(shared_memory.Create(options));
- base::SharedMemoryHandle shm_handle = base::SharedMemory::DuplicateHandle(
- shared_memory.handle());
- MojoHandle sb1;
- ASSERT_EQ(MOJO_RESULT_OK,
- CreateSharedBufferWrapper(shm_handle, 123, false, &sb1));
-
- // 2. Map |sb1| and write something into it.
- char* buffer = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoMapBuffer(sb1, 0, 123, reinterpret_cast<void**>(&buffer), 0));
- ASSERT_TRUE(buffer);
- memcpy(buffer, kHelloWorld, sizeof(kHelloWorld));
-
- // 3. Duplicate |sb1| into |sb2| and pass to |server_mp|.
- MojoHandle sb2 = MOJO_HANDLE_INVALID;
- EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(sb1, 0, &sb2));
- EXPECT_NE(MOJO_HANDLE_INVALID, sb2);
- WriteMessageWithHandles(server_mp, "hello", &sb2, 1);
-
- // 4. Read a message from |server_mp|.
- EXPECT_EQ("bye", ReadMessage(server_mp));
-
- // 5. Expect that the contents of the shared buffer have changed.
- EXPECT_EQ(kByeWorld, std::string(buffer));
-
- // 6. Map the original base::SharedMemory and expect it contains the
- // expected value.
- ASSERT_TRUE(shared_memory.Map(123));
- EXPECT_EQ(kByeWorld,
- std::string(static_cast<char*>(shared_memory.memory())));
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(sb1));
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient, EmbedderTest,
- client_mp) {
- // 1. Read the first message from |client_mp|, which should have |sb1| which
- // should be a shared buffer handle.
- MojoHandle sb1;
- EXPECT_EQ("hello", ReadMessageWithHandles(client_mp, &sb1, 1));
-
- // 2. Map |sb1|.
- char* buffer = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoMapBuffer(sb1, 0, 123, reinterpret_cast<void**>(&buffer), 0));
- ASSERT_TRUE(buffer);
-
- // 3. Ensure |buffer| contains the values we expect.
- EXPECT_EQ(kHelloWorld, std::string(buffer));
-
- // 4. Write into |buffer| and send a message back.
- memcpy(buffer, kByeWorld, sizeof(kByeWorld));
- WriteMessage(client_mp, "bye");
-
- // 5. Extract the shared memory handle and ensure we can map it and read the
- // contents.
- base::SharedMemoryHandle shm_handle;
- ASSERT_EQ(MOJO_RESULT_OK,
- PassSharedMemoryHandle(sb1, &shm_handle, nullptr, nullptr));
- base::SharedMemory shared_memory(shm_handle, false);
- ASSERT_TRUE(shared_memory.Map(123));
- EXPECT_NE(buffer, shared_memory.memory());
- EXPECT_EQ(kByeWorld, std::string(static_cast<char*>(shared_memory.memory())));
-
- // 6. Close |sb1|. Should fail because |PassSharedMemoryHandle()| should have
- // closed the handle.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(sb1));
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-TEST_F(EmbedderTest, MultiprocessMachSharedMemory) {
- RUN_CHILD_ON_PIPE(MultiprocessSharedMemoryClient, server_mp)
- // 1. Create a Mach base::SharedMemory object and create a mojo shared
- // buffer from it.
- base::SharedMemoryCreateOptions options;
- options.size = 123;
- base::SharedMemory shared_memory;
- ASSERT_TRUE(shared_memory.Create(options));
- base::SharedMemoryHandle shm_handle = base::SharedMemory::DuplicateHandle(
- shared_memory.handle());
- MojoHandle sb1;
- ASSERT_EQ(MOJO_RESULT_OK,
- CreateSharedBufferWrapper(shm_handle, 123, false, &sb1));
-
- // 2. Map |sb1| and write something into it.
- char* buffer = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoMapBuffer(sb1, 0, 123, reinterpret_cast<void**>(&buffer), 0));
- ASSERT_TRUE(buffer);
- memcpy(buffer, kHelloWorld, sizeof(kHelloWorld));
-
- // 3. Duplicate |sb1| into |sb2| and pass to |server_mp|.
- MojoHandle sb2 = MOJO_HANDLE_INVALID;
- EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(sb1, 0, &sb2));
- EXPECT_NE(MOJO_HANDLE_INVALID, sb2);
- WriteMessageWithHandles(server_mp, "hello", &sb2, 1);
-
- // 4. Read a message from |server_mp|.
- EXPECT_EQ("bye", ReadMessage(server_mp));
-
- // 5. Expect that the contents of the shared buffer have changed.
- EXPECT_EQ(kByeWorld, std::string(buffer));
-
- // 6. Map the original base::SharedMemory and expect it contains the
- // expected value.
- ASSERT_TRUE(shared_memory.Map(123));
- EXPECT_EQ(kByeWorld,
- std::string(static_cast<char*>(shared_memory.memory())));
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(sb1));
- END_CHILD()
-}
-
-enum class HandleType {
- POSIX,
- MACH,
- MACH_NULL,
-};
-
-const HandleType kTestHandleTypes[] = {
- HandleType::MACH,
- HandleType::MACH_NULL,
- HandleType::POSIX,
- HandleType::POSIX,
- HandleType::MACH,
-};
-
-// Test that we can mix file descriptors and mach port handles.
-TEST_F(EmbedderTest, MultiprocessMixMachAndFds) {
- const size_t kShmSize = 1234;
- RUN_CHILD_ON_PIPE(MultiprocessMixMachAndFdsClient, server_mp)
- // 1. Create fds or Mach objects and mojo handles from them.
- MojoHandle platform_handles[arraysize(kTestHandleTypes)];
- for (size_t i = 0; i < arraysize(kTestHandleTypes); i++) {
- const auto type = kTestHandleTypes[i];
- ScopedPlatformHandle scoped_handle;
- if (type == HandleType::POSIX) {
- // The easiest source of fds is opening /dev/null.
- base::File file(base::FilePath("/dev/null"),
- base::File::FLAG_OPEN | base::File::FLAG_WRITE);
- ASSERT_TRUE(file.IsValid());
- scoped_handle.reset(PlatformHandle(file.TakePlatformFile()));
- EXPECT_EQ(PlatformHandle::Type::POSIX, scoped_handle.get().type);
- } else if (type == HandleType::MACH_NULL) {
- scoped_handle.reset(PlatformHandle(
- static_cast<mach_port_t>(MACH_PORT_NULL)));
- EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
- } else {
- base::SharedMemoryCreateOptions options;
- options.size = kShmSize;
- base::SharedMemory shared_memory;
- ASSERT_TRUE(shared_memory.Create(options));
- base::SharedMemoryHandle shm_handle =
- base::SharedMemory::DuplicateHandle(shared_memory.handle());
- scoped_handle.reset(PlatformHandle(shm_handle.GetMemoryObject()));
- EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
- }
- ASSERT_EQ(MOJO_RESULT_OK, CreatePlatformHandleWrapper(
- std::move(scoped_handle), platform_handles + i));
- }
-
- // 2. Send all the handles to the child.
- WriteMessageWithHandles(server_mp, "hello", platform_handles,
- arraysize(kTestHandleTypes));
-
- // 3. Read a message from |server_mp|.
- EXPECT_EQ("bye", ReadMessage(server_mp));
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient, EmbedderTest,
- client_mp) {
- const int kNumHandles = arraysize(kTestHandleTypes);
- MojoHandle platform_handles[kNumHandles];
-
- // 1. Read from |client_mp|, which should have a message containing
- // |kNumHandles| handles.
- EXPECT_EQ("hello",
- ReadMessageWithHandles(client_mp, platform_handles, kNumHandles));
-
- // 2. Extract each handle, and verify the type.
- for (int i = 0; i < kNumHandles; i++) {
- const auto type = kTestHandleTypes[i];
- ScopedPlatformHandle scoped_handle;
- ASSERT_EQ(MOJO_RESULT_OK,
- PassWrappedPlatformHandle(platform_handles[i], &scoped_handle));
- if (type == HandleType::POSIX) {
- EXPECT_NE(0, scoped_handle.get().handle);
- EXPECT_EQ(PlatformHandle::Type::POSIX, scoped_handle.get().type);
- } else if (type == HandleType::MACH_NULL) {
- EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
- scoped_handle.get().port);
- EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
- } else {
- EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
- scoped_handle.get().port);
- EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
- }
- }
-
- // 3. Say bye!
- WriteMessage(client_mp, "bye");
-}
-
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
-
-// TODO(vtl): Test immediate write & close.
-// TODO(vtl): Test broken-connection cases.
-
-#endif // !defined(OS_IOS)
-
-NamedPlatformHandle GenerateChannelName() {
-#if defined(OS_POSIX)
- base::FilePath temp_dir;
- CHECK(base::PathService::Get(base::DIR_TEMP, &temp_dir));
- return NamedPlatformHandle(
- temp_dir.AppendASCII(GenerateRandomToken()).value());
-#else
- return NamedPlatformHandle(GenerateRandomToken());
-#endif
-}
-
-void CreateClientHandleOnIoThread(const NamedPlatformHandle& named_handle,
- ScopedPlatformHandle* output) {
- *output = CreateClientHandle(named_handle);
-}
-
-TEST_F(EmbedderTest, ClosePendingPeerConnection) {
- NamedPlatformHandle named_handle = GenerateChannelName();
- std::string peer_token = GenerateRandomToken();
- ScopedMessagePipeHandle server_pipe =
- ConnectToPeerProcess(CreateServerHandle(named_handle), peer_token);
- ClosePeerConnection(peer_token);
- EXPECT_EQ(MOJO_RESULT_OK,
- Wait(server_pipe.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED));
- base::MessageLoop message_loop;
- base::RunLoop run_loop;
- ScopedPlatformHandle client_handle;
- // Closing the channel involves posting a task to the IO thread to do the
- // work. By the time the local message pipe has been observerd as closed,
- // that task will have been posted. Therefore, a task to create the client
- // connection should be handled after the channel is closed.
- GetIOTaskRunner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&CreateClientHandleOnIoThread, named_handle, &client_handle),
- run_loop.QuitClosure());
- run_loop.Run();
- EXPECT_FALSE(client_handle.is_valid());
-}
-
-#if !defined(OS_IOS)
-
-TEST_F(EmbedderTest, ClosePipeToConnectedPeer) {
- set_launch_type(LaunchType::PEER);
- auto& controller = StartClient("ClosePipeToConnectedPeerClient");
- MojoHandle server_mp = controller.pipe();
- // 1. Write a message to |server_mp| (attaching nothing).
- WriteMessage(server_mp, "hello");
-
- // 2. Read a message from |server_mp|.
- EXPECT_EQ("world!", ReadMessage(server_mp));
-
- controller.ClosePeerConnection();
-
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(server_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- EXPECT_EQ(0, controller.WaitForShutdown());
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ClosePipeToConnectedPeerClient, EmbedderTest,
- client_mp) {
- // 1. Read the first message from |client_mp|.
- EXPECT_EQ("hello", ReadMessage(client_mp));
-
- // 2. Write a message to |client_mp| (attaching nothing).
- WriteMessage(client_mp, "world!");
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(client_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-TEST_F(EmbedderTest, ClosePipeToConnectingPeer) {
- set_launch_type(LaunchType::PEER);
- auto& controller = StartClient("ClosePipeToConnectingPeerClient");
- controller.ClosePeerConnection();
-
- MojoHandle server_mp = controller.pipe();
-
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(server_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- EXPECT_EQ(0, controller.WaitForShutdown());
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ClosePipeToConnectingPeerClient, EmbedderTest,
- client_mp) {
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(client_mp, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-#endif // !defined(OS_IOS)
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/entrypoints.cc b/mojo/edk/embedder/entrypoints.cc
deleted file mode 100644
index 9081368..0000000
--- a/mojo/edk/embedder/entrypoints.cc
+++ /dev/null
@@ -1,283 +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/entrypoints.h"
-
-#include <stdint.h>
-
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/public/c/system/buffer.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/functions.h"
-#include "mojo/public/c/system/message_pipe.h"
-#include "mojo/public/c/system/platform_handle.h"
-
-using mojo::edk::internal::g_core;
-
-// Definitions of the system functions.
-extern "C" {
-
-MojoTimeTicks MojoGetTimeTicksNowImpl() {
- return g_core->GetTimeTicksNow();
-}
-
-MojoResult MojoCloseImpl(MojoHandle handle) {
- return g_core->Close(handle);
-}
-
-MojoResult MojoQueryHandleSignalsStateImpl(
- MojoHandle handle,
- MojoHandleSignalsState* signals_state) {
- return g_core->QueryHandleSignalsState(handle, signals_state);
-}
-
-MojoResult MojoCreateWatcherImpl(MojoWatcherCallback callback,
- MojoHandle* watcher_handle) {
- return g_core->CreateWatcher(callback, watcher_handle);
-}
-
-MojoResult MojoArmWatcherImpl(MojoHandle watcher_handle,
- uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states) {
- return g_core->ArmWatcher(watcher_handle, num_ready_contexts, ready_contexts,
- ready_results, ready_signals_states);
-}
-
-MojoResult MojoWatchImpl(MojoHandle watcher_handle,
- MojoHandle handle,
- MojoHandleSignals signals,
- uintptr_t context) {
- return g_core->Watch(watcher_handle, handle, signals, context);
-}
-
-MojoResult MojoCancelWatchImpl(MojoHandle watcher_handle, uintptr_t context) {
- return g_core->CancelWatch(watcher_handle, context);
-}
-
-MojoResult MojoAllocMessageImpl(uint32_t num_bytes,
- const MojoHandle* handles,
- uint32_t num_handles,
- MojoAllocMessageFlags flags,
- MojoMessageHandle* message) {
- return g_core->AllocMessage(num_bytes, handles, num_handles, flags, message);
-}
-
-MojoResult MojoFreeMessageImpl(MojoMessageHandle message) {
- return g_core->FreeMessage(message);
-}
-
-MojoResult MojoGetMessageBufferImpl(MojoMessageHandle message, void** buffer) {
- return g_core->GetMessageBuffer(message, buffer);
-}
-
-MojoResult MojoCreateMessagePipeImpl(
- const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1) {
- return g_core->CreateMessagePipe(options, message_pipe_handle0,
- message_pipe_handle1);
-}
-
-MojoResult MojoWriteMessageImpl(MojoHandle message_pipe_handle,
- const void* bytes,
- uint32_t num_bytes,
- const MojoHandle* handles,
- uint32_t num_handles,
- MojoWriteMessageFlags flags) {
- return g_core->WriteMessage(message_pipe_handle, bytes, num_bytes, handles,
- num_handles, flags);
-}
-
-MojoResult MojoWriteMessageNewImpl(MojoHandle message_pipe_handle,
- MojoMessageHandle message,
- MojoWriteMessageFlags flags) {
- return g_core->WriteMessageNew(message_pipe_handle, message, flags);
-}
-
-MojoResult MojoReadMessageImpl(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags) {
- return g_core->ReadMessage(
- message_pipe_handle, bytes, num_bytes, handles, num_handles, flags);
-}
-
-MojoResult MojoReadMessageNewImpl(MojoHandle message_pipe_handle,
- MojoMessageHandle* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags) {
- return g_core->ReadMessageNew(
- message_pipe_handle, message, num_bytes, handles, num_handles, flags);
-}
-
-MojoResult MojoFuseMessagePipesImpl(MojoHandle handle0, MojoHandle handle1) {
- return g_core->FuseMessagePipes(handle0, handle1);
-}
-
-MojoResult MojoCreateDataPipeImpl(const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle) {
- return g_core->CreateDataPipe(options, data_pipe_producer_handle,
- data_pipe_consumer_handle);
-}
-
-MojoResult MojoWriteDataImpl(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_elements,
- MojoWriteDataFlags flags) {
- return g_core->WriteData(data_pipe_producer_handle, elements, num_elements,
- flags);
-}
-
-MojoResult MojoBeginWriteDataImpl(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_elements,
- MojoWriteDataFlags flags) {
- return g_core->BeginWriteData(data_pipe_producer_handle, buffer,
- buffer_num_elements, flags);
-}
-
-MojoResult MojoEndWriteDataImpl(MojoHandle data_pipe_producer_handle,
- uint32_t num_elements_written) {
- return g_core->EndWriteData(data_pipe_producer_handle, num_elements_written);
-}
-
-MojoResult MojoReadDataImpl(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_elements,
- MojoReadDataFlags flags) {
- return g_core->ReadData(data_pipe_consumer_handle, elements, num_elements,
- flags);
-}
-
-MojoResult MojoBeginReadDataImpl(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_elements,
- MojoReadDataFlags flags) {
- return g_core->BeginReadData(data_pipe_consumer_handle, buffer,
- buffer_num_elements, flags);
-}
-
-MojoResult MojoEndReadDataImpl(MojoHandle data_pipe_consumer_handle,
- uint32_t num_elements_read) {
- return g_core->EndReadData(data_pipe_consumer_handle, num_elements_read);
-}
-
-MojoResult MojoCreateSharedBufferImpl(
- const struct MojoCreateSharedBufferOptions* options,
- uint64_t num_bytes,
- MojoHandle* shared_buffer_handle) {
- return g_core->CreateSharedBuffer(options, num_bytes, shared_buffer_handle);
-}
-
-MojoResult MojoDuplicateBufferHandleImpl(
- MojoHandle buffer_handle,
- const struct MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle) {
- return g_core->DuplicateBufferHandle(buffer_handle, options,
- new_buffer_handle);
-}
-
-MojoResult MojoMapBufferImpl(MojoHandle buffer_handle,
- uint64_t offset,
- uint64_t num_bytes,
- void** buffer,
- MojoMapBufferFlags flags) {
- return g_core->MapBuffer(buffer_handle, offset, num_bytes, buffer, flags);
-}
-
-MojoResult MojoUnmapBufferImpl(void* buffer) {
- return g_core->UnmapBuffer(buffer);
-}
-
-MojoResult MojoWrapPlatformHandleImpl(const MojoPlatformHandle* platform_handle,
- MojoHandle* mojo_handle) {
- return g_core->WrapPlatformHandle(platform_handle, mojo_handle);
-}
-
-MojoResult MojoUnwrapPlatformHandleImpl(MojoHandle mojo_handle,
- MojoPlatformHandle* platform_handle) {
- return g_core->UnwrapPlatformHandle(mojo_handle, platform_handle);
-}
-
-MojoResult MojoWrapPlatformSharedBufferHandleImpl(
- const MojoPlatformHandle* platform_handle,
- size_t num_bytes,
- MojoPlatformSharedBufferHandleFlags flags,
- MojoHandle* mojo_handle) {
- return g_core->WrapPlatformSharedBufferHandle(platform_handle, num_bytes,
- flags, mojo_handle);
-}
-
-MojoResult MojoUnwrapPlatformSharedBufferHandleImpl(
- MojoHandle mojo_handle,
- MojoPlatformHandle* platform_handle,
- size_t* num_bytes,
- MojoPlatformSharedBufferHandleFlags* flags) {
- return g_core->UnwrapPlatformSharedBufferHandle(mojo_handle, platform_handle,
- num_bytes, flags);
-}
-
-MojoResult MojoNotifyBadMessageImpl(MojoMessageHandle message,
- const char* error,
- size_t error_num_bytes) {
- return g_core->NotifyBadMessage(message, error, error_num_bytes);
-}
-
-MojoResult MojoGetPropertyImpl(MojoPropertyType type, void* value) {
- return g_core->GetProperty(type, value);
-}
-
-} // extern "C"
-
-namespace mojo {
-namespace edk {
-
-MojoSystemThunks MakeSystemThunks() {
- MojoSystemThunks system_thunks = {sizeof(MojoSystemThunks),
- MojoGetTimeTicksNowImpl,
- MojoCloseImpl,
- MojoQueryHandleSignalsStateImpl,
- MojoCreateMessagePipeImpl,
- MojoWriteMessageImpl,
- MojoReadMessageImpl,
- MojoCreateDataPipeImpl,
- MojoWriteDataImpl,
- MojoBeginWriteDataImpl,
- MojoEndWriteDataImpl,
- MojoReadDataImpl,
- MojoBeginReadDataImpl,
- MojoEndReadDataImpl,
- MojoCreateSharedBufferImpl,
- MojoDuplicateBufferHandleImpl,
- MojoMapBufferImpl,
- MojoUnmapBufferImpl,
- MojoCreateWatcherImpl,
- MojoWatchImpl,
- MojoCancelWatchImpl,
- MojoArmWatcherImpl,
- MojoFuseMessagePipesImpl,
- MojoWriteMessageNewImpl,
- MojoReadMessageNewImpl,
- MojoAllocMessageImpl,
- MojoFreeMessageImpl,
- MojoGetMessageBufferImpl,
- MojoWrapPlatformHandleImpl,
- MojoUnwrapPlatformHandleImpl,
- MojoWrapPlatformSharedBufferHandleImpl,
- MojoUnwrapPlatformSharedBufferHandleImpl,
- MojoNotifyBadMessageImpl,
- MojoGetPropertyImpl};
- return system_thunks;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/entrypoints.h b/mojo/edk/embedder/entrypoints.h
deleted file mode 100644
index 8e448c1..0000000
--- a/mojo/edk/embedder/entrypoints.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_EMBEDDER_ENTRYPOINTS_H_
-#define MOJO_EDK_EMBEDDER_ENTRYPOINTS_H_
-
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/c/system/thunks.h"
-
-namespace mojo {
-namespace edk {
-
-// Creates a MojoSystemThunks struct populated with the EDK's implementation of
-// each function. This may be used by embedders to populate thunks for
-// application loading.
-MOJO_SYSTEM_IMPL_EXPORT MojoSystemThunks MakeSystemThunks();
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_ENTRYPOINTS_H_
diff --git a/mojo/edk/embedder/named_platform_channel_pair.h b/mojo/edk/embedder/named_platform_channel_pair.h
deleted file mode 100644
index 5a83ae3..0000000
--- a/mojo/edk/embedder/named_platform_channel_pair.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_EMBEDDER_NAMED_PLATFORM_CHANNEL_PAIR_H_
-#define MOJO_EDK_EMBEDDER_NAMED_PLATFORM_CHANNEL_PAIR_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace base {
-class CommandLine;
-}
-
-namespace mojo {
-namespace edk {
-
-// This is used to create a named bidirectional pipe to connect new child
-// processes. The resulting server handle should be passed to the EDK, and the
-// child end passed as a pipe name on the command line to the child process. The
-// child process can then retrieve the pipe name from the command line and
-// resolve it into a client handle.
-class MOJO_SYSTEM_IMPL_EXPORT NamedPlatformChannelPair {
- public:
- struct Options {
-#if defined(OS_WIN)
- // If non-empty, a security descriptor to use when creating the pipe. If
- // empty, a default security descriptor will be used. See
- // kDefaultSecurityDescriptor in named_platform_handle_utils_win.cc.
- base::string16 security_descriptor;
-#endif
- };
-
- NamedPlatformChannelPair(const Options& options = {});
- ~NamedPlatformChannelPair();
-
- // Note: It is NOT acceptable to use this handle as a generic pipe channel. It
- // MUST be passed to PendingProcessConnection::Connect() only.
- ScopedPlatformHandle PassServerHandle();
-
- // To be called in the child process, after the parent process called
- // |PrepareToPassClientHandleToChildProcess()| and launched the child (using
- // the provided data), to create a client handle connected to the server
- // handle (in the parent process).
- static ScopedPlatformHandle PassClientHandleFromParentProcess(
- const base::CommandLine& command_line);
-
- // Prepares to pass the client channel to a new child process, to be launched
- // using |LaunchProcess()| (from base/launch.h). Modifies |*command_line| and
- // |*handle_passing_info| as needed.
- // Note: For Windows, this method only works on Vista and later.
- void PrepareToPassClientHandleToChildProcess(
- base::CommandLine* command_line) const;
-
- const NamedPlatformHandle& handle() const { return pipe_handle_; }
-
- private:
- NamedPlatformHandle pipe_handle_;
- ScopedPlatformHandle server_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(NamedPlatformChannelPair);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_NAMED_PLATFORM_CHANNEL_PAIR_H_
diff --git a/mojo/edk/embedder/named_platform_channel_pair_win.cc b/mojo/edk/embedder/named_platform_channel_pair_win.cc
deleted file mode 100644
index 96589ff..0000000
--- a/mojo/edk/embedder/named_platform_channel_pair_win.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/embedder/named_platform_channel_pair.h"
-
-#include <windows.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/windows_version.h"
-#include "mojo/edk/embedder/named_platform_handle_utils.h"
-#include "mojo/edk/embedder/platform_handle.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-const char kMojoNamedPlatformChannelPipeSwitch[] =
- "mojo-named-platform-channel-pipe";
-
-std::wstring GeneratePipeName() {
- return base::StringPrintf(L"%u.%u.%I64u", GetCurrentProcessId(),
- GetCurrentThreadId(), base::RandUint64());
-}
-
-} // namespace
-
-NamedPlatformChannelPair::NamedPlatformChannelPair(
- const NamedPlatformChannelPair::Options& options)
- : pipe_handle_(GeneratePipeName()) {
- CreateServerHandleOptions server_handle_options;
- server_handle_options.security_descriptor = options.security_descriptor;
- server_handle_options.enforce_uniqueness = true;
- server_handle_ = CreateServerHandle(pipe_handle_, server_handle_options);
- PCHECK(server_handle_.is_valid());
-}
-
-NamedPlatformChannelPair::~NamedPlatformChannelPair() {}
-
-ScopedPlatformHandle NamedPlatformChannelPair::PassServerHandle() {
- return std::move(server_handle_);
-}
-
-// static
-ScopedPlatformHandle
-NamedPlatformChannelPair::PassClientHandleFromParentProcess(
- const base::CommandLine& command_line) {
- // In order to support passing the pipe name on the command line, the pipe
- // handle is lazily created from the pipe name when requested.
- NamedPlatformHandle handle(
- command_line.GetSwitchValueNative(kMojoNamedPlatformChannelPipeSwitch));
-
- if (!handle.is_valid())
- return ScopedPlatformHandle();
-
- return CreateClientHandle(handle);
-}
-
-void NamedPlatformChannelPair::PrepareToPassClientHandleToChildProcess(
- base::CommandLine* command_line) const {
- DCHECK(command_line);
-
- // 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(kMojoNamedPlatformChannelPipeSwitch))
- << "Child command line already has switch --"
- << kMojoNamedPlatformChannelPipeSwitch << "="
- << command_line->GetSwitchValueNative(
- kMojoNamedPlatformChannelPipeSwitch);
- // (Any existing switch won't actually be removed from the command line, but
- // the last one appended takes precedence.)
- command_line->AppendSwitchNative(kMojoNamedPlatformChannelPipeSwitch,
- pipe_handle_.name);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/named_platform_handle.h b/mojo/edk/embedder/named_platform_handle.h
deleted file mode 100644
index 15ca656..0000000
--- a/mojo/edk/embedder/named_platform_handle.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_H_
-#define MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_H_
-
-#include <string>
-
-#include "base/strings/string16.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-#if defined(OS_POSIX)
-struct MOJO_SYSTEM_IMPL_EXPORT NamedPlatformHandle {
- NamedPlatformHandle() {}
- explicit NamedPlatformHandle(const base::StringPiece& name)
- : name(name.as_string()) {}
-
- bool is_valid() const { return !name.empty(); }
-
- std::string name;
-};
-#elif defined(OS_WIN)
-struct MOJO_SYSTEM_IMPL_EXPORT NamedPlatformHandle {
- NamedPlatformHandle() {}
- explicit NamedPlatformHandle(const base::StringPiece& name)
- : name(base::UTF8ToUTF16(name)) {}
-
- explicit NamedPlatformHandle(const base::StringPiece16& name)
- : name(name.as_string()) {}
-
- bool is_valid() const { return !name.empty(); }
-
- base::string16 pipe_name() const { return L"\\\\.\\pipe\\mojo." + name; }
-
- base::string16 name;
-};
-#else
-#error "Platform not yet supported."
-#endif
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_H_
diff --git a/mojo/edk/embedder/named_platform_handle_utils.h b/mojo/edk/embedder/named_platform_handle_utils.h
deleted file mode 100644
index b767ea0..0000000
--- a/mojo/edk/embedder/named_platform_handle_utils.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_UTILS_H_
-#define MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_UTILS_H_
-
-#include "build/build_config.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-#if defined(OS_WIN)
-#include "base/strings/string16.h"
-#endif
-
-namespace mojo {
-namespace edk {
-
-struct NamedPlatformHandle;
-
-#if defined(OS_POSIX)
-
-// The maximum length of the name of a unix domain socket. The standard size on
-// linux is 108, mac is 104. To maintain consistency across platforms we
-// standardize on the smaller value.
-const size_t kMaxSocketNameLength = 104;
-
-#endif
-
-struct CreateServerHandleOptions {
-#if defined(OS_WIN)
- // If true, creating a server handle will fail if another pipe with the same
- // name exists.
- bool enforce_uniqueness = true;
-
- // If non-empty, a security descriptor to use when creating the pipe. If
- // empty, a default security descriptor will be used. See
- // kDefaultSecurityDescriptor in named_platform_handle_utils_win.cc.
- base::string16 security_descriptor;
-#endif
-};
-
-// Creates a client platform handle from |handle|. This may block until |handle|
-// is ready to receive connections.
-MOJO_SYSTEM_IMPL_EXPORT ScopedPlatformHandle
-CreateClientHandle(const NamedPlatformHandle& handle);
-
-// Creates a server platform handle from |handle|.
-MOJO_SYSTEM_IMPL_EXPORT ScopedPlatformHandle
-CreateServerHandle(const NamedPlatformHandle& handle,
- const CreateServerHandleOptions& options = {});
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_NAMED_PLATFORM_HANDLE_UTILS_H_
diff --git a/mojo/edk/embedder/named_platform_handle_utils_posix.cc b/mojo/edk/embedder/named_platform_handle_utils_posix.cc
deleted file mode 100644
index 056f4d6..0000000
--- a/mojo/edk/embedder/named_platform_handle_utils_posix.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/embedder/named_platform_handle_utils.h"
-
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-// This function fills in |unix_addr| with the appropriate data for the socket,
-// and sets |unix_addr_len| to the length of the data therein.
-// Returns true on success, or false on failure (typically because |handle.name|
-// violated the naming rules).
-bool MakeUnixAddr(const NamedPlatformHandle& handle,
- struct sockaddr_un* unix_addr,
- size_t* unix_addr_len) {
- DCHECK(unix_addr);
- DCHECK(unix_addr_len);
- DCHECK(handle.is_valid());
-
- // We reject handle.name.length() == kMaxSocketNameLength to make room for the
- // NUL terminator at the end of the string.
- if (handle.name.length() >= kMaxSocketNameLength) {
- LOG(ERROR) << "Socket name too long: " << handle.name;
- return false;
- }
-
- // Create unix_addr structure.
- memset(unix_addr, 0, sizeof(struct sockaddr_un));
- unix_addr->sun_family = AF_UNIX;
- strncpy(unix_addr->sun_path, handle.name.c_str(), kMaxSocketNameLength);
- *unix_addr_len =
- offsetof(struct sockaddr_un, sun_path) + handle.name.length();
- return true;
-}
-
-// This function creates a unix domain socket, and set it as non-blocking.
-// If successful, this returns a ScopedPlatformHandle containing the socket.
-// Otherwise, this returns an invalid ScopedPlatformHandle.
-ScopedPlatformHandle CreateUnixDomainSocket(bool needs_connection) {
- // Create the unix domain socket.
- PlatformHandle socket_handle(socket(AF_UNIX, SOCK_STREAM, 0));
- socket_handle.needs_connection = needs_connection;
- ScopedPlatformHandle handle(socket_handle);
- if (!handle.is_valid()) {
- PLOG(ERROR) << "Failed to create AF_UNIX socket.";
- return ScopedPlatformHandle();
- }
-
- // Now set it as non-blocking.
- if (!base::SetNonBlocking(handle.get().handle)) {
- PLOG(ERROR) << "base::SetNonBlocking() failed " << handle.get().handle;
- return ScopedPlatformHandle();
- }
- return handle;
-}
-
-} // namespace
-
-ScopedPlatformHandle CreateClientHandle(
- const NamedPlatformHandle& named_handle) {
- if (!named_handle.is_valid())
- return ScopedPlatformHandle();
-
- struct sockaddr_un unix_addr;
- size_t unix_addr_len;
- if (!MakeUnixAddr(named_handle, &unix_addr, &unix_addr_len))
- return ScopedPlatformHandle();
-
- ScopedPlatformHandle handle = CreateUnixDomainSocket(false);
- if (!handle.is_valid())
- return ScopedPlatformHandle();
-
- if (HANDLE_EINTR(connect(handle.get().handle,
- reinterpret_cast<sockaddr*>(&unix_addr),
- unix_addr_len)) < 0) {
- PLOG(ERROR) << "connect " << named_handle.name;
- return ScopedPlatformHandle();
- }
-
- return handle;
-}
-
-ScopedPlatformHandle CreateServerHandle(
- const NamedPlatformHandle& named_handle,
- const CreateServerHandleOptions& options) {
- if (!named_handle.is_valid())
- return ScopedPlatformHandle();
-
- // Make sure the path we need exists.
- base::FilePath socket_dir = base::FilePath(named_handle.name).DirName();
- if (!base::CreateDirectory(socket_dir)) {
- LOG(ERROR) << "Couldn't create directory: " << socket_dir.value();
- return ScopedPlatformHandle();
- }
-
- // Delete any old FS instances.
- if (unlink(named_handle.name.c_str()) < 0 && errno != ENOENT) {
- PLOG(ERROR) << "unlink " << named_handle.name;
- return ScopedPlatformHandle();
- }
-
- struct sockaddr_un unix_addr;
- size_t unix_addr_len;
- if (!MakeUnixAddr(named_handle, &unix_addr, &unix_addr_len))
- return ScopedPlatformHandle();
-
- ScopedPlatformHandle handle = CreateUnixDomainSocket(true);
- if (!handle.is_valid())
- return ScopedPlatformHandle();
-
- // Bind the socket.
- if (bind(handle.get().handle, reinterpret_cast<const sockaddr*>(&unix_addr),
- unix_addr_len) < 0) {
- PLOG(ERROR) << "bind " << named_handle.name;
- return ScopedPlatformHandle();
- }
-
- // Start listening on the socket.
- if (listen(handle.get().handle, SOMAXCONN) < 0) {
- PLOG(ERROR) << "listen " << named_handle.name;
- unlink(named_handle.name.c_str());
- return ScopedPlatformHandle();
- }
- return handle;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/named_platform_handle_utils_win.cc b/mojo/edk/embedder/named_platform_handle_utils_win.cc
deleted file mode 100644
index a145847..0000000
--- a/mojo/edk/embedder/named_platform_handle_utils_win.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/embedder/named_platform_handle_utils.h"
-
-#include <sddl.h>
-#include <windows.h>
-
-#include <memory>
-
-#include "base/logging.h"
-#include "base/win/windows_version.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-// A DACL to grant:
-// GA = Generic All
-// access to:
-// SY = LOCAL_SYSTEM
-// BA = BUILTIN_ADMINISTRATORS
-// OW = OWNER_RIGHTS
-constexpr base::char16 kDefaultSecurityDescriptor[] =
- L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;OW)";
-
-} // namespace
-
-ScopedPlatformHandle CreateClientHandle(
- const NamedPlatformHandle& named_handle) {
- if (!named_handle.is_valid())
- return ScopedPlatformHandle();
-
- base::string16 pipe_name = named_handle.pipe_name();
-
- // Note: This may block.
- if (!WaitNamedPipeW(pipe_name.c_str(), NMPWAIT_USE_DEFAULT_WAIT))
- return ScopedPlatformHandle();
-
- const DWORD kDesiredAccess = GENERIC_READ | GENERIC_WRITE;
- // The SECURITY_ANONYMOUS flag means that the server side cannot impersonate
- // the client.
- const DWORD kFlags =
- SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | FILE_FLAG_OVERLAPPED;
- ScopedPlatformHandle handle(
- PlatformHandle(CreateFileW(pipe_name.c_str(), kDesiredAccess,
- 0, // No sharing.
- nullptr, OPEN_EXISTING, kFlags,
- nullptr))); // No template file.
- // The server may have stopped accepting a connection between the
- // WaitNamedPipe() and CreateFile(). If this occurs, an invalid handle is
- // returned.
- DPLOG_IF(ERROR, !handle.is_valid())
- << "Named pipe " << named_handle.pipe_name()
- << " could not be opened after WaitNamedPipe succeeded";
- return handle;
-}
-
-ScopedPlatformHandle CreateServerHandle(
- const NamedPlatformHandle& named_handle,
- const CreateServerHandleOptions& options) {
- if (!named_handle.is_valid())
- return ScopedPlatformHandle();
-
- PSECURITY_DESCRIPTOR security_desc = nullptr;
- ULONG security_desc_len = 0;
- PCHECK(ConvertStringSecurityDescriptorToSecurityDescriptor(
- options.security_descriptor.empty() ? kDefaultSecurityDescriptor
- : options.security_descriptor.c_str(),
- SDDL_REVISION_1, &security_desc, &security_desc_len));
- std::unique_ptr<void, decltype(::LocalFree)*> p(security_desc, ::LocalFree);
- SECURITY_ATTRIBUTES security_attributes = {sizeof(SECURITY_ATTRIBUTES),
- security_desc, FALSE};
-
- const DWORD kOpenMode = options.enforce_uniqueness
- ? PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
- FILE_FLAG_FIRST_PIPE_INSTANCE
- : PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED;
- const DWORD kPipeMode =
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_REJECT_REMOTE_CLIENTS;
- PlatformHandle handle(
- CreateNamedPipeW(named_handle.pipe_name().c_str(), kOpenMode, kPipeMode,
- options.enforce_uniqueness ? 1 : 255, // Max instances.
- 4096, // Out buffer size.
- 4096, // In buffer size.
- 5000, // Timeout in milliseconds.
- &security_attributes));
- handle.needs_connection = true;
- return ScopedPlatformHandle(handle);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/pending_process_connection.cc b/mojo/edk/embedder/pending_process_connection.cc
deleted file mode 100644
index d6be76e..0000000
--- a/mojo/edk/embedder/pending_process_connection.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2017 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/pending_process_connection.h"
-
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/core.h"
-
-namespace mojo {
-namespace edk {
-
-PendingProcessConnection::PendingProcessConnection()
- : process_token_(GenerateRandomToken()) {
- DCHECK(internal::g_core);
-}
-
-PendingProcessConnection::~PendingProcessConnection() {
- if (has_message_pipes_ && !connected_) {
- DCHECK(internal::g_core);
- internal::g_core->ChildLaunchFailed(process_token_);
- }
-}
-
-ScopedMessagePipeHandle PendingProcessConnection::CreateMessagePipe(
- std::string* token) {
- has_message_pipes_ = true;
- DCHECK(internal::g_core);
- *token = GenerateRandomToken();
- return internal::g_core->CreateParentMessagePipe(*token, process_token_);
-}
-
-void PendingProcessConnection::Connect(
- base::ProcessHandle process,
- ConnectionParams connection_params,
- const ProcessErrorCallback& error_callback) {
- // It's now safe to avoid cleanup in the destructor, as the lifetime of any
- // associated resources is effectively bound to the |channel| passed to
- // AddChild() below.
- DCHECK(!connected_);
- connected_ = true;
-
- DCHECK(internal::g_core);
- internal::g_core->AddChild(process, std::move(connection_params),
- process_token_, error_callback);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/pending_process_connection.h b/mojo/edk/embedder/pending_process_connection.h
deleted file mode 100644
index ca18227..0000000
--- a/mojo/edk/embedder/pending_process_connection.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2017 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_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
-#define MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/process/process_handle.h"
-#include "mojo/edk/embedder/connection_params.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-
-namespace mojo {
-namespace edk {
-
-using ProcessErrorCallback = base::Callback<void(const std::string& error)>;
-
-// Represents a potential connection to an external process. Use this object
-// to make other processes reachable from this one via Mojo IPC. Typical usage
-// might look something like:
-//
-// PendingProcessConnection connection;
-//
-// std::string pipe_token;
-// ScopedMessagePipeHandle pipe = connection.CreateMessagePipe(&pipe_token);
-//
-// // New pipes to the process are fully functional and can be used right
-// // away, even if the process doesn't exist yet.
-// GoDoSomethingInteresting(std::move(pipe));
-//
-// ScopedPlatformChannelPair channel;
-//
-// // Give the pipe token to the child process via command-line.
-// child_command_line.AppendSwitchASCII("yer-pipe", pipe_token);
-//
-// // Magic child process launcher which gives one end of the pipe to the
-// // new process.
-// LaunchProcess(child_command_line, channel.PassClientHandle());
-//
-// // Some time later...
-// connection.Connect(new_process, channel.PassServerHandle());
-//
-// If at any point during the above process, |connection| is destroyed before
-// Connect() can be called, |pipe| will imminently behave as if its peer has
-// been closed.
-//
-// Otherwise, if the remote process in this example eventually calls:
-//
-// mojo::edk::SetParentPipeHandle(std::move(client_channel_handle));
-//
-// std::string token = command_line.GetSwitchValueASCII("yer-pipe");
-// ScopedMessagePipeHandle pipe = mojo::edk::CreateChildMessagePipe(token);
-//
-// it will be connected to this process, and its |pipe| will be connected to
-// this process's |pipe|.
-//
-// If the remote process exits or otherwise closes its client channel handle
-// before calling CreateChildMessagePipe for a given message pipe token,
-// this process's end of the corresponding message pipe will imminently behave
-// as if its peer has been closed.
-//
-class MOJO_SYSTEM_IMPL_EXPORT PendingProcessConnection {
- public:
- PendingProcessConnection();
- ~PendingProcessConnection();
-
- // Creates a message pipe associated with a new globally unique string value
- // which will be placed in |*token|.
- //
- // The other end of the new pipe is obtainable in the remote process (or in
- // this process, to facilitate "single-process mode" in some applications) by
- // passing the new |*token| value to mojo::edk::CreateChildMessagePipe. It's
- // the caller's responsibility to communicate the value of |*token| to the
- // remote process by any means available, e.g. a command-line argument on
- // process launch, or some other out-of-band communication channel for an
- // existing process.
- //
- // NOTES: This may be called any number of times to create multiple message
- // pipes to the same remote process. This call ALWAYS succeeds, returning
- // a valid message pipe handle and populating |*token| with a new unique
- // string value.
- ScopedMessagePipeHandle CreateMessagePipe(std::string* token);
-
- // Connects to the process. This must be called at most once, with the process
- // handle in |process|.
- //
- // |connection_param| contains the platform handle of an OS pipe which can be
- // used to communicate with the connected process. The other end of that pipe
- // must ultimately be passed to mojo::edk::SetParentPipeHandle in the remote
- // process, and getting that end of the pipe into the other process is the
- // embedder's responsibility.
- //
- // If this method is not called by the time the PendingProcessConnection is
- // destroyed, it's assumed that the process is unavailable (e.g. process
- // launch failed or the process has otherwise been terminated early), and
- // any associated resources, such as remote endpoints of messages pipes
- // created by CreateMessagePipe above) will be cleaned up at that time.
- void Connect(
- base::ProcessHandle process,
- ConnectionParams connection_params,
- const ProcessErrorCallback& error_callback = ProcessErrorCallback());
-
- private:
- // A GUID representing a potential new process to be connected to this one.
- const std::string process_token_;
-
- // Indicates whether this object has been used to create new message pipes.
- bool has_message_pipes_ = false;
-
- // Indicates whether Connect() has been called yet.
- bool connected_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(PendingProcessConnection);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
diff --git a/mojo/edk/embedder/platform_channel_pair.cc b/mojo/edk/embedder/platform_channel_pair.cc
deleted file mode 100644
index ee1905a..0000000
--- a/mojo/edk/embedder/platform_channel_pair.cc
+++ /dev/null
@@ -1,34 +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 <utility>
-
-#include "base/logging.h"
-
-namespace mojo {
-namespace edk {
-
-const char PlatformChannelPair::kMojoPlatformChannelHandleSwitch[] =
- "mojo-platform-channel-handle";
-
-PlatformChannelPair::~PlatformChannelPair() {
-}
-
-ScopedPlatformHandle PlatformChannelPair::PassServerHandle() {
- return std::move(server_handle_);
-}
-
-ScopedPlatformHandle PlatformChannelPair::PassClientHandle() {
- return std::move(client_handle_);
-}
-
-void PlatformChannelPair::ChildProcessLaunched() {
- DCHECK(client_handle_.is_valid());
- client_handle_.reset();
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_channel_pair.h b/mojo/edk/embedder/platform_channel_pair.h
deleted file mode 100644
index 9c93f76..0000000
--- a/mojo/edk/embedder/platform_channel_pair.h
+++ /dev/null
@@ -1,106 +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_EMBEDDER_PLATFORM_CHANNEL_PAIR_H_
-#define MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_PAIR_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/process/launch.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace base {
-class CommandLine;
-}
-
-namespace mojo {
-namespace edk {
-
-// It would be nice to refactor base/process/launch.h to have a more platform-
-// independent way of representing handles that are passed to child processes.
-#if defined(OS_WIN)
-using HandlePassingInformation = base::HandlesToInheritVector;
-#elif defined(OS_POSIX)
-using HandlePassingInformation = base::FileHandleMappingVector;
-#else
-#error "Unsupported."
-#endif
-
-// This is used to create a pair of |PlatformHandle|s that are connected by a
-// suitable (platform-specific) bidirectional "pipe" (e.g., socket on POSIX,
-// named pipe on Windows). The resulting handles can then be used in the same
-// process (e.g., in tests) or between processes. (The "server" handle is the
-// one that will be used in the process that created the pair, whereas the
-// "client" handle is the one that will be used in a different process.)
-//
-// This class provides facilities for passing the client handle to a child
-// process. The parent should call |PrepareToPassClientHandlelToChildProcess()|
-// to get the data needed to do this, spawn the child using that data, and then
-// call |ChildProcessLaunched()|. Note that on Windows this facility (will) only
-// work on Vista and later (TODO(vtl)).
-//
-// Note: |PlatformChannelPair()|, |PassClientHandleFromParentProcess()| and
-// |PrepareToPassClientHandleToChildProcess()| have platform-specific
-// 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|.
-class MOJO_SYSTEM_IMPL_EXPORT PlatformChannelPair {
- public:
- static const char kMojoPlatformChannelHandleSwitch[];
-
- // If |client_is_blocking| is true, then the client handle only supports
- // blocking reads and writes. The default is nonblocking.
- PlatformChannelPair(bool client_is_blocking = false);
- ~PlatformChannelPair();
-
- ScopedPlatformHandle PassServerHandle();
-
- // For in-process use (e.g., in tests or to pass over another channel).
- ScopedPlatformHandle PassClientHandle();
-
- // To be called in the child process, after the parent process called
- // |PrepareToPassClientHandleToChildProcess()| and launched the child (using
- // the provided data), to create a client handle connected to the server
- // handle (in the parent process).
- // TODO(jcivelli): remove the command_line param. http://crbug.com/670106
- static ScopedPlatformHandle PassClientHandleFromParentProcess(
- const base::CommandLine& command_line);
-
- // Like above, but gets the handle from the passed in string.
- static ScopedPlatformHandle PassClientHandleFromParentProcessFromString(
- const std::string& value);
-
- // Prepares to pass the client channel to a new child process, to be launched
- // using |LaunchProcess()| (from base/launch.h). Modifies |*command_line| and
- // |*handle_passing_info| as needed.
- // Note: For Windows, this method only works on Vista and later.
- void PrepareToPassClientHandleToChildProcess(
- base::CommandLine* command_line,
- HandlePassingInformation* handle_passing_info) const;
-
- // Like above, but returns a string instead of changing the command line.
- std::string PrepareToPassClientHandleToChildProcessAsString(
- HandlePassingInformation* handle_passing_info) const;
-
- // To be called once the child process has been successfully launched, to do
- // any cleanup necessary.
- void ChildProcessLaunched();
-
- private:
- ScopedPlatformHandle server_handle_;
- ScopedPlatformHandle client_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformChannelPair);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_PAIR_H_
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 fe9f8f5..0000000
--- a/mojo/edk/embedder/platform_channel_pair_posix.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/embedder/platform_channel_pair.h"
-
-#include <fcntl.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <limits>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/posix/global_descriptors.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/platform_handle.h"
-
-#if !defined(OS_NACL_SFI)
-#include <sys/socket.h>
-#else
-#include "native_client/src/public/imc_syscalls.h"
-#endif
-
-#if !defined(SO_PEEK_OFF)
-#define SO_PEEK_OFF 42
-#endif
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-#if defined(OS_ANDROID) || defined(__ANDROID__)
-enum {
- // Leave room for any other descriptors defined in content for example.
- // TODO(jcivelli): consider changing base::GlobalDescriptors to generate a
- // key when setting the file descriptor (http://crbug.com/676442).
- kAndroidClientHandleDescriptor =
- base::GlobalDescriptors::kBaseDescriptor + 10000,
-};
-#else
-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;
-}
-#endif
-
-} // namespace
-
-PlatformChannelPair::PlatformChannelPair(bool client_is_blocking) {
- // Create the Unix domain socket.
- int fds[2];
- // TODO(vtl): Maybe fail gracefully if |socketpair()| fails.
-
-#if defined(OS_NACL_SFI)
- PCHECK(imc_socketpair(fds) == 0);
-#else
- PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
-
- // Set the ends to nonblocking.
- PCHECK(fcntl(fds[0], F_SETFL, O_NONBLOCK) == 0);
- if (!client_is_blocking)
- 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)
-#endif // defined(OS_NACL_SFI)
-
- 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);
- return PassClientHandleFromParentProcessFromString(client_fd_string);
-}
-
-ScopedPlatformHandle
-PlatformChannelPair::PassClientHandleFromParentProcessFromString(
- const std::string& value) {
- int client_fd = -1;
-#if defined(OS_ANDROID) || defined(__ANDROID__)
- base::GlobalDescriptors::Key key = -1;
- if (value.empty() || !base::StringToUint(value, &key)) {
- LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
- return ScopedPlatformHandle();
- }
- client_fd = base::GlobalDescriptors::GetInstance()->Get(key);
-#else
- if (value.empty() ||
- !base::StringToInt(value, &client_fd) ||
- client_fd < base::GlobalDescriptors::kBaseDescriptor) {
- LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
- return ScopedPlatformHandle();
- }
-#endif
- return ScopedPlatformHandle(PlatformHandle(client_fd));
-}
-
-void PlatformChannelPair::PrepareToPassClientHandleToChildProcess(
- base::CommandLine* command_line,
- base::FileHandleMappingVector* handle_passing_info) const {
- DCHECK(command_line);
-
- // 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,
- PrepareToPassClientHandleToChildProcessAsString(handle_passing_info));
-}
-
-std::string
-PlatformChannelPair::PrepareToPassClientHandleToChildProcessAsString(
- HandlePassingInformation* handle_passing_info) const {
-#if defined(OS_ANDROID) || defined(__ANDROID__)
- int fd = client_handle_.get().handle;
- handle_passing_info->push_back(
- std::pair<int, int>(fd, kAndroidClientHandleDescriptor));
- return base::UintToString(kAndroidClientHandleDescriptor);
-#else
- DCHECK(handle_passing_info);
- // This is an arbitrary sanity check. (Note that this guarantees that the loop
- // below will terminate sanely.)
- CHECK_LT(handle_passing_info->size(), 1000u);
-
- DCHECK(client_handle_.is_valid());
-
- // Find a suitable FD to map our client handle to in the child process.
- // This has quadratic time complexity in the size of |*handle_passing_info|,
- // but |*handle_passing_info| should be very small (usually/often empty).
- int target_fd = base::GlobalDescriptors::kBaseDescriptor;
- while (IsTargetDescriptorUsed(*handle_passing_info, target_fd))
- target_fd++;
-
- handle_passing_info->push_back(
- std::pair<int, int>(client_handle_.get().handle, target_fd));
- return base::IntToString(target_fd);
-#endif
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc b/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc
deleted file mode 100644
index a3fd275..0000000
--- a/mojo/edk/embedder/platform_channel_pair_posix_unittest.cc
+++ /dev/null
@@ -1,261 +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 <errno.h>
-#include <poll.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <deque>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "mojo/edk/embedder/platform_channel_utils_posix.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/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-void WaitReadable(PlatformHandle h) {
- struct pollfd pfds = {};
- pfds.fd = h.handle;
- pfds.events = POLLIN;
- CHECK_EQ(poll(&pfds, 1, -1), 1);
-}
-
-class PlatformChannelPairPosixTest : public testing::Test {
- public:
- PlatformChannelPairPosixTest() {}
- ~PlatformChannelPairPosixTest() override {}
-
- void SetUp() override {
- // Make sure |SIGPIPE| isn't being ignored.
- struct sigaction action = {};
- action.sa_handler = SIG_DFL;
- ASSERT_EQ(0, sigaction(SIGPIPE, &action, &old_action_));
- }
-
- void TearDown() override {
- // Restore the |SIGPIPE| handler.
- ASSERT_EQ(0, sigaction(SIGPIPE, &old_action_, nullptr));
- }
-
- private:
- struct sigaction old_action_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairPosixTest);
-};
-
-TEST_F(PlatformChannelPairPosixTest, NoSigPipe) {
- PlatformChannelPair channel_pair;
- ScopedPlatformHandle server_handle = channel_pair.PassServerHandle();
- ScopedPlatformHandle client_handle = channel_pair.PassClientHandle();
-
- // Write to the client.
- static const char kHello[] = "hello";
- EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
- write(client_handle.get().handle, kHello, sizeof(kHello)));
-
- // Close the client.
- client_handle.reset();
-
- // Read from the server; this should be okay.
- char buffer[100] = {};
- EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
- read(server_handle.get().handle, buffer, sizeof(buffer)));
- EXPECT_STREQ(kHello, buffer);
-
- // Try reading again.
- ssize_t result = read(server_handle.get().handle, buffer, sizeof(buffer));
- // We should probably get zero (for "end of file"), but -1 would also be okay.
- EXPECT_TRUE(result == 0 || result == -1);
- if (result == -1)
- PLOG(WARNING) << "read (expected 0 for EOF)";
-
- // Test our replacement for |write()|/|send()|.
- result = PlatformChannelWrite(server_handle.get(), kHello, sizeof(kHello));
- EXPECT_EQ(-1, result);
- if (errno != EPIPE)
- PLOG(WARNING) << "write (expected EPIPE)";
-
- // Test our replacement for |writev()|/|sendv()|.
- struct iovec iov[2] = {{const_cast<char*>(kHello), sizeof(kHello)},
- {const_cast<char*>(kHello), sizeof(kHello)}};
- result = PlatformChannelWritev(server_handle.get(), iov, 2);
- EXPECT_EQ(-1, result);
- if (errno != EPIPE)
- PLOG(WARNING) << "write (expected EPIPE)";
-}
-
-TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
- PlatformChannelPair channel_pair;
- 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);
-
- EXPECT_EQ(static_cast<ssize_t>(send_string.size()),
- PlatformChannelWrite(server_handle.get(), send_string.data(),
- send_string.size()));
-
- WaitReadable(client_handle.get());
-
- char buf[10000] = {};
- std::deque<PlatformHandle> received_handles;
- ssize_t result = PlatformChannelRecvmsg(client_handle.get(), buf,
- sizeof(buf), &received_handles);
- EXPECT_EQ(static_cast<ssize_t>(send_string.size()), result);
- EXPECT_EQ(send_string, std::string(buf, static_cast<size_t>(result)));
- EXPECT_TRUE(received_handles.empty());
- }
-}
-
-TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- static const char kHello[] = "hello";
-
- PlatformChannelPair channel_pair;
- 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)
- const size_t kNumHandlesToSend = kPlatformChannelMaxNumHandles / 2;
-#else
- const size_t kNumHandlesToSend = kPlatformChannelMaxNumHandles;
-#endif
-
- for (size_t i = 1; i < kNumHandlesToSend; i++) {
- // Make |i| files, with the j-th file consisting of j copies of the digit
- // |c|.
- const char c = '0' + (i % 10);
- ScopedPlatformHandleVectorPtr platform_handles(new PlatformHandleVector);
- for (size_t j = 1; j <= i; j++) {
- base::FilePath unused;
- base::ScopedFILE fp(
- base::CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
- ASSERT_TRUE(fp);
- ASSERT_EQ(j, fwrite(std::string(j, c).data(), 1, j, fp.get()));
- platform_handles->push_back(
- test::PlatformHandleFromFILE(std::move(fp)).release());
- ASSERT_TRUE(platform_handles->back().is_valid());
- }
-
- // Send the FDs (+ "hello").
- struct iovec iov = {const_cast<char*>(kHello), sizeof(kHello)};
- // We assume that the |sendmsg()| actually sends all the data.
- EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
- PlatformChannelSendmsgWithHandles(server_handle.get(), &iov, 1,
- &platform_handles->at(0),
- platform_handles->size()));
-
- WaitReadable(client_handle.get());
-
- char buf[10000] = {};
- std::deque<PlatformHandle> received_handles;
- // We assume that the |recvmsg()| actually reads all the data.
- EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
- PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
- &received_handles));
- EXPECT_STREQ(kHello, buf);
- EXPECT_EQ(i, received_handles.size());
-
- for (size_t j = 0; !received_handles.empty(); j++) {
- base::ScopedFILE fp(test::FILEFromPlatformHandle(
- ScopedPlatformHandle(received_handles.front()), "rb"));
- received_handles.pop_front();
- ASSERT_TRUE(fp);
- rewind(fp.get());
- char read_buf[kNumHandlesToSend];
- size_t bytes_read = fread(read_buf, 1, sizeof(read_buf), fp.get());
- EXPECT_EQ(j + 1, bytes_read);
- EXPECT_EQ(std::string(j + 1, c), std::string(read_buf, bytes_read));
- }
- }
-}
-
-TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- static const char kHello[] = "hello";
-
- PlatformChannelPair channel_pair;
- ScopedPlatformHandle server_handle = channel_pair.PassServerHandle();
- ScopedPlatformHandle client_handle = channel_pair.PassClientHandle();
-
- const std::string file_contents("hello world");
-
- {
- base::FilePath unused;
- base::ScopedFILE fp(
- base::CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
- ASSERT_TRUE(fp);
- ASSERT_EQ(file_contents.size(),
- fwrite(file_contents.data(), 1, file_contents.size(), fp.get()));
- ScopedPlatformHandleVectorPtr platform_handles(new PlatformHandleVector);
- platform_handles->push_back(
- test::PlatformHandleFromFILE(std::move(fp)).release());
- ASSERT_TRUE(platform_handles->back().is_valid());
-
- // Send the FD (+ "hello").
- struct iovec iov = {const_cast<char*>(kHello), sizeof(kHello)};
- // We assume that the |sendmsg()| actually sends all the data.
- EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
- PlatformChannelSendmsgWithHandles(server_handle.get(), &iov, 1,
- &platform_handles->at(0),
- platform_handles->size()));
- }
-
- WaitReadable(client_handle.get());
-
- // Start with an invalid handle in the deque.
- std::deque<PlatformHandle> received_handles;
- received_handles.push_back(PlatformHandle());
-
- char buf[100] = {};
- // We assume that the |recvmsg()| actually reads all the data.
- EXPECT_EQ(static_cast<ssize_t>(sizeof(kHello)),
- PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
- &received_handles));
- EXPECT_STREQ(kHello, buf);
- ASSERT_EQ(2u, received_handles.size());
- EXPECT_FALSE(received_handles[0].is_valid());
- EXPECT_TRUE(received_handles[1].is_valid());
-
- {
- base::ScopedFILE fp(test::FILEFromPlatformHandle(
- ScopedPlatformHandle(received_handles[1]), "rb"));
- received_handles[1] = PlatformHandle();
- ASSERT_TRUE(fp);
- rewind(fp.get());
- char read_buf[100];
- size_t bytes_read = fread(read_buf, 1, sizeof(read_buf), fp.get());
- EXPECT_EQ(file_contents.size(), bytes_read);
- EXPECT_EQ(file_contents, std::string(read_buf, bytes_read));
- }
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_channel_pair_win.cc b/mojo/edk/embedder/platform_channel_pair_win.cc
deleted file mode 100644
index f523ade..0000000
--- a/mojo/edk/embedder/platform_channel_pair_win.cc
+++ /dev/null
@@ -1,123 +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 <windows.h>
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/win/windows_version.h"
-#include "mojo/edk/embedder/platform_handle.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-std::wstring GeneratePipeName() {
- return base::StringPrintf(L"\\\\.\\pipe\\mojo.%u.%u.%I64u",
- GetCurrentProcessId(), GetCurrentThreadId(),
- base::RandUint64());
-}
-
-} // namespace
-
-PlatformChannelPair::PlatformChannelPair(bool client_is_blocking) {
- std::wstring pipe_name = GeneratePipeName();
-
- DWORD kOpenMode =
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE;
- const DWORD kPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE;
- server_handle_.reset(PlatformHandle(
- CreateNamedPipeW(pipe_name.c_str(), kOpenMode, kPipeMode,
- 1, // Max instances.
- 4096, // Out buffer size.
- 4096, // In buffer size.
- 5000, // Timeout in milliseconds.
- nullptr))); // Default security descriptor.
- PCHECK(server_handle_.is_valid());
-
- const DWORD kDesiredAccess = GENERIC_READ | GENERIC_WRITE;
- // The SECURITY_ANONYMOUS flag means that the server side cannot impersonate
- // the client.
- DWORD kFlags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
- if (!client_is_blocking)
- kFlags |= FILE_FLAG_OVERLAPPED;
- // Allow the handle to be inherited by child processes.
- SECURITY_ATTRIBUTES security_attributes = {
- sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
- client_handle_.reset(
- PlatformHandle(CreateFileW(pipe_name.c_str(), kDesiredAccess,
- 0, // No sharing.
- &security_attributes, OPEN_EXISTING, kFlags,
- nullptr))); // No template file.
- PCHECK(client_handle_.is_valid());
-
- // Since a client has connected, ConnectNamedPipe() should return zero and
- // GetLastError() should return ERROR_PIPE_CONNECTED.
- CHECK(!ConnectNamedPipe(server_handle_.get().handle, nullptr));
- PCHECK(GetLastError() == ERROR_PIPE_CONNECTED);
-}
-
-// static
-ScopedPlatformHandle PlatformChannelPair::PassClientHandleFromParentProcess(
- const base::CommandLine& command_line) {
- std::string client_handle_string =
- command_line.GetSwitchValueASCII(kMojoPlatformChannelHandleSwitch);
- return PassClientHandleFromParentProcessFromString(client_handle_string);
-}
-
-ScopedPlatformHandle
-PlatformChannelPair::PassClientHandleFromParentProcessFromString(
- const std::string& value) {
- int client_handle_value = 0;
- if (value.empty() ||
- !base::StringToInt(value, &client_handle_value)) {
- LOG(ERROR) << "Missing or invalid --" << kMojoPlatformChannelHandleSwitch;
- return ScopedPlatformHandle();
- }
-
- return ScopedPlatformHandle(
- PlatformHandle(LongToHandle(client_handle_value)));
-}
-
-void PlatformChannelPair::PrepareToPassClientHandleToChildProcess(
- base::CommandLine* command_line,
- base::HandlesToInheritVector* handle_passing_info) const {
- DCHECK(command_line);
-
- // 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,
- PrepareToPassClientHandleToChildProcessAsString(handle_passing_info));
-}
-
-std::string
-PlatformChannelPair::PrepareToPassClientHandleToChildProcessAsString(
- HandlePassingInformation* handle_passing_info) const {
- DCHECK(handle_passing_info);
- DCHECK(client_handle_.is_valid());
-
- if (base::win::GetVersion() >= base::win::VERSION_VISTA)
- handle_passing_info->push_back(client_handle_.get().handle);
-
- return base::IntToString(HandleToLong(client_handle_.get().handle));
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_channel_utils_posix.cc b/mojo/edk/embedder/platform_channel_utils_posix.cc
deleted file mode 100644
index 689b6ee..0000000
--- a/mojo/edk/embedder/platform_channel_utils_posix.cc
+++ /dev/null
@@ -1,282 +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_utils_posix.h"
-
-#include <stddef.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <utility>
-
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-
-#if !defined(OS_NACL)
-#include <sys/uio.h>
-#endif
-
-#if !defined(SO_PEEK_OFF)
-#define SO_PEEK_OFF 42
-#endif
-
-namespace mojo {
-namespace edk {
-namespace {
-
-#if !defined(OS_NACL)
-bool IsRecoverableError() {
- return errno == ECONNABORTED || errno == EMFILE || errno == ENFILE ||
- errno == ENOMEM || errno == ENOBUFS;
-}
-
-bool GetPeerEuid(PlatformHandle handle, uid_t* peer_euid) {
- DCHECK(peer_euid);
-#if defined(OS_MACOSX) || defined(OS_OPENBSD) || defined(OS_FREEBSD)
- uid_t socket_euid;
- gid_t socket_gid;
- if (getpeereid(handle.handle, &socket_euid, &socket_gid) < 0) {
- PLOG(ERROR) << "getpeereid " << handle.handle;
- return false;
- }
- *peer_euid = socket_euid;
- return true;
-#else
- struct ucred cred;
- socklen_t cred_len = sizeof(cred);
- if (getsockopt(handle.handle, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) <
- 0) {
- PLOG(ERROR) << "getsockopt " << handle.handle;
- return false;
- }
- if (static_cast<unsigned>(cred_len) < sizeof(cred)) {
- NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
- return false;
- }
- *peer_euid = cred.uid;
- return true;
-#endif
-}
-
-bool IsPeerAuthorized(PlatformHandle peer_handle) {
- uid_t peer_euid;
- if (!GetPeerEuid(peer_handle, &peer_euid))
- return false;
- if (peer_euid != geteuid()) {
- DLOG(ERROR) << "Client euid is not authorised";
- return false;
- }
- return true;
-}
-#endif // !defined(OS_NACL)
-
-} // namespace
-
-// On Linux, |SIGPIPE| is suppressed by passing |MSG_NOSIGNAL| to
-// |send()|/|sendmsg()|. (There is no way of suppressing |SIGPIPE| on
-// |write()|/|writev().) On Mac, |SIGPIPE| is suppressed by setting the
-// |SO_NOSIGPIPE| option on the socket.
-//
-// Performance notes:
-// - On Linux, we have to use |send()|/|sendmsg()| rather than
-// |write()|/|writev()| in order to suppress |SIGPIPE|. This is okay, since
-// |send()| is (slightly) faster than |write()| (!), while |sendmsg()| is
-// quite comparable to |writev()|.
-// - On Mac, we may use |write()|/|writev()|. Here, |write()| is considerably
-// faster than |send()|, whereas |sendmsg()| is quite comparable to
-// |writev()|.
-// - On both platforms, an appropriate |sendmsg()|/|writev()| is considerably
-// faster than two |send()|s/|write()|s.
-// - Relative numbers (minimum real times from 10 runs) for one |write()| of
-// 1032 bytes, one |send()| of 1032 bytes, one |writev()| of 32+1000 bytes,
-// one |sendmsg()| of 32+1000 bytes, two |write()|s of 32 and 1000 bytes, two
-// |send()|s of 32 and 1000 bytes:
-// - Linux: 0.81 s, 0.77 s, 0.87 s, 0.89 s, 1.31 s, 1.22 s
-// - Mac: 2.21 s, 2.91 s, 2.98 s, 3.08 s, 3.59 s, 4.74 s
-
-// Flags to use with calling |send()| or |sendmsg()| (see above).
-#if defined(OS_MACOSX)
-const int kSendFlags = 0;
-#else
-const int kSendFlags = MSG_NOSIGNAL;
-#endif
-
-ssize_t PlatformChannelWrite(PlatformHandle h,
- const void* bytes,
- size_t num_bytes) {
- DCHECK(h.is_valid());
- DCHECK(bytes);
- DCHECK_GT(num_bytes, 0u);
-
-#if defined(OS_MACOSX) || defined(OS_NACL_NONSFI)
- // send() is not available under NaCl-nonsfi.
- return HANDLE_EINTR(write(h.handle, bytes, num_bytes));
-#else
- return send(h.handle, bytes, num_bytes, kSendFlags);
-#endif
-}
-
-ssize_t PlatformChannelWritev(PlatformHandle h,
- struct iovec* iov,
- size_t num_iov) {
- DCHECK(h.is_valid());
- DCHECK(iov);
- DCHECK_GT(num_iov, 0u);
-
-#if defined(OS_MACOSX)
- return HANDLE_EINTR(writev(h.handle, iov, static_cast<int>(num_iov)));
-#else
- struct msghdr msg = {};
- msg.msg_iov = iov;
- msg.msg_iovlen = num_iov;
- return HANDLE_EINTR(sendmsg(h.handle, &msg, kSendFlags));
-#endif
-}
-
-ssize_t PlatformChannelSendmsgWithHandles(PlatformHandle h,
- struct iovec* iov,
- size_t num_iov,
- PlatformHandle* platform_handles,
- size_t num_platform_handles) {
- DCHECK(iov);
- DCHECK_GT(num_iov, 0u);
- DCHECK(platform_handles);
- DCHECK_GT(num_platform_handles, 0u);
- DCHECK_LE(num_platform_handles, kPlatformChannelMaxNumHandles);
-
- char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))];
- struct msghdr msg = {};
- msg.msg_iov = iov;
- msg.msg_iovlen = num_iov;
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = CMSG_LEN(num_platform_handles * sizeof(int));
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(num_platform_handles * sizeof(int));
- for (size_t i = 0; i < num_platform_handles; i++) {
- DCHECK(platform_handles[i].is_valid());
- reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] = platform_handles[i].handle;
- }
-
- return HANDLE_EINTR(sendmsg(h.handle, &msg, kSendFlags));
-}
-
-bool PlatformChannelSendHandles(PlatformHandle h,
- PlatformHandle* handles,
- size_t num_handles) {
- DCHECK(handles);
- DCHECK_GT(num_handles, 0u);
- DCHECK_LE(num_handles, kPlatformChannelMaxNumHandles);
-
- // Note: |sendmsg()| fails on Mac if we don't write at least one character.
- struct iovec iov = {const_cast<char*>(""), 1};
- char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))];
- struct msghdr msg = {};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = CMSG_LEN(num_handles * sizeof(int));
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(num_handles * sizeof(int));
- for (size_t i = 0; i < num_handles; i++) {
- DCHECK(handles[i].is_valid());
- reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] = handles[i].handle;
- }
-
- ssize_t result = HANDLE_EINTR(sendmsg(h.handle, &msg, kSendFlags));
- if (result < 1) {
- DCHECK_EQ(result, -1);
- return false;
- }
-
- for (size_t i = 0; i < num_handles; i++)
- handles[i].CloseIfNecessary();
- return true;
-}
-
-ssize_t PlatformChannelRecvmsg(PlatformHandle h,
- void* buf,
- size_t num_bytes,
- std::deque<PlatformHandle>* platform_handles,
- bool block) {
- DCHECK(buf);
- DCHECK_GT(num_bytes, 0u);
- DCHECK(platform_handles);
-
- struct iovec iov = {buf, num_bytes};
- char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))];
- struct msghdr msg = {};
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = sizeof(cmsg_buf);
-
- ssize_t result =
- HANDLE_EINTR(recvmsg(h.handle, &msg, block ? 0 : MSG_DONTWAIT));
- if (result < 0)
- return result;
-
- // Success; no control messages.
- if (msg.msg_controllen == 0)
- return result;
-
- DCHECK(!(msg.msg_flags & MSG_CTRUNC));
-
- for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- size_t payload_length = cmsg->cmsg_len - CMSG_LEN(0);
- DCHECK_EQ(payload_length % sizeof(int), 0u);
- size_t num_fds = payload_length / sizeof(int);
- const int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
- for (size_t i = 0; i < num_fds; i++) {
- platform_handles->push_back(PlatformHandle(fds[i]));
- DCHECK(platform_handles->back().is_valid());
- }
- }
- }
-
- return result;
-}
-
-bool ServerAcceptConnection(PlatformHandle server_handle,
- ScopedPlatformHandle* connection_handle,
- bool check_peer_user) {
- DCHECK(server_handle.is_valid());
- connection_handle->reset();
-#if defined(OS_NACL)
- NOTREACHED();
- return false;
-#else
- ScopedPlatformHandle accept_handle(
- PlatformHandle(HANDLE_EINTR(accept(server_handle.handle, NULL, 0))));
- if (!accept_handle.is_valid())
- return IsRecoverableError();
-
- // Verify that the IPC channel peer is running as the same user.
- if (check_peer_user && !IsPeerAuthorized(accept_handle.get())) {
- return true;
- }
-
- if (!base::SetNonBlocking(accept_handle.get().handle)) {
- PLOG(ERROR) << "base::SetNonBlocking() failed "
- << accept_handle.get().handle;
- // It's safe to keep listening on |server_handle| even if the attempt to set
- // O_NONBLOCK failed on the client fd.
- return true;
- }
-
- *connection_handle = std::move(accept_handle);
- return true;
-#endif // defined(OS_NACL)
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_channel_utils_posix.h b/mojo/edk/embedder/platform_channel_utils_posix.h
deleted file mode 100644
index 23cfa92..0000000
--- a/mojo/edk/embedder/platform_channel_utils_posix.h
+++ /dev/null
@@ -1,87 +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_EMBEDDER_PLATFORM_CHANNEL_UTILS_POSIX_H_
-#define MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_POSIX_H_
-
-#include <stddef.h>
-#include <sys/types.h> // For |ssize_t|.
-
-#include <deque>
-#include <memory>
-
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-struct iovec; // Declared in <sys/uio.h>.
-
-namespace mojo {
-namespace edk {
-class ScopedPlatformHandle;
-
-// The maximum number of handles that can be sent "at once" using
-// |PlatformChannelSendmsgWithHandles()|. This must be less than the Linux
-// kernel's SCM_MAX_FD which is 253.
-const size_t kPlatformChannelMaxNumHandles = 128;
-
-// Use these to write to a socket created using |PlatformChannelPair| (or
-// equivalent). These are like |write()| and |writev()|, but handle |EINTR| and
-// never raise |SIGPIPE|. (Note: On Mac, the suppression of |SIGPIPE| is set up
-// by |PlatformChannelPair|.)
-MOJO_SYSTEM_IMPL_EXPORT ssize_t
-PlatformChannelWrite(PlatformHandle h, const void* bytes, size_t num_bytes);
-MOJO_SYSTEM_IMPL_EXPORT ssize_t
-PlatformChannelWritev(PlatformHandle h, struct iovec* iov, size_t num_iov);
-
-// Writes data, and the given set of |PlatformHandle|s (i.e., file descriptors)
-// over the Unix domain socket given by |h| (e.g., created using
-// |PlatformChannelPair()|). All the handles must be valid, and there must be at
-// least one and at most |kPlatformChannelMaxNumHandles| handles. The return
-// value is as for |sendmsg()|, namely -1 on failure and otherwise the number of
-// bytes of data sent on success (note that this may not be all the data
-// specified by |iov|). (The handles are not closed, regardless of success or
-// failure.)
-MOJO_SYSTEM_IMPL_EXPORT ssize_t
-PlatformChannelSendmsgWithHandles(PlatformHandle h,
- struct iovec* iov,
- size_t num_iov,
- PlatformHandle* platform_handles,
- size_t num_platform_handles);
-
-// TODO(vtl): Remove this once I've switched things over to
-// |PlatformChannelSendmsgWithHandles()|.
-// Sends |PlatformHandle|s (i.e., file descriptors) over the Unix domain socket
-// (e.g., created using PlatformChannelPair|). (These will be sent in a single
-// message having one null byte of data and one control message header with all
-// the file descriptors.) All of the handles must be valid, and there must be at
-// most |kPlatformChannelMaxNumHandles| (and at least one handle). Returns true
-// on success, in which case it closes all the handles.
-MOJO_SYSTEM_IMPL_EXPORT bool PlatformChannelSendHandles(PlatformHandle h,
- PlatformHandle* handles,
- size_t num_handles);
-
-// Wrapper around |recvmsg()|, which will extract any attached file descriptors
-// (in the control message) to |PlatformHandle|s (and append them to
-// |platform_handles|). (This also handles |EINTR|.)
-MOJO_SYSTEM_IMPL_EXPORT ssize_t
-PlatformChannelRecvmsg(PlatformHandle h,
- void* buf,
- size_t num_bytes,
- std::deque<PlatformHandle>* platform_handles,
- bool block = false);
-
-// Returns false if |server_handle| encounters an unrecoverable error.
-// Returns true if it's valid to keep listening on |server_handle|. In this
-// case, it's possible that a connection wasn't successfully established; then,
-// |connection_handle| will be invalid. If |check_peer_user| is True, the
-// connection will be rejected if the peer is running as a different user.
-MOJO_SYSTEM_IMPL_EXPORT bool ServerAcceptConnection(
- PlatformHandle server_handle,
- ScopedPlatformHandle* connection_handle,
- bool check_peer_user = true);
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PLATFORM_CHANNEL_UTILS_POSIX_H_
diff --git a/mojo/edk/embedder/platform_handle.cc b/mojo/edk/embedder/platform_handle.cc
deleted file mode 100644
index b6b2cd2..0000000
--- a/mojo/edk/embedder/platform_handle.cc
+++ /dev/null
@@ -1,74 +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/embedder/platform_handle.h"
-
-#include "build/build_config.h"
-#if defined(OS_POSIX)
-#include <unistd.h>
-#elif defined(OS_WIN)
-#include <windows.h>
-#else
-#error "Platform not yet supported."
-#endif
-
-#include "base/logging.h"
-
-namespace mojo {
-namespace edk {
-
-void PlatformHandle::CloseIfNecessary() {
- if (!is_valid())
- return;
-
-#if defined(OS_POSIX)
- if (type == Type::POSIX) {
- bool success = (close(handle) == 0);
- DPCHECK(success);
- handle = -1;
- }
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- else if (type == Type::MACH) {
- kern_return_t rv = mach_port_deallocate(mach_task_self(), port);
- DPCHECK(rv == KERN_SUCCESS);
- port = MACH_PORT_NULL;
- }
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
-#elif defined(OS_WIN)
- if (owning_process != base::GetCurrentProcessHandle()) {
- // This handle may have been duplicated to a new target process but not yet
- // sent there. In this case CloseHandle should NOT be called. From MSDN
- // documentation for DuplicateHandle[1]:
- //
- // Normally the target process closes a duplicated handle when that
- // process is finished using the handle. To close a duplicated handle
- // from the source process, call DuplicateHandle with the following
- // parameters:
- //
- // * Set hSourceProcessHandle to the target process from the
- // call that created the handle.
- // * Set hSourceHandle to the duplicated handle to close.
- // * Set lpTargetHandle to NULL.
- // * Set dwOptions to DUPLICATE_CLOSE_SOURCE.
- //
- // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251
- //
- // NOTE: It's possible for this operation to fail if the owning process
- // was terminated or is in the process of being terminated. Either way,
- // there is nothing we can reasonably do about failure, so we ignore it.
- DuplicateHandle(owning_process, handle, NULL, &handle, 0, FALSE,
- DUPLICATE_CLOSE_SOURCE);
- return;
- }
-
- bool success = !!CloseHandle(handle);
- DPCHECK(success);
- handle = INVALID_HANDLE_VALUE;
-#else
-#error "Platform not yet supported."
-#endif
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_handle.h b/mojo/edk/embedder/platform_handle.h
deleted file mode 100644
index 4866e75..0000000
--- a/mojo/edk/embedder/platform_handle.h
+++ /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.
-
-#ifndef MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_H_
-#define MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_H_
-
-#include "build/build_config.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-
-#include "base/process/process_handle.h"
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
-#include <mach/mach.h>
-#endif
-
-namespace mojo {
-namespace edk {
-
-#if defined(OS_POSIX)
-struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandle {
- PlatformHandle() {}
- explicit PlatformHandle(int handle) : handle(handle) {}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- explicit PlatformHandle(mach_port_t port)
- : type(Type::MACH), port(port) {}
-#endif
-
- void CloseIfNecessary();
-
- bool is_valid() const {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (type == Type::MACH || type == Type::MACH_NAME)
- return port != MACH_PORT_NULL;
-#endif
- return handle != -1;
- }
-
- enum class Type {
- POSIX,
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- MACH,
- // MACH_NAME isn't a real Mach port. But rather the "name" of one that can
- // be resolved to a real port later. This distinction is needed so that the
- // "port" doesn't try to be closed if CloseIfNecessary() is called. Having
- // this also allows us to do checks in other places.
- MACH_NAME,
-#endif
- };
- Type type = Type::POSIX;
-
- int handle = -1;
-
- // A POSIX handle may be a listen handle that can accept a connection.
- bool needs_connection = false;
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- mach_port_t port = MACH_PORT_NULL;
-#endif
-};
-#elif defined(OS_WIN)
-struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandle {
- PlatformHandle() : PlatformHandle(INVALID_HANDLE_VALUE) {}
- explicit PlatformHandle(HANDLE handle)
- : handle(handle), owning_process(base::GetCurrentProcessHandle()) {}
-
- void CloseIfNecessary();
-
- bool is_valid() const { return handle != INVALID_HANDLE_VALUE; }
-
- HANDLE handle;
-
- // A Windows HANDLE may be duplicated to another process but not yet sent to
- // that process. This tracks the handle's owning process.
- base::ProcessHandle owning_process;
-
- // A Windows HANDLE may be an unconnected named pipe. In this case, we need to
- // wait for a connection before communicating on the pipe.
- bool needs_connection = false;
-};
-#else
-#error "Platform not yet supported."
-#endif
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_H_
diff --git a/mojo/edk/embedder/platform_handle_utils.h b/mojo/edk/embedder/platform_handle_utils.h
deleted file mode 100644
index fa683e4..0000000
--- a/mojo/edk/embedder/platform_handle_utils.h
+++ /dev/null
@@ -1,33 +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_EMBEDDER_PLATFORM_HANDLE_UTILS_H_
-#define MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_UTILS_H_
-
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-// Closes all the |PlatformHandle|s in the given container.
-template <typename PlatformHandleContainer>
-MOJO_SYSTEM_IMPL_EXPORT inline void CloseAllPlatformHandles(
- PlatformHandleContainer* platform_handles) {
- for (typename PlatformHandleContainer::iterator it =
- platform_handles->begin();
- it != platform_handles->end(); ++it)
- it->CloseIfNecessary();
-}
-
-// Duplicates the given |PlatformHandle| (which must be valid). (Returns an
-// invalid |ScopedPlatformHandle| on failure.)
-MOJO_SYSTEM_IMPL_EXPORT ScopedPlatformHandle
-DuplicatePlatformHandle(PlatformHandle platform_handle);
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_UTILS_H_
diff --git a/mojo/edk/embedder/platform_handle_utils_posix.cc b/mojo/edk/embedder/platform_handle_utils_posix.cc
deleted file mode 100644
index 5604f96..0000000
--- a/mojo/edk/embedder/platform_handle_utils_posix.cc
+++ /dev/null
@@ -1,24 +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_handle_utils.h"
-
-#include <unistd.h>
-
-#include "base/logging.h"
-
-namespace mojo {
-namespace edk {
-
-ScopedPlatformHandle DuplicatePlatformHandle(PlatformHandle platform_handle) {
- DCHECK(platform_handle.is_valid());
- // Note that |dup()| returns -1 on error (which is exactly the value we use
- // for invalid |PlatformHandle| FDs).
- PlatformHandle duped(dup(platform_handle.handle));
- duped.needs_connection = platform_handle.needs_connection;
- return ScopedPlatformHandle(duped);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_handle_utils_win.cc b/mojo/edk/embedder/platform_handle_utils_win.cc
deleted file mode 100644
index 32ed49a..0000000
--- a/mojo/edk/embedder/platform_handle_utils_win.cc
+++ /dev/null
@@ -1,28 +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_handle_utils.h"
-
-#include <windows.h>
-
-#include "base/logging.h"
-
-namespace mojo {
-namespace edk {
-
-ScopedPlatformHandle DuplicatePlatformHandle(PlatformHandle platform_handle) {
- DCHECK(platform_handle.is_valid());
-
- HANDLE new_handle;
- CHECK_NE(platform_handle.handle, INVALID_HANDLE_VALUE);
- if (!DuplicateHandle(GetCurrentProcess(), platform_handle.handle,
- GetCurrentProcess(), &new_handle, 0, TRUE,
- DUPLICATE_SAME_ACCESS))
- return ScopedPlatformHandle();
- DCHECK_NE(new_handle, INVALID_HANDLE_VALUE);
- return ScopedPlatformHandle(PlatformHandle(new_handle));
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_handle_vector.h b/mojo/edk/embedder/platform_handle_vector.h
deleted file mode 100644
index 9892b23..0000000
--- a/mojo/edk/embedder/platform_handle_vector.h
+++ /dev/null
@@ -1,35 +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_EMBEDDER_PLATFORM_HANDLE_VECTOR_H_
-#define MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_VECTOR_H_
-
-#include <memory>
-#include <vector>
-
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/embedder/platform_handle_utils.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-using PlatformHandleVector = std::vector<PlatformHandle>;
-
-// A deleter (for use with |scoped_ptr|) which closes all handles and then
-// |delete|s the |PlatformHandleVector|.
-struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandleVectorDeleter {
- void operator()(PlatformHandleVector* platform_handles) const {
- CloseAllPlatformHandles(platform_handles);
- delete platform_handles;
- }
-};
-
-using ScopedPlatformHandleVectorPtr =
- std::unique_ptr<PlatformHandleVector, PlatformHandleVectorDeleter>;
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PLATFORM_HANDLE_VECTOR_H_
diff --git a/mojo/edk/embedder/platform_shared_buffer.cc b/mojo/edk/embedder/platform_shared_buffer.cc
deleted file mode 100644
index 58af44d..0000000
--- a/mojo/edk/embedder/platform_shared_buffer.cc
+++ /dev/null
@@ -1,325 +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_shared_buffer.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process_handle.h"
-#include "base/sys_info.h"
-#include "mojo/edk/embedder/platform_handle_utils.h"
-
-#if defined(OS_NACL)
-// For getpagesize() on NaCl.
-#include <unistd.h>
-#endif
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-// Takes ownership of |memory_handle|.
-ScopedPlatformHandle SharedMemoryToPlatformHandle(
- base::SharedMemoryHandle memory_handle) {
-#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
- return ScopedPlatformHandle(PlatformHandle(memory_handle.fd));
-#elif defined(OS_WIN)
- return ScopedPlatformHandle(PlatformHandle(memory_handle.GetHandle()));
-#else
- return ScopedPlatformHandle(PlatformHandle(memory_handle.GetMemoryObject()));
-#endif
-}
-
-} // namespace
-
-// static
-PlatformSharedBuffer* PlatformSharedBuffer::Create(size_t num_bytes) {
- DCHECK_GT(num_bytes, 0u);
-
- PlatformSharedBuffer* rv = new PlatformSharedBuffer(num_bytes, false);
- if (!rv->Init()) {
- // We can't just delete it directly, due to the "in destructor" (debug)
- // check.
- scoped_refptr<PlatformSharedBuffer> deleter(rv);
- return nullptr;
- }
-
- return rv;
-}
-
-// static
-PlatformSharedBuffer* PlatformSharedBuffer::CreateFromPlatformHandle(
- size_t num_bytes,
- bool read_only,
- ScopedPlatformHandle platform_handle) {
- DCHECK_GT(num_bytes, 0u);
-
- PlatformSharedBuffer* rv = new PlatformSharedBuffer(num_bytes, read_only);
- if (!rv->InitFromPlatformHandle(std::move(platform_handle))) {
- // We can't just delete it directly, due to the "in destructor" (debug)
- // check.
- scoped_refptr<PlatformSharedBuffer> deleter(rv);
- return nullptr;
- }
-
- return rv;
-}
-
-// static
-PlatformSharedBuffer* PlatformSharedBuffer::CreateFromPlatformHandlePair(
- size_t num_bytes,
- ScopedPlatformHandle rw_platform_handle,
- ScopedPlatformHandle ro_platform_handle) {
- DCHECK_GT(num_bytes, 0u);
- DCHECK(rw_platform_handle.is_valid());
- DCHECK(ro_platform_handle.is_valid());
-
- PlatformSharedBuffer* rv = new PlatformSharedBuffer(num_bytes, false);
- if (!rv->InitFromPlatformHandlePair(std::move(rw_platform_handle),
- std::move(ro_platform_handle))) {
- // We can't just delete it directly, due to the "in destructor" (debug)
- // check.
- scoped_refptr<PlatformSharedBuffer> deleter(rv);
- return nullptr;
- }
-
- return rv;
-}
-
-// static
-PlatformSharedBuffer* PlatformSharedBuffer::CreateFromSharedMemoryHandle(
- size_t num_bytes,
- bool read_only,
- base::SharedMemoryHandle handle) {
- DCHECK_GT(num_bytes, 0u);
-
- PlatformSharedBuffer* rv = new PlatformSharedBuffer(num_bytes, read_only);
- rv->InitFromSharedMemoryHandle(handle);
-
- return rv;
-}
-
-size_t PlatformSharedBuffer::GetNumBytes() const {
- return num_bytes_;
-}
-
-bool PlatformSharedBuffer::IsReadOnly() const {
- return read_only_;
-}
-
-std::unique_ptr<PlatformSharedBufferMapping> PlatformSharedBuffer::Map(
- size_t offset,
- size_t length) {
- if (!IsValidMap(offset, length))
- return nullptr;
-
- return MapNoCheck(offset, length);
-}
-
-bool PlatformSharedBuffer::IsValidMap(size_t offset, size_t length) {
- if (offset > num_bytes_ || length == 0)
- return false;
-
- // Note: This is an overflow-safe check of |offset + length > num_bytes_|
- // (that |num_bytes >= offset| is verified above).
- if (length > num_bytes_ - offset)
- return false;
-
- return true;
-}
-
-std::unique_ptr<PlatformSharedBufferMapping> PlatformSharedBuffer::MapNoCheck(
- size_t offset,
- size_t length) {
- DCHECK(IsValidMap(offset, length));
- DCHECK(shared_memory_);
- base::SharedMemoryHandle handle;
- {
- base::AutoLock locker(lock_);
- handle = base::SharedMemory::DuplicateHandle(shared_memory_->handle());
- }
- if (handle == base::SharedMemory::NULLHandle())
- return nullptr;
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping(
- new PlatformSharedBufferMapping(handle, read_only_, offset, length));
- if (mapping->Map())
- return base::WrapUnique(mapping.release());
-
- return nullptr;
-}
-
-ScopedPlatformHandle PlatformSharedBuffer::DuplicatePlatformHandle() {
- DCHECK(shared_memory_);
- base::SharedMemoryHandle handle;
- {
- base::AutoLock locker(lock_);
- handle = base::SharedMemory::DuplicateHandle(shared_memory_->handle());
- }
- if (handle == base::SharedMemory::NULLHandle())
- return ScopedPlatformHandle();
-
- return SharedMemoryToPlatformHandle(handle);
-}
-
-ScopedPlatformHandle PlatformSharedBuffer::PassPlatformHandle() {
- DCHECK(HasOneRef());
-
- // The only way to pass a handle from base::SharedMemory is to duplicate it
- // and close the original.
- ScopedPlatformHandle handle = DuplicatePlatformHandle();
-
- base::AutoLock locker(lock_);
- shared_memory_->Close();
- return handle;
-}
-
-base::SharedMemoryHandle PlatformSharedBuffer::DuplicateSharedMemoryHandle() {
- DCHECK(shared_memory_);
-
- base::AutoLock locker(lock_);
- return base::SharedMemory::DuplicateHandle(shared_memory_->handle());
-}
-
-PlatformSharedBuffer* PlatformSharedBuffer::CreateReadOnlyDuplicate() {
- DCHECK(shared_memory_);
-
- if (ro_shared_memory_) {
- base::AutoLock locker(lock_);
- base::SharedMemoryHandle handle;
- handle = base::SharedMemory::DuplicateHandle(ro_shared_memory_->handle());
- if (handle == base::SharedMemory::NULLHandle())
- return nullptr;
- return CreateFromSharedMemoryHandle(num_bytes_, true, handle);
- }
-
- base::SharedMemoryHandle handle;
- bool success;
- {
- base::AutoLock locker(lock_);
- success = shared_memory_->ShareReadOnlyToProcess(
- base::GetCurrentProcessHandle(), &handle);
- }
- if (!success || handle == base::SharedMemory::NULLHandle())
- return nullptr;
-
- return CreateFromSharedMemoryHandle(num_bytes_, true, handle);
-}
-
-PlatformSharedBuffer::PlatformSharedBuffer(size_t num_bytes, bool read_only)
- : num_bytes_(num_bytes), read_only_(read_only) {}
-
-PlatformSharedBuffer::~PlatformSharedBuffer() {}
-
-bool PlatformSharedBuffer::Init() {
- DCHECK(!shared_memory_);
- DCHECK(!read_only_);
-
- base::SharedMemoryCreateOptions options;
- options.size = num_bytes_;
- // By default, we can share as read-only.
- options.share_read_only = true;
-
- shared_memory_.reset(new base::SharedMemory);
- return shared_memory_->Create(options);
-}
-
-bool PlatformSharedBuffer::InitFromPlatformHandle(
- ScopedPlatformHandle platform_handle) {
- DCHECK(!shared_memory_);
-
-#if defined(OS_WIN)
- base::SharedMemoryHandle handle(platform_handle.release().handle,
- base::GetCurrentProcId());
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- base::SharedMemoryHandle handle;
- handle = base::SharedMemoryHandle(platform_handle.release().port, num_bytes_,
- base::GetCurrentProcId());
-#else
- base::SharedMemoryHandle handle(platform_handle.release().handle, false);
-#endif
-
- shared_memory_.reset(new base::SharedMemory(handle, read_only_));
- return true;
-}
-
-bool PlatformSharedBuffer::InitFromPlatformHandlePair(
- ScopedPlatformHandle rw_platform_handle,
- ScopedPlatformHandle ro_platform_handle) {
-#if defined(OS_MACOSX)
- NOTREACHED();
- return false;
-#else // defined(OS_MACOSX)
-
-#if defined(OS_WIN)
- base::SharedMemoryHandle handle(rw_platform_handle.release().handle,
- base::GetCurrentProcId());
- base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
- base::GetCurrentProcId());
-#else // defined(OS_WIN)
- base::SharedMemoryHandle handle(rw_platform_handle.release().handle, false);
- base::SharedMemoryHandle ro_handle(ro_platform_handle.release().handle,
- false);
-#endif // defined(OS_WIN)
-
- DCHECK(!shared_memory_);
- shared_memory_.reset(new base::SharedMemory(handle, false));
- ro_shared_memory_.reset(new base::SharedMemory(ro_handle, true));
- return true;
-
-#endif // defined(OS_MACOSX)
-}
-
-void PlatformSharedBuffer::InitFromSharedMemoryHandle(
- base::SharedMemoryHandle handle) {
- DCHECK(!shared_memory_);
-
- shared_memory_.reset(new base::SharedMemory(handle, read_only_));
-}
-
-PlatformSharedBufferMapping::~PlatformSharedBufferMapping() {
- Unmap();
-}
-
-void* PlatformSharedBufferMapping::GetBase() const {
- return base_;
-}
-
-size_t PlatformSharedBufferMapping::GetLength() const {
- return length_;
-}
-
-bool PlatformSharedBufferMapping::Map() {
- // Mojo shared buffers can be mapped at any offset. However,
- // base::SharedMemory must be mapped at a page boundary. So calculate what the
- // nearest whole page offset is, and build a mapping that's offset from that.
-#if defined(OS_NACL)
- // base::SysInfo isn't available under NaCl.
- size_t page_size = getpagesize();
-#else
- size_t page_size = base::SysInfo::VMAllocationGranularity();
-#endif
- size_t offset_rounding = offset_ % page_size;
- size_t real_offset = offset_ - offset_rounding;
- size_t real_length = length_ + offset_rounding;
-
- if (!shared_memory_.MapAt(static_cast<off_t>(real_offset), real_length))
- return false;
-
- base_ = static_cast<char*>(shared_memory_.memory()) + offset_rounding;
- return true;
-}
-
-void PlatformSharedBufferMapping::Unmap() {
- shared_memory_.Unmap();
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/platform_shared_buffer.h b/mojo/edk/embedder/platform_shared_buffer.h
deleted file mode 100644
index 45be723..0000000
--- a/mojo/edk/embedder/platform_shared_buffer.h
+++ /dev/null
@@ -1,178 +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_EMBEDDER_PLATFORM_SHARED_BUFFER_H_
-#define MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/shared_memory_handle.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-class PlatformSharedBufferMapping;
-
-// |PlatformSharedBuffer| is a thread-safe, ref-counted wrapper around
-// OS-specific shared memory. It has the following features:
-// - A |PlatformSharedBuffer| simply represents a piece of shared memory that
-// *may* be mapped and *may* be shared to another process.
-// - A single |PlatformSharedBuffer| may be mapped multiple times. The
-// lifetime of the mapping (owned by |PlatformSharedBufferMapping|) is
-// separate from the lifetime of the |PlatformSharedBuffer|.
-// - Sizes/offsets (of the shared memory and mappings) are arbitrary, and not
-// restricted by page size. However, more memory may actually be mapped than
-// requested.
-class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedBuffer
- : public base::RefCountedThreadSafe<PlatformSharedBuffer> {
- public:
- // Creates a shared buffer of size |num_bytes| bytes (initially zero-filled).
- // |num_bytes| must be nonzero. Returns null on failure.
- static PlatformSharedBuffer* Create(size_t num_bytes);
-
- // Creates a shared buffer of size |num_bytes| from the existing platform
- // handle |platform_handle|. Returns null on failure.
- static PlatformSharedBuffer* CreateFromPlatformHandle(
- size_t num_bytes,
- bool read_only,
- ScopedPlatformHandle platform_handle);
-
- // Creates a shared buffer of size |num_bytes| from the existing pair of
- // read/write and read-only handles |rw_platform_handle| and
- // |ro_platform_handle|. Returns null on failure.
- static PlatformSharedBuffer* CreateFromPlatformHandlePair(
- size_t num_bytes,
- ScopedPlatformHandle rw_platform_handle,
- ScopedPlatformHandle ro_platform_handle);
-
- // Creates a shared buffer of size |num_bytes| from the existing shared memory
- // handle |handle|.
- static PlatformSharedBuffer* CreateFromSharedMemoryHandle(
- size_t num_bytes,
- bool read_only,
- base::SharedMemoryHandle handle);
-
- // Gets the size of shared buffer (in number of bytes).
- size_t GetNumBytes() const;
-
- // Returns whether this shared buffer is read-only.
- bool IsReadOnly() const;
-
- // Maps (some) of the shared buffer into memory; [|offset|, |offset + length|]
- // must be contained in [0, |num_bytes|], and |length| must be at least 1.
- // Returns null on failure.
- std::unique_ptr<PlatformSharedBufferMapping> Map(size_t offset,
- size_t length);
-
- // Checks if |offset| and |length| are valid arguments.
- bool IsValidMap(size_t offset, size_t length);
-
- // Like |Map()|, but doesn't check its arguments (which should have been
- // preflighted using |IsValidMap()|).
- std::unique_ptr<PlatformSharedBufferMapping> MapNoCheck(size_t offset,
- size_t length);
-
- // Duplicates the underlying platform handle and passes it to the caller.
- ScopedPlatformHandle DuplicatePlatformHandle();
-
- // Duplicates the underlying shared memory handle and passes it to the caller.
- base::SharedMemoryHandle DuplicateSharedMemoryHandle();
-
- // Passes the underlying platform handle to the caller. This should only be
- // called if there's a unique reference to this object (owned by the caller).
- // After calling this, this object should no longer be used, but should only
- // be disposed of.
- ScopedPlatformHandle PassPlatformHandle();
-
- // Create and return a read-only duplicate of this shared buffer. If this
- // shared buffer isn't capable of returning a read-only duplicate, then
- // nullptr will be returned.
- PlatformSharedBuffer* CreateReadOnlyDuplicate();
-
- private:
- friend class base::RefCountedThreadSafe<PlatformSharedBuffer>;
-
- PlatformSharedBuffer(size_t num_bytes, bool read_only);
- ~PlatformSharedBuffer();
-
- // This is called by |Create()| before this object is given to anyone.
- bool Init();
-
- // This is like |Init()|, but for |CreateFromPlatformHandle()|. (Note: It
- // should verify that |platform_handle| is an appropriate handle for the
- // claimed |num_bytes_|.)
- bool InitFromPlatformHandle(ScopedPlatformHandle platform_handle);
-
- bool InitFromPlatformHandlePair(ScopedPlatformHandle rw_platform_handle,
- ScopedPlatformHandle ro_platform_handle);
-
- void InitFromSharedMemoryHandle(base::SharedMemoryHandle handle);
-
- const size_t num_bytes_;
- const bool read_only_;
-
- base::Lock lock_;
- std::unique_ptr<base::SharedMemory> shared_memory_;
-
- // A separate read-only shared memory for platforms that need it (i.e. Linux
- // with sync broker).
- std::unique_ptr<base::SharedMemory> ro_shared_memory_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformSharedBuffer);
-};
-
-// A mapping of a |PlatformSharedBuffer| (compararable to a "file view" in
-// Windows); see above. Created by |PlatformSharedBuffer::Map()|. Automatically
-// unmaps memory on destruction.
-//
-// Mappings are NOT thread-safe.
-//
-// Note: This is an entirely separate class (instead of
-// |PlatformSharedBuffer::Mapping|) so that it can be forward-declared.
-class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedBufferMapping {
- public:
- ~PlatformSharedBufferMapping();
-
- void* GetBase() const;
- size_t GetLength() const;
-
- private:
- friend class PlatformSharedBuffer;
-
- PlatformSharedBufferMapping(base::SharedMemoryHandle handle,
- bool read_only,
- size_t offset,
- size_t length)
- : offset_(offset),
- length_(length),
- base_(nullptr),
- shared_memory_(handle, read_only) {}
-
- bool Map();
- void Unmap();
-
- const size_t offset_;
- const size_t length_;
- void* base_;
-
- // Since mapping life cycles are separate from PlatformSharedBuffer and a
- // buffer can be mapped multiple times, we have our own SharedMemory object
- // created from a duplicate handle.
- base::SharedMemory shared_memory_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformSharedBufferMapping);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_PLATFORM_SHARED_BUFFER_H_
diff --git a/mojo/edk/embedder/platform_shared_buffer_unittest.cc b/mojo/edk/embedder/platform_shared_buffer_unittest.cc
deleted file mode 100644
index f1593f0..0000000
--- a/mojo/edk/embedder/platform_shared_buffer_unittest.cc
+++ /dev/null
@@ -1,227 +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_shared_buffer.h"
-
-#include <stddef.h>
-
-#include <limits>
-#include <memory>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/sys_info.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-namespace mojo {
-namespace edk {
-namespace {
-
-TEST(PlatformSharedBufferTest, Basic) {
- const size_t kNumInts = 100;
- const size_t kNumBytes = kNumInts * sizeof(int);
- // A fudge so that we're not just writing zero bytes 75% of the time.
- const int kFudge = 1234567890;
-
- // Make some memory.
- scoped_refptr<PlatformSharedBuffer> buffer(
- PlatformSharedBuffer::Create(kNumBytes));
- ASSERT_TRUE(buffer);
-
- // Map it all, scribble some stuff, and then unmap it.
- {
- EXPECT_TRUE(buffer->IsValidMap(0, kNumBytes));
- std::unique_ptr<PlatformSharedBufferMapping> mapping(
- buffer->Map(0, kNumBytes));
- ASSERT_TRUE(mapping);
- ASSERT_TRUE(mapping->GetBase());
- int* stuff = static_cast<int*>(mapping->GetBase());
- for (size_t i = 0; i < kNumInts; i++)
- stuff[i] = static_cast<int>(i) + kFudge;
- }
-
- // Map it all again, check that our scribbling is still there, then do a
- // partial mapping and scribble on that, check that everything is coherent,
- // unmap the first mapping, scribble on some of the second mapping, and then
- // unmap it.
- {
- ASSERT_TRUE(buffer->IsValidMap(0, kNumBytes));
- // Use |MapNoCheck()| this time.
- std::unique_ptr<PlatformSharedBufferMapping> mapping1(
- buffer->MapNoCheck(0, kNumBytes));
- ASSERT_TRUE(mapping1);
- ASSERT_TRUE(mapping1->GetBase());
- int* stuff1 = static_cast<int*>(mapping1->GetBase());
- for (size_t i = 0; i < kNumInts; i++)
- EXPECT_EQ(static_cast<int>(i) + kFudge, stuff1[i]) << i;
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping2(
- buffer->Map((kNumInts / 2) * sizeof(int), 2 * sizeof(int)));
- ASSERT_TRUE(mapping2);
- ASSERT_TRUE(mapping2->GetBase());
- int* stuff2 = static_cast<int*>(mapping2->GetBase());
- EXPECT_EQ(static_cast<int>(kNumInts / 2) + kFudge, stuff2[0]);
- EXPECT_EQ(static_cast<int>(kNumInts / 2) + 1 + kFudge, stuff2[1]);
-
- stuff2[0] = 123;
- stuff2[1] = 456;
- EXPECT_EQ(123, stuff1[kNumInts / 2]);
- EXPECT_EQ(456, stuff1[kNumInts / 2 + 1]);
-
- mapping1.reset();
-
- EXPECT_EQ(123, stuff2[0]);
- EXPECT_EQ(456, stuff2[1]);
- stuff2[1] = 789;
- }
-
- // Do another partial mapping and check that everything is the way we expect
- // it to be.
- {
- EXPECT_TRUE(buffer->IsValidMap(sizeof(int), kNumBytes - sizeof(int)));
- std::unique_ptr<PlatformSharedBufferMapping> mapping(
- buffer->Map(sizeof(int), kNumBytes - sizeof(int)));
- ASSERT_TRUE(mapping);
- ASSERT_TRUE(mapping->GetBase());
- int* stuff = static_cast<int*>(mapping->GetBase());
-
- for (size_t j = 0; j < kNumInts - 1; j++) {
- int i = static_cast<int>(j) + 1;
- if (i == kNumInts / 2) {
- EXPECT_EQ(123, stuff[j]);
- } else if (i == kNumInts / 2 + 1) {
- EXPECT_EQ(789, stuff[j]);
- } else {
- EXPECT_EQ(i + kFudge, stuff[j]) << i;
- }
- }
- }
-}
-
-// TODO(vtl): Bigger buffers.
-
-TEST(PlatformSharedBufferTest, InvalidMappings) {
- scoped_refptr<PlatformSharedBuffer> buffer(PlatformSharedBuffer::Create(100));
- ASSERT_TRUE(buffer);
-
- // Zero length not allowed.
- EXPECT_FALSE(buffer->Map(0, 0));
- EXPECT_FALSE(buffer->IsValidMap(0, 0));
-
- // Okay:
- EXPECT_TRUE(buffer->Map(0, 100));
- EXPECT_TRUE(buffer->IsValidMap(0, 100));
- // Offset + length too big.
- EXPECT_FALSE(buffer->Map(0, 101));
- EXPECT_FALSE(buffer->IsValidMap(0, 101));
- EXPECT_FALSE(buffer->Map(1, 100));
- EXPECT_FALSE(buffer->IsValidMap(1, 100));
-
- // Okay:
- EXPECT_TRUE(buffer->Map(50, 50));
- EXPECT_TRUE(buffer->IsValidMap(50, 50));
- // Offset + length too big.
- EXPECT_FALSE(buffer->Map(50, 51));
- EXPECT_FALSE(buffer->IsValidMap(50, 51));
- EXPECT_FALSE(buffer->Map(51, 50));
- EXPECT_FALSE(buffer->IsValidMap(51, 50));
-}
-
-TEST(PlatformSharedBufferTest, TooBig) {
- // If |size_t| is 32-bit, it's quite possible/likely that |Create()| succeeds
- // (since it only involves creating a 4 GB file).
- size_t max_size = std::numeric_limits<size_t>::max();
- if (base::SysInfo::AmountOfVirtualMemory() &&
- max_size > static_cast<size_t>(base::SysInfo::AmountOfVirtualMemory()))
- max_size = static_cast<size_t>(base::SysInfo::AmountOfVirtualMemory());
- scoped_refptr<PlatformSharedBuffer> buffer(
- PlatformSharedBuffer::Create(max_size));
- // But, assuming |sizeof(size_t) == sizeof(void*)|, mapping all of it should
- // always fail.
- if (buffer)
- EXPECT_FALSE(buffer->Map(0, max_size));
-}
-
-// Tests that separate mappings get distinct addresses.
-// Note: It's not inconceivable that the OS could ref-count identical mappings
-// 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(PlatformSharedBufferTest, MappingsDistinct) {
- scoped_refptr<PlatformSharedBuffer> buffer(PlatformSharedBuffer::Create(100));
- std::unique_ptr<PlatformSharedBufferMapping> mapping1(buffer->Map(0, 100));
- std::unique_ptr<PlatformSharedBufferMapping> mapping2(buffer->Map(0, 100));
- EXPECT_NE(mapping1->GetBase(), mapping2->GetBase());
-}
-
-TEST(PlatformSharedBufferTest, BufferZeroInitialized) {
- static const size_t kSizes[] = {10, 100, 1000, 10000, 100000};
- for (size_t i = 0; i < arraysize(kSizes); i++) {
- scoped_refptr<PlatformSharedBuffer> buffer(
- PlatformSharedBuffer::Create(kSizes[i]));
- std::unique_ptr<PlatformSharedBufferMapping> mapping(
- buffer->Map(0, kSizes[i]));
- for (size_t j = 0; j < kSizes[i]; j++) {
- // "Assert" instead of "expect" so we don't spam the output with thousands
- // of failures if we fail.
- ASSERT_EQ('\0', static_cast<char*>(mapping->GetBase())[j])
- << "size " << kSizes[i] << ", offset " << j;
- }
- }
-}
-
-TEST(PlatformSharedBufferTest, MappingsOutliveBuffer) {
- std::unique_ptr<PlatformSharedBufferMapping> mapping1;
- std::unique_ptr<PlatformSharedBufferMapping> mapping2;
-
- {
- scoped_refptr<PlatformSharedBuffer> buffer(
- PlatformSharedBuffer::Create(100));
- mapping1 = buffer->Map(0, 100);
- mapping2 = buffer->Map(50, 50);
- static_cast<char*>(mapping1->GetBase())[50] = 'x';
- }
-
- EXPECT_EQ('x', static_cast<char*>(mapping2->GetBase())[0]);
-
- static_cast<char*>(mapping2->GetBase())[1] = 'y';
- EXPECT_EQ('y', static_cast<char*>(mapping1->GetBase())[51]);
-}
-
-TEST(PlatformSharedBufferTest, FromSharedMemoryHandle) {
- const size_t kBufferSize = 1234;
- base::SharedMemoryCreateOptions options;
- options.size = kBufferSize;
- base::SharedMemory shared_memory;
- ASSERT_TRUE(shared_memory.Create(options));
- ASSERT_TRUE(shared_memory.Map(kBufferSize));
-
- base::SharedMemoryHandle shm_handle =
- base::SharedMemory::DuplicateHandle(shared_memory.handle());
- scoped_refptr<PlatformSharedBuffer> simple_buffer(
- PlatformSharedBuffer::CreateFromSharedMemoryHandle(
- kBufferSize, false /* read_only */, shm_handle));
- ASSERT_TRUE(simple_buffer);
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping =
- simple_buffer->Map(0, kBufferSize);
- ASSERT_TRUE(mapping);
-
- const int kOffset = 123;
- char* base_memory = static_cast<char*>(shared_memory.memory());
- char* mojo_memory = static_cast<char*>(mapping->GetBase());
- base_memory[kOffset] = 0;
- EXPECT_EQ(0, mojo_memory[kOffset]);
- base_memory[kOffset] = 'a';
- EXPECT_EQ('a', mojo_memory[kOffset]);
- mojo_memory[kOffset] = 'z';
- EXPECT_EQ('z', base_memory[kOffset]);
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/scoped_ipc_support.cc b/mojo/edk/embedder/scoped_ipc_support.cc
deleted file mode 100644
index f67210a..0000000
--- a/mojo/edk/embedder/scoped_ipc_support.cc
+++ /dev/null
@@ -1,39 +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/embedder/scoped_ipc_support.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_restrictions.h"
-#include "mojo/edk/embedder/embedder.h"
-
-namespace mojo {
-namespace edk {
-
-ScopedIPCSupport::ScopedIPCSupport(
- scoped_refptr<base::TaskRunner> io_thread_task_runner,
- ShutdownPolicy shutdown_policy) : shutdown_policy_(shutdown_policy) {
- InitIPCSupport(io_thread_task_runner);
-}
-
-ScopedIPCSupport::~ScopedIPCSupport() {
- if (shutdown_policy_ == ShutdownPolicy::FAST) {
- ShutdownIPCSupport(base::Bind(&base::DoNothing));
- return;
- }
-
- base::WaitableEvent shutdown_event(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- ShutdownIPCSupport(base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(&shutdown_event)));
-
- base::ThreadRestrictions::ScopedAllowWait allow_io;
- shutdown_event.Wait();
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/embedder/scoped_ipc_support.h b/mojo/edk/embedder/scoped_ipc_support.h
deleted file mode 100644
index 22d8e50..0000000
--- a/mojo/edk/embedder/scoped_ipc_support.h
+++ /dev/null
@@ -1,118 +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_EDK_EMBEDDER_SCOPED_IPC_SUPPORT_H_
-#define MOJO_EDK_EMBEDDER_SCOPED_IPC_SUPPORT_H_
-
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace base {
-class TaskRunner;
-}
-
-namespace mojo {
-namespace edk {
-
-// A simple class that calls |InitIPCSupport()| on construction and
-// |ShutdownIPCSupport()| on destruction, blocking the destructor on clean IPC
-// shutdown completion.
-class MOJO_SYSTEM_IMPL_EXPORT ScopedIPCSupport {
- public:
- // ShutdownPolicy is a type for specifying the desired Mojo IPC support
- // shutdown behavior used during ScopedIPCSupport destruction.
- //
- // What follows is a quick overview of why shutdown behavior is interesting
- // and how you might decide which behavior is right for your use case.
- //
- // BACKGROUND
- // ==========
- //
- // In order to facilitate efficient and reliable transfer of Mojo message pipe
- // endpoints across process boundaries, the underlying model for a message
- // pipe is actually a self-collapsing cycle of "ports." See
- // //mojo/edk/system/ports for gritty implementation details.
- //
- // Ports are essentially globally unique identifiers used for system-wide
- // message routing. Every message pipe consists of at least two such ports:
- // the pipe's two concrete endpoints.
- //
- // When a message pipe endpoint is transferred over another message pipe, that
- // endpoint's port (which subsequently exists only internally with no
- // publicly-reachable handle) enters a transient proxying state for the
- // remainder of its lifetime. Once sufficient information has been
- // proagated throughout the system and this proxying port can be safely
- // bypassed, it is garbage-collected.
- //
- // If a process is terminated while hosting any active proxy ports, this
- // will necessarily break the message pipe(s) to which those ports belong.
- //
- // WHEN TO USE CLEAN SHUTDOWN
- // ==========================
- //
- // Consider three processes, A, B, and C. Suppose A creates a message pipe,
- // sending one end to B and the other to C. For some brief period of time,
- // messages sent by B or C over this pipe may be proxied through A.
- //
- // If A is suddenly terminated, there may be no way for B's messages to reach
- // C (and vice versa), since the message pipe state may not have been fully
- // propagated to all concerned processes in the system. As such, both B and C
- // may have no choice but to signal peer closure on their respective ends of
- // the pipe, and thus the pipe may be broken despite a lack of intent by
- // either B or C.
- //
- // This can also happen if A creates a pipe and passes one end to B, who then
- // passes it along to C. B may temporarily proxy messages for this pipe
- // between A and C, and B's sudden demise will in turn beget the pipe's
- // own sudden demise.
- //
- // In situations where these sort of arrangements may occur, potentially
- // proxying processes must ensure they are shut down cleanly in order to avoid
- // flaky system behavior.
- //
- // WHEN TO USE FAST SHUTDOWN
- // =========================
- //
- // As a general rule of thumb, if your process never creates a message pipe
- // where both ends are passed to other processes, or never forwards a pipe
- // endpoint from one process to another, fast shutdown is safe. Satisfaction
- // of these constraints can be difficult to prove though, so clean shutdown is
- // a safe default choice.
- //
- // Content renderer processes are a good example of a case where fast shutdown
- // is safe, because as a matter of security and stability, a renderer cannot
- // be trusted to do any proxying on behalf of two other processes anyway.
- //
- // There are other practical scenarios where fast shutdown is safe even if
- // the process may have live proxies. For example, content's browser process
- // is treated as a sort of master process in the system, in the sense that if
- // the browser is terminated, no other part of the system is expected to
- // continue normal operation anyway. In this case the side-effects of fast
- // shutdown are irrelevant, so fast shutdown is preferred.
- enum class ShutdownPolicy {
- // Clean shutdown. This causes the ScopedIPCSupport destructor to *block*
- // the calling thread until clean shutdown is complete. See explanation
- // above for details.
- CLEAN,
-
- // Fast shutdown. In this case a cheap best-effort attempt is made to
- // shut down the IPC system, but no effort is made to wait for its
- // completion. See explanation above for details.
- FAST,
- };
-
- ScopedIPCSupport(scoped_refptr<base::TaskRunner> io_thread_task_runner,
- ShutdownPolicy shutdown_policy);
- ~ScopedIPCSupport();
-
- private:
- const ShutdownPolicy shutdown_policy_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupport);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_SCOPED_IPC_SUPPORT_H_
diff --git a/mojo/edk/embedder/scoped_platform_handle.h b/mojo/edk/embedder/scoped_platform_handle.h
deleted file mode 100644
index 15b80ea..0000000
--- a/mojo/edk/embedder/scoped_platform_handle.h
+++ /dev/null
@@ -1,63 +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_EMBEDDER_SCOPED_PLATFORM_HANDLE_H_
-#define MOJO_EDK_EMBEDDER_SCOPED_PLATFORM_HANDLE_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/c/system/macros.h"
-
-namespace mojo {
-namespace edk {
-
-class MOJO_SYSTEM_IMPL_EXPORT ScopedPlatformHandle {
- public:
- ScopedPlatformHandle() {}
- explicit ScopedPlatformHandle(PlatformHandle handle) : handle_(handle) {}
- ~ScopedPlatformHandle() { handle_.CloseIfNecessary(); }
-
- // Move-only constructor and operator=.
- ScopedPlatformHandle(ScopedPlatformHandle&& other)
- : handle_(other.release()) {}
-
- ScopedPlatformHandle& operator=(ScopedPlatformHandle&& other) {
- if (this != &other)
- handle_ = other.release();
- return *this;
- }
-
- const PlatformHandle& get() const { return handle_; }
-
- void swap(ScopedPlatformHandle& other) {
- PlatformHandle temp = handle_;
- handle_ = other.handle_;
- other.handle_ = temp;
- }
-
- PlatformHandle release() WARN_UNUSED_RESULT {
- PlatformHandle rv = handle_;
- handle_ = PlatformHandle();
- return rv;
- }
-
- void reset(PlatformHandle handle = PlatformHandle()) {
- handle_.CloseIfNecessary();
- handle_ = handle;
- }
-
- bool is_valid() const { return handle_.is_valid(); }
-
- private:
- PlatformHandle handle_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedPlatformHandle);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_SCOPED_PLATFORM_HANDLE_H_
diff --git a/mojo/edk/embedder/test_embedder.cc b/mojo/edk/embedder/test_embedder.cc
deleted file mode 100644
index 9658010..0000000
--- a/mojo/edk/embedder/test_embedder.cc
+++ /dev/null
@@ -1,46 +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/test_embedder.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/handle_table.h"
-
-namespace mojo {
-
-namespace edk {
-namespace internal {
-
-bool ShutdownCheckNoLeaks(Core* core) {
- std::vector<MojoHandle> leaked_handles;
- core->GetActiveHandlesForTest(&leaked_handles);
- if (leaked_handles.empty())
- return true;
- for (auto handle : leaked_handles)
- LOG(ERROR) << "Mojo embedder shutdown: Leaking handle " << handle;
- return false;
-}
-
-} // namespace internal
-
-namespace test {
-
-bool Shutdown() {
- CHECK(internal::g_core);
- bool rv = internal::ShutdownCheckNoLeaks(internal::g_core);
- delete internal::g_core;
- internal::g_core = nullptr;
-
- return rv;
-}
-
-} // namespace test
-} // namespace edk
-
-} // namespace mojo
diff --git a/mojo/edk/embedder/test_embedder.h b/mojo/edk/embedder/test_embedder.h
deleted file mode 100644
index c64ba17..0000000
--- a/mojo/edk/embedder/test_embedder.h
+++ /dev/null
@@ -1,28 +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_EMBEDDER_TEST_EMBEDDER_H_
-#define MOJO_EDK_EMBEDDER_TEST_EMBEDDER_H_
-
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-// This shuts down the global, singleton instance. (Note: "Real" embedders are
-// not expected to ever shut down this instance. This |Shutdown()| function will
-// do more work to ensure that tests don't leak, etc.) Returns true if there
-// were no problems, false if there were leaks -- i.e., handles still open -- or
-// any other problems.
-//
-// Note: It is up to the caller to ensure that there are not outstanding
-// callbacks from |CreateChannel()| before calling this.
-MOJO_SYSTEM_IMPL_EXPORT bool Shutdown();
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_EMBEDDER_TEST_EMBEDDER_H_
diff --git a/mojo/edk/js/BUILD.gn b/mojo/edk/js/BUILD.gn
deleted file mode 100644
index fc1e03c..0000000
--- a/mojo/edk/js/BUILD.gn
+++ /dev/null
@@ -1,35 +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.
-
-component("js") {
- sources = [
- "core.cc",
- "core.h",
- "drain_data.cc",
- "drain_data.h",
- "handle.cc",
- "handle.h",
- "handle_close_observer.h",
- "js_export.h",
- "mojo_runner_delegate.cc",
- "mojo_runner_delegate.h",
- "support.cc",
- "support.h",
- "threading.cc",
- "threading.h",
- "waiting_callback.cc",
- "waiting_callback.h",
- ]
-
- public_deps = [
- "//base",
- "//gin",
- "//v8",
- ]
-
- deps = [
- "//mojo/public/cpp/system",
- ]
- defines = [ "MOJO_JS_IMPLEMENTATION" ]
-}
diff --git a/mojo/edk/js/core.cc b/mojo/edk/js/core.cc
deleted file mode 100644
index baccc4c..0000000
--- a/mojo/edk/js/core.cc
+++ /dev/null
@@ -1,454 +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/js/core.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "gin/arguments.h"
-#include "gin/array_buffer.h"
-#include "gin/converter.h"
-#include "gin/dictionary.h"
-#include "gin/function_template.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "gin/per_isolate_data.h"
-#include "gin/public/wrapper_info.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/drain_data.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/public/cpp/system/wait.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-MojoResult CloseHandle(gin::Handle<HandleWrapper> handle) {
- if (!handle->get().is_valid())
- return MOJO_RESULT_INVALID_ARGUMENT;
- handle->Close();
- return MOJO_RESULT_OK;
-}
-
-gin::Dictionary QueryHandleSignalsState(const gin::Arguments& args,
- mojo::Handle handle) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- if (!handle.is_valid()) {
- dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
- } else {
- HandleSignalsState state = handle.QuerySignalsState();
- dictionary.Set("result", MOJO_RESULT_OK);
- dictionary.Set("satisfiedSignals", state.satisfied_signals);
- dictionary.Set("satisfiableSignals", state.satisfiable_signals);
- }
- return dictionary;
-}
-
-gin::Dictionary WaitHandle(const gin::Arguments& args,
- mojo::Handle handle,
- MojoHandleSignals signals) {
- v8::Isolate* isolate = args.isolate();
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate);
-
- MojoHandleSignalsState signals_state;
- MojoResult result = Wait(handle, signals, &signals_state);
- dictionary.Set("result", result);
-
- if (result != MOJO_RESULT_OK && result != MOJO_RESULT_FAILED_PRECONDITION) {
- dictionary.Set("signalsState", v8::Null(isolate).As<v8::Value>());
- } else {
- gin::Dictionary signalsStateDict = gin::Dictionary::CreateEmpty(isolate);
- signalsStateDict.Set("satisfiedSignals", signals_state.satisfied_signals);
- signalsStateDict.Set("satisfiableSignals",
- signals_state.satisfiable_signals);
- dictionary.Set("signalsState", signalsStateDict);
- }
-
- return dictionary;
-}
-
-gin::Dictionary CreateMessagePipe(const gin::Arguments& args) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
-
- MojoHandle handle0 = MOJO_HANDLE_INVALID;
- MojoHandle handle1 = MOJO_HANDLE_INVALID;
- MojoResult result = MOJO_RESULT_OK;
-
- v8::Handle<v8::Value> options_value = args.PeekNext();
- if (options_value.IsEmpty() || options_value->IsNull() ||
- options_value->IsUndefined()) {
- result = MojoCreateMessagePipe(NULL, &handle0, &handle1);
- } else if (options_value->IsObject()) {
- gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
- MojoCreateMessagePipeOptions options;
- // For future struct_size, we can probably infer that from the presence of
- // properties in options_dict. For now, it's always 8.
- options.struct_size = 8;
- // Ideally these would be optional. But the interface makes it hard to
- // typecheck them then.
- if (!options_dict.Get("flags", &options.flags)) {
- return dictionary;
- }
-
- result = MojoCreateMessagePipe(&options, &handle0, &handle1);
- } else {
- return dictionary;
- }
-
- CHECK_EQ(MOJO_RESULT_OK, result);
-
- dictionary.Set("result", result);
- dictionary.Set("handle0", mojo::Handle(handle0));
- dictionary.Set("handle1", mojo::Handle(handle1));
- return dictionary;
-}
-
-MojoResult WriteMessage(
- mojo::Handle handle,
- const gin::ArrayBufferView& buffer,
- const std::vector<gin::Handle<HandleWrapper> >& handles,
- MojoWriteMessageFlags flags) {
- std::vector<MojoHandle> raw_handles(handles.size());
- for (size_t i = 0; i < handles.size(); ++i)
- raw_handles[i] = handles[i]->get().value();
- MojoResult rv = MojoWriteMessage(handle.value(),
- buffer.bytes(),
- static_cast<uint32_t>(buffer.num_bytes()),
- raw_handles.empty() ? NULL : &raw_handles[0],
- static_cast<uint32_t>(raw_handles.size()),
- flags);
- // MojoWriteMessage takes ownership of the handles, so release them here.
- for (size_t i = 0; i < handles.size(); ++i)
- ignore_result(handles[i]->release());
-
- return rv;
-}
-
-gin::Dictionary ReadMessage(const gin::Arguments& args,
- mojo::Handle handle,
- MojoReadMessageFlags flags) {
- uint32_t num_bytes = 0;
- uint32_t num_handles = 0;
- MojoResult result = MojoReadMessage(
- handle.value(), NULL, &num_bytes, NULL, &num_handles, flags);
- if (result != MOJO_RESULT_RESOURCE_EXHAUSTED) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", result);
- return dictionary;
- }
-
- v8::Handle<v8::ArrayBuffer> array_buffer =
- v8::ArrayBuffer::New(args.isolate(), num_bytes);
- std::vector<mojo::Handle> handles(num_handles);
-
- gin::ArrayBuffer buffer;
- ConvertFromV8(args.isolate(), array_buffer, &buffer);
- CHECK(buffer.num_bytes() == num_bytes);
-
- result = MojoReadMessage(handle.value(),
- buffer.bytes(),
- &num_bytes,
- handles.empty() ? NULL :
- reinterpret_cast<MojoHandle*>(&handles[0]),
- &num_handles,
- flags);
-
- CHECK(buffer.num_bytes() == num_bytes);
- CHECK(handles.size() == num_handles);
-
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", result);
- dictionary.Set("buffer", array_buffer);
- dictionary.Set("handles", handles);
- return dictionary;
-}
-
-gin::Dictionary CreateDataPipe(const gin::Arguments& args) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
-
- MojoHandle producer_handle = MOJO_HANDLE_INVALID;
- MojoHandle consumer_handle = MOJO_HANDLE_INVALID;
- MojoResult result = MOJO_RESULT_OK;
-
- v8::Handle<v8::Value> options_value = args.PeekNext();
- if (options_value.IsEmpty() || options_value->IsNull() ||
- options_value->IsUndefined()) {
- result = MojoCreateDataPipe(NULL, &producer_handle, &consumer_handle);
- } else if (options_value->IsObject()) {
- gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
- MojoCreateDataPipeOptions options;
- // For future struct_size, we can probably infer that from the presence of
- // properties in options_dict. For now, it's always 16.
- options.struct_size = 16;
- // Ideally these would be optional. But the interface makes it hard to
- // typecheck them then.
- if (!options_dict.Get("flags", &options.flags) ||
- !options_dict.Get("elementNumBytes", &options.element_num_bytes) ||
- !options_dict.Get("capacityNumBytes", &options.capacity_num_bytes)) {
- return dictionary;
- }
-
- result = MojoCreateDataPipe(&options, &producer_handle, &consumer_handle);
- } else {
- return dictionary;
- }
-
- CHECK_EQ(MOJO_RESULT_OK, result);
-
- dictionary.Set("result", result);
- dictionary.Set("producerHandle", mojo::Handle(producer_handle));
- dictionary.Set("consumerHandle", mojo::Handle(consumer_handle));
- return dictionary;
-}
-
-gin::Dictionary WriteData(const gin::Arguments& args,
- mojo::Handle handle,
- const gin::ArrayBufferView& buffer,
- MojoWriteDataFlags flags) {
- uint32_t num_bytes = static_cast<uint32_t>(buffer.num_bytes());
- MojoResult result =
- MojoWriteData(handle.value(), buffer.bytes(), &num_bytes, flags);
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", result);
- dictionary.Set("numBytes", num_bytes);
- return dictionary;
-}
-
-gin::Dictionary ReadData(const gin::Arguments& args,
- mojo::Handle handle,
- MojoReadDataFlags flags) {
- uint32_t num_bytes = 0;
- MojoResult result = MojoReadData(
- handle.value(), NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY);
- if (result != MOJO_RESULT_OK) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", result);
- return dictionary;
- }
-
- v8::Handle<v8::ArrayBuffer> array_buffer =
- v8::ArrayBuffer::New(args.isolate(), num_bytes);
- gin::ArrayBuffer buffer;
- ConvertFromV8(args.isolate(), array_buffer, &buffer);
- CHECK_EQ(num_bytes, buffer.num_bytes());
-
- result = MojoReadData(handle.value(), buffer.bytes(), &num_bytes, flags);
- CHECK_EQ(num_bytes, buffer.num_bytes());
-
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- dictionary.Set("result", result);
- dictionary.Set("buffer", array_buffer);
- return dictionary;
-}
-
-// Asynchronously read all of the data available for the specified data pipe
-// consumer handle until the remote handle is closed or an error occurs. A
-// Promise is returned whose settled value is an object like this:
-// {result: core.RESULT_OK, buffer: dataArrayBuffer}. If the read failed,
-// then the Promise is rejected, the result will be the actual error code,
-// and the buffer will contain whatever was read before the error occurred.
-// The drainData data pipe handle argument is closed automatically.
-
-v8::Handle<v8::Value> DoDrainData(gin::Arguments* args,
- gin::Handle<HandleWrapper> handle) {
- return (new DrainData(args->isolate(), handle->release()))->GetPromise();
-}
-
-bool IsHandle(gin::Arguments* args, v8::Handle<v8::Value> val) {
- gin::Handle<mojo::edk::js::HandleWrapper> ignore_handle;
- return gin::Converter<gin::Handle<mojo::edk::js::HandleWrapper>>::FromV8(
- args->isolate(), val, &ignore_handle);
-}
-
-gin::Dictionary CreateSharedBuffer(const gin::Arguments& args,
- uint64_t num_bytes,
- MojoCreateSharedBufferOptionsFlags flags) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- MojoHandle handle = MOJO_HANDLE_INVALID;
- MojoCreateSharedBufferOptions options;
- // The |flags| is mandatory parameter for CreateSharedBuffer, and it will
- // be always initialized in MojoCreateSharedBufferOptions struct. For
- // forward compatibility, set struct_size to be 8 bytes (struct_size + flags),
- // so that validator will only check the field that is set.
- options.struct_size = 8;
- options.flags = flags;
- MojoResult result = MojoCreateSharedBuffer(&options, num_bytes, &handle);
- if (result != MOJO_RESULT_OK) {
- dictionary.Set("result", result);
- return dictionary;
- }
-
- dictionary.Set("result", result);
- dictionary.Set("handle", mojo::Handle(handle));
-
- return dictionary;
-}
-
-gin::Dictionary DuplicateBufferHandle(
- const gin::Arguments& args,
- mojo::Handle handle,
- MojoDuplicateBufferHandleOptionsFlags flags) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- MojoHandle duped = MOJO_HANDLE_INVALID;
- MojoDuplicateBufferHandleOptions options;
- // The |flags| is mandatory parameter for DuplicateBufferHandle, and it will
- // be always initialized in MojoDuplicateBufferHandleOptions struct. For
- // forward compatibility, set struct_size to be 8 bytes (struct_size + flags),
- // so that validator will only check the field that is set.
- options.struct_size = 8;
- options.flags = flags;
- MojoResult result =
- MojoDuplicateBufferHandle(handle.value(), &options, &duped);
- if (result != MOJO_RESULT_OK) {
- dictionary.Set("result", result);
- return dictionary;
- }
-
- dictionary.Set("result", result);
- dictionary.Set("handle", mojo::Handle(duped));
-
- return dictionary;
-}
-
-gin::Dictionary MapBuffer(const gin::Arguments& args,
- mojo::Handle handle,
- uint64_t offset,
- uint64_t num_bytes,
- MojoMapBufferFlags flags) {
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
- void* data = nullptr;
- MojoResult result =
- MojoMapBuffer(handle.value(), offset, num_bytes, &data, flags);
- if (result != MOJO_RESULT_OK) {
- dictionary.Set("result", result);
- return dictionary;
- }
-
- v8::Handle<v8::ArrayBuffer> array_buffer =
- v8::ArrayBuffer::New(args.isolate(), data, num_bytes);
-
- dictionary.Set("result", result);
- dictionary.Set("buffer", array_buffer);
-
- return dictionary;
-}
-
-MojoResult UnmapBuffer(const gin::Arguments& args,
- const v8::Handle<v8::ArrayBuffer>& buffer) {
- // Buffer must be external, created by MapBuffer
- if (!buffer->IsExternal())
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return MojoUnmapBuffer(buffer->GetContents().Data());
-}
-
-gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
-
-} // namespace
-
-const char Core::kModuleName[] = "mojo/public/js/core";
-
-v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) {
- gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
- v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
- &g_wrapper_info);
-
- if (templ.IsEmpty()) {
- templ =
- gin::ObjectTemplateBuilder(isolate)
- // TODO(mpcomplete): Should these just be methods on the JS Handle
- // object?
- .SetMethod("close", CloseHandle)
- .SetMethod("queryHandleSignalsState", QueryHandleSignalsState)
- .SetMethod("wait", WaitHandle)
- .SetMethod("createMessagePipe", CreateMessagePipe)
- .SetMethod("writeMessage", WriteMessage)
- .SetMethod("readMessage", ReadMessage)
- .SetMethod("createDataPipe", CreateDataPipe)
- .SetMethod("writeData", WriteData)
- .SetMethod("readData", ReadData)
- .SetMethod("drainData", DoDrainData)
- .SetMethod("isHandle", IsHandle)
- .SetMethod("createSharedBuffer", CreateSharedBuffer)
- .SetMethod("duplicateBufferHandle", DuplicateBufferHandle)
- .SetMethod("mapBuffer", MapBuffer)
- .SetMethod("unmapBuffer", UnmapBuffer)
-
- .SetValue("RESULT_OK", MOJO_RESULT_OK)
- .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED)
- .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN)
- .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT)
- .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED)
- .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND)
- .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS)
- .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED)
- .SetValue("RESULT_RESOURCE_EXHAUSTED",
- MOJO_RESULT_RESOURCE_EXHAUSTED)
- .SetValue("RESULT_FAILED_PRECONDITION",
- MOJO_RESULT_FAILED_PRECONDITION)
- .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED)
- .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE)
- .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED)
- .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL)
- .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE)
- .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS)
- .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY)
- .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT)
-
- .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE)
- .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
- .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE)
- .SetValue("HANDLE_SIGNAL_PEER_CLOSED",
- MOJO_HANDLE_SIGNAL_PEER_CLOSED)
-
- .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE",
- MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE)
-
- .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE)
-
- .SetValue("READ_MESSAGE_FLAG_NONE", MOJO_READ_MESSAGE_FLAG_NONE)
- .SetValue("READ_MESSAGE_FLAG_MAY_DISCARD",
- MOJO_READ_MESSAGE_FLAG_MAY_DISCARD)
-
- .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE",
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE)
-
- .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE)
- .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE",
- MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)
-
- .SetValue("READ_DATA_FLAG_NONE", MOJO_READ_DATA_FLAG_NONE)
- .SetValue("READ_DATA_FLAG_ALL_OR_NONE",
- MOJO_READ_DATA_FLAG_ALL_OR_NONE)
- .SetValue("READ_DATA_FLAG_DISCARD", MOJO_READ_DATA_FLAG_DISCARD)
- .SetValue("READ_DATA_FLAG_QUERY", MOJO_READ_DATA_FLAG_QUERY)
- .SetValue("READ_DATA_FLAG_PEEK", MOJO_READ_DATA_FLAG_PEEK)
- .SetValue("CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE",
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE)
-
- .SetValue("DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE",
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE)
-
- .SetValue("DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY",
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY)
-
- .SetValue("MAP_BUFFER_FLAG_NONE", MOJO_MAP_BUFFER_FLAG_NONE)
- .Build();
-
- data->SetObjectTemplate(&g_wrapper_info, templ);
- }
-
- return templ->NewInstance();
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/core.h b/mojo/edk/js/core.h
deleted file mode 100644
index 97ef5df..0000000
--- a/mojo/edk/js/core.h
+++ /dev/null
@@ -1,25 +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_JS_CORE_H_
-#define MOJO_EDK_JS_CORE_H_
-
-#include "mojo/edk/js/js_export.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT Core {
- public:
- static const char kModuleName[];
- static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_CORE_H_
diff --git a/mojo/edk/js/drain_data.cc b/mojo/edk/js/drain_data.cc
deleted file mode 100644
index 334ced3..0000000
--- a/mojo/edk/js/drain_data.cc
+++ /dev/null
@@ -1,129 +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/js/drain_data.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "gin/array_buffer.h"
-#include "gin/converter.h"
-#include "gin/dictionary.h"
-#include "gin/per_context_data.h"
-#include "gin/per_isolate_data.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-DrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle)
- : isolate_(isolate),
- handle_(DataPipeConsumerHandle(handle.value())),
- handle_watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC) {
- v8::Handle<v8::Context> context(isolate_->GetCurrentContext());
- runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
-
- WaitForData();
-}
-
-v8::Handle<v8::Value> DrainData::GetPromise() {
- CHECK(resolver_.IsEmpty());
- v8::Handle<v8::Promise::Resolver> resolver(
- v8::Promise::Resolver::New(isolate_));
- resolver_.Reset(isolate_, resolver);
- return resolver->GetPromise();
-}
-
-DrainData::~DrainData() {
- resolver_.Reset();
-}
-
-void DrainData::WaitForData() {
- handle_watcher_.Watch(
- handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
- base::Bind(&DrainData::DataReady, base::Unretained(this)));
-}
-
-void DrainData::DataReady(MojoResult result) {
- if (result != MOJO_RESULT_OK) {
- DeliverData(result);
- return;
- }
- while (result == MOJO_RESULT_OK) {
- result = ReadData();
- if (result == MOJO_RESULT_SHOULD_WAIT)
- WaitForData();
- else if (result != MOJO_RESULT_OK)
- DeliverData(result);
- }
-}
-
-MojoResult DrainData::ReadData() {
- const void* buffer;
- uint32_t num_bytes = 0;
- MojoResult result = BeginReadDataRaw(
- handle_.get(), &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
- if (result != MOJO_RESULT_OK)
- return result;
- const char* p = static_cast<const char*>(buffer);
- data_buffers_.push_back(base::MakeUnique<DataBuffer>(p, p + num_bytes));
- return EndReadDataRaw(handle_.get(), num_bytes);
-}
-
-void DrainData::DeliverData(MojoResult result) {
- if (!runner_) {
- delete this;
- return;
- }
-
- size_t total_bytes = 0;
- for (unsigned i = 0; i < data_buffers_.size(); i++)
- total_bytes += data_buffers_[i]->size();
-
- // Create a total_bytes length ArrayBuffer return value.
- gin::Runner::Scope scope(runner_.get());
- v8::Handle<v8::ArrayBuffer> array_buffer =
- v8::ArrayBuffer::New(isolate_, total_bytes);
- gin::ArrayBuffer buffer;
- ConvertFromV8(isolate_, array_buffer, &buffer);
- CHECK_EQ(total_bytes, buffer.num_bytes());
-
- // Copy the data_buffers into the ArrayBuffer.
- char* array_buffer_ptr = static_cast<char*>(buffer.bytes());
- size_t offset = 0;
- for (size_t i = 0; i < data_buffers_.size(); i++) {
- size_t num_bytes = data_buffers_[i]->size();
- if (num_bytes == 0)
- continue;
- const char* data_buffer_ptr = &((*data_buffers_[i])[0]);
- memcpy(array_buffer_ptr + offset, data_buffer_ptr, num_bytes);
- offset += num_bytes;
- }
-
- // The "settled" value of the promise always includes all of the data
- // that was read before either an error occurred or the remote pipe handle
- // was closed. The latter is indicated by MOJO_RESULT_FAILED_PRECONDITION.
-
- v8::Handle<v8::Promise::Resolver> resolver(
- v8::Local<v8::Promise::Resolver>::New(isolate_, resolver_));
-
- gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate_);
- dictionary.Set("result", result);
- dictionary.Set("buffer", array_buffer);
- v8::Handle<v8::Value> settled_value(ConvertToV8(isolate_, dictionary));
-
- if (result == MOJO_RESULT_FAILED_PRECONDITION)
- resolver->Resolve(settled_value);
- else
- resolver->Reject(settled_value);
-
- delete this;
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/drain_data.h b/mojo/edk/js/drain_data.h
deleted file mode 100644
index 42da90f..0000000
--- a/mojo/edk/js/drain_data.h
+++ /dev/null
@@ -1,65 +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_JS_DRAIN_DATA_H_
-#define MOJO_EDK_JS_DRAIN_DATA_H_
-
-#include <memory>
-#include <vector>
-
-#include "gin/runner.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-// This class is the implementation of the Mojo JavaScript core module's
-// drainData() method. It is not intended to be used directly. The caller
-// allocates a DrainData on the heap and returns GetPromise() to JS. The
-// implementation deletes itself after reading as much data as possible
-// and rejecting or resolving the Promise.
-
-class DrainData {
- public:
- // Starts waiting for data on the specified data pipe consumer handle.
- // See WaitForData(). The constructor does not block.
- DrainData(v8::Isolate* isolate, mojo::Handle handle);
-
- // Returns a Promise that will be settled when no more data can be read.
- // Should be called just once on a newly allocated DrainData object.
- v8::Handle<v8::Value> GetPromise();
-
- private:
- ~DrainData();
-
- // Waits for data to be available. DataReady() will be notified.
- void WaitForData();
-
- // Use ReadData() to read whatever is availble now on handle_ and save
- // it in data_buffers_.
- void DataReady(MojoResult result);
- MojoResult ReadData();
-
- // When the remote data pipe handle is closed, or an error occurs, deliver
- // all of the buffered data to the JS Promise and then delete this.
- void DeliverData(MojoResult result);
-
- using DataBuffer = std::vector<char>;
-
- v8::Isolate* isolate_;
- ScopedDataPipeConsumerHandle handle_;
- SimpleWatcher handle_watcher_;
- base::WeakPtr<gin::Runner> runner_;
- v8::UniquePersistent<v8::Promise::Resolver> resolver_;
- std::vector<std::unique_ptr<DataBuffer>> data_buffers_;
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_DRAIN_DATA_H_
diff --git a/mojo/edk/js/handle.cc b/mojo/edk/js/handle.cc
deleted file mode 100644
index 7da8e9f..0000000
--- a/mojo/edk/js/handle.cc
+++ /dev/null
@@ -1,85 +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/js/handle.h"
-
-#include "mojo/edk/js/handle_close_observer.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-gin::WrapperInfo HandleWrapper::kWrapperInfo = { gin::kEmbedderNativeGin };
-
-HandleWrapper::HandleWrapper(MojoHandle handle)
- : handle_(mojo::Handle(handle)) {
-}
-
-HandleWrapper::~HandleWrapper() {
- NotifyCloseObservers();
-}
-
-void HandleWrapper::Close() {
- NotifyCloseObservers();
- handle_.reset();
-}
-
-void HandleWrapper::AddCloseObserver(HandleCloseObserver* observer) {
- close_observers_.AddObserver(observer);
-}
-
-void HandleWrapper::RemoveCloseObserver(HandleCloseObserver* observer) {
- close_observers_.RemoveObserver(observer);
-}
-
-void HandleWrapper::NotifyCloseObservers() {
- if (!handle_.is_valid())
- return;
-
- for (auto& observer : close_observers_)
- observer.OnWillCloseHandle();
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-namespace gin {
-
-v8::Handle<v8::Value> Converter<mojo::Handle>::ToV8(v8::Isolate* isolate,
- const mojo::Handle& val) {
- if (!val.is_valid())
- return v8::Null(isolate);
- return mojo::edk::js::HandleWrapper::Create(isolate, val.value()).ToV8();
-}
-
-bool Converter<mojo::Handle>::FromV8(v8::Isolate* isolate,
- v8::Handle<v8::Value> val,
- mojo::Handle* out) {
- if (val->IsNull()) {
- *out = mojo::Handle();
- return true;
- }
-
- gin::Handle<mojo::edk::js::HandleWrapper> handle;
- if (!Converter<gin::Handle<mojo::edk::js::HandleWrapper>>::FromV8(
- isolate, val, &handle))
- return false;
-
- *out = handle->get();
- return true;
-}
-
-v8::Handle<v8::Value> Converter<mojo::MessagePipeHandle>::ToV8(
- v8::Isolate* isolate, mojo::MessagePipeHandle val) {
- return Converter<mojo::Handle>::ToV8(isolate, val);
-}
-
-bool Converter<mojo::MessagePipeHandle>::FromV8(v8::Isolate* isolate,
- v8::Handle<v8::Value> val,
- mojo::MessagePipeHandle* out) {
- return Converter<mojo::Handle>::FromV8(isolate, val, out);
-}
-
-} // namespace gin
diff --git a/mojo/edk/js/handle.h b/mojo/edk/js/handle.h
deleted file mode 100644
index 60652ed..0000000
--- a/mojo/edk/js/handle.h
+++ /dev/null
@@ -1,107 +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_JS_HANDLE_H_
-#define MOJO_EDK_JS_HANDLE_H_
-
-#include <stdint.h>
-
-#include "base/observer_list.h"
-#include "gin/converter.h"
-#include "gin/handle.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/js_export.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class HandleCloseObserver;
-
-// Wrapper for mojo Handles exposed to JavaScript. This ensures the Handle
-// is Closed when its JS object is garbage collected.
-class MOJO_JS_EXPORT HandleWrapper : public gin::Wrappable<HandleWrapper> {
- public:
- static gin::WrapperInfo kWrapperInfo;
-
- static gin::Handle<HandleWrapper> Create(v8::Isolate* isolate,
- MojoHandle handle) {
- return gin::CreateHandle(isolate, new HandleWrapper(handle));
- }
-
- mojo::Handle get() const { return handle_.get(); }
- mojo::Handle release() { return handle_.release(); }
- void Close();
-
- void AddCloseObserver(HandleCloseObserver* observer);
- void RemoveCloseObserver(HandleCloseObserver* observer);
-
- protected:
- HandleWrapper(MojoHandle handle);
- ~HandleWrapper() override;
- void NotifyCloseObservers();
-
- mojo::ScopedHandle handle_;
- base::ObserverList<HandleCloseObserver> close_observers_;
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-namespace gin {
-
-// Note: It's important to use this converter rather than the one for
-// MojoHandle, since that will do a simple int32_t conversion. It's unfortunate
-// there's no way to prevent against accidental use.
-// TODO(mpcomplete): define converters for all Handle subtypes.
-template <>
-struct MOJO_JS_EXPORT Converter<mojo::Handle> {
- static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
- const mojo::Handle& val);
- static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
- mojo::Handle* out);
-};
-
-template <>
-struct MOJO_JS_EXPORT Converter<mojo::MessagePipeHandle> {
- static v8::Handle<v8::Value> ToV8(v8::Isolate* isolate,
- mojo::MessagePipeHandle val);
- static bool FromV8(v8::Isolate* isolate,
- v8::Handle<v8::Value> val,
- mojo::MessagePipeHandle* out);
-};
-
-// We need to specialize the normal gin::Handle converter in order to handle
-// converting |null| to a wrapper for an empty mojo::Handle.
-template <>
-struct MOJO_JS_EXPORT Converter<gin::Handle<mojo::edk::js::HandleWrapper>> {
- static v8::Handle<v8::Value> ToV8(
- v8::Isolate* isolate,
- const gin::Handle<mojo::edk::js::HandleWrapper>& val) {
- return val.ToV8();
- }
-
- static bool FromV8(v8::Isolate* isolate,
- v8::Handle<v8::Value> val,
- gin::Handle<mojo::edk::js::HandleWrapper>* out) {
- if (val->IsNull()) {
- *out = mojo::edk::js::HandleWrapper::Create(isolate, MOJO_HANDLE_INVALID);
- return true;
- }
-
- mojo::edk::js::HandleWrapper* object = NULL;
- if (!Converter<mojo::edk::js::HandleWrapper*>::FromV8(isolate, val,
- &object)) {
- return false;
- }
- *out = gin::Handle<mojo::edk::js::HandleWrapper>(val, object);
- return true;
- }
-};
-
-} // namespace gin
-
-#endif // MOJO_EDK_JS_HANDLE_H_
diff --git a/mojo/edk/js/handle_close_observer.h b/mojo/edk/js/handle_close_observer.h
deleted file mode 100644
index c7b935e..0000000
--- a/mojo/edk/js/handle_close_observer.h
+++ /dev/null
@@ -1,24 +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_JS_HANDLE_CLOSE_OBSERVER_H_
-#define MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class HandleCloseObserver {
- public:
- virtual void OnWillCloseHandle() = 0;
-
- protected:
- virtual ~HandleCloseObserver() {}
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
diff --git a/mojo/edk/js/handle_unittest.cc b/mojo/edk/js/handle_unittest.cc
deleted file mode 100644
index dd2562f..0000000
--- a/mojo/edk/js/handle_unittest.cc
+++ /dev/null
@@ -1,92 +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 "base/macros.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/handle_close_observer.h"
-#include "mojo/public/cpp/system/core.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class HandleWrapperTest : public testing::Test,
- public HandleCloseObserver {
- public:
- HandleWrapperTest() : closes_observed_(0) {}
-
- void OnWillCloseHandle() override { closes_observed_++; }
-
- protected:
- int closes_observed_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HandleWrapperTest);
-};
-
-class TestHandleWrapper : public HandleWrapper {
- public:
- explicit TestHandleWrapper(MojoHandle handle) : HandleWrapper(handle) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestHandleWrapper);
-};
-
-// Test that calling Close() on a HandleWrapper for an invalid handle does not
-// notify observers.
-TEST_F(HandleWrapperTest, CloseWithInvalidHandle) {
- {
- TestHandleWrapper wrapper(MOJO_HANDLE_INVALID);
- wrapper.AddCloseObserver(this);
- ASSERT_EQ(0, closes_observed_);
- wrapper.Close();
- EXPECT_EQ(0, closes_observed_);
- }
- EXPECT_EQ(0, closes_observed_);
-}
-
-// Test that destroying a HandleWrapper for an invalid handle does not notify
-// observers.
-TEST_F(HandleWrapperTest, DestroyWithInvalidHandle) {
- {
- TestHandleWrapper wrapper(MOJO_HANDLE_INVALID);
- wrapper.AddCloseObserver(this);
- ASSERT_EQ(0, closes_observed_);
- }
- EXPECT_EQ(0, closes_observed_);
-}
-
-// Test that calling Close on a HandleWrapper for a valid handle notifies
-// observers once.
-TEST_F(HandleWrapperTest, CloseWithValidHandle) {
- {
- mojo::MessagePipe pipe;
- TestHandleWrapper wrapper(pipe.handle0.release().value());
- wrapper.AddCloseObserver(this);
- ASSERT_EQ(0, closes_observed_);
- wrapper.Close();
- EXPECT_EQ(1, closes_observed_);
- // Check that calling close again doesn't notify observers.
- wrapper.Close();
- EXPECT_EQ(1, closes_observed_);
- }
- // Check that destroying a closed HandleWrapper doesn't notify observers.
- EXPECT_EQ(1, closes_observed_);
-}
-
-// Test that destroying a HandleWrapper for a valid handle notifies observers.
-TEST_F(HandleWrapperTest, DestroyWithValidHandle) {
- {
- mojo::MessagePipe pipe;
- TestHandleWrapper wrapper(pipe.handle0.release().value());
- wrapper.AddCloseObserver(this);
- ASSERT_EQ(0, closes_observed_);
- }
- EXPECT_EQ(1, closes_observed_);
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/js_export.h b/mojo/edk/js/js_export.h
deleted file mode 100644
index 179113c..0000000
--- a/mojo/edk/js/js_export.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_JS_EXPORT_H_
-#define MOJO_EDK_JS_JS_EXPORT_H_
-
-// Defines MOJO_JS_EXPORT so that functionality implemented by //mojo/edk/js can
-// be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(MOJO_JS_IMPLEMENTATION)
-#define MOJO_JS_EXPORT __declspec(dllexport)
-#else
-#define MOJO_JS_EXPORT __declspec(dllimport)
-#endif // defined(MOJO_JS_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(MOJO_JS_IMPLEMENTATION)
-#define MOJO_JS_EXPORT __attribute__((visibility("default")))
-#else
-#define MOJO_JS_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define MOJO_JS_EXPORT
-#endif
-
-#endif // MOJO_EDK_JS_JS_EXPORT_H_
diff --git a/mojo/edk/js/mojo_runner_delegate.cc b/mojo/edk/js/mojo_runner_delegate.cc
deleted file mode 100644
index dda0b2c..0000000
--- a/mojo/edk/js/mojo_runner_delegate.cc
+++ /dev/null
@@ -1,80 +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/js/mojo_runner_delegate.h"
-
-#include "base/bind.h"
-#include "base/path_service.h"
-#include "gin/converter.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/modules/timer.h"
-#include "gin/try_catch.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/support.h"
-#include "mojo/edk/js/threading.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-// TODO(abarth): Rather than loading these modules from the file system, we
-// should load them from the network via Mojo IPC.
-std::vector<base::FilePath> GetModuleSearchPaths() {
- std::vector<base::FilePath> search_paths(2);
- PathService::Get(base::DIR_SOURCE_ROOT, &search_paths[0]);
- PathService::Get(base::DIR_EXE, &search_paths[1]);
- search_paths[1] = search_paths[1].AppendASCII("gen");
- return search_paths;
-}
-
-void StartCallback(base::WeakPtr<gin::Runner> runner,
- MojoHandle pipe,
- v8::Handle<v8::Value> module) {
- v8::Isolate* isolate = runner->GetContextHolder()->isolate();
- v8::Handle<v8::Function> start;
- CHECK(gin::ConvertFromV8(isolate, module, &start));
-
- v8::Handle<v8::Value> args[] = {
- gin::ConvertToV8(isolate, Handle(pipe)) };
- runner->Call(start, runner->global(), 1, args);
-}
-
-} // namespace
-
-MojoRunnerDelegate::MojoRunnerDelegate()
- : ModuleRunnerDelegate(GetModuleSearchPaths()) {
- AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
- AddBuiltinModule(gin::TimerModule::kName, gin::TimerModule::GetModule);
- AddBuiltinModule(Core::kModuleName, Core::GetModule);
- AddBuiltinModule(Support::kModuleName, Support::GetModule);
- AddBuiltinModule(Threading::kModuleName, Threading::GetModule);
-}
-
-MojoRunnerDelegate::~MojoRunnerDelegate() {
-}
-
-void MojoRunnerDelegate::Start(gin::Runner* runner,
- MojoHandle pipe,
- const std::string& module) {
- gin::Runner::Scope scope(runner);
- gin::ModuleRegistry* registry =
- gin::ModuleRegistry::From(runner->GetContextHolder()->context());
- registry->LoadModule(runner->GetContextHolder()->isolate(), module,
- base::Bind(StartCallback, runner->GetWeakPtr(), pipe));
- AttemptToLoadMoreModules(runner);
-}
-
-void MojoRunnerDelegate::UnhandledException(gin::ShellRunner* runner,
- gin::TryCatch& try_catch) {
- gin::ModuleRunnerDelegate::UnhandledException(runner, try_catch);
- LOG(ERROR) << try_catch.GetStackTrace();
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/mojo_runner_delegate.h b/mojo/edk/js/mojo_runner_delegate.h
deleted file mode 100644
index 9ab325c..0000000
--- a/mojo/edk/js/mojo_runner_delegate.h
+++ /dev/null
@@ -1,36 +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_JS_MOJO_RUNNER_DELEGATE_H_
-#define MOJO_EDK_JS_MOJO_RUNNER_DELEGATE_H_
-
-#include "base/macros.h"
-#include "gin/modules/module_runner_delegate.h"
-#include "mojo/edk/js/js_export.h"
-#include "mojo/public/c/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT MojoRunnerDelegate : public gin::ModuleRunnerDelegate {
- public:
- MojoRunnerDelegate();
- ~MojoRunnerDelegate() override;
-
- void Start(gin::Runner* runner, MojoHandle pipe, const std::string& module);
-
- private:
- // From ModuleRunnerDelegate:
- void UnhandledException(gin::ShellRunner* runner,
- gin::TryCatch& try_catch) override;
-
- DISALLOW_COPY_AND_ASSIGN(MojoRunnerDelegate);
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_MOJO_RUNNER_DELEGATE_H_
diff --git a/mojo/edk/js/support.cc b/mojo/edk/js/support.cc
deleted file mode 100644
index 404cb9b..0000000
--- a/mojo/edk/js/support.cc
+++ /dev/null
@@ -1,77 +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/js/support.h"
-
-#include "base/bind.h"
-#include "gin/arguments.h"
-#include "gin/converter.h"
-#include "gin/function_template.h"
-#include "gin/object_template_builder.h"
-#include "gin/per_isolate_data.h"
-#include "gin/public/wrapper_info.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/waiting_callback.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-WaitingCallback* AsyncWait(const gin::Arguments& args,
- gin::Handle<HandleWrapper> handle,
- MojoHandleSignals signals,
- v8::Handle<v8::Function> callback) {
- return WaitingCallback::Create(
- args.isolate(), callback, handle, signals, true /* one_shot */).get();
-}
-
-void CancelWait(WaitingCallback* waiting_callback) {
- waiting_callback->Cancel();
-}
-
-WaitingCallback* Watch(const gin::Arguments& args,
- gin::Handle<HandleWrapper> handle,
- MojoHandleSignals signals,
- v8::Handle<v8::Function> callback) {
- return WaitingCallback::Create(
- args.isolate(), callback, handle, signals, false /* one_shot */).get();
-}
-
-void CancelWatch(WaitingCallback* waiting_callback) {
- waiting_callback->Cancel();
-}
-
-gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
-
-} // namespace
-
-const char Support::kModuleName[] = "mojo/public/js/support";
-
-v8::Local<v8::Value> Support::GetModule(v8::Isolate* isolate) {
- gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
- v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
- &g_wrapper_info);
-
- if (templ.IsEmpty()) {
- templ = gin::ObjectTemplateBuilder(isolate)
- // TODO(rockot): Remove asyncWait and cancelWait.
- .SetMethod("asyncWait", AsyncWait)
- .SetMethod("cancelWait", CancelWait)
- .SetMethod("watch", Watch)
- .SetMethod("cancelWatch", CancelWatch)
- .Build();
-
- data->SetObjectTemplate(&g_wrapper_info, templ);
- }
-
- return templ->NewInstance();
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/support.h b/mojo/edk/js/support.h
deleted file mode 100644
index 551f5ac..0000000
--- a/mojo/edk/js/support.h
+++ /dev/null
@@ -1,25 +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_JS_SUPPORT_H_
-#define MOJO_EDK_JS_SUPPORT_H_
-
-#include "mojo/edk/js/js_export.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT Support {
- public:
- static const char kModuleName[];
- static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_SUPPORT_H_
diff --git a/mojo/edk/js/tests/BUILD.gn b/mojo/edk/js/tests/BUILD.gn
deleted file mode 100644
index f56c4b9..0000000
--- a/mojo/edk/js/tests/BUILD.gn
+++ /dev/null
@@ -1,68 +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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-import("//testing/test.gni")
-
-# TODO(hansmuller): The organization of tests in this directory is weird:
-# * Really, js_unittests tests public stuff, so that should live in public
-# and be reworked as some sort of apptest.
-# * Both js_unittests and js_integration_tests should auto-generate their
-# tests somehow. The .cc files are just test runner stubs, including
-# explicit lists of .js files.
-
-group("tests") {
- testonly = true
- deps = [
- ":mojo_js_integration_tests",
- ":mojo_js_unittests",
- ]
-}
-
-test("mojo_js_integration_tests") {
- deps = [
- ":js_to_cpp_bindings",
- "//gin:gin_test",
- "//mojo/common",
- "//mojo/edk/js",
- "//mojo/edk/test:run_all_unittests",
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/system",
- "//mojo/public/js:bindings",
- ]
-
- sources = [
- "js_to_cpp_tests.cc",
- ]
-
- data = [
- "js_to_cpp_tests.js",
- ]
-
- configs += [ "//v8:external_startup_data" ]
-}
-
-mojom("js_to_cpp_bindings") {
- sources = [
- "js_to_cpp.mojom",
- ]
-}
-
-test("mojo_js_unittests") {
- deps = [
- "//base",
- "//gin:gin_test",
- "//mojo/edk/js",
- "//mojo/edk/test:run_all_unittests",
- "//mojo/edk/test:test_support",
- "//mojo/public/cpp/system",
- "//mojo/public/interfaces/bindings/tests:test_interfaces",
- "//mojo/public/js:tests",
- ]
-
- sources = [
- "//mojo/edk/js/handle_unittest.cc",
- "run_js_unittests.cc",
- ]
-}
diff --git a/mojo/edk/js/tests/js_to_cpp.mojom b/mojo/edk/js/tests/js_to_cpp.mojom
deleted file mode 100644
index 688b22b..0000000
--- a/mojo/edk/js/tests/js_to_cpp.mojom
+++ /dev/null
@@ -1,54 +0,0 @@
-module js_to_cpp;
-
-// This struct encompasses all of the basic types, so that they
-// may be sent from C++ to JS and back for validation.
-struct EchoArgs {
- int64 si64;
- int32 si32;
- int16 si16;
- int8 si8;
- uint64 ui64;
- uint32 ui32;
- uint16 ui16;
- uint8 ui8;
- float float_val;
- float float_inf;
- float float_nan;
- double double_val;
- double double_inf;
- double double_nan;
- string? name;
- array<string>? string_array;
- handle<message_pipe>? message_handle;
- handle<data_pipe_consumer>? data_handle;
-};
-
-struct EchoArgsList {
- EchoArgsList? next;
- EchoArgs? item;
-};
-
-// Note: For messages which control test flow, pick numbers that are unlikely
-// to be hit as a result of our deliberate corruption of response messages.
-interface CppSide {
- // Sent for all tests to notify that the JS side is now ready.
- StartTest@88888888();
-
- // Indicates end for echo, bit-flip, and back-pointer tests.
- TestFinished@99999999();
-
- // Responses from specific tests.
- PingResponse();
- EchoResponse(EchoArgsList list);
- BitFlipResponse(EchoArgsList arg);
- BackPointerResponse(EchoArgsList arg);
-};
-
-interface JsSide {
- SetCppSide(CppSide cpp);
-
- Ping();
- Echo(int32 numIterations, EchoArgs arg);
- BitFlip(EchoArgs arg);
- BackPointer(EchoArgs arg);
-};
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.cc b/mojo/edk/js/tests/js_to_cpp_tests.cc
deleted file mode 100644
index b6b74e3..0000000
--- a/mojo/edk/js/tests/js_to_cpp_tests.cc
+++ /dev/null
@@ -1,455 +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 <stddef.h>
-#include <stdint.h>
-
-#include <string>
-#include <utility>
-
-#include "base/at_exit.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "gin/array_buffer.h"
-#include "gin/public/isolate_holder.h"
-#include "gin/v8_initializer.h"
-#include "mojo/common/data_pipe_utils.h"
-#include "mojo/edk/js/mojo_runner_delegate.h"
-#include "mojo/edk/js/tests/js_to_cpp.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/lib/validation_errors.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/system/wait.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-// Global value updated by some checks to prevent compilers from optimizing
-// reads out of existence.
-uint32_t g_waste_accumulator = 0;
-
-namespace {
-
-// Negative numbers with different values in each byte, the last of
-// which can survive promotion to double and back.
-const int8_t kExpectedInt8Value = -65;
-const int16_t kExpectedInt16Value = -16961;
-const int32_t kExpectedInt32Value = -1145258561;
-const int64_t kExpectedInt64Value = -77263311946305LL;
-
-// Positive numbers with different values in each byte, the last of
-// which can survive promotion to double and back.
-const uint8_t kExpectedUInt8Value = 65;
-const uint16_t kExpectedUInt16Value = 16961;
-const uint32_t kExpectedUInt32Value = 1145258561;
-const uint64_t kExpectedUInt64Value = 77263311946305LL;
-
-// Double/float values, including special case constants.
-const double kExpectedDoubleVal = 3.14159265358979323846;
-const double kExpectedDoubleInf = std::numeric_limits<double>::infinity();
-const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN();
-const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal);
-const float kExpectedFloatInf = std::numeric_limits<float>::infinity();
-const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN();
-
-// NaN has the property that it is not equal to itself.
-#define EXPECT_NAN(x) EXPECT_NE(x, x)
-
-void CheckDataPipe(ScopedDataPipeConsumerHandle data_pipe_handle) {
- std::string buffer;
- bool result = common::BlockingCopyToString(std::move(data_pipe_handle),
- &buffer);
- EXPECT_TRUE(result);
- EXPECT_EQ(64u, buffer.size());
- for (int i = 0; i < 64; ++i) {
- EXPECT_EQ(i, buffer[i]);
- }
-}
-
-void CheckMessagePipe(MessagePipeHandle message_pipe_handle) {
- unsigned char buffer[100];
- uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
- MojoResult result = Wait(message_pipe_handle, MOJO_HANDLE_SIGNAL_READABLE);
- EXPECT_EQ(MOJO_RESULT_OK, result);
- result = ReadMessageRaw(
- message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(64u, buffer_size);
- for (int i = 0; i < 64; ++i) {
- EXPECT_EQ(255 - i, buffer[i]);
- }
-}
-
-js_to_cpp::EchoArgsPtr BuildSampleEchoArgs() {
- js_to_cpp::EchoArgsPtr args(js_to_cpp::EchoArgs::New());
- args->si64 = kExpectedInt64Value;
- args->si32 = kExpectedInt32Value;
- args->si16 = kExpectedInt16Value;
- args->si8 = kExpectedInt8Value;
- args->ui64 = kExpectedUInt64Value;
- args->ui32 = kExpectedUInt32Value;
- args->ui16 = kExpectedUInt16Value;
- args->ui8 = kExpectedUInt8Value;
- args->float_val = kExpectedFloatVal;
- args->float_inf = kExpectedFloatInf;
- args->float_nan = kExpectedFloatNan;
- args->double_val = kExpectedDoubleVal;
- args->double_inf = kExpectedDoubleInf;
- args->double_nan = kExpectedDoubleNan;
- args->name.emplace("coming");
- args->string_array.emplace(3);
- (*args->string_array)[0] = "one";
- (*args->string_array)[1] = "two";
- (*args->string_array)[2] = "three";
- return args;
-}
-
-void CheckSampleEchoArgs(js_to_cpp::EchoArgsPtr arg) {
- EXPECT_EQ(kExpectedInt64Value, arg->si64);
- EXPECT_EQ(kExpectedInt32Value, arg->si32);
- EXPECT_EQ(kExpectedInt16Value, arg->si16);
- EXPECT_EQ(kExpectedInt8Value, arg->si8);
- EXPECT_EQ(kExpectedUInt64Value, arg->ui64);
- EXPECT_EQ(kExpectedUInt32Value, arg->ui32);
- EXPECT_EQ(kExpectedUInt16Value, arg->ui16);
- EXPECT_EQ(kExpectedUInt8Value, arg->ui8);
- EXPECT_EQ(kExpectedFloatVal, arg->float_val);
- EXPECT_EQ(kExpectedFloatInf, arg->float_inf);
- EXPECT_NAN(arg->float_nan);
- EXPECT_EQ(kExpectedDoubleVal, arg->double_val);
- EXPECT_EQ(kExpectedDoubleInf, arg->double_inf);
- EXPECT_NAN(arg->double_nan);
- EXPECT_EQ(std::string("coming"), *arg->name);
- EXPECT_EQ(std::string("one"), (*arg->string_array)[0]);
- EXPECT_EQ(std::string("two"), (*arg->string_array)[1]);
- EXPECT_EQ(std::string("three"), (*arg->string_array)[2]);
- CheckDataPipe(std::move(arg->data_handle));
- CheckMessagePipe(arg->message_handle.get());
-}
-
-void CheckSampleEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) {
- if (list.is_null())
- return;
- CheckSampleEchoArgs(std::move(list->item));
- CheckSampleEchoArgsList(list->next);
-}
-
-// More forgiving checks are needed in the face of potentially corrupt
-// messages. The values don't matter so long as all accesses are within
-// bounds.
-void CheckCorruptedString(const std::string& arg) {
- for (size_t i = 0; i < arg.size(); ++i)
- g_waste_accumulator += arg[i];
-}
-
-void CheckCorruptedString(const base::Optional<std::string>& arg) {
- if (!arg)
- return;
- CheckCorruptedString(*arg);
-}
-
-void CheckCorruptedStringArray(
- const base::Optional<std::vector<std::string>>& string_array) {
- if (!string_array)
- return;
- for (size_t i = 0; i < string_array->size(); ++i)
- CheckCorruptedString((*string_array)[i]);
-}
-
-void CheckCorruptedDataPipe(MojoHandle data_pipe_handle) {
- unsigned char buffer[100];
- uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
- MojoResult result = MojoReadData(
- data_pipe_handle, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE);
- if (result != MOJO_RESULT_OK)
- return;
- for (uint32_t i = 0; i < buffer_size; ++i)
- g_waste_accumulator += buffer[i];
-}
-
-void CheckCorruptedMessagePipe(MojoHandle message_pipe_handle) {
- unsigned char buffer[100];
- uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
- MojoResult result = MojoReadMessage(
- message_pipe_handle, buffer, &buffer_size, 0, 0, 0);
- if (result != MOJO_RESULT_OK)
- return;
- for (uint32_t i = 0; i < buffer_size; ++i)
- g_waste_accumulator += buffer[i];
-}
-
-void CheckCorruptedEchoArgs(const js_to_cpp::EchoArgsPtr& arg) {
- if (arg.is_null())
- return;
- CheckCorruptedString(arg->name);
- CheckCorruptedStringArray(arg->string_array);
- if (arg->data_handle.is_valid())
- CheckCorruptedDataPipe(arg->data_handle.get().value());
- if (arg->message_handle.is_valid())
- CheckCorruptedMessagePipe(arg->message_handle.get().value());
-}
-
-void CheckCorruptedEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) {
- if (list.is_null())
- return;
- CheckCorruptedEchoArgs(list->item);
- CheckCorruptedEchoArgsList(list->next);
-}
-
-// Base Provider implementation class. It's expected that tests subclass and
-// override the appropriate Provider functions. When test is done quit the
-// run_loop().
-class CppSideConnection : public js_to_cpp::CppSide {
- public:
- CppSideConnection()
- : run_loop_(nullptr),
- js_side_(nullptr),
- mishandled_messages_(0),
- binding_(this) {}
- ~CppSideConnection() override {}
-
- void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
- base::RunLoop* run_loop() { return run_loop_; }
-
- void set_js_side(js_to_cpp::JsSide* js_side) { js_side_ = js_side; }
- js_to_cpp::JsSide* js_side() { return js_side_; }
-
- void Bind(InterfaceRequest<js_to_cpp::CppSide> request) {
- binding_.Bind(std::move(request));
- // Keep the pipe open even after validation errors.
- binding_.EnableTestingMode();
- }
-
- // js_to_cpp::CppSide:
- void StartTest() override { NOTREACHED(); }
-
- void TestFinished() override { NOTREACHED(); }
-
- void PingResponse() override { mishandled_messages_ += 1; }
-
- void EchoResponse(js_to_cpp::EchoArgsListPtr list) override {
- mishandled_messages_ += 1;
- }
-
- void BitFlipResponse(js_to_cpp::EchoArgsListPtr list) override {
- mishandled_messages_ += 1;
- }
-
- void BackPointerResponse(js_to_cpp::EchoArgsListPtr list) override {
- mishandled_messages_ += 1;
- }
-
- protected:
- base::RunLoop* run_loop_;
- js_to_cpp::JsSide* js_side_;
- int mishandled_messages_;
- mojo::Binding<js_to_cpp::CppSide> binding_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CppSideConnection);
-};
-
-// Trivial test to verify a message sent from JS is received.
-class PingCppSideConnection : public CppSideConnection {
- public:
- PingCppSideConnection() : got_message_(false) {}
- ~PingCppSideConnection() override {}
-
- // js_to_cpp::CppSide:
- void StartTest() override { js_side_->Ping(); }
-
- void PingResponse() override {
- got_message_ = true;
- run_loop()->Quit();
- }
-
- bool DidSucceed() {
- return got_message_ && !mishandled_messages_;
- }
-
- private:
- bool got_message_;
- DISALLOW_COPY_AND_ASSIGN(PingCppSideConnection);
-};
-
-// Test that parameters are passed with correct values.
-class EchoCppSideConnection : public CppSideConnection {
- public:
- EchoCppSideConnection() :
- message_count_(0),
- termination_seen_(false) {
- }
- ~EchoCppSideConnection() override {}
-
- // js_to_cpp::CppSide:
- void StartTest() override {
- js_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs());
- }
-
- void EchoResponse(js_to_cpp::EchoArgsListPtr list) override {
- const js_to_cpp::EchoArgsPtr& special_arg = list->item;
- message_count_ += 1;
- EXPECT_EQ(-1, special_arg->si64);
- EXPECT_EQ(-1, special_arg->si32);
- EXPECT_EQ(-1, special_arg->si16);
- EXPECT_EQ(-1, special_arg->si8);
- EXPECT_EQ(std::string("going"), *special_arg->name);
- CheckSampleEchoArgsList(list->next);
- }
-
- void TestFinished() override {
- termination_seen_ = true;
- run_loop()->Quit();
- }
-
- bool DidSucceed() {
- return termination_seen_ &&
- !mishandled_messages_ &&
- message_count_ == kExpectedMessageCount;
- }
-
- private:
- static const int kExpectedMessageCount = 10;
- int message_count_;
- bool termination_seen_;
- DISALLOW_COPY_AND_ASSIGN(EchoCppSideConnection);
-};
-
-// Test that corrupted messages don't wreak havoc.
-class BitFlipCppSideConnection : public CppSideConnection {
- public:
- BitFlipCppSideConnection() : termination_seen_(false) {}
- ~BitFlipCppSideConnection() override {}
-
- // js_to_cpp::CppSide:
- void StartTest() override { js_side_->BitFlip(BuildSampleEchoArgs()); }
-
- void BitFlipResponse(js_to_cpp::EchoArgsListPtr list) override {
- CheckCorruptedEchoArgsList(list);
- }
-
- void TestFinished() override {
- termination_seen_ = true;
- run_loop()->Quit();
- }
-
- bool DidSucceed() {
- return termination_seen_;
- }
-
- private:
- bool termination_seen_;
- DISALLOW_COPY_AND_ASSIGN(BitFlipCppSideConnection);
-};
-
-// Test that severely random messages don't wreak havoc.
-class BackPointerCppSideConnection : public CppSideConnection {
- public:
- BackPointerCppSideConnection() : termination_seen_(false) {}
- ~BackPointerCppSideConnection() override {}
-
- // js_to_cpp::CppSide:
- void StartTest() override { js_side_->BackPointer(BuildSampleEchoArgs()); }
-
- void BackPointerResponse(js_to_cpp::EchoArgsListPtr list) override {
- CheckCorruptedEchoArgsList(list);
- }
-
- void TestFinished() override {
- termination_seen_ = true;
- run_loop()->Quit();
- }
-
- bool DidSucceed() {
- return termination_seen_;
- }
-
- private:
- bool termination_seen_;
- DISALLOW_COPY_AND_ASSIGN(BackPointerCppSideConnection);
-};
-
-} // namespace
-
-class JsToCppTest : public testing::Test {
- public:
- JsToCppTest() {}
-
- void RunTest(const std::string& test, CppSideConnection* cpp_side) {
- cpp_side->set_run_loop(&run_loop_);
-
- js_to_cpp::JsSidePtr js_side;
- auto js_side_proxy = MakeRequest(&js_side);
-
- cpp_side->set_js_side(js_side.get());
- js_to_cpp::CppSidePtr cpp_side_ptr;
- cpp_side->Bind(MakeRequest(&cpp_side_ptr));
-
- js_side->SetCppSide(std::move(cpp_side_ptr));
-
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
- gin::V8Initializer::LoadV8Snapshot();
- gin::V8Initializer::LoadV8Natives();
-#endif
-
- gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
- gin::IsolateHolder::kStableV8Extras,
- gin::ArrayBufferAllocator::SharedInstance());
- gin::IsolateHolder instance(base::ThreadTaskRunnerHandle::Get());
- MojoRunnerDelegate delegate;
- gin::ShellRunner runner(&delegate, instance.isolate());
- delegate.Start(&runner, js_side_proxy.PassMessagePipe().release().value(),
- test);
-
- run_loop_.Run();
- }
-
- private:
- base::ShadowingAtExitManager at_exit_;
- base::MessageLoop loop;
- base::RunLoop run_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(JsToCppTest);
-};
-
-TEST_F(JsToCppTest, Ping) {
- PingCppSideConnection cpp_side_connection;
- RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
- EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-TEST_F(JsToCppTest, Echo) {
- EchoCppSideConnection cpp_side_connection;
- RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
- EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-TEST_F(JsToCppTest, BitFlip) {
- // These tests generate a lot of expected validation errors. Suppress logging.
- mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
-
- BitFlipCppSideConnection cpp_side_connection;
- RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
- EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-TEST_F(JsToCppTest, BackPointer) {
- // These tests generate a lot of expected validation errors. Suppress logging.
- mojo::internal::ScopedSuppressValidationErrorLoggingForTests log_suppression;
-
- BackPointerCppSideConnection cpp_side_connection;
- RunTest("mojo/edk/js/tests/js_to_cpp_tests", &cpp_side_connection);
- EXPECT_TRUE(cpp_side_connection.DidSucceed());
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/tests/js_to_cpp_tests.js b/mojo/edk/js/tests/js_to_cpp_tests.js
deleted file mode 100644
index 6b69fca..0000000
--- a/mojo/edk/js/tests/js_to_cpp_tests.js
+++ /dev/null
@@ -1,223 +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.
-
-define('mojo/edk/js/tests/js_to_cpp_tests', [
- 'console',
- 'mojo/edk/js/tests/js_to_cpp.mojom',
- 'mojo/public/js/bindings',
- 'mojo/public/js/connector',
- 'mojo/public/js/core',
-], function (console, jsToCpp, bindings, connector, core) {
- var retainedJsSide;
- var retainedJsSideStub;
- var sampleData;
- var sampleMessage;
- var BAD_VALUE = 13;
- var DATA_PIPE_PARAMS = {
- flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
- elementNumBytes: 1,
- capacityNumBytes: 64
- };
-
- function JsSideConnection() {
- this.binding = new bindings.Binding(jsToCpp.JsSide, this);
- }
-
- JsSideConnection.prototype.setCppSide = function(cppSide) {
- this.cppSide_ = cppSide;
- this.cppSide_.startTest();
- };
-
- JsSideConnection.prototype.ping = function (arg) {
- this.cppSide_.pingResponse();
- };
-
- JsSideConnection.prototype.echo = function (numIterations, arg) {
- var dataPipe1;
- var dataPipe2;
- var i;
- var messagePipe1;
- var messagePipe2;
- var specialArg;
-
- // Ensure expected negative values are negative.
- if (arg.si64 > 0)
- arg.si64 = BAD_VALUE;
-
- if (arg.si32 > 0)
- arg.si32 = BAD_VALUE;
-
- if (arg.si16 > 0)
- arg.si16 = BAD_VALUE;
-
- if (arg.si8 > 0)
- arg.si8 = BAD_VALUE;
-
- for (i = 0; i < numIterations; ++i) {
- dataPipe1 = core.createDataPipe(DATA_PIPE_PARAMS);
- dataPipe2 = core.createDataPipe(DATA_PIPE_PARAMS);
- messagePipe1 = core.createMessagePipe();
- messagePipe2 = core.createMessagePipe();
-
- arg.data_handle = dataPipe1.consumerHandle;
- arg.message_handle = messagePipe1.handle1;
-
- specialArg = new jsToCpp.EchoArgs();
- specialArg.si64 = -1;
- specialArg.si32 = -1;
- specialArg.si16 = -1;
- specialArg.si8 = -1;
- specialArg.name = 'going';
- specialArg.data_handle = dataPipe2.consumerHandle;
- specialArg.message_handle = messagePipe2.handle1;
-
- writeDataPipe(dataPipe1, sampleData);
- writeDataPipe(dataPipe2, sampleData);
- writeMessagePipe(messagePipe1, sampleMessage);
- writeMessagePipe(messagePipe2, sampleMessage);
-
- this.cppSide_.echoResponse(createEchoArgsList(specialArg, arg));
-
- core.close(dataPipe1.producerHandle);
- core.close(dataPipe2.producerHandle);
- core.close(messagePipe1.handle0);
- core.close(messagePipe2.handle0);
- }
- this.cppSide_.testFinished();
- };
-
- JsSideConnection.prototype.bitFlip = function (arg) {
- var iteration = 0;
- var dataPipe;
- var messagePipe;
- var proto = connector.Connector.prototype;
- var stopSignalled = false;
-
- proto.realAccept = proto.accept;
- proto.accept = function (message) {
- var offset = iteration / 8;
- var mask;
- var value;
- if (offset < message.buffer.arrayBuffer.byteLength) {
- mask = 1 << (iteration % 8);
- value = message.buffer.getUint8(offset) ^ mask;
- message.buffer.setUint8(offset, value);
- return this.realAccept(message);
- }
- stopSignalled = true;
- return false;
- };
-
- while (!stopSignalled) {
- dataPipe = core.createDataPipe(DATA_PIPE_PARAMS);
- messagePipe = core.createMessagePipe();
- writeDataPipe(dataPipe, sampleData);
- writeMessagePipe(messagePipe, sampleMessage);
- arg.data_handle = dataPipe.consumerHandle;
- arg.message_handle = messagePipe.handle1;
-
- this.cppSide_.bitFlipResponse(createEchoArgsList(arg));
-
- core.close(dataPipe.producerHandle);
- core.close(messagePipe.handle0);
- iteration += 1;
- }
-
- proto.accept = proto.realAccept;
- proto.realAccept = null;
- this.cppSide_.testFinished();
- };
-
- JsSideConnection.prototype.backPointer = function (arg) {
- var iteration = 0;
- var dataPipe;
- var messagePipe;
- var proto = connector.Connector.prototype;
- var stopSignalled = false;
-
- proto.realAccept = proto.accept;
- proto.accept = function (message) {
- var delta = 8 * (1 + iteration % 32);
- var offset = 8 * ((iteration / 32) | 0);
- if (offset < message.buffer.arrayBuffer.byteLength - 4) {
- message.buffer.dataView.setUint32(offset, 0x100000000 - delta, true);
- message.buffer.dataView.setUint32(offset + 4, 0xffffffff, true);
- return this.realAccept(message);
- }
- stopSignalled = true;
- return false;
- };
-
- while (!stopSignalled) {
- dataPipe = core.createDataPipe(DATA_PIPE_PARAMS);
- messagePipe = core.createMessagePipe();
- writeDataPipe(dataPipe, sampleData);
- writeMessagePipe(messagePipe, sampleMessage);
- arg.data_handle = dataPipe.consumerHandle;
- arg.message_handle = messagePipe.handle1;
-
- this.cppSide_.backPointerResponse(createEchoArgsList(arg));
-
- core.close(dataPipe.producerHandle);
- core.close(messagePipe.handle0);
- iteration += 1;
- }
-
- proto.accept = proto.realAccept;
- proto.realAccept = null;
- this.cppSide_.testFinished();
- };
-
- function writeDataPipe(pipe, data) {
- var writeResult = core.writeData(
- pipe.producerHandle, data, core.WRITE_DATA_FLAG_ALL_OR_NONE);
-
- if (writeResult.result != core.RESULT_OK) {
- console.log('ERROR: Data pipe write result was ' + writeResult.result);
- return false;
- }
- if (writeResult.numBytes != data.length) {
- console.log('ERROR: Data pipe write length was ' + writeResult.numBytes);
- return false;
- }
- return true;
- }
-
- function writeMessagePipe(pipe, arrayBuffer) {
- var result = core.writeMessage(pipe.handle0, arrayBuffer, [], 0);
- if (result != core.RESULT_OK) {
- console.log('ERROR: Message pipe write result was ' + result);
- return false;
- }
- return true;
- }
-
- function createEchoArgsListElement(item, next) {
- var list = new jsToCpp.EchoArgsList();
- list.item = item;
- list.next = next;
- return list;
- }
-
- function createEchoArgsList() {
- var genuineArray = Array.prototype.slice.call(arguments);
- return genuineArray.reduceRight(function (previous, current) {
- return createEchoArgsListElement(current, previous);
- }, null);
- }
-
- return function(jsSideRequestHandle) {
- var i;
- sampleData = new Uint8Array(DATA_PIPE_PARAMS.capacityNumBytes);
- for (i = 0; i < sampleData.length; ++i) {
- sampleData[i] = i;
- }
- sampleMessage = new Uint8Array(DATA_PIPE_PARAMS.capacityNumBytes);
- for (i = 0; i < sampleMessage.length; ++i) {
- sampleMessage[i] = 255 - i;
- }
- retainedJsSide = new JsSideConnection;
- retainedJsSide.binding.bind(jsSideRequestHandle);
- };
-});
diff --git a/mojo/edk/js/tests/run_js_unittests.cc b/mojo/edk/js/tests/run_js_unittests.cc
deleted file mode 100644
index 13e796b..0000000
--- a/mojo/edk/js/tests/run_js_unittests.cc
+++ /dev/null
@@ -1,61 +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 "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/modules/timer.h"
-#include "gin/test/file_runner.h"
-#include "gin/test/gtest.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/support.h"
-#include "mojo/edk/js/threading.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-namespace {
-
-class TestRunnerDelegate : public gin::FileRunnerDelegate {
- public:
- TestRunnerDelegate() {
- AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
- AddBuiltinModule(gin::TimerModule::kName, gin::TimerModule::GetModule);
- AddBuiltinModule(Core::kModuleName, Core::GetModule);
- AddBuiltinModule(Threading::kModuleName, Threading::GetModule);
- AddBuiltinModule(Support::kModuleName, Support::GetModule);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestRunnerDelegate);
-};
-
-void RunTest(std::string test, bool run_until_idle) {
- base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
- path = path.AppendASCII("mojo")
- .AppendASCII("public")
- .AppendASCII("js")
- .AppendASCII("tests")
- .AppendASCII(test);
- TestRunnerDelegate delegate;
- gin::RunTestFromFile(path, &delegate, run_until_idle);
-}
-
-// TODO(abarth): Should we autogenerate these stubs from GYP?
-TEST(JSTest, Core) {
- RunTest("core_unittest.js", true);
-}
-
-TEST(JSTest, Validation) {
- RunTest("validation_unittest.js", true);
-}
-
-} // namespace
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/threading.cc b/mojo/edk/js/threading.cc
deleted file mode 100644
index db9f12d..0000000
--- a/mojo/edk/js/threading.cc
+++ /dev/null
@@ -1,49 +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/js/threading.h"
-
-#include "base/message_loop/message_loop.h"
-#include "gin/object_template_builder.h"
-#include "gin/per_isolate_data.h"
-#include "mojo/edk/js/handle.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-void Quit() {
- base::MessageLoop::current()->QuitNow();
-}
-
-gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
-
-} // namespace
-
-const char Threading::kModuleName[] = "mojo/public/js/threading";
-
-v8::Local<v8::Value> Threading::GetModule(v8::Isolate* isolate) {
- gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
- v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
- &g_wrapper_info);
-
- if (templ.IsEmpty()) {
- templ = gin::ObjectTemplateBuilder(isolate)
- .SetMethod("quit", Quit)
- .Build();
-
- data->SetObjectTemplate(&g_wrapper_info, templ);
- }
-
- return templ->NewInstance();
-}
-
-Threading::Threading() {
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/threading.h b/mojo/edk/js/threading.h
deleted file mode 100644
index 653d076..0000000
--- a/mojo/edk/js/threading.h
+++ /dev/null
@@ -1,28 +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_JS_THREADING_H_
-#define MOJO_EDK_JS_THREADING_H_
-
-#include "gin/public/wrapper_info.h"
-#include "mojo/edk/js/js_export.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT Threading {
- public:
- static const char kModuleName[];
- static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
- private:
- Threading();
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_THREADING_H_
diff --git a/mojo/edk/js/waiting_callback.cc b/mojo/edk/js/waiting_callback.cc
deleted file mode 100644
index 6ad4bd0..0000000
--- a/mojo/edk/js/waiting_callback.cc
+++ /dev/null
@@ -1,95 +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/js/waiting_callback.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "gin/per_context_data.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-v8::Handle<v8::Private> GetHiddenPropertyName(v8::Isolate* isolate) {
- return v8::Private::ForApi(
- isolate, gin::StringToV8(isolate, "::mojo::js::WaitingCallback"));
-}
-
-} // namespace
-
-gin::WrapperInfo WaitingCallback::kWrapperInfo = { gin::kEmbedderNativeGin };
-
-// static
-gin::Handle<WaitingCallback> WaitingCallback::Create(
- v8::Isolate* isolate,
- v8::Handle<v8::Function> callback,
- gin::Handle<HandleWrapper> handle_wrapper,
- MojoHandleSignals signals,
- bool one_shot) {
- gin::Handle<WaitingCallback> waiting_callback = gin::CreateHandle(
- isolate, new WaitingCallback(isolate, callback, one_shot));
- MojoResult result = waiting_callback->watcher_.Watch(
- handle_wrapper->get(), signals,
- base::Bind(&WaitingCallback::OnHandleReady,
- base::Unretained(waiting_callback.get())));
-
- // The signals may already be unsatisfiable.
- if (result == MOJO_RESULT_FAILED_PRECONDITION)
- waiting_callback->OnHandleReady(MOJO_RESULT_FAILED_PRECONDITION);
-
- return waiting_callback;
-}
-
-void WaitingCallback::Cancel() {
- if (watcher_.IsWatching())
- watcher_.Cancel();
-}
-
-WaitingCallback::WaitingCallback(v8::Isolate* isolate,
- v8::Handle<v8::Function> callback,
- bool one_shot)
- : one_shot_(one_shot),
- watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC),
- weak_factory_(this) {
- v8::Handle<v8::Context> context = isolate->GetCurrentContext();
- runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
- GetWrapper(isolate)
- ->SetPrivate(context, GetHiddenPropertyName(isolate), callback)
- .FromJust();
-}
-
-WaitingCallback::~WaitingCallback() {
- Cancel();
-}
-
-void WaitingCallback::OnHandleReady(MojoResult result) {
- if (!runner_)
- return;
-
- gin::Runner::Scope scope(runner_.get());
- v8::Isolate* isolate = runner_->GetContextHolder()->isolate();
-
- v8::Handle<v8::Value> hidden_value =
- GetWrapper(isolate)
- ->GetPrivate(runner_->GetContextHolder()->context(),
- GetHiddenPropertyName(isolate))
- .ToLocalChecked();
- v8::Handle<v8::Function> callback;
- CHECK(gin::ConvertFromV8(isolate, hidden_value, &callback));
-
- v8::Handle<v8::Value> args[] = { gin::ConvertToV8(isolate, result) };
- runner_->Call(callback, runner_->global(), 1, args);
-
- if (one_shot_ || result == MOJO_RESULT_CANCELLED) {
- runner_.reset();
- Cancel();
- }
-}
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/js/waiting_callback.h b/mojo/edk/js/waiting_callback.h
deleted file mode 100644
index f97b389..0000000
--- a/mojo/edk/js/waiting_callback.h
+++ /dev/null
@@ -1,67 +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_JS_WAITING_CALLBACK_H_
-#define MOJO_EDK_JS_WAITING_CALLBACK_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "gin/handle.h"
-#include "gin/runner.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class WaitingCallback : public gin::Wrappable<WaitingCallback> {
- public:
- static gin::WrapperInfo kWrapperInfo;
-
- // Creates a new WaitingCallback.
- //
- // If |one_shot| is true, the callback will only ever be called at most once.
- // If false, the callback may be called any number of times until the
- // WaitingCallback is explicitly cancelled.
- static gin::Handle<WaitingCallback> Create(
- v8::Isolate* isolate,
- v8::Handle<v8::Function> callback,
- gin::Handle<HandleWrapper> handle_wrapper,
- MojoHandleSignals signals,
- bool one_shot);
-
- // Cancels the callback. Does nothing if a callback is not pending. This is
- // implicitly invoked from the destructor but can be explicitly invoked as
- // necessary.
- void Cancel();
-
- private:
- WaitingCallback(v8::Isolate* isolate,
- v8::Handle<v8::Function> callback,
- bool one_shot);
- ~WaitingCallback() override;
-
- // Callback from the Watcher.
- void OnHandleReady(MojoResult result);
-
- // Indicates whether this is a one-shot callback or not. If so, it uses the
- // deprecated HandleWatcher to wait for signals; otherwise it uses the new
- // system Watcher API.
- const bool one_shot_;
-
- base::WeakPtr<gin::Runner> runner_;
- SimpleWatcher watcher_;
- base::WeakPtrFactory<WaitingCallback> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(WaitingCallback);
-};
-
-} // namespace js
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_JS_WAITING_CALLBACK_H_
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn
deleted file mode 100644
index a68cd44..0000000
--- a/mojo/edk/system/BUILD.gn
+++ /dev/null
@@ -1,205 +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.
-
-import("//build/config/nacl/config.gni")
-import("//testing/test.gni")
-import("../../../mojo/public/tools/bindings/mojom.gni")
-
-if (is_android) {
- import("//build/config/android/config.gni")
- import("//build/config/android/rules.gni")
-}
-
-component("system") {
- output_name = "mojo_system_impl"
-
- sources = [
- "atomic_flag.h",
- "broker.h",
- "broker_host.cc",
- "broker_host.h",
- "broker_posix.cc",
- "broker_win.cc",
- "channel.cc",
- "channel.h",
- "channel_posix.cc",
- "channel_win.cc",
- "configuration.cc",
- "configuration.h",
- "core.cc",
- "core.h",
- "data_pipe_consumer_dispatcher.cc",
- "data_pipe_consumer_dispatcher.h",
- "data_pipe_control_message.cc",
- "data_pipe_control_message.h",
- "data_pipe_producer_dispatcher.cc",
- "data_pipe_producer_dispatcher.h",
- "dispatcher.cc",
- "dispatcher.h",
- "handle_signals_state.h",
- "handle_table.cc",
- "handle_table.h",
- "mapping_table.cc",
- "mapping_table.h",
- "message_for_transit.cc",
- "message_for_transit.h",
- "message_pipe_dispatcher.cc",
- "message_pipe_dispatcher.h",
- "node_channel.cc",
- "node_channel.h",
- "node_controller.cc",
- "node_controller.h",
- "options_validation.h",
- "platform_handle_dispatcher.cc",
- "platform_handle_dispatcher.h",
- "ports_message.cc",
- "ports_message.h",
- "request_context.cc",
- "request_context.h",
- "shared_buffer_dispatcher.cc",
- "shared_buffer_dispatcher.h",
- "watch.cc",
- "watch.h",
- "watcher_dispatcher.cc",
- "watcher_dispatcher.h",
- "watcher_set.cc",
- "watcher_set.h",
- ]
-
- defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
-
- public_deps = [
- "//mojo/edk/embedder",
- "//mojo/edk/embedder:platform",
- "//mojo/edk/system/ports",
- "//mojo/public/c/system",
- "//mojo/public/cpp/system",
- ]
-
- deps = [
- "//base",
- ]
-
- if (!is_nacl) {
- deps += [ "//crypto" ]
- }
-
- if (is_win) {
- cflags = [ "/wd4324" ] # Structure was padded due to __declspec(align()),
- # which is uninteresting.
- }
-
- if (is_mac && !is_ios) {
- sources += [
- "mach_port_relay.cc",
- "mach_port_relay.h",
- ]
- }
-
- if (is_nacl && !is_nacl_nonsfi) {
- sources -= [
- "broker_host.cc",
- "broker_posix.cc",
- "channel_posix.cc",
- ]
- }
-
- # Use target_os == "chromeos" instead of is_chromeos because we need to
- # build NaCl targets (i.e. IRT) for ChromeOS the same as the rest of ChromeOS.
- if (is_android || target_os == "chromeos") {
- defines += [ "MOJO_EDK_LEGACY_PROTOCOL" ]
- }
-
- allow_circular_includes_from = [ "//mojo/edk/embedder" ]
-}
-
-group("tests") {
- testonly = true
- deps = [
- ":mojo_system_unittests",
- ]
-
- if (!is_ios) {
- deps += [ ":mojo_message_pipe_perftests" ]
- }
-}
-
-source_set("test_utils") {
- testonly = true
-
- sources = [
- "test_utils.cc",
- "test_utils.h",
- ]
-
- public_deps = [
- "//mojo/public/c/system",
- "//mojo/public/cpp/system",
- ]
-
- deps = [
- "//base",
- "//base/test:test_support",
- "//mojo/edk/test:test_support",
- "//testing/gtest:gtest",
- ]
-}
-
-test("mojo_system_unittests") {
- sources = [
- "channel_unittest.cc",
- "core_test_base.cc",
- "core_test_base.h",
- "core_unittest.cc",
- "message_pipe_unittest.cc",
- "options_validation_unittest.cc",
- "platform_handle_dispatcher_unittest.cc",
- "shared_buffer_dispatcher_unittest.cc",
- "shared_buffer_unittest.cc",
- "signals_unittest.cc",
- "watcher_unittest.cc",
- ]
-
- if (!is_ios) {
- sources += [
- "data_pipe_unittest.cc",
- "multiprocess_message_pipe_unittest.cc",
- "platform_wrapper_unittest.cc",
- ]
- }
-
- deps = [
- ":test_utils",
- "//base",
- "//base/test:test_support",
- "//mojo/edk/embedder:embedder_unittests",
- "//mojo/edk/system",
- "//mojo/edk/system/ports:tests",
- "//mojo/edk/test:run_all_unittests",
- "//mojo/edk/test:test_support",
- "//mojo/public/cpp/system",
- "//testing/gmock",
- "//testing/gtest",
- ]
-
- allow_circular_includes_from = [ "//mojo/edk/embedder:embedder_unittests" ]
-}
-
-if (!is_ios) {
- test("mojo_message_pipe_perftests") {
- sources = [
- "message_pipe_perftest.cc",
- ]
-
- deps = [
- ":test_utils",
- "//base",
- "//base/test:test_support",
- "//mojo/edk/system",
- "//mojo/edk/test:run_all_perftests",
- "//mojo/edk/test:test_support",
- "//testing/gtest",
- ]
- }
-}
diff --git a/mojo/edk/system/atomic_flag.h b/mojo/edk/system/atomic_flag.h
deleted file mode 100644
index 6bdcfaa..0000000
--- a/mojo/edk/system/atomic_flag.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_ATOMIC_FLAG_H_
-#define MOJO_EDK_SYSTEM_ATOMIC_FLAG_H_
-
-#include "base/atomicops.h"
-#include "base/macros.h"
-
-namespace mojo {
-namespace edk {
-
-// AtomicFlag is a boolean flag that can be set and tested atomically. It is
-// intended to be used to fast-path checks where the common case would normally
-// release the governing mutex immediately after checking.
-//
-// Example usage:
-// void DoFoo(Bar* bar) {
-// AutoLock l(lock_);
-// queue_.push_back(bar);
-// flag_.Set(true);
-// }
-//
-// void Baz() {
-// if (!flag_) // Assume this is the common case.
-// return;
-//
-// AutoLock l(lock_);
-// ... drain queue_ ...
-// flag_.Set(false);
-// }
-class AtomicFlag {
- public:
- AtomicFlag() : flag_(0) {}
- ~AtomicFlag() {}
-
- void Set(bool value) {
- base::subtle::Release_Store(&flag_, value ? 1 : 0);
- }
-
- bool Get() const {
- return base::subtle::Acquire_Load(&flag_) ? true : false;
- }
-
- operator const bool() const { return Get(); }
-
- private:
- base::subtle::Atomic32 flag_;
-
- DISALLOW_COPY_AND_ASSIGN(AtomicFlag);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_ATOMIC_FLAG_H_
diff --git a/mojo/edk/system/broker.h b/mojo/edk/system/broker.h
deleted file mode 100644
index 1577972..0000000
--- a/mojo/edk/system/broker.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_BROKER_H_
-#define MOJO_EDK_SYSTEM_BROKER_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-
-namespace mojo {
-namespace edk {
-
-class PlatformSharedBuffer;
-
-// The Broker is a channel to the parent process, which allows synchronous IPCs.
-class Broker {
- public:
- // Note: This is blocking, and will wait for the first message over
- // |platform_handle|.
- explicit Broker(ScopedPlatformHandle platform_handle);
- ~Broker();
-
- // Returns the platform handle that should be used to establish a NodeChannel
- // to the parent process.
- ScopedPlatformHandle GetParentPlatformHandle();
-
- // Request a shared buffer from the parent process. Blocks the current thread.
- scoped_refptr<PlatformSharedBuffer> GetSharedBuffer(size_t num_bytes);
-
- private:
- // Handle to the parent process, used for synchronous IPCs.
- ScopedPlatformHandle sync_channel_;
-
- // Handle to the parent process which is recieved in the first first message
- // over |sync_channel_|.
- ScopedPlatformHandle parent_channel_;
-
- // Lock to only allow one sync message at a time. This avoids having to deal
- // with message ordering since we can only have one request at a time
- // in-flight.
- base::Lock lock_;
-
- DISALLOW_COPY_AND_ASSIGN(Broker);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_BROKER_H_
diff --git a/mojo/edk/system/broker_host.cc b/mojo/edk/system/broker_host.cc
deleted file mode 100644
index 6096034..0000000
--- a/mojo/edk/system/broker_host.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/broker_host.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/edk/embedder/named_platform_channel_pair.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/broker_messages.h"
-
-namespace mojo {
-namespace edk {
-
-BrokerHost::BrokerHost(base::ProcessHandle client_process,
- ScopedPlatformHandle platform_handle)
-#if defined(OS_WIN)
- : client_process_(client_process)
-#endif
-{
- CHECK(platform_handle.is_valid());
-
- base::MessageLoop::current()->AddDestructionObserver(this);
-
- channel_ = Channel::Create(this, ConnectionParams(std::move(platform_handle)),
- base::ThreadTaskRunnerHandle::Get());
- channel_->Start();
-}
-
-BrokerHost::~BrokerHost() {
- // We're always destroyed on the creation thread, which is the IO thread.
- base::MessageLoop::current()->RemoveDestructionObserver(this);
-
- if (channel_)
- channel_->ShutDown();
-}
-
-bool BrokerHost::PrepareHandlesForClient(PlatformHandleVector* handles) {
-#if defined(OS_WIN)
- if (!Channel::Message::RewriteHandles(
- base::GetCurrentProcessHandle(), client_process_, handles)) {
- // NOTE: We only log an error here. We do not signal a logical error or
- // prevent any message from being sent. The client should handle unexpected
- // invalid handles appropriately.
- DLOG(ERROR) << "Failed to rewrite one or more handles to broker client.";
- return false;
- }
-#endif
- return true;
-}
-
-bool BrokerHost::SendChannel(ScopedPlatformHandle handle) {
- CHECK(handle.is_valid());
- CHECK(channel_);
-
-#if defined(OS_WIN)
- InitData* data;
- Channel::MessagePtr message =
- CreateBrokerMessage(BrokerMessageType::INIT, 1, 0, &data);
- data->pipe_name_length = 0;
-#else
- Channel::MessagePtr message =
- CreateBrokerMessage(BrokerMessageType::INIT, 1, nullptr);
-#endif
- ScopedPlatformHandleVectorPtr handles;
- handles.reset(new PlatformHandleVector(1));
- handles->at(0) = handle.release();
-
- // This may legitimately fail on Windows if the client process is in another
- // session, e.g., is an elevated process.
- if (!PrepareHandlesForClient(handles.get()))
- return false;
-
- message->SetHandles(std::move(handles));
- channel_->Write(std::move(message));
- return true;
-}
-
-#if defined(OS_WIN)
-
-void BrokerHost::SendNamedChannel(const base::StringPiece16& pipe_name) {
- InitData* data;
- base::char16* name_data;
- Channel::MessagePtr message = CreateBrokerMessage(
- BrokerMessageType::INIT, 0, sizeof(*name_data) * pipe_name.length(),
- &data, reinterpret_cast<void**>(&name_data));
- data->pipe_name_length = static_cast<uint32_t>(pipe_name.length());
- std::copy(pipe_name.begin(), pipe_name.end(), name_data);
- channel_->Write(std::move(message));
-}
-
-#endif // defined(OS_WIN)
-
-void BrokerHost::OnBufferRequest(uint32_t num_bytes) {
- scoped_refptr<PlatformSharedBuffer> read_only_buffer;
- scoped_refptr<PlatformSharedBuffer> buffer =
- PlatformSharedBuffer::Create(num_bytes);
- if (buffer)
- read_only_buffer = buffer->CreateReadOnlyDuplicate();
- if (!read_only_buffer)
- buffer = nullptr;
-
- Channel::MessagePtr message = CreateBrokerMessage(
- BrokerMessageType::BUFFER_RESPONSE, buffer ? 2 : 0, nullptr);
- if (buffer) {
- ScopedPlatformHandleVectorPtr handles;
- handles.reset(new PlatformHandleVector(2));
- handles->at(0) = buffer->PassPlatformHandle().release();
- handles->at(1) = read_only_buffer->PassPlatformHandle().release();
- PrepareHandlesForClient(handles.get());
- message->SetHandles(std::move(handles));
- }
-
- channel_->Write(std::move(message));
-}
-
-void BrokerHost::OnChannelMessage(const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) {
- if (payload_size < sizeof(BrokerMessageHeader))
- return;
-
- const BrokerMessageHeader* header =
- static_cast<const BrokerMessageHeader*>(payload);
- switch (header->type) {
- case BrokerMessageType::BUFFER_REQUEST:
- if (payload_size ==
- sizeof(BrokerMessageHeader) + sizeof(BufferRequestData)) {
- const BufferRequestData* request =
- reinterpret_cast<const BufferRequestData*>(header + 1);
- OnBufferRequest(request->size);
- }
- break;
-
- default:
- LOG(ERROR) << "Unexpected broker message type: " << header->type;
- break;
- }
-}
-
-void BrokerHost::OnChannelError() { delete this; }
-
-void BrokerHost::WillDestroyCurrentMessageLoop() { delete this; }
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/broker_host.h b/mojo/edk/system/broker_host.h
deleted file mode 100644
index a7995d2..0000000
--- a/mojo/edk/system/broker_host.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_BROKER_HOST_H_
-#define MOJO_EDK_SYSTEM_BROKER_HOST_H_
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/process/process_handle.h"
-#include "base/strings/string_piece.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/channel.h"
-
-namespace mojo {
-namespace edk {
-
-// The BrokerHost is a channel to the child process, which services synchronous
-// IPCs.
-class BrokerHost : public Channel::Delegate,
- public base::MessageLoop::DestructionObserver {
- public:
- BrokerHost(base::ProcessHandle client_process, ScopedPlatformHandle handle);
-
- // Send |handle| to the child, to be used to establish a NodeChannel to us.
- bool SendChannel(ScopedPlatformHandle handle);
-
-#if defined(OS_WIN)
- // Sends a named channel to the child. Like above, but for named pipes.
- void SendNamedChannel(const base::StringPiece16& pipe_name);
-#endif
-
- private:
- ~BrokerHost() override;
-
- bool PrepareHandlesForClient(PlatformHandleVector* handles);
-
- // Channel::Delegate:
- void OnChannelMessage(const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) override;
- void OnChannelError() override;
-
- // base::MessageLoop::DestructionObserver:
- void WillDestroyCurrentMessageLoop() override;
-
- void OnBufferRequest(uint32_t num_bytes);
-
-#if defined(OS_WIN)
- base::ProcessHandle client_process_;
-#endif
-
- scoped_refptr<Channel> channel_;
-
- DISALLOW_COPY_AND_ASSIGN(BrokerHost);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_BROKER_HOST_H_
diff --git a/mojo/edk/system/broker_messages.h b/mojo/edk/system/broker_messages.h
deleted file mode 100644
index 0f0dd9d..0000000
--- a/mojo/edk/system/broker_messages.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_BROKER_MESSAGES_H_
-#define MOJO_EDK_SYSTEM_BROKER_MESSAGES_H_
-
-#include "mojo/edk/system/channel.h"
-
-namespace mojo {
-namespace edk {
-
-#pragma pack(push, 1)
-
-enum BrokerMessageType : uint32_t {
- INIT,
- BUFFER_REQUEST,
- BUFFER_RESPONSE,
-};
-
-struct BrokerMessageHeader {
- BrokerMessageType type;
- uint32_t padding;
-};
-
-static_assert(IsAlignedForChannelMessage(sizeof(BrokerMessageHeader)),
- "Invalid header size.");
-
-struct BufferRequestData {
- uint32_t size;
-};
-
-#if defined(OS_WIN)
-struct InitData {
- // NOTE: InitData in the payload is followed by string16 data with exactly
- // |pipe_name_length| wide characters (i.e., |pipe_name_length|*2 bytes.)
- // This applies to Windows only.
- uint32_t pipe_name_length;
-};
-#endif
-
-#pragma pack(pop)
-
-template <typename T>
-inline Channel::MessagePtr CreateBrokerMessage(
- BrokerMessageType type,
- size_t num_handles,
- size_t extra_data_size,
- T** out_message_data,
- void** out_extra_data = nullptr) {
- const size_t message_size = sizeof(BrokerMessageHeader) +
- sizeof(**out_message_data) + extra_data_size;
- Channel::MessagePtr message(new Channel::Message(message_size, num_handles));
- BrokerMessageHeader* header =
- reinterpret_cast<BrokerMessageHeader*>(message->mutable_payload());
- header->type = type;
- header->padding = 0;
- *out_message_data = reinterpret_cast<T*>(header + 1);
- if (out_extra_data)
- *out_extra_data = *out_message_data + 1;
- return message;
-}
-
-inline Channel::MessagePtr CreateBrokerMessage(
- BrokerMessageType type,
- size_t num_handles,
- std::nullptr_t** dummy_out_data) {
- Channel::MessagePtr message(
- new Channel::Message(sizeof(BrokerMessageHeader), num_handles));
- BrokerMessageHeader* header =
- reinterpret_cast<BrokerMessageHeader*>(message->mutable_payload());
- header->type = type;
- header->padding = 0;
- return message;
-}
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_BROKER_MESSAGES_H_
diff --git a/mojo/edk/system/broker_posix.cc b/mojo/edk/system/broker_posix.cc
deleted file mode 100644
index 8742f70..0000000
--- a/mojo/edk/system/broker_posix.cc
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/broker.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <utility>
-
-#include "base/logging.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/platform_channel_utils_posix.h"
-#include "mojo/edk/embedder/platform_handle_utils.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/broker_messages.h"
-#include "mojo/edk/system/channel.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-bool WaitForBrokerMessage(PlatformHandle platform_handle,
- BrokerMessageType expected_type,
- size_t expected_num_handles,
- std::deque<PlatformHandle>* incoming_handles) {
- Channel::MessagePtr message(
- new Channel::Message(sizeof(BrokerMessageHeader), expected_num_handles));
- std::deque<PlatformHandle> incoming_platform_handles;
- ssize_t read_result = PlatformChannelRecvmsg(
- platform_handle, const_cast<void*>(message->data()),
- message->data_num_bytes(), &incoming_platform_handles, true /* block */);
- bool error = false;
- if (read_result < 0) {
- PLOG(ERROR) << "Recvmsg error";
- error = true;
- } else if (static_cast<size_t>(read_result) != message->data_num_bytes()) {
- LOG(ERROR) << "Invalid node channel message";
- error = true;
- } else if (incoming_platform_handles.size() != expected_num_handles) {
- LOG(ERROR) << "Received unexpected number of handles";
- error = true;
- }
-
- if (!error) {
- const BrokerMessageHeader* header =
- reinterpret_cast<const BrokerMessageHeader*>(message->payload());
- if (header->type != expected_type) {
- LOG(ERROR) << "Unexpected message";
- error = true;
- }
- }
-
- if (error) {
- CloseAllPlatformHandles(&incoming_platform_handles);
- } else {
- if (incoming_handles)
- incoming_handles->swap(incoming_platform_handles);
- }
- return !error;
-}
-
-} // namespace
-
-Broker::Broker(ScopedPlatformHandle platform_handle)
- : sync_channel_(std::move(platform_handle)) {
- CHECK(sync_channel_.is_valid());
-
- // Mark the channel as blocking.
- int flags = fcntl(sync_channel_.get().handle, F_GETFL);
- PCHECK(flags != -1);
- flags = fcntl(sync_channel_.get().handle, F_SETFL, flags & ~O_NONBLOCK);
- PCHECK(flags != -1);
-
- // Wait for the first message, which should contain a handle.
- std::deque<PlatformHandle> incoming_platform_handles;
- if (WaitForBrokerMessage(sync_channel_.get(), BrokerMessageType::INIT, 1,
- &incoming_platform_handles)) {
- parent_channel_ = ScopedPlatformHandle(incoming_platform_handles.front());
- }
-}
-
-Broker::~Broker() = default;
-
-ScopedPlatformHandle Broker::GetParentPlatformHandle() {
- return std::move(parent_channel_);
-}
-
-scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) {
- base::AutoLock lock(lock_);
-
- BufferRequestData* buffer_request;
- Channel::MessagePtr out_message = CreateBrokerMessage(
- BrokerMessageType::BUFFER_REQUEST, 0, 0, &buffer_request);
- buffer_request->size = num_bytes;
- ssize_t write_result = PlatformChannelWrite(
- sync_channel_.get(), out_message->data(), out_message->data_num_bytes());
- if (write_result < 0) {
- PLOG(ERROR) << "Error sending sync broker message";
- return nullptr;
- } else if (static_cast<size_t>(write_result) !=
- out_message->data_num_bytes()) {
- LOG(ERROR) << "Error sending complete broker message";
- return nullptr;
- }
-
- std::deque<PlatformHandle> incoming_platform_handles;
- if (WaitForBrokerMessage(sync_channel_.get(),
- BrokerMessageType::BUFFER_RESPONSE, 2,
- &incoming_platform_handles)) {
- ScopedPlatformHandle rw_handle(incoming_platform_handles.front());
- incoming_platform_handles.pop_front();
- ScopedPlatformHandle ro_handle(incoming_platform_handles.front());
- return PlatformSharedBuffer::CreateFromPlatformHandlePair(
- num_bytes, std::move(rw_handle), std::move(ro_handle));
- }
-
- return nullptr;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/broker_win.cc b/mojo/edk/system/broker_win.cc
deleted file mode 100644
index 063282c..0000000
--- a/mojo/edk/system/broker_win.cc
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <windows.h>
-
-#include <limits>
-#include <utility>
-
-#include "base/debug/alias.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_piece.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-#include "mojo/edk/embedder/named_platform_handle_utils.h"
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/broker.h"
-#include "mojo/edk/system/broker_messages.h"
-#include "mojo/edk/system/channel.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-// 256 bytes should be enough for anyone!
-const size_t kMaxBrokerMessageSize = 256;
-
-bool TakeHandlesFromBrokerMessage(Channel::Message* message,
- size_t num_handles,
- ScopedPlatformHandle* out_handles) {
- if (message->num_handles() != num_handles) {
- DLOG(ERROR) << "Received unexpected number of handles in broker message";
- return false;
- }
-
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- DCHECK(handles);
- DCHECK_EQ(handles->size(), num_handles);
- DCHECK(out_handles);
-
- for (size_t i = 0; i < num_handles; ++i)
- out_handles[i] = ScopedPlatformHandle((*handles)[i]);
- handles->clear();
- return true;
-}
-
-Channel::MessagePtr WaitForBrokerMessage(PlatformHandle platform_handle,
- BrokerMessageType expected_type) {
- char buffer[kMaxBrokerMessageSize];
- DWORD bytes_read = 0;
- BOOL result = ::ReadFile(platform_handle.handle, buffer,
- kMaxBrokerMessageSize, &bytes_read, nullptr);
- if (!result) {
- // The pipe may be broken if the browser side has been closed, e.g. during
- // browser shutdown. In that case the ReadFile call will fail and we
- // shouldn't continue waiting.
- PLOG(ERROR) << "Error reading broker pipe";
- return nullptr;
- }
-
- Channel::MessagePtr message =
- Channel::Message::Deserialize(buffer, static_cast<size_t>(bytes_read));
- if (!message || message->payload_size() < sizeof(BrokerMessageHeader)) {
- LOG(ERROR) << "Invalid broker message";
-
- base::debug::Alias(&buffer[0]);
- base::debug::Alias(&bytes_read);
- base::debug::Alias(message.get());
- CHECK(false);
- return nullptr;
- }
-
- const BrokerMessageHeader* header =
- reinterpret_cast<const BrokerMessageHeader*>(message->payload());
- if (header->type != expected_type) {
- LOG(ERROR) << "Unexpected broker message type";
-
- base::debug::Alias(&buffer[0]);
- base::debug::Alias(&bytes_read);
- base::debug::Alias(message.get());
- CHECK(false);
- return nullptr;
- }
-
- return message;
-}
-
-} // namespace
-
-Broker::Broker(ScopedPlatformHandle handle) : sync_channel_(std::move(handle)) {
- CHECK(sync_channel_.is_valid());
- Channel::MessagePtr message =
- WaitForBrokerMessage(sync_channel_.get(), BrokerMessageType::INIT);
-
- // If we fail to read a message (broken pipe), just return early. The parent
- // handle will be null and callers must handle this gracefully.
- if (!message)
- return;
-
- if (!TakeHandlesFromBrokerMessage(message.get(), 1, &parent_channel_)) {
- // If the message has no handles, we expect it to carry pipe name instead.
- const BrokerMessageHeader* header =
- static_cast<const BrokerMessageHeader*>(message->payload());
- CHECK_GE(message->payload_size(),
- sizeof(BrokerMessageHeader) + sizeof(InitData));
- const InitData* data = reinterpret_cast<const InitData*>(header + 1);
- CHECK_EQ(message->payload_size(),
- sizeof(BrokerMessageHeader) + sizeof(InitData) +
- data->pipe_name_length * sizeof(base::char16));
- const base::char16* name_data =
- reinterpret_cast<const base::char16*>(data + 1);
- CHECK(data->pipe_name_length);
- parent_channel_ = CreateClientHandle(NamedPlatformHandle(
- base::StringPiece16(name_data, data->pipe_name_length)));
- }
-}
-
-Broker::~Broker() {}
-
-ScopedPlatformHandle Broker::GetParentPlatformHandle() {
- return std::move(parent_channel_);
-}
-
-scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) {
- base::AutoLock lock(lock_);
- BufferRequestData* buffer_request;
- Channel::MessagePtr out_message = CreateBrokerMessage(
- BrokerMessageType::BUFFER_REQUEST, 0, 0, &buffer_request);
- buffer_request->size = base::checked_cast<uint32_t>(num_bytes);
- DWORD bytes_written = 0;
- BOOL result = ::WriteFile(sync_channel_.get().handle, out_message->data(),
- static_cast<DWORD>(out_message->data_num_bytes()),
- &bytes_written, nullptr);
- if (!result ||
- static_cast<size_t>(bytes_written) != out_message->data_num_bytes()) {
- LOG(ERROR) << "Error sending sync broker message";
- return nullptr;
- }
-
- ScopedPlatformHandle handles[2];
- Channel::MessagePtr response = WaitForBrokerMessage(
- sync_channel_.get(), BrokerMessageType::BUFFER_RESPONSE);
- if (response &&
- TakeHandlesFromBrokerMessage(response.get(), 2, &handles[0])) {
- return PlatformSharedBuffer::CreateFromPlatformHandlePair(
- num_bytes, std::move(handles[0]), std::move(handles[1]));
- }
-
- return nullptr;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/channel.cc b/mojo/edk/system/channel.cc
deleted file mode 100644
index 8a44d36..0000000
--- a/mojo/edk/system/channel.cc
+++ /dev/null
@@ -1,683 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/channel.h"
-
-#include <stddef.h>
-#include <string.h>
-
-#include <algorithm>
-#include <limits>
-#include <utility>
-
-#include "base/macros.h"
-#include "base/memory/aligned_memory.h"
-#include "base/process/process_handle.h"
-#include "mojo/edk/embedder/platform_handle.h"
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "base/mac/mach_logging.h"
-#elif defined(OS_WIN)
-#include "base/win/win_util.h"
-#endif
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-static_assert(
- IsAlignedForChannelMessage(sizeof(Channel::Message::LegacyHeader)),
- "Invalid LegacyHeader size.");
-
-static_assert(IsAlignedForChannelMessage(sizeof(Channel::Message::Header)),
- "Invalid Header size.");
-
-static_assert(sizeof(Channel::Message::LegacyHeader) == 8,
- "LegacyHeader must be 8 bytes on ChromeOS and Android");
-
-static_assert(offsetof(Channel::Message::LegacyHeader, num_bytes) ==
- offsetof(Channel::Message::Header, num_bytes),
- "num_bytes should be at the same offset in both Header structs.");
-static_assert(offsetof(Channel::Message::LegacyHeader, message_type) ==
- offsetof(Channel::Message::Header, message_type),
- "message_type should be at the same offset in both Header "
- "structs.");
-
-} // namespace
-
-const size_t kReadBufferSize = 4096;
-const size_t kMaxUnusedReadBufferCapacity = 4096;
-const size_t kMaxChannelMessageSize = 256 * 1024 * 1024;
-const size_t kMaxAttachedHandles = 128;
-
-Channel::Message::Message(size_t payload_size, size_t max_handles)
-#if defined(MOJO_EDK_LEGACY_PROTOCOL)
- : Message(payload_size, max_handles, MessageType::NORMAL_LEGACY) {
-}
-#else
- : Message(payload_size, max_handles, MessageType::NORMAL) {
-}
-#endif
-
-Channel::Message::Message(size_t payload_size,
- size_t max_handles,
- MessageType message_type)
- : max_handles_(max_handles) {
- DCHECK_LE(max_handles_, kMaxAttachedHandles);
-
- const bool is_legacy_message = (message_type == MessageType::NORMAL_LEGACY);
- size_t extra_header_size = 0;
-#if defined(OS_WIN)
- // On Windows we serialize HANDLEs into the extra header space.
- extra_header_size = max_handles_ * sizeof(HandleEntry);
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- // On OSX, some of the platform handles may be mach ports, which are
- // serialised into the message buffer. Since there could be a mix of fds and
- // mach ports, we store the mach ports as an <index, port> pair (of uint32_t),
- // so that the original ordering of handles can be re-created.
- if (max_handles) {
- extra_header_size =
- sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry));
- }
-#endif
- // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes.
- if (!IsAlignedForChannelMessage(extra_header_size)) {
- extra_header_size += kChannelMessageAlignment -
- (extra_header_size % kChannelMessageAlignment);
- }
- DCHECK(IsAlignedForChannelMessage(extra_header_size));
- const size_t header_size =
- is_legacy_message ? sizeof(LegacyHeader) : sizeof(Header);
- DCHECK(extra_header_size == 0 || !is_legacy_message);
-
- size_ = header_size + extra_header_size + payload_size;
- data_ = static_cast<char*>(base::AlignedAlloc(size_,
- kChannelMessageAlignment));
- // Only zero out the header and not the payload. Since the payload is going to
- // be memcpy'd, zeroing the payload is unnecessary work and a significant
- // performance issue when dealing with large messages. Any sanitizer errors
- // complaining about an uninitialized read in the payload area should be
- // treated as an error and fixed.
- memset(data_, 0, header_size + extra_header_size);
-
- DCHECK_LE(size_, std::numeric_limits<uint32_t>::max());
- legacy_header()->num_bytes = static_cast<uint32_t>(size_);
-
- DCHECK_LE(header_size + extra_header_size,
- std::numeric_limits<uint16_t>::max());
- legacy_header()->message_type = message_type;
-
- if (is_legacy_message) {
- legacy_header()->num_handles = static_cast<uint16_t>(max_handles);
- } else {
- header()->num_header_bytes =
- static_cast<uint16_t>(header_size + extra_header_size);
- }
-
- if (max_handles_ > 0) {
-#if defined(OS_WIN)
- handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header());
- // Initialize all handles to invalid values.
- for (size_t i = 0; i < max_handles_; ++i)
- handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE);
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- mach_ports_header_ =
- reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header());
- mach_ports_header_->num_ports = 0;
- // Initialize all handles to invalid values.
- for (size_t i = 0; i < max_handles_; ++i) {
- mach_ports_header_->entries[i] =
- {0, static_cast<uint32_t>(MACH_PORT_NULL)};
- }
-#endif
- }
-}
-
-Channel::Message::~Message() {
- base::AlignedFree(data_);
-}
-
-// static
-Channel::MessagePtr Channel::Message::Deserialize(const void* data,
- size_t data_num_bytes) {
- if (data_num_bytes < sizeof(LegacyHeader))
- return nullptr;
-
- const LegacyHeader* legacy_header =
- reinterpret_cast<const LegacyHeader*>(data);
- if (legacy_header->num_bytes != data_num_bytes) {
- DLOG(ERROR) << "Decoding invalid message: " << legacy_header->num_bytes
- << " != " << data_num_bytes;
- return nullptr;
- }
-
- const Header* header = nullptr;
- if (legacy_header->message_type == MessageType::NORMAL)
- header = reinterpret_cast<const Header*>(data);
-
- uint32_t extra_header_size = 0;
- size_t payload_size = 0;
- const char* payload = nullptr;
- if (!header) {
- payload_size = data_num_bytes - sizeof(LegacyHeader);
- payload = static_cast<const char*>(data) + sizeof(LegacyHeader);
- } else {
- if (header->num_bytes < header->num_header_bytes ||
- header->num_header_bytes < sizeof(Header)) {
- DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < "
- << header->num_header_bytes;
- return nullptr;
- }
- extra_header_size = header->num_header_bytes - sizeof(Header);
- payload_size = data_num_bytes - header->num_header_bytes;
- payload = static_cast<const char*>(data) + header->num_header_bytes;
- }
-
-#if defined(OS_WIN)
- uint32_t max_handles = extra_header_size / sizeof(HandleEntry);
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- if (extra_header_size > 0 &&
- extra_header_size < sizeof(MachPortsExtraHeader)) {
- DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < "
- << sizeof(MachPortsExtraHeader);
- return nullptr;
- }
- uint32_t max_handles =
- extra_header_size == 0
- ? 0
- : (extra_header_size - sizeof(MachPortsExtraHeader)) /
- sizeof(MachPortsEntry);
-#else
- const uint32_t max_handles = 0;
-#endif // defined(OS_WIN)
-
- const uint16_t num_handles =
- header ? header->num_handles : legacy_header->num_handles;
- if (num_handles > max_handles || max_handles > kMaxAttachedHandles) {
- DLOG(ERROR) << "Decoding invalid message: " << num_handles << " > "
- << max_handles;
- return nullptr;
- }
-
- MessagePtr message(
- new Message(payload_size, max_handles, legacy_header->message_type));
- DCHECK_EQ(message->data_num_bytes(), data_num_bytes);
-
- // Copy all payload bytes.
- if (payload_size)
- memcpy(message->mutable_payload(), payload, payload_size);
-
- if (header) {
- DCHECK_EQ(message->extra_header_size(), extra_header_size);
- DCHECK_EQ(message->header()->num_header_bytes, header->num_header_bytes);
-
- if (message->extra_header_size()) {
- // Copy extra header bytes.
- memcpy(message->mutable_extra_header(),
- static_cast<const char*>(data) + sizeof(Header),
- message->extra_header_size());
- }
- message->header()->num_handles = header->num_handles;
- } else {
- message->legacy_header()->num_handles = legacy_header->num_handles;
- }
-
-#if defined(OS_WIN)
- ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector(num_handles));
- for (size_t i = 0; i < num_handles; i++) {
- (*handles)[i].handle =
- base::win::Uint32ToHandle(message->handles_[i].handle);
- }
- message->SetHandles(std::move(handles));
-#endif
-
- return message;
-}
-
-const void* Channel::Message::extra_header() const {
- DCHECK(!is_legacy_message());
- return data_ + sizeof(Header);
-}
-
-void* Channel::Message::mutable_extra_header() {
- DCHECK(!is_legacy_message());
- return data_ + sizeof(Header);
-}
-
-size_t Channel::Message::extra_header_size() const {
- return header()->num_header_bytes - sizeof(Header);
-}
-
-void* Channel::Message::mutable_payload() {
- if (is_legacy_message())
- return static_cast<void*>(legacy_header() + 1);
- return data_ + header()->num_header_bytes;
-}
-
-const void* Channel::Message::payload() const {
- if (is_legacy_message())
- return static_cast<const void*>(legacy_header() + 1);
- return data_ + header()->num_header_bytes;
-}
-
-size_t Channel::Message::payload_size() const {
- if (is_legacy_message())
- return legacy_header()->num_bytes - sizeof(LegacyHeader);
- return size_ - header()->num_header_bytes;
-}
-
-size_t Channel::Message::num_handles() const {
- return is_legacy_message() ? legacy_header()->num_handles
- : header()->num_handles;
-}
-
-bool Channel::Message::has_handles() const {
- return (is_legacy_message() ? legacy_header()->num_handles
- : header()->num_handles) > 0;
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-bool Channel::Message::has_mach_ports() const {
- if (!has_handles())
- return false;
-
- for (const auto& handle : (*handle_vector_)) {
- if (handle.type == PlatformHandle::Type::MACH ||
- handle.type == PlatformHandle::Type::MACH_NAME) {
- return true;
- }
- }
- return false;
-}
-#endif
-
-bool Channel::Message::is_legacy_message() const {
- return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
-}
-
-Channel::Message::LegacyHeader* Channel::Message::legacy_header() const {
- return reinterpret_cast<LegacyHeader*>(data_);
-}
-
-Channel::Message::Header* Channel::Message::header() const {
- DCHECK(!is_legacy_message());
- return reinterpret_cast<Header*>(data_);
-}
-
-void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) {
- if (is_legacy_message()) {
- // Old semantics for ChromeOS and Android
- if (legacy_header()->num_handles == 0) {
- CHECK(!new_handles || new_handles->size() == 0);
- return;
- }
- CHECK(new_handles && new_handles->size() == legacy_header()->num_handles);
- std::swap(handle_vector_, new_handles);
- return;
- }
-
- if (max_handles_ == 0) {
- CHECK(!new_handles || new_handles->size() == 0);
- return;
- }
-
- CHECK(new_handles && new_handles->size() <= max_handles_);
- header()->num_handles = static_cast<uint16_t>(new_handles->size());
- std::swap(handle_vector_, new_handles);
-#if defined(OS_WIN)
- memset(handles_, 0, extra_header_size());
- for (size_t i = 0; i < handle_vector_->size(); i++)
- handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle);
-#endif // defined(OS_WIN)
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- size_t mach_port_index = 0;
- if (mach_ports_header_) {
- for (size_t i = 0; i < max_handles_; ++i) {
- mach_ports_header_->entries[i] =
- {0, static_cast<uint32_t>(MACH_PORT_NULL)};
- }
- for (size_t i = 0; i < handle_vector_->size(); i++) {
- if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH ||
- (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) {
- mach_port_t port = (*handle_vector_)[i].port;
- mach_ports_header_->entries[mach_port_index].index = i;
- mach_ports_header_->entries[mach_port_index].mach_port = port;
- mach_port_index++;
- }
- }
- mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index);
- }
-#endif
-}
-
-ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (mach_ports_header_) {
- for (size_t i = 0; i < max_handles_; ++i) {
- mach_ports_header_->entries[i] =
- {0, static_cast<uint32_t>(MACH_PORT_NULL)};
- }
- mach_ports_header_->num_ports = 0;
- }
-#endif
- if (is_legacy_message())
- legacy_header()->num_handles = 0;
- else
- header()->num_handles = 0;
- return std::move(handle_vector_);
-}
-
-ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() {
-#if defined(OS_WIN)
- // Not necessary on Windows.
- NOTREACHED();
- return nullptr;
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- if (handle_vector_) {
- for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) {
- if (it->type == PlatformHandle::Type::MACH ||
- it->type == PlatformHandle::Type::MACH_NAME) {
- // For Mach port names, we can can just leak them. They're not real
- // ports anyways. For real ports, they're leaked because this is a child
- // process and the remote process will take ownership.
- it = handle_vector_->erase(it);
- } else {
- ++it;
- }
- }
- }
- return std::move(handle_vector_);
-#else
- return std::move(handle_vector_);
-#endif
-}
-
-#if defined(OS_WIN)
-// static
-bool Channel::Message::RewriteHandles(base::ProcessHandle from_process,
- base::ProcessHandle to_process,
- PlatformHandleVector* handles) {
- bool success = true;
- for (size_t i = 0; i < handles->size(); ++i) {
- if (!(*handles)[i].is_valid()) {
- DLOG(ERROR) << "Refusing to duplicate invalid handle.";
- continue;
- }
- DCHECK_EQ((*handles)[i].owning_process, from_process);
- BOOL result = DuplicateHandle(
- from_process, (*handles)[i].handle, to_process,
- &(*handles)[i].handle, 0, FALSE,
- DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
- if (result) {
- (*handles)[i].owning_process = to_process;
- } else {
- success = false;
-
- // If handle duplication fails, the source handle will already be closed
- // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with
- // an invalid handle.
- (*handles)[i].handle = INVALID_HANDLE_VALUE;
- (*handles)[i].owning_process = base::GetCurrentProcessHandle();
- }
- }
- return success;
-}
-#endif
-
-// Helper class for managing a Channel's read buffer allocations. This maintains
-// a single contiguous buffer with the layout:
-//
-// [discarded bytes][occupied bytes][unoccupied bytes]
-//
-// The Reserve() method ensures that a certain capacity of unoccupied bytes are
-// available. It does not claim that capacity and only allocates new capacity
-// when strictly necessary.
-//
-// Claim() marks unoccupied bytes as occupied.
-//
-// Discard() marks occupied bytes as discarded, signifying that their contents
-// can be forgotten or overwritten.
-//
-// Realign() moves occupied bytes to the front of the buffer so that those
-// occupied bytes are properly aligned.
-//
-// The most common Channel behavior in practice should result in very few
-// allocations and copies, as memory is claimed and discarded shortly after
-// being reserved, and future reservations will immediately reuse discarded
-// memory.
-class Channel::ReadBuffer {
- public:
- ReadBuffer() {
- size_ = kReadBufferSize;
- data_ = static_cast<char*>(base::AlignedAlloc(size_,
- kChannelMessageAlignment));
- }
-
- ~ReadBuffer() {
- DCHECK(data_);
- base::AlignedFree(data_);
- }
-
- const char* occupied_bytes() const { return data_ + num_discarded_bytes_; }
-
- size_t num_occupied_bytes() const {
- return num_occupied_bytes_ - num_discarded_bytes_;
- }
-
- // Ensures the ReadBuffer has enough contiguous space allocated to hold
- // |num_bytes| more bytes; returns the address of the first available byte.
- char* Reserve(size_t num_bytes) {
- if (num_occupied_bytes_ + num_bytes > size_) {
- size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes);
- void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment);
- memcpy(new_data, data_, num_occupied_bytes_);
- base::AlignedFree(data_);
- data_ = static_cast<char*>(new_data);
- }
-
- return data_ + num_occupied_bytes_;
- }
-
- // Marks the first |num_bytes| unoccupied bytes as occupied.
- void Claim(size_t num_bytes) {
- DCHECK_LE(num_occupied_bytes_ + num_bytes, size_);
- num_occupied_bytes_ += num_bytes;
- }
-
- // Marks the first |num_bytes| occupied bytes as discarded. This may result in
- // shrinkage of the internal buffer, and it is not safe to assume the result
- // of a previous Reserve() call is still valid after this.
- void Discard(size_t num_bytes) {
- DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_);
- num_discarded_bytes_ += num_bytes;
-
- if (num_discarded_bytes_ == num_occupied_bytes_) {
- // We can just reuse the buffer from the beginning in this common case.
- num_discarded_bytes_ = 0;
- num_occupied_bytes_ = 0;
- }
-
- if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) {
- // In the uncommon case that we have a lot of discarded data at the
- // front of the buffer, simply move remaining data to a smaller buffer.
- size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_;
- size_ = std::max(num_preserved_bytes, kReadBufferSize);
- char* new_data = static_cast<char*>(
- base::AlignedAlloc(size_, kChannelMessageAlignment));
- memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes);
- base::AlignedFree(data_);
- data_ = new_data;
- num_discarded_bytes_ = 0;
- num_occupied_bytes_ = num_preserved_bytes;
- }
-
- if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) {
- // Opportunistically shrink the read buffer back down to a small size if
- // it's grown very large. We only do this if there are no remaining
- // unconsumed bytes in the buffer to avoid copies in most the common
- // cases.
- size_ = kMaxUnusedReadBufferCapacity;
- base::AlignedFree(data_);
- data_ = static_cast<char*>(
- base::AlignedAlloc(size_, kChannelMessageAlignment));
- }
- }
-
- void Realign() {
- size_t num_bytes = num_occupied_bytes();
- memmove(data_, occupied_bytes(), num_bytes);
- num_discarded_bytes_ = 0;
- num_occupied_bytes_ = num_bytes;
- }
-
- private:
- char* data_ = nullptr;
-
- // The total size of the allocated buffer.
- size_t size_ = 0;
-
- // The number of discarded bytes at the beginning of the allocated buffer.
- size_t num_discarded_bytes_ = 0;
-
- // The total number of occupied bytes, including discarded bytes.
- size_t num_occupied_bytes_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(ReadBuffer);
-};
-
-Channel::Channel(Delegate* delegate)
- : delegate_(delegate), read_buffer_(new ReadBuffer) {
-}
-
-Channel::~Channel() {
-}
-
-void Channel::ShutDown() {
- delegate_ = nullptr;
- ShutDownImpl();
-}
-
-char* Channel::GetReadBuffer(size_t *buffer_capacity) {
- DCHECK(read_buffer_);
- size_t required_capacity = *buffer_capacity;
- if (!required_capacity)
- required_capacity = kReadBufferSize;
-
- *buffer_capacity = required_capacity;
- return read_buffer_->Reserve(required_capacity);
-}
-
-bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) {
- bool did_dispatch_message = false;
- read_buffer_->Claim(bytes_read);
- while (read_buffer_->num_occupied_bytes() >= sizeof(Message::LegacyHeader)) {
- // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could
- // happen on architectures that don't allow misaligned words access (i.e.
- // anything other than x86). Only re-align when necessary to avoid copies.
- if (!IsAlignedForChannelMessage(
- reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()))) {
- read_buffer_->Realign();
- }
-
- // We have at least enough data available for a LegacyHeader.
- const Message::LegacyHeader* legacy_header =
- reinterpret_cast<const Message::LegacyHeader*>(
- read_buffer_->occupied_bytes());
-
- if (legacy_header->num_bytes < sizeof(Message::LegacyHeader) ||
- legacy_header->num_bytes > kMaxChannelMessageSize) {
- LOG(ERROR) << "Invalid message size: " << legacy_header->num_bytes;
- return false;
- }
-
- if (read_buffer_->num_occupied_bytes() < legacy_header->num_bytes) {
- // Not enough data available to read the full message. Hint to the
- // implementation that it should try reading the full size of the message.
- *next_read_size_hint =
- legacy_header->num_bytes - read_buffer_->num_occupied_bytes();
- return true;
- }
-
- const Message::Header* header = nullptr;
- if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY) {
- header = reinterpret_cast<const Message::Header*>(legacy_header);
- }
-
- size_t extra_header_size = 0;
- const void* extra_header = nullptr;
- size_t payload_size = 0;
- void* payload = nullptr;
- if (header) {
- if (header->num_header_bytes < sizeof(Message::Header) ||
- header->num_header_bytes > header->num_bytes) {
- LOG(ERROR) << "Invalid message header size: "
- << header->num_header_bytes;
- return false;
- }
- extra_header_size = header->num_header_bytes - sizeof(Message::Header);
- extra_header = extra_header_size ? header + 1 : nullptr;
- payload_size = header->num_bytes - header->num_header_bytes;
- payload = payload_size
- ? reinterpret_cast<Message::Header*>(
- const_cast<char*>(read_buffer_->occupied_bytes()) +
- header->num_header_bytes)
- : nullptr;
- } else {
- payload_size = legacy_header->num_bytes - sizeof(Message::LegacyHeader);
- payload = payload_size
- ? const_cast<Message::LegacyHeader*>(&legacy_header[1])
- : nullptr;
- }
-
- const uint16_t num_handles =
- header ? header->num_handles : legacy_header->num_handles;
- ScopedPlatformHandleVectorPtr handles;
- if (num_handles > 0) {
- if (!GetReadPlatformHandles(num_handles, extra_header, extra_header_size,
- &handles)) {
- return false;
- }
-
- if (!handles) {
- // Not enough handles available for this message.
- break;
- }
- }
-
- // We've got a complete message! Dispatch it and try another.
- if (legacy_header->message_type != Message::MessageType::NORMAL_LEGACY &&
- legacy_header->message_type != Message::MessageType::NORMAL) {
- if (!OnControlMessage(legacy_header->message_type, payload, payload_size,
- std::move(handles))) {
- return false;
- }
- did_dispatch_message = true;
- } else if (delegate_) {
- delegate_->OnChannelMessage(payload, payload_size, std::move(handles));
- did_dispatch_message = true;
- }
-
- read_buffer_->Discard(legacy_header->num_bytes);
- }
-
- *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize;
- return true;
-}
-
-void Channel::OnError() {
- if (delegate_)
- delegate_->OnChannelError();
-}
-
-bool Channel::OnControlMessage(Message::MessageType message_type,
- const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) {
- return false;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/channel.h b/mojo/edk/system/channel.h
deleted file mode 100644
index 33a510c..0000000
--- a/mojo/edk/system/channel.h
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_CHANNEL_H_
-#define MOJO_EDK_SYSTEM_CHANNEL_H_
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/process/process_handle.h"
-#include "base/task_runner.h"
-#include "mojo/edk/embedder/connection_params.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-
-namespace mojo {
-namespace edk {
-
-const size_t kChannelMessageAlignment = 8;
-
-constexpr bool IsAlignedForChannelMessage(size_t n) {
- return n % kChannelMessageAlignment == 0;
-}
-
-// Channel provides a thread-safe interface to read and write arbitrary
-// delimited messages over an underlying I/O channel, optionally transferring
-// one or more platform handles in the process.
-class MOJO_SYSTEM_IMPL_EXPORT Channel
- : public base::RefCountedThreadSafe<Channel> {
- public:
- struct Message;
-
- using MessagePtr = std::unique_ptr<Message>;
-
- // A message to be written to a channel.
- struct MOJO_SYSTEM_IMPL_EXPORT Message {
- enum class MessageType : uint16_t {
- // An old format normal message, that uses the LegacyHeader.
- // Only used on Android and ChromeOS.
- // TODO(jcivelli): remove legacy support when Arc++ has updated to Mojo
- // with normal versioned messages. crbug.com/695645
- NORMAL_LEGACY = 0,
-#if defined(OS_MACOSX)
- // A control message containing handles to echo back.
- HANDLES_SENT,
- // A control message containing handles that can now be closed.
- HANDLES_SENT_ACK,
-#endif
- // A normal message that uses Header and can contain extra header values.
- NORMAL,
- };
-
-#pragma pack(push, 1)
- // Old message wire format for ChromeOS and Android, used by NORMAL_LEGACY
- // messages.
- struct LegacyHeader {
- // Message size in bytes, including the header.
- uint32_t num_bytes;
-
- // Number of attached handles.
- uint16_t num_handles;
-
- MessageType message_type;
- };
-
- // Header used by NORMAL messages.
- // To preserve backward compatibility with LegacyHeader, the num_bytes and
- // message_type field must be at the same offset as in LegacyHeader.
- struct Header {
- // Message size in bytes, including the header.
- uint32_t num_bytes;
-
- // Total size of header, including extra header data (i.e. HANDLEs on
- // windows).
- uint16_t num_header_bytes;
-
- MessageType message_type;
-
- // Number of attached handles. May be less than the reserved handle
- // storage size in this message on platforms that serialise handles as
- // data (i.e. HANDLEs on Windows, Mach ports on OSX).
- uint16_t num_handles;
-
- char padding[6];
- };
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- struct MachPortsEntry {
- // Index of Mach port in the original vector of PlatformHandles.
- uint16_t index;
-
- // Mach port name.
- uint32_t mach_port;
- static_assert(sizeof(mach_port_t) <= sizeof(uint32_t),
- "mach_port_t must be no larger than uint32_t");
- };
- static_assert(sizeof(MachPortsEntry) == 6,
- "sizeof(MachPortsEntry) must be 6 bytes");
-
- // Structure of the extra header field when present on OSX.
- struct MachPortsExtraHeader {
- // Actual number of Mach ports encoded in the extra header.
- uint16_t num_ports;
-
- // Array of encoded Mach ports. If |num_ports| > 0, |entries[0]| through
- // to |entries[num_ports-1]| inclusive are valid.
- MachPortsEntry entries[0];
- };
- static_assert(sizeof(MachPortsExtraHeader) == 2,
- "sizeof(MachPortsExtraHeader) must be 2 bytes");
-#elif defined(OS_WIN)
- struct HandleEntry {
- // The windows HANDLE. HANDLEs are guaranteed to fit inside 32-bits.
- // See: https://msdn.microsoft.com/en-us/library/aa384203(VS.85).aspx
- uint32_t handle;
- };
- static_assert(sizeof(HandleEntry) == 4,
- "sizeof(HandleEntry) must be 4 bytes");
-#endif
-#pragma pack(pop)
-
- // Allocates and owns a buffer for message data with enough capacity for
- // |payload_size| bytes plus a header, plus |max_handles| platform handles.
- Message(size_t payload_size, size_t max_handles);
- Message(size_t payload_size, size_t max_handles, MessageType message_type);
- ~Message();
-
- // Constructs a Message from serialized message data.
- static MessagePtr Deserialize(const void* data, size_t data_num_bytes);
-
- const void* data() const { return data_; }
- size_t data_num_bytes() const { return size_; }
-
- const void* extra_header() const;
- void* mutable_extra_header();
- size_t extra_header_size() const;
-
- void* mutable_payload();
- const void* payload() const;
- size_t payload_size() const;
-
- size_t num_handles() const;
- bool has_handles() const;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- bool has_mach_ports() const;
-#endif
-
- bool is_legacy_message() const;
- LegacyHeader* legacy_header() const;
- Header* header() const;
-
- // Note: SetHandles() and TakeHandles() invalidate any previous value of
- // handles().
- void SetHandles(ScopedPlatformHandleVectorPtr new_handles);
- ScopedPlatformHandleVectorPtr TakeHandles();
- // Version of TakeHandles that returns a vector of platform handles suitable
- // for transfer over an underlying OS mechanism. i.e. file descriptors over
- // a unix domain socket. Any handle that cannot be transferred this way,
- // such as Mach ports, will be removed.
- ScopedPlatformHandleVectorPtr TakeHandlesForTransport();
-
-#if defined(OS_WIN)
- // Prepares the handles in this message for use in a different process.
- // Upon calling this the handles should belong to |from_process|; after the
- // call they'll belong to |to_process|. The source handles are always
- // closed by this call. Returns false iff one or more handles failed
- // duplication.
- static bool RewriteHandles(base::ProcessHandle from_process,
- base::ProcessHandle to_process,
- PlatformHandleVector* handles);
-#endif
-
- void SetVersionForTest(uint16_t version_number);
-
- private:
- size_t size_ = 0;
- size_t max_handles_ = 0;
- char* data_ = nullptr;
-
- ScopedPlatformHandleVectorPtr handle_vector_;
-
-#if defined(OS_WIN)
- // On Windows, handles are serialised into the extra header section.
- HandleEntry* handles_ = nullptr;
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- // On OSX, handles are serialised into the extra header section.
- MachPortsExtraHeader* mach_ports_header_ = nullptr;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(Message);
- };
-
- // Delegate methods are called from the I/O task runner with which the Channel
- // was created (see Channel::Create).
- class Delegate {
- public:
- virtual ~Delegate() {}
-
- // Notify of a received message. |payload| is not owned and must not be
- // retained; it will be null if |payload_size| is 0. |handles| are
- // transferred to the callee.
- virtual void OnChannelMessage(const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) = 0;
-
- // Notify that an error has occured and the Channel will cease operation.
- virtual void OnChannelError() = 0;
- };
-
- // Creates a new Channel around a |platform_handle|, taking ownership of the
- // handle. All I/O on the handle will be performed on |io_task_runner|.
- // Note that ShutDown() MUST be called on the Channel some time before
- // |delegate| is destroyed.
- static scoped_refptr<Channel> Create(
- Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner);
-
- // Request that the channel be shut down. This should always be called before
- // releasing the last reference to a Channel to ensure that it's cleaned up
- // on its I/O task runner's thread.
- //
- // Delegate methods will no longer be invoked after this call.
- void ShutDown();
-
- // Begin processing I/O events. Delegate methods must only be invoked after
- // this call.
- virtual void Start() = 0;
-
- // Stop processing I/O events.
- virtual void ShutDownImpl() = 0;
-
- // Queues an outgoing message on the Channel. This message will either
- // eventually be written or will fail to write and trigger
- // Delegate::OnChannelError.
- virtual void Write(MessagePtr message) = 0;
-
- // Causes the platform handle to leak when this channel is shut down instead
- // of closing it.
- virtual void LeakHandle() = 0;
-
- protected:
- explicit Channel(Delegate* delegate);
- virtual ~Channel();
-
- // Called by the implementation when it wants somewhere to stick data.
- // |*buffer_capacity| may be set by the caller to indicate the desired buffer
- // size. If 0, a sane default size will be used instead.
- //
- // Returns the address of a buffer which can be written to, and indicates its
- // actual capacity in |*buffer_capacity|.
- char* GetReadBuffer(size_t* buffer_capacity);
-
- // Called by the implementation when new data is available in the read
- // buffer. Returns false to indicate an error. Upon success,
- // |*next_read_size_hint| will be set to a recommended size for the next
- // read done by the implementation.
- bool OnReadComplete(size_t bytes_read, size_t* next_read_size_hint);
-
- // Called by the implementation when something goes horribly wrong. It is NOT
- // OK to call this synchronously from any public interface methods.
- void OnError();
-
- // Retrieves the set of platform handles read for a given message.
- // |extra_header| and |extra_header_size| correspond to the extra header data.
- // Depending on the Channel implementation, this body may encode platform
- // handles, or handles may be stored and managed elsewhere by the
- // implementation.
- //
- // Returns |false| on unrecoverable error (i.e. the Channel should be closed).
- // Returns |true| otherwise. Note that it is possible on some platforms for an
- // insufficient number of handles to be available when this call is made, but
- // this is not necessarily an error condition. In such cases this returns
- // |true| but |*handles| will also be reset to null.
- virtual bool GetReadPlatformHandles(
- size_t num_handles,
- const void* extra_header,
- size_t extra_header_size,
- ScopedPlatformHandleVectorPtr* handles) = 0;
-
- // Handles a received control message. Returns |true| if the message is
- // accepted, or |false| otherwise.
- virtual bool OnControlMessage(Message::MessageType message_type,
- const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles);
-
- private:
- friend class base::RefCountedThreadSafe<Channel>;
-
- class ReadBuffer;
-
- Delegate* delegate_;
- const std::unique_ptr<ReadBuffer> read_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(Channel);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_CHANNEL_H_
diff --git a/mojo/edk/system/channel_posix.cc b/mojo/edk/system/channel_posix.cc
deleted file mode 100644
index 8b4ca7f..0000000
--- a/mojo/edk/system/channel_posix.cc
+++ /dev/null
@@ -1,572 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/channel.h"
-
-#include <errno.h>
-#include <sys/socket.h>
-
-#include <algorithm>
-#include <deque>
-#include <limits>
-#include <memory>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/synchronization/lock.h"
-#include "base/task_runner.h"
-#include "mojo/edk/embedder/platform_channel_utils_posix.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-
-#if !defined(OS_NACL)
-#include <sys/uio.h>
-#endif
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-const size_t kMaxBatchReadCapacity = 256 * 1024;
-
-// A view over a Channel::Message object. The write queue uses these since
-// large messages may need to be sent in chunks.
-class MessageView {
- public:
- // Owns |message|. |offset| indexes the first unsent byte in the message.
- MessageView(Channel::MessagePtr message, size_t offset)
- : message_(std::move(message)),
- offset_(offset),
- handles_(message_->TakeHandlesForTransport()) {
- DCHECK_GT(message_->data_num_bytes(), offset_);
- }
-
- MessageView(MessageView&& other) { *this = std::move(other); }
-
- MessageView& operator=(MessageView&& other) {
- message_ = std::move(other.message_);
- offset_ = other.offset_;
- handles_ = std::move(other.handles_);
- return *this;
- }
-
- ~MessageView() {}
-
- const void* data() const {
- return static_cast<const char*>(message_->data()) + offset_;
- }
-
- size_t data_num_bytes() const { return message_->data_num_bytes() - offset_; }
-
- size_t data_offset() const { return offset_; }
- void advance_data_offset(size_t num_bytes) {
- DCHECK_GT(message_->data_num_bytes(), offset_ + num_bytes);
- offset_ += num_bytes;
- }
-
- ScopedPlatformHandleVectorPtr TakeHandles() { return std::move(handles_); }
- Channel::MessagePtr TakeMessage() { return std::move(message_); }
-
- void SetHandles(ScopedPlatformHandleVectorPtr handles) {
- handles_ = std::move(handles);
- }
-
- private:
- Channel::MessagePtr message_;
- size_t offset_;
- ScopedPlatformHandleVectorPtr handles_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageView);
-};
-
-class ChannelPosix : public Channel,
- public base::MessageLoop::DestructionObserver,
- public base::MessageLoopForIO::Watcher {
- public:
- ChannelPosix(Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner)
- : Channel(delegate),
- self_(this),
- handle_(connection_params.TakeChannelHandle()),
- io_task_runner_(io_task_runner)
-#if defined(OS_MACOSX)
- ,
- handles_to_close_(new PlatformHandleVector)
-#endif
- {
- CHECK(handle_.is_valid());
- }
-
- void Start() override {
- if (io_task_runner_->RunsTasksOnCurrentThread()) {
- StartOnIOThread();
- } else {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ChannelPosix::StartOnIOThread, this));
- }
- }
-
- void ShutDownImpl() override {
- // Always shut down asynchronously when called through the public interface.
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ChannelPosix::ShutDownOnIOThread, this));
- }
-
- void Write(MessagePtr message) override {
- bool write_error = false;
- {
- base::AutoLock lock(write_lock_);
- if (reject_writes_)
- return;
- if (outgoing_messages_.empty()) {
- if (!WriteNoLock(MessageView(std::move(message), 0)))
- reject_writes_ = write_error = true;
- } else {
- outgoing_messages_.emplace_back(std::move(message), 0);
- }
- }
- if (write_error) {
- // Do not synchronously invoke OnError(). Write() may have been called by
- // the delegate and we don't want to re-enter it.
- io_task_runner_->PostTask(FROM_HERE,
- base::Bind(&ChannelPosix::OnError, this));
- }
- }
-
- void LeakHandle() override {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
- leak_handle_ = true;
- }
-
- bool GetReadPlatformHandles(
- size_t num_handles,
- const void* extra_header,
- size_t extra_header_size,
- ScopedPlatformHandleVectorPtr* handles) override {
- if (num_handles > std::numeric_limits<uint16_t>::max())
- return false;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // On OSX, we can have mach ports which are located in the extra header
- // section.
- using MachPortsEntry = Channel::Message::MachPortsEntry;
- using MachPortsExtraHeader = Channel::Message::MachPortsExtraHeader;
- CHECK(extra_header_size >=
- sizeof(MachPortsExtraHeader) + num_handles * sizeof(MachPortsEntry));
- const MachPortsExtraHeader* mach_ports_header =
- reinterpret_cast<const MachPortsExtraHeader*>(extra_header);
- size_t num_mach_ports = mach_ports_header->num_ports;
- CHECK(num_mach_ports <= num_handles);
- if (incoming_platform_handles_.size() + num_mach_ports < num_handles) {
- handles->reset();
- return true;
- }
-
- handles->reset(new PlatformHandleVector(num_handles));
- const MachPortsEntry* mach_ports = mach_ports_header->entries;
- for (size_t i = 0, mach_port_index = 0; i < num_handles; ++i) {
- if (mach_port_index < num_mach_ports &&
- mach_ports[mach_port_index].index == i) {
- (*handles)->at(i) = PlatformHandle(
- static_cast<mach_port_t>(mach_ports[mach_port_index].mach_port));
- CHECK((*handles)->at(i).type == PlatformHandle::Type::MACH);
- // These are actually just Mach port names until they're resolved from
- // the remote process.
- (*handles)->at(i).type = PlatformHandle::Type::MACH_NAME;
- mach_port_index++;
- } else {
- CHECK(!incoming_platform_handles_.empty());
- (*handles)->at(i) = incoming_platform_handles_.front();
- incoming_platform_handles_.pop_front();
- }
- }
-#else
- if (incoming_platform_handles_.size() < num_handles) {
- handles->reset();
- return true;
- }
-
- handles->reset(new PlatformHandleVector(num_handles));
- for (size_t i = 0; i < num_handles; ++i) {
- (*handles)->at(i) = incoming_platform_handles_.front();
- incoming_platform_handles_.pop_front();
- }
-#endif
-
- return true;
- }
-
- private:
- ~ChannelPosix() override {
- DCHECK(!read_watcher_);
- DCHECK(!write_watcher_);
- for (auto handle : incoming_platform_handles_)
- handle.CloseIfNecessary();
- }
-
- void StartOnIOThread() {
- DCHECK(!read_watcher_);
- DCHECK(!write_watcher_);
- read_watcher_.reset(
- new base::MessageLoopForIO::FileDescriptorWatcher(FROM_HERE));
- base::MessageLoop::current()->AddDestructionObserver(this);
- if (handle_.get().needs_connection) {
- base::MessageLoopForIO::current()->WatchFileDescriptor(
- handle_.get().handle, false /* persistent */,
- base::MessageLoopForIO::WATCH_READ, read_watcher_.get(), this);
- } else {
- write_watcher_.reset(
- new base::MessageLoopForIO::FileDescriptorWatcher(FROM_HERE));
- base::MessageLoopForIO::current()->WatchFileDescriptor(
- handle_.get().handle, true /* persistent */,
- base::MessageLoopForIO::WATCH_READ, read_watcher_.get(), this);
- base::AutoLock lock(write_lock_);
- FlushOutgoingMessagesNoLock();
- }
- }
-
- void WaitForWriteOnIOThread() {
- base::AutoLock lock(write_lock_);
- WaitForWriteOnIOThreadNoLock();
- }
-
- void WaitForWriteOnIOThreadNoLock() {
- if (pending_write_)
- return;
- if (!write_watcher_)
- return;
- if (io_task_runner_->RunsTasksOnCurrentThread()) {
- pending_write_ = true;
- base::MessageLoopForIO::current()->WatchFileDescriptor(
- handle_.get().handle, false /* persistent */,
- base::MessageLoopForIO::WATCH_WRITE, write_watcher_.get(), this);
- } else {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ChannelPosix::WaitForWriteOnIOThread, this));
- }
- }
-
- void ShutDownOnIOThread() {
- base::MessageLoop::current()->RemoveDestructionObserver(this);
-
- read_watcher_.reset();
- write_watcher_.reset();
- if (leak_handle_)
- ignore_result(handle_.release());
- handle_.reset();
-#if defined(OS_MACOSX)
- handles_to_close_.reset();
-#endif
-
- // May destroy the |this| if it was the last reference.
- self_ = nullptr;
- }
-
- // base::MessageLoop::DestructionObserver:
- void WillDestroyCurrentMessageLoop() override {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
- if (self_)
- ShutDownOnIOThread();
- }
-
- // base::MessageLoopForIO::Watcher:
- void OnFileCanReadWithoutBlocking(int fd) override {
- CHECK_EQ(fd, handle_.get().handle);
- if (handle_.get().needs_connection) {
-#if !defined(OS_NACL)
- read_watcher_.reset();
- base::MessageLoop::current()->RemoveDestructionObserver(this);
-
- ScopedPlatformHandle accept_fd;
- ServerAcceptConnection(handle_.get(), &accept_fd);
- if (!accept_fd.is_valid()) {
- OnError();
- return;
- }
- handle_ = std::move(accept_fd);
- StartOnIOThread();
-#else
- NOTREACHED();
-#endif
- return;
- }
-
- bool read_error = false;
- size_t next_read_size = 0;
- size_t buffer_capacity = 0;
- size_t total_bytes_read = 0;
- size_t bytes_read = 0;
- do {
- buffer_capacity = next_read_size;
- char* buffer = GetReadBuffer(&buffer_capacity);
- DCHECK_GT(buffer_capacity, 0u);
-
- ssize_t read_result = PlatformChannelRecvmsg(
- handle_.get(),
- buffer,
- buffer_capacity,
- &incoming_platform_handles_);
-
- if (read_result > 0) {
- bytes_read = static_cast<size_t>(read_result);
- total_bytes_read += bytes_read;
- if (!OnReadComplete(bytes_read, &next_read_size)) {
- read_error = true;
- break;
- }
- } else if (read_result == 0 ||
- (errno != EAGAIN && errno != EWOULDBLOCK)) {
- read_error = true;
- break;
- }
- } while (bytes_read == buffer_capacity &&
- total_bytes_read < kMaxBatchReadCapacity &&
- next_read_size > 0);
- if (read_error) {
- // Stop receiving read notifications.
- read_watcher_.reset();
-
- OnError();
- }
- }
-
- void OnFileCanWriteWithoutBlocking(int fd) override {
- bool write_error = false;
- {
- base::AutoLock lock(write_lock_);
- pending_write_ = false;
- if (!FlushOutgoingMessagesNoLock())
- reject_writes_ = write_error = true;
- }
- if (write_error)
- OnError();
- }
-
- // Attempts to write a message directly to the channel. If the full message
- // cannot be written, it's queued and a wait is initiated to write the message
- // ASAP on the I/O thread.
- bool WriteNoLock(MessageView message_view) {
- if (handle_.get().needs_connection) {
- outgoing_messages_.emplace_front(std::move(message_view));
- return true;
- }
- size_t bytes_written = 0;
- do {
- message_view.advance_data_offset(bytes_written);
-
- ssize_t result;
- ScopedPlatformHandleVectorPtr handles = message_view.TakeHandles();
- if (handles && handles->size()) {
- iovec iov = {
- const_cast<void*>(message_view.data()),
- message_view.data_num_bytes()
- };
- // TODO: Handle lots of handles.
- result = PlatformChannelSendmsgWithHandles(
- handle_.get(), &iov, 1, handles->data(), handles->size());
- if (result >= 0) {
-#if defined(OS_MACOSX)
- // There is a bug on OSX which makes it dangerous to close
- // a file descriptor while it is in transit. So instead we
- // store the file descriptor in a set and send a message to
- // the recipient, which is queued AFTER the message that
- // sent the FD. The recipient will reply to the message,
- // letting us know that it is now safe to close the file
- // descriptor. For more information, see:
- // http://crbug.com/298276
- std::vector<int> fds;
- for (auto& handle : *handles)
- fds.push_back(handle.handle);
- {
- base::AutoLock l(handles_to_close_lock_);
- for (auto& handle : *handles)
- handles_to_close_->push_back(handle);
- }
- MessagePtr fds_message(
- new Channel::Message(sizeof(fds[0]) * fds.size(), 0,
- Message::MessageType::HANDLES_SENT));
- memcpy(fds_message->mutable_payload(), fds.data(),
- sizeof(fds[0]) * fds.size());
- outgoing_messages_.emplace_back(std::move(fds_message), 0);
- handles->clear();
-#else
- handles.reset();
-#endif // defined(OS_MACOSX)
- }
- } else {
- result = PlatformChannelWrite(handle_.get(), message_view.data(),
- message_view.data_num_bytes());
- }
-
- if (result < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK
-#if defined(OS_MACOSX)
- // On OS X if sendmsg() is trying to send fds between processes and
- // there isn't enough room in the output buffer to send the fd
- // structure over atomically then EMSGSIZE is returned.
- //
- // EMSGSIZE presents a problem since the system APIs can only call
- // us when there's room in the socket buffer and not when there is
- // "enough" room.
- //
- // The current behavior is to return to the event loop when EMSGSIZE
- // is received and hopefull service another FD. This is however
- // still technically a busy wait since the event loop will call us
- // right back until the receiver has read enough data to allow
- // passing the FD over atomically.
- && errno != EMSGSIZE
-#endif
- ) {
- return false;
- }
- message_view.SetHandles(std::move(handles));
- outgoing_messages_.emplace_front(std::move(message_view));
- WaitForWriteOnIOThreadNoLock();
- return true;
- }
-
- bytes_written = static_cast<size_t>(result);
- } while (bytes_written < message_view.data_num_bytes());
-
- return FlushOutgoingMessagesNoLock();
- }
-
- bool FlushOutgoingMessagesNoLock() {
- std::deque<MessageView> messages;
- std::swap(outgoing_messages_, messages);
-
- while (!messages.empty()) {
- if (!WriteNoLock(std::move(messages.front())))
- return false;
-
- messages.pop_front();
- if (!outgoing_messages_.empty()) {
- // The message was requeued by WriteNoLock(), so we have to wait for
- // pipe to become writable again. Repopulate the message queue and exit.
- // If sending the message triggered any control messages, they may be
- // in |outgoing_messages_| in addition to or instead of the message
- // being sent.
- std::swap(messages, outgoing_messages_);
- while (!messages.empty()) {
- outgoing_messages_.push_front(std::move(messages.back()));
- messages.pop_back();
- }
- return true;
- }
- }
-
- return true;
- }
-
-#if defined(OS_MACOSX)
- bool OnControlMessage(Message::MessageType message_type,
- const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) override {
- switch (message_type) {
- case Message::MessageType::HANDLES_SENT: {
- if (payload_size == 0)
- break;
- MessagePtr message(new Channel::Message(
- payload_size, 0, Message::MessageType::HANDLES_SENT_ACK));
- memcpy(message->mutable_payload(), payload, payload_size);
- Write(std::move(message));
- return true;
- }
-
- case Message::MessageType::HANDLES_SENT_ACK: {
- size_t num_fds = payload_size / sizeof(int);
- if (num_fds == 0 || payload_size % sizeof(int) != 0)
- break;
-
- const int* fds = reinterpret_cast<const int*>(payload);
- if (!CloseHandles(fds, num_fds))
- break;
- return true;
- }
-
- default:
- break;
- }
-
- return false;
- }
-
- // Closes handles referenced by |fds|. Returns false if |num_fds| is 0, or if
- // |fds| does not match a sequence of handles in |handles_to_close_|.
- bool CloseHandles(const int* fds, size_t num_fds) {
- base::AutoLock l(handles_to_close_lock_);
- if (!num_fds)
- return false;
-
- auto start =
- std::find_if(handles_to_close_->begin(), handles_to_close_->end(),
- [&fds](const PlatformHandle& handle) {
- return handle.handle == fds[0];
- });
- if (start == handles_to_close_->end())
- return false;
-
- auto it = start;
- size_t i = 0;
- // The FDs in the message should match a sequence of handles in
- // |handles_to_close_|.
- for (; i < num_fds && it != handles_to_close_->end(); i++, ++it) {
- if (it->handle != fds[i])
- return false;
-
- it->CloseIfNecessary();
- }
- if (i != num_fds)
- return false;
-
- handles_to_close_->erase(start, it);
- return true;
- }
-#endif // defined(OS_MACOSX)
-
- // Keeps the Channel alive at least until explicit shutdown on the IO thread.
- scoped_refptr<Channel> self_;
-
- ScopedPlatformHandle handle_;
- scoped_refptr<base::TaskRunner> io_task_runner_;
-
- // These watchers must only be accessed on the IO thread.
- std::unique_ptr<base::MessageLoopForIO::FileDescriptorWatcher> read_watcher_;
- std::unique_ptr<base::MessageLoopForIO::FileDescriptorWatcher> write_watcher_;
-
- std::deque<PlatformHandle> incoming_platform_handles_;
-
- // Protects |pending_write_| and |outgoing_messages_|.
- base::Lock write_lock_;
- bool pending_write_ = false;
- bool reject_writes_ = false;
- std::deque<MessageView> outgoing_messages_;
-
- bool leak_handle_ = false;
-
-#if defined(OS_MACOSX)
- base::Lock handles_to_close_lock_;
- ScopedPlatformHandleVectorPtr handles_to_close_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(ChannelPosix);
-};
-
-} // namespace
-
-// static
-scoped_refptr<Channel> Channel::Create(
- Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner) {
- return new ChannelPosix(delegate, std::move(connection_params),
- io_task_runner);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/channel_unittest.cc b/mojo/edk/system/channel_unittest.cc
deleted file mode 100644
index ce2c804..0000000
--- a/mojo/edk/system/channel_unittest.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2017 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/channel.h"
-#include "base/memory/ptr_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-class TestChannel : public Channel {
- public:
- TestChannel(Channel::Delegate* delegate) : Channel(delegate) {}
-
- char* GetReadBufferTest(size_t* buffer_capacity) {
- return GetReadBuffer(buffer_capacity);
- }
-
- bool OnReadCompleteTest(size_t bytes_read, size_t* next_read_size_hint) {
- return OnReadComplete(bytes_read, next_read_size_hint);
- }
-
- MOCK_METHOD4(GetReadPlatformHandles,
- bool(size_t num_handles,
- const void* extra_header,
- size_t extra_header_size,
- ScopedPlatformHandleVectorPtr* handles));
- MOCK_METHOD0(Start, void());
- MOCK_METHOD0(ShutDownImpl, void());
- MOCK_METHOD0(LeakHandle, void());
-
- void Write(MessagePtr message) {}
-
- protected:
- ~TestChannel() override {}
-};
-
-// Not using GMock as I don't think it supports movable types.
-class MockChannelDelegate : public Channel::Delegate {
- public:
- MockChannelDelegate() {}
-
- size_t GetReceivedPayloadSize() const { return payload_size_; }
-
- const void* GetReceivedPayload() const { return payload_.get(); }
-
- protected:
- void OnChannelMessage(const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) override {
- payload_.reset(new char[payload_size]);
- memcpy(payload_.get(), payload, payload_size);
- payload_size_ = payload_size;
- }
-
- // Notify that an error has occured and the Channel will cease operation.
- void OnChannelError() override {}
-
- private:
- size_t payload_size_ = 0;
- std::unique_ptr<char[]> payload_;
-};
-
-Channel::MessagePtr CreateDefaultMessage(bool legacy_message) {
- const size_t payload_size = 100;
- Channel::MessagePtr message = base::MakeUnique<Channel::Message>(
- payload_size, 0,
- legacy_message ? Channel::Message::MessageType::NORMAL_LEGACY
- : Channel::Message::MessageType::NORMAL);
- char* payload = static_cast<char*>(message->mutable_payload());
- for (size_t i = 0; i < payload_size; i++) {
- payload[i] = static_cast<char>(i);
- }
- return message;
-}
-
-void TestMemoryEqual(const void* data1,
- size_t data1_size,
- const void* data2,
- size_t data2_size) {
- ASSERT_EQ(data1_size, data2_size);
- const unsigned char* data1_char = static_cast<const unsigned char*>(data1);
- const unsigned char* data2_char = static_cast<const unsigned char*>(data2);
- for (size_t i = 0; i < data1_size; i++) {
- // ASSERT so we don't log tons of errors if the data is different.
- ASSERT_EQ(data1_char[i], data2_char[i]);
- }
-}
-
-void TestMessagesAreEqual(Channel::Message* message1,
- Channel::Message* message2,
- bool legacy_messages) {
- // If any of the message is null, this is probably not what you wanted to
- // test.
- ASSERT_NE(nullptr, message1);
- ASSERT_NE(nullptr, message2);
-
- ASSERT_EQ(message1->payload_size(), message2->payload_size());
- EXPECT_EQ(message1->has_handles(), message2->has_handles());
-
- TestMemoryEqual(message1->payload(), message1->payload_size(),
- message2->payload(), message2->payload_size());
-
- if (legacy_messages)
- return;
-
- ASSERT_EQ(message1->extra_header_size(), message2->extra_header_size());
- TestMemoryEqual(message1->extra_header(), message1->extra_header_size(),
- message2->extra_header(), message2->extra_header_size());
-}
-
-TEST(ChannelTest, LegacyMessageDeserialization) {
- Channel::MessagePtr message = CreateDefaultMessage(true /* legacy_message */);
- Channel::MessagePtr deserialized_message =
- Channel::Message::Deserialize(message->data(), message->data_num_bytes());
- TestMessagesAreEqual(message.get(), deserialized_message.get(),
- true /* legacy_message */);
-}
-
-TEST(ChannelTest, NonLegacyMessageDeserialization) {
- Channel::MessagePtr message =
- CreateDefaultMessage(false /* legacy_message */);
- Channel::MessagePtr deserialized_message =
- Channel::Message::Deserialize(message->data(), message->data_num_bytes());
- TestMessagesAreEqual(message.get(), deserialized_message.get(),
- false /* legacy_message */);
-}
-
-TEST(ChannelTest, OnReadLegacyMessage) {
- size_t buffer_size = 100 * 1024;
- Channel::MessagePtr message = CreateDefaultMessage(true /* legacy_message */);
-
- MockChannelDelegate channel_delegate;
- scoped_refptr<TestChannel> channel = new TestChannel(&channel_delegate);
- char* read_buffer = channel->GetReadBufferTest(&buffer_size);
- ASSERT_LT(message->data_num_bytes(),
- buffer_size); // Bad test. Increase buffer
- // size.
- memcpy(read_buffer, message->data(), message->data_num_bytes());
-
- size_t next_read_size_hint = 0;
- EXPECT_TRUE(channel->OnReadCompleteTest(message->data_num_bytes(),
- &next_read_size_hint));
-
- TestMemoryEqual(message->payload(), message->payload_size(),
- channel_delegate.GetReceivedPayload(),
- channel_delegate.GetReceivedPayloadSize());
-}
-
-TEST(ChannelTest, OnReadNonLegacyMessage) {
- size_t buffer_size = 100 * 1024;
- Channel::MessagePtr message =
- CreateDefaultMessage(false /* legacy_message */);
-
- MockChannelDelegate channel_delegate;
- scoped_refptr<TestChannel> channel = new TestChannel(&channel_delegate);
- char* read_buffer = channel->GetReadBufferTest(&buffer_size);
- ASSERT_LT(message->data_num_bytes(),
- buffer_size); // Bad test. Increase buffer
- // size.
- memcpy(read_buffer, message->data(), message->data_num_bytes());
-
- size_t next_read_size_hint = 0;
- EXPECT_TRUE(channel->OnReadCompleteTest(message->data_num_bytes(),
- &next_read_size_hint));
-
- TestMemoryEqual(message->payload(), message->payload_size(),
- channel_delegate.GetReceivedPayload(),
- channel_delegate.GetReceivedPayloadSize());
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/channel_win.cc b/mojo/edk/system/channel_win.cc
deleted file mode 100644
index c15df16..0000000
--- a/mojo/edk/system/channel_win.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/channel.h"
-
-#include <stdint.h>
-#include <windows.h>
-
-#include <algorithm>
-#include <deque>
-#include <limits>
-#include <memory>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/synchronization/lock.h"
-#include "base/task_runner.h"
-#include "base/win/win_util.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-// A view over a Channel::Message object. The write queue uses these since
-// large messages may need to be sent in chunks.
-class MessageView {
- public:
- // Owns |message|. |offset| indexes the first unsent byte in the message.
- MessageView(Channel::MessagePtr message, size_t offset)
- : message_(std::move(message)),
- offset_(offset) {
- DCHECK_GT(message_->data_num_bytes(), offset_);
- }
-
- MessageView(MessageView&& other) { *this = std::move(other); }
-
- MessageView& operator=(MessageView&& other) {
- message_ = std::move(other.message_);
- offset_ = other.offset_;
- return *this;
- }
-
- ~MessageView() {}
-
- const void* data() const {
- return static_cast<const char*>(message_->data()) + offset_;
- }
-
- size_t data_num_bytes() const { return message_->data_num_bytes() - offset_; }
-
- size_t data_offset() const { return offset_; }
- void advance_data_offset(size_t num_bytes) {
- DCHECK_GE(message_->data_num_bytes(), offset_ + num_bytes);
- offset_ += num_bytes;
- }
-
- Channel::MessagePtr TakeChannelMessage() { return std::move(message_); }
-
- private:
- Channel::MessagePtr message_;
- size_t offset_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageView);
-};
-
-class ChannelWin : public Channel,
- public base::MessageLoop::DestructionObserver,
- public base::MessageLoopForIO::IOHandler {
- public:
- ChannelWin(Delegate* delegate,
- ScopedPlatformHandle handle,
- scoped_refptr<base::TaskRunner> io_task_runner)
- : Channel(delegate),
- self_(this),
- handle_(std::move(handle)),
- io_task_runner_(io_task_runner) {
- CHECK(handle_.is_valid());
-
- wait_for_connect_ = handle_.get().needs_connection;
- }
-
- void Start() override {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ChannelWin::StartOnIOThread, this));
- }
-
- void ShutDownImpl() override {
- // Always shut down asynchronously when called through the public interface.
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ChannelWin::ShutDownOnIOThread, this));
- }
-
- void Write(MessagePtr message) override {
- bool write_error = false;
- {
- base::AutoLock lock(write_lock_);
- if (reject_writes_)
- return;
-
- bool write_now = !delay_writes_ && outgoing_messages_.empty();
- outgoing_messages_.emplace_back(std::move(message), 0);
-
- if (write_now && !WriteNoLock(outgoing_messages_.front()))
- reject_writes_ = write_error = true;
- }
- if (write_error) {
- // Do not synchronously invoke OnError(). Write() may have been called by
- // the delegate and we don't want to re-enter it.
- io_task_runner_->PostTask(FROM_HERE,
- base::Bind(&ChannelWin::OnError, this));
- }
- }
-
- void LeakHandle() override {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
- leak_handle_ = true;
- }
-
- bool GetReadPlatformHandles(
- size_t num_handles,
- const void* extra_header,
- size_t extra_header_size,
- ScopedPlatformHandleVectorPtr* handles) override {
- if (num_handles > std::numeric_limits<uint16_t>::max())
- return false;
- using HandleEntry = Channel::Message::HandleEntry;
- size_t handles_size = sizeof(HandleEntry) * num_handles;
- if (handles_size > extra_header_size)
- return false;
- DCHECK(extra_header);
- handles->reset(new PlatformHandleVector(num_handles));
- const HandleEntry* extra_header_handles =
- reinterpret_cast<const HandleEntry*>(extra_header);
- for (size_t i = 0; i < num_handles; i++) {
- (*handles)->at(i).handle =
- base::win::Uint32ToHandle(extra_header_handles[i].handle);
- }
- return true;
- }
-
- private:
- // May run on any thread.
- ~ChannelWin() override {}
-
- void StartOnIOThread() {
- base::MessageLoop::current()->AddDestructionObserver(this);
- base::MessageLoopForIO::current()->RegisterIOHandler(
- handle_.get().handle, this);
-
- if (wait_for_connect_) {
- BOOL ok = ConnectNamedPipe(handle_.get().handle,
- &connect_context_.overlapped);
- if (ok) {
- PLOG(ERROR) << "Unexpected success while waiting for pipe connection";
- OnError();
- return;
- }
-
- const DWORD err = GetLastError();
- switch (err) {
- case ERROR_PIPE_CONNECTED:
- wait_for_connect_ = false;
- break;
- case ERROR_IO_PENDING:
- AddRef();
- return;
- case ERROR_NO_DATA:
- OnError();
- return;
- }
- }
-
- // Now that we have registered our IOHandler, we can start writing.
- {
- base::AutoLock lock(write_lock_);
- if (delay_writes_) {
- delay_writes_ = false;
- WriteNextNoLock();
- }
- }
-
- // Keep this alive in case we synchronously run shutdown.
- scoped_refptr<ChannelWin> keep_alive(this);
- ReadMore(0);
- }
-
- void ShutDownOnIOThread() {
- base::MessageLoop::current()->RemoveDestructionObserver(this);
-
- // BUG(crbug.com/583525): This function is expected to be called once, and
- // |handle_| should be valid at this point.
- CHECK(handle_.is_valid());
- CancelIo(handle_.get().handle);
- if (leak_handle_)
- ignore_result(handle_.release());
- handle_.reset();
-
- // May destroy the |this| if it was the last reference.
- self_ = nullptr;
- }
-
- // base::MessageLoop::DestructionObserver:
- void WillDestroyCurrentMessageLoop() override {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
- if (self_)
- ShutDownOnIOThread();
- }
-
- // base::MessageLoop::IOHandler:
- void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
- DWORD bytes_transfered,
- DWORD error) override {
- if (error != ERROR_SUCCESS) {
- OnError();
- } else if (context == &connect_context_) {
- DCHECK(wait_for_connect_);
- wait_for_connect_ = false;
- ReadMore(0);
-
- base::AutoLock lock(write_lock_);
- if (delay_writes_) {
- delay_writes_ = false;
- WriteNextNoLock();
- }
- } else if (context == &read_context_) {
- OnReadDone(static_cast<size_t>(bytes_transfered));
- } else {
- CHECK(context == &write_context_);
- OnWriteDone(static_cast<size_t>(bytes_transfered));
- }
- Release(); // Balancing reference taken after ReadFile / WriteFile.
- }
-
- void OnReadDone(size_t bytes_read) {
- if (bytes_read > 0) {
- size_t next_read_size = 0;
- if (OnReadComplete(bytes_read, &next_read_size)) {
- ReadMore(next_read_size);
- } else {
- OnError();
- }
- } else if (bytes_read == 0) {
- OnError();
- }
- }
-
- void OnWriteDone(size_t bytes_written) {
- if (bytes_written == 0)
- return;
-
- bool write_error = false;
- {
- base::AutoLock lock(write_lock_);
-
- DCHECK(!outgoing_messages_.empty());
-
- MessageView& message_view = outgoing_messages_.front();
- message_view.advance_data_offset(bytes_written);
- if (message_view.data_num_bytes() == 0) {
- Channel::MessagePtr message = message_view.TakeChannelMessage();
- outgoing_messages_.pop_front();
-
- // Clear any handles so they don't get closed on destruction.
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- if (handles)
- handles->clear();
- }
-
- if (!WriteNextNoLock())
- reject_writes_ = write_error = true;
- }
- if (write_error)
- OnError();
- }
-
- void ReadMore(size_t next_read_size_hint) {
- size_t buffer_capacity = next_read_size_hint;
- char* buffer = GetReadBuffer(&buffer_capacity);
- DCHECK_GT(buffer_capacity, 0u);
-
- BOOL ok = ReadFile(handle_.get().handle,
- buffer,
- static_cast<DWORD>(buffer_capacity),
- NULL,
- &read_context_.overlapped);
-
- if (ok || GetLastError() == ERROR_IO_PENDING) {
- AddRef(); // Will be balanced in OnIOCompleted
- } else {
- OnError();
- }
- }
-
- // Attempts to write a message directly to the channel. If the full message
- // cannot be written, it's queued and a wait is initiated to write the message
- // ASAP on the I/O thread.
- bool WriteNoLock(const MessageView& message_view) {
- BOOL ok = WriteFile(handle_.get().handle,
- message_view.data(),
- static_cast<DWORD>(message_view.data_num_bytes()),
- NULL,
- &write_context_.overlapped);
-
- if (ok || GetLastError() == ERROR_IO_PENDING) {
- AddRef(); // Will be balanced in OnIOCompleted.
- return true;
- }
- return false;
- }
-
- bool WriteNextNoLock() {
- if (outgoing_messages_.empty())
- return true;
- return WriteNoLock(outgoing_messages_.front());
- }
-
- // Keeps the Channel alive at least until explicit shutdown on the IO thread.
- scoped_refptr<Channel> self_;
-
- ScopedPlatformHandle handle_;
- scoped_refptr<base::TaskRunner> io_task_runner_;
-
- base::MessageLoopForIO::IOContext connect_context_;
- base::MessageLoopForIO::IOContext read_context_;
- base::MessageLoopForIO::IOContext write_context_;
-
- // Protects |reject_writes_| and |outgoing_messages_|.
- base::Lock write_lock_;
-
- bool delay_writes_ = true;
-
- bool reject_writes_ = false;
- std::deque<MessageView> outgoing_messages_;
-
- bool wait_for_connect_;
-
- bool leak_handle_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(ChannelWin);
-};
-
-} // namespace
-
-// static
-scoped_refptr<Channel> Channel::Create(
- Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner) {
- return new ChannelWin(delegate, connection_params.TakeChannelHandle(),
- io_task_runner);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/configuration.cc b/mojo/edk/system/configuration.cc
deleted file mode 100644
index f5eb2b8..0000000
--- a/mojo/edk/system/configuration.cc
+++ /dev/null
@@ -1,25 +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/configuration.h"
-
-namespace mojo {
-namespace edk {
-namespace internal {
-
-// These default values should be synced with the documentation in
-// mojo/edk/embedder/configuration.h.
-Configuration g_configuration = {
- 1000000, // max_handle_table_size
- 1000000, // max_mapping_table_sze
- 4 * 1024 * 1024, // max_message_num_bytes
- 10000, // max_message_num_handles
- 256 * 1024 * 1024, // max_data_pipe_capacity_bytes
- 1024 * 1024, // default_data_pipe_capacity_bytes
- 16, // data_pipe_buffer_alignment_bytes
- 1024 * 1024 * 1024}; // max_shared_memory_num_bytes
-
-} // namespace internal
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/configuration.h b/mojo/edk/system/configuration.h
deleted file mode 100644
index 038835f..0000000
--- a/mojo/edk/system/configuration.h
+++ /dev/null
@@ -1,29 +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_SYSTEM_CONFIGURATION_H_
-#define MOJO_EDK_SYSTEM_CONFIGURATION_H_
-
-#include "mojo/edk/embedder/configuration.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-namespace internal {
-MOJO_SYSTEM_IMPL_EXPORT extern Configuration g_configuration;
-} // namespace internal
-
-MOJO_SYSTEM_IMPL_EXPORT inline const Configuration& GetConfiguration() {
- return internal::g_configuration;
-}
-
-MOJO_SYSTEM_IMPL_EXPORT inline Configuration* GetMutableConfiguration() {
- return &internal::g_configuration;
-}
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_CONFIGURATION_H_
diff --git a/mojo/edk/system/core.cc b/mojo/edk/system/core.cc
deleted file mode 100644
index 360e8c3..0000000
--- a/mojo/edk/system/core.cc
+++ /dev/null
@@ -1,1019 +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/core.h"
-
-#include <string.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/containers/stack_container.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/rand_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/channel.h"
-#include "mojo/edk/system/configuration.h"
-#include "mojo/edk/system/data_pipe_consumer_dispatcher.h"
-#include "mojo/edk/system/data_pipe_producer_dispatcher.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/message_for_transit.h"
-#include "mojo/edk/system/message_pipe_dispatcher.h"
-#include "mojo/edk/system/platform_handle_dispatcher.h"
-#include "mojo/edk/system/ports/name.h"
-#include "mojo/edk/system/ports/node.h"
-#include "mojo/edk/system/request_context.h"
-#include "mojo/edk/system/shared_buffer_dispatcher.h"
-#include "mojo/edk/system/watcher_dispatcher.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-// This is an unnecessarily large limit that is relatively easy to enforce.
-const uint32_t kMaxHandlesPerMessage = 1024 * 1024;
-
-// TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process
-// pipes too; for now we just use a constant. This only affects bootstrap pipes.
-const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL;
-
-MojoResult MojoPlatformHandleToScopedPlatformHandle(
- const MojoPlatformHandle* platform_handle,
- ScopedPlatformHandle* out_handle) {
- if (platform_handle->struct_size != sizeof(MojoPlatformHandle))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (platform_handle->type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) {
- out_handle->reset();
- return MOJO_RESULT_OK;
- }
-
- PlatformHandle handle;
- switch (platform_handle->type) {
-#if defined(OS_POSIX)
- case MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR:
- handle.handle = static_cast<int>(platform_handle->value);
- break;
-#endif
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- case MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT:
- handle.type = PlatformHandle::Type::MACH;
- handle.port = static_cast<mach_port_t>(platform_handle->value);
- break;
-#endif
-
-#if defined(OS_WIN)
- case MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE:
- handle.handle = reinterpret_cast<HANDLE>(platform_handle->value);
- break;
-#endif
-
- default:
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- out_handle->reset(handle);
- return MOJO_RESULT_OK;
-}
-
-MojoResult ScopedPlatformHandleToMojoPlatformHandle(
- ScopedPlatformHandle handle,
- MojoPlatformHandle* platform_handle) {
- if (platform_handle->struct_size != sizeof(MojoPlatformHandle))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (!handle.is_valid()) {
- platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
- return MOJO_RESULT_OK;
- }
-
-#if defined(OS_POSIX)
- switch (handle.get().type) {
- case PlatformHandle::Type::POSIX:
- platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
- platform_handle->value = static_cast<uint64_t>(handle.release().handle);
- break;
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- case PlatformHandle::Type::MACH:
- platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
- platform_handle->value = static_cast<uint64_t>(handle.release().port);
- break;
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
-
- default:
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-#elif defined(OS_WIN)
- platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE;
- platform_handle->value = reinterpret_cast<uint64_t>(handle.release().handle);
-#endif // defined(OS_WIN)
-
- return MOJO_RESULT_OK;
-}
-
-} // namespace
-
-Core::Core() {}
-
-Core::~Core() {
- if (node_controller_ && node_controller_->io_task_runner()) {
- // If this races with IO thread shutdown the callback will be dropped and
- // the NodeController will be shutdown on this thread anyway, which is also
- // just fine.
- scoped_refptr<base::TaskRunner> io_task_runner =
- node_controller_->io_task_runner();
- io_task_runner->PostTask(FROM_HERE,
- base::Bind(&Core::PassNodeControllerToIOThread,
- base::Passed(&node_controller_)));
- }
-}
-
-void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) {
- GetNodeController()->SetIOTaskRunner(io_task_runner);
-}
-
-NodeController* Core::GetNodeController() {
- base::AutoLock lock(node_controller_lock_);
- if (!node_controller_)
- node_controller_.reset(new NodeController(this));
- return node_controller_.get();
-}
-
-scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) {
- base::AutoLock lock(handles_lock_);
- return handles_.GetDispatcher(handle);
-}
-
-void Core::SetDefaultProcessErrorCallback(
- const ProcessErrorCallback& callback) {
- default_process_error_callback_ = callback;
-}
-
-void Core::AddChild(base::ProcessHandle process_handle,
- ConnectionParams connection_params,
- const std::string& child_token,
- const ProcessErrorCallback& process_error_callback) {
- GetNodeController()->ConnectToChild(process_handle,
- std::move(connection_params), child_token,
- process_error_callback);
-}
-
-void Core::ChildLaunchFailed(const std::string& child_token) {
- RequestContext request_context;
- GetNodeController()->CloseChildPorts(child_token);
-}
-
-ScopedMessagePipeHandle Core::ConnectToPeerProcess(
- ScopedPlatformHandle pipe_handle,
- const std::string& peer_token) {
- RequestContext request_context;
- ports::PortRef port0, port1;
- GetNodeController()->node()->CreatePortPair(&port0, &port1);
- MojoHandle handle = AddDispatcher(new MessagePipeDispatcher(
- GetNodeController(), port0, kUnknownPipeIdForDebug, 0));
- ConnectionParams connection_params(std::move(pipe_handle));
- GetNodeController()->ConnectToPeer(std::move(connection_params), port1,
- peer_token);
- return ScopedMessagePipeHandle(MessagePipeHandle(handle));
-}
-
-void Core::ClosePeerConnection(const std::string& peer_token) {
- GetNodeController()->ClosePeerConnection(peer_token);
-}
-
-void Core::InitChild(ConnectionParams connection_params) {
- GetNodeController()->ConnectToParent(std::move(connection_params));
-}
-
-void Core::SetMachPortProvider(base::PortProvider* port_provider) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- GetNodeController()->CreateMachPortRelay(port_provider);
-#endif
-}
-
-MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
- base::AutoLock lock(handles_lock_);
- return handles_.AddDispatcher(dispatcher);
-}
-
-bool Core::AddDispatchersFromTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
- MojoHandle* handles) {
- bool failed = false;
- {
- base::AutoLock lock(handles_lock_);
- if (!handles_.AddDispatchersFromTransit(dispatchers, handles))
- failed = true;
- }
- if (failed) {
- for (auto d : dispatchers)
- d.dispatcher->Close();
- return false;
- }
- return true;
-}
-
-MojoResult Core::CreatePlatformHandleWrapper(
- ScopedPlatformHandle platform_handle,
- MojoHandle* wrapper_handle) {
- MojoHandle h = AddDispatcher(
- PlatformHandleDispatcher::Create(std::move(platform_handle)));
- if (h == MOJO_HANDLE_INVALID)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- *wrapper_handle = h;
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::PassWrappedPlatformHandle(
- MojoHandle wrapper_handle,
- ScopedPlatformHandle* platform_handle) {
- base::AutoLock lock(handles_lock_);
- scoped_refptr<Dispatcher> d;
- MojoResult result = handles_.GetAndRemoveDispatcher(wrapper_handle, &d);
- if (result != MOJO_RESULT_OK)
- return result;
- if (d->GetType() == Dispatcher::Type::PLATFORM_HANDLE) {
- PlatformHandleDispatcher* phd =
- static_cast<PlatformHandleDispatcher*>(d.get());
- *platform_handle = phd->PassPlatformHandle();
- } else {
- result = MOJO_RESULT_INVALID_ARGUMENT;
- }
- d->Close();
- return result;
-}
-
-MojoResult Core::CreateSharedBufferWrapper(
- base::SharedMemoryHandle shared_memory_handle,
- size_t num_bytes,
- bool read_only,
- MojoHandle* mojo_wrapper_handle) {
- DCHECK(num_bytes);
- scoped_refptr<PlatformSharedBuffer> platform_buffer =
- PlatformSharedBuffer::CreateFromSharedMemoryHandle(num_bytes, read_only,
- shared_memory_handle);
- if (!platform_buffer)
- return MOJO_RESULT_UNKNOWN;
-
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- MojoResult result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
- platform_buffer, &dispatcher);
- if (result != MOJO_RESULT_OK)
- return result;
- MojoHandle h = AddDispatcher(dispatcher);
- if (h == MOJO_HANDLE_INVALID)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- *mojo_wrapper_handle = h;
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::PassSharedMemoryHandle(
- MojoHandle mojo_handle,
- base::SharedMemoryHandle* shared_memory_handle,
- size_t* num_bytes,
- bool* read_only) {
- if (!shared_memory_handle)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- scoped_refptr<Dispatcher> dispatcher;
- MojoResult result = MOJO_RESULT_OK;
- {
- base::AutoLock lock(handles_lock_);
- // Get the dispatcher and check it before removing it from the handle table
- // to ensure that the dispatcher is of the correct type. This ensures we
- // don't close and remove the wrong type of dispatcher.
- dispatcher = handles_.GetDispatcher(mojo_handle);
- if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- result = handles_.GetAndRemoveDispatcher(mojo_handle, &dispatcher);
- if (result != MOJO_RESULT_OK)
- return result;
- }
-
- SharedBufferDispatcher* shm_dispatcher =
- static_cast<SharedBufferDispatcher*>(dispatcher.get());
- scoped_refptr<PlatformSharedBuffer> platform_shared_buffer =
- shm_dispatcher->PassPlatformSharedBuffer();
-
- if (!platform_shared_buffer)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (num_bytes)
- *num_bytes = platform_shared_buffer->GetNumBytes();
- if (read_only)
- *read_only = platform_shared_buffer->IsReadOnly();
- *shared_memory_handle = platform_shared_buffer->DuplicateSharedMemoryHandle();
-
- shm_dispatcher->Close();
- return result;
-}
-
-void Core::RequestShutdown(const base::Closure& callback) {
- GetNodeController()->RequestShutdown(callback);
-}
-
-ScopedMessagePipeHandle Core::CreateParentMessagePipe(
- const std::string& token, const std::string& child_token) {
- RequestContext request_context;
- ports::PortRef port0, port1;
- GetNodeController()->node()->CreatePortPair(&port0, &port1);
- MojoHandle handle = AddDispatcher(
- new MessagePipeDispatcher(GetNodeController(), port0,
- kUnknownPipeIdForDebug, 0));
- GetNodeController()->ReservePort(token, port1, child_token);
- return ScopedMessagePipeHandle(MessagePipeHandle(handle));
-}
-
-ScopedMessagePipeHandle Core::CreateChildMessagePipe(const std::string& token) {
- RequestContext request_context;
- ports::PortRef port0, port1;
- GetNodeController()->node()->CreatePortPair(&port0, &port1);
- MojoHandle handle = AddDispatcher(
- new MessagePipeDispatcher(GetNodeController(), port0,
- kUnknownPipeIdForDebug, 1));
- GetNodeController()->MergePortIntoParent(token, port1);
- return ScopedMessagePipeHandle(MessagePipeHandle(handle));
-}
-
-MojoResult Core::SetProperty(MojoPropertyType type, const void* value) {
- base::AutoLock locker(property_lock_);
- switch (type) {
- case MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED:
- property_sync_call_allowed_ = *static_cast<const bool*>(value);
- return MOJO_RESULT_OK;
- default:
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-}
-
-MojoTimeTicks Core::GetTimeTicksNow() {
- return base::TimeTicks::Now().ToInternalValue();
-}
-
-MojoResult Core::Close(MojoHandle handle) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher;
- {
- base::AutoLock lock(handles_lock_);
- MojoResult rv = handles_.GetAndRemoveDispatcher(handle, &dispatcher);
- if (rv != MOJO_RESULT_OK)
- return rv;
- }
- dispatcher->Close();
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::QueryHandleSignalsState(
- MojoHandle handle,
- MojoHandleSignalsState* signals_state) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
- if (!dispatcher || !signals_state)
- return MOJO_RESULT_INVALID_ARGUMENT;
- *signals_state = dispatcher->GetHandleSignalsState();
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::CreateWatcher(MojoWatcherCallback callback,
- MojoHandle* watcher_handle) {
- RequestContext request_context;
- if (!watcher_handle)
- return MOJO_RESULT_INVALID_ARGUMENT;
- *watcher_handle = AddDispatcher(new WatcherDispatcher(callback));
- if (*watcher_handle == MOJO_HANDLE_INVALID)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::Watch(MojoHandle watcher_handle,
- MojoHandle handle,
- MojoHandleSignals signals,
- uintptr_t context) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> watcher = GetDispatcher(watcher_handle);
- if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
- return MOJO_RESULT_INVALID_ARGUMENT;
- scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle);
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watcher->WatchDispatcher(dispatcher, signals, context);
-}
-
-MojoResult Core::CancelWatch(MojoHandle watcher_handle, uintptr_t context) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> watcher = GetDispatcher(watcher_handle);
- if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watcher->CancelWatch(context);
-}
-
-MojoResult Core::ArmWatcher(MojoHandle watcher_handle,
- uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> watcher = GetDispatcher(watcher_handle);
- if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watcher->Arm(num_ready_contexts, ready_contexts, ready_results,
- ready_signals_states);
-}
-
-MojoResult Core::AllocMessage(uint32_t num_bytes,
- const MojoHandle* handles,
- uint32_t num_handles,
- MojoAllocMessageFlags flags,
- MojoMessageHandle* message) {
- if (!message)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (num_handles == 0) { // Fast path: no handles.
- std::unique_ptr<MessageForTransit> msg;
- MojoResult rv = MessageForTransit::Create(&msg, num_bytes, nullptr, 0);
- if (rv != MOJO_RESULT_OK)
- return rv;
-
- *message = reinterpret_cast<MojoMessageHandle>(msg.release());
- return MOJO_RESULT_OK;
- }
-
- if (!handles)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (num_handles > kMaxHandlesPerMessage)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- std::vector<Dispatcher::DispatcherInTransit> dispatchers;
- {
- base::AutoLock lock(handles_lock_);
- MojoResult rv = handles_.BeginTransit(handles, num_handles, &dispatchers);
- if (rv != MOJO_RESULT_OK) {
- handles_.CancelTransit(dispatchers);
- return rv;
- }
- }
- DCHECK_EQ(num_handles, dispatchers.size());
-
- std::unique_ptr<MessageForTransit> msg;
- MojoResult rv = MessageForTransit::Create(
- &msg, num_bytes, dispatchers.data(), num_handles);
-
- {
- base::AutoLock lock(handles_lock_);
- if (rv == MOJO_RESULT_OK) {
- handles_.CompleteTransitAndClose(dispatchers);
- *message = reinterpret_cast<MojoMessageHandle>(msg.release());
- } else {
- handles_.CancelTransit(dispatchers);
- }
- }
-
- return rv;
-}
-
-MojoResult Core::FreeMessage(MojoMessageHandle message) {
- if (!message)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- delete reinterpret_cast<MessageForTransit*>(message);
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::GetMessageBuffer(MojoMessageHandle message, void** buffer) {
- if (!message)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- *buffer = reinterpret_cast<MessageForTransit*>(message)->mutable_bytes();
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::GetProperty(MojoPropertyType type, void* value) {
- base::AutoLock locker(property_lock_);
- switch (type) {
- case MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED:
- *static_cast<bool*>(value) = property_sync_call_allowed_;
- return MOJO_RESULT_OK;
- default:
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-}
-
-MojoResult Core::CreateMessagePipe(
- const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1) {
- RequestContext request_context;
- ports::PortRef port0, port1;
- GetNodeController()->node()->CreatePortPair(&port0, &port1);
-
- CHECK(message_pipe_handle0);
- CHECK(message_pipe_handle1);
-
- uint64_t pipe_id = base::RandUint64();
-
- *message_pipe_handle0 = AddDispatcher(
- new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0));
- if (*message_pipe_handle0 == MOJO_HANDLE_INVALID)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- *message_pipe_handle1 = AddDispatcher(
- new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1));
- if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) {
- scoped_refptr<Dispatcher> unused;
- unused->Close();
-
- base::AutoLock lock(handles_lock_);
- handles_.GetAndRemoveDispatcher(*message_pipe_handle0, &unused);
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
- uint32_t num_bytes,
- const MojoHandle* handles,
- uint32_t num_handles,
- MojoWriteMessageFlags flags) {
- if (num_bytes && !bytes)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- MojoMessageHandle message;
- MojoResult rv = AllocMessage(num_bytes, handles, num_handles,
- MOJO_ALLOC_MESSAGE_FLAG_NONE, &message);
- if (rv != MOJO_RESULT_OK)
- return rv;
-
- if (num_bytes) {
- void* buffer = nullptr;
- rv = GetMessageBuffer(message, &buffer);
- DCHECK_EQ(rv, MOJO_RESULT_OK);
- memcpy(buffer, bytes, num_bytes);
- }
-
- return WriteMessageNew(message_pipe_handle, message, flags);
-}
-
-MojoResult Core::WriteMessageNew(MojoHandle message_pipe_handle,
- MojoMessageHandle message,
- MojoWriteMessageFlags flags) {
- RequestContext request_context;
- std::unique_ptr<MessageForTransit> message_for_transit(
- reinterpret_cast<MessageForTransit*>(message));
- auto dispatcher = GetDispatcher(message_pipe_handle);
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->WriteMessage(std::move(message_for_transit), flags);
-}
-
-MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags) {
- CHECK((!num_handles || !*num_handles || handles) &&
- (!num_bytes || !*num_bytes || bytes));
- RequestContext request_context;
- auto dispatcher = GetDispatcher(message_pipe_handle);
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
- std::unique_ptr<MessageForTransit> message;
- MojoResult rv =
- dispatcher->ReadMessage(&message, num_bytes, handles, num_handles, flags,
- false /* ignore_num_bytes */);
- if (rv != MOJO_RESULT_OK)
- return rv;
-
- if (message && message->num_bytes())
- memcpy(bytes, message->bytes(), message->num_bytes());
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::ReadMessageNew(MojoHandle message_pipe_handle,
- MojoMessageHandle* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags) {
- CHECK(message);
- CHECK(!num_handles || !*num_handles || handles);
- RequestContext request_context;
- auto dispatcher = GetDispatcher(message_pipe_handle);
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
- std::unique_ptr<MessageForTransit> msg;
- MojoResult rv =
- dispatcher->ReadMessage(&msg, num_bytes, handles, num_handles, flags,
- true /* ignore_num_bytes */);
- if (rv != MOJO_RESULT_OK)
- return rv;
- *message = reinterpret_cast<MojoMessageHandle>(msg.release());
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::FuseMessagePipes(MojoHandle handle0, MojoHandle handle1) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher0;
- scoped_refptr<Dispatcher> dispatcher1;
-
- bool valid_handles = true;
- {
- base::AutoLock lock(handles_lock_);
- MojoResult result0 = handles_.GetAndRemoveDispatcher(handle0, &dispatcher0);
- MojoResult result1 = handles_.GetAndRemoveDispatcher(handle1, &dispatcher1);
- if (result0 != MOJO_RESULT_OK || result1 != MOJO_RESULT_OK ||
- dispatcher0->GetType() != Dispatcher::Type::MESSAGE_PIPE ||
- dispatcher1->GetType() != Dispatcher::Type::MESSAGE_PIPE)
- valid_handles = false;
- }
-
- if (!valid_handles) {
- if (dispatcher0)
- dispatcher0->Close();
- if (dispatcher1)
- dispatcher1->Close();
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- MessagePipeDispatcher* mpd0 =
- static_cast<MessagePipeDispatcher*>(dispatcher0.get());
- MessagePipeDispatcher* mpd1 =
- static_cast<MessagePipeDispatcher*>(dispatcher1.get());
-
- if (!mpd0->Fuse(mpd1))
- return MOJO_RESULT_FAILED_PRECONDITION;
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::NotifyBadMessage(MojoMessageHandle message,
- const char* error,
- size_t error_num_bytes) {
- if (!message)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- const PortsMessage& ports_message =
- reinterpret_cast<MessageForTransit*>(message)->ports_message();
- if (ports_message.source_node() == ports::kInvalidNodeName) {
- DVLOG(1) << "Received invalid message from unknown node.";
- if (!default_process_error_callback_.is_null())
- default_process_error_callback_.Run(std::string(error, error_num_bytes));
- return MOJO_RESULT_OK;
- }
-
- GetNodeController()->NotifyBadMessageFrom(
- ports_message.source_node(), std::string(error, error_num_bytes));
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::CreateDataPipe(
- const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle) {
- RequestContext request_context;
- if (options && options->struct_size != sizeof(MojoCreateDataPipeOptions))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- MojoCreateDataPipeOptions create_options;
- create_options.struct_size = sizeof(MojoCreateDataPipeOptions);
- create_options.flags = options ? options->flags : 0;
- create_options.element_num_bytes = options ? options->element_num_bytes : 1;
- // TODO(rockot): Use Configuration to get default data pipe capacity.
- create_options.capacity_num_bytes =
- options && options->capacity_num_bytes ? options->capacity_num_bytes
- : 64 * 1024;
-
- // TODO(rockot): Broker through the parent when necessary.
- scoped_refptr<PlatformSharedBuffer> ring_buffer =
- GetNodeController()->CreateSharedBuffer(
- create_options.capacity_num_bytes);
- if (!ring_buffer)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- ports::PortRef port0, port1;
- GetNodeController()->node()->CreatePortPair(&port0, &port1);
-
- CHECK(data_pipe_producer_handle);
- CHECK(data_pipe_consumer_handle);
-
- uint64_t pipe_id = base::RandUint64();
-
- scoped_refptr<Dispatcher> producer = new DataPipeProducerDispatcher(
- GetNodeController(), port0, ring_buffer, create_options,
- true /* initialized */, pipe_id);
- scoped_refptr<Dispatcher> consumer = new DataPipeConsumerDispatcher(
- GetNodeController(), port1, ring_buffer, create_options,
- true /* initialized */, pipe_id);
-
- *data_pipe_producer_handle = AddDispatcher(producer);
- *data_pipe_consumer_handle = AddDispatcher(consumer);
- if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID ||
- *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) {
- if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) {
- scoped_refptr<Dispatcher> unused;
- base::AutoLock lock(handles_lock_);
- handles_.GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused);
- }
- producer->Close();
- consumer->Close();
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_bytes,
- MojoWriteDataFlags flags) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(
- GetDispatcher(data_pipe_producer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->WriteData(elements, num_bytes, flags);
-}
-
-MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(
- GetDispatcher(data_pipe_producer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags);
-}
-
-MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle,
- uint32_t num_bytes_written) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(
- GetDispatcher(data_pipe_producer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->EndWriteData(num_bytes_written);
-}
-
-MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(
- GetDispatcher(data_pipe_consumer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->ReadData(elements, num_bytes, flags);
-}
-
-MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(
- GetDispatcher(data_pipe_consumer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags);
-}
-
-MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle,
- uint32_t num_bytes_read) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(
- GetDispatcher(data_pipe_consumer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- return dispatcher->EndReadData(num_bytes_read);
-}
-
-MojoResult Core::CreateSharedBuffer(
- const MojoCreateSharedBufferOptions* options,
- uint64_t num_bytes,
- MojoHandle* shared_buffer_handle) {
- RequestContext request_context;
- MojoCreateSharedBufferOptions validated_options = {};
- MojoResult result = SharedBufferDispatcher::ValidateCreateOptions(
- options, &validated_options);
- if (result != MOJO_RESULT_OK)
- return result;
-
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- result = SharedBufferDispatcher::Create(
- validated_options, GetNodeController(), num_bytes, &dispatcher);
- if (result != MOJO_RESULT_OK) {
- DCHECK(!dispatcher);
- return result;
- }
-
- *shared_buffer_handle = AddDispatcher(dispatcher);
- if (*shared_buffer_handle == MOJO_HANDLE_INVALID) {
- LOG(ERROR) << "Handle table full";
- dispatcher->Close();
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::DuplicateBufferHandle(
- MojoHandle buffer_handle,
- const MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- // Don't verify |options| here; that's the dispatcher's job.
- scoped_refptr<Dispatcher> new_dispatcher;
- MojoResult result =
- dispatcher->DuplicateBufferHandle(options, &new_dispatcher);
- if (result != MOJO_RESULT_OK)
- return result;
-
- *new_buffer_handle = AddDispatcher(new_dispatcher);
- if (*new_buffer_handle == MOJO_HANDLE_INVALID) {
- LOG(ERROR) << "Handle table full";
- dispatcher->Close();
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::MapBuffer(MojoHandle buffer_handle,
- uint64_t offset,
- uint64_t num_bytes,
- void** buffer,
- MojoMapBufferFlags flags) {
- RequestContext request_context;
- scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle));
- if (!dispatcher)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping;
- MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping);
- if (result != MOJO_RESULT_OK)
- return result;
-
- DCHECK(mapping);
- void* address = mapping->GetBase();
- {
- base::AutoLock locker(mapping_table_lock_);
- result = mapping_table_.AddMapping(std::move(mapping));
- }
- if (result != MOJO_RESULT_OK)
- return result;
-
- *buffer = address;
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::UnmapBuffer(void* buffer) {
- RequestContext request_context;
- base::AutoLock lock(mapping_table_lock_);
- return mapping_table_.RemoveMapping(buffer);
-}
-
-MojoResult Core::WrapPlatformHandle(const MojoPlatformHandle* platform_handle,
- MojoHandle* mojo_handle) {
- ScopedPlatformHandle handle;
- MojoResult result = MojoPlatformHandleToScopedPlatformHandle(platform_handle,
- &handle);
- if (result != MOJO_RESULT_OK)
- return result;
-
- return CreatePlatformHandleWrapper(std::move(handle), mojo_handle);
-}
-
-MojoResult Core::UnwrapPlatformHandle(MojoHandle mojo_handle,
- MojoPlatformHandle* platform_handle) {
- ScopedPlatformHandle handle;
- MojoResult result = PassWrappedPlatformHandle(mojo_handle, &handle);
- if (result != MOJO_RESULT_OK)
- return result;
-
- return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle),
- platform_handle);
-}
-
-MojoResult Core::WrapPlatformSharedBufferHandle(
- const MojoPlatformHandle* platform_handle,
- size_t size,
- MojoPlatformSharedBufferHandleFlags flags,
- MojoHandle* mojo_handle) {
- DCHECK(size);
- ScopedPlatformHandle handle;
- MojoResult result = MojoPlatformHandleToScopedPlatformHandle(platform_handle,
- &handle);
- if (result != MOJO_RESULT_OK)
- return result;
-
- bool read_only = flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_READ_ONLY;
- scoped_refptr<PlatformSharedBuffer> platform_buffer =
- PlatformSharedBuffer::CreateFromPlatformHandle(size, read_only,
- std::move(handle));
- if (!platform_buffer)
- return MOJO_RESULT_UNKNOWN;
-
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
- platform_buffer, &dispatcher);
- if (result != MOJO_RESULT_OK)
- return result;
-
- MojoHandle h = AddDispatcher(dispatcher);
- if (h == MOJO_HANDLE_INVALID) {
- dispatcher->Close();
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- *mojo_handle = h;
- return MOJO_RESULT_OK;
-}
-
-MojoResult Core::UnwrapPlatformSharedBufferHandle(
- MojoHandle mojo_handle,
- MojoPlatformHandle* platform_handle,
- size_t* size,
- MojoPlatformSharedBufferHandleFlags* flags) {
- scoped_refptr<Dispatcher> dispatcher;
- MojoResult result = MOJO_RESULT_OK;
- {
- base::AutoLock lock(handles_lock_);
- result = handles_.GetAndRemoveDispatcher(mojo_handle, &dispatcher);
- if (result != MOJO_RESULT_OK)
- return result;
- }
-
- if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) {
- dispatcher->Close();
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- SharedBufferDispatcher* shm_dispatcher =
- static_cast<SharedBufferDispatcher*>(dispatcher.get());
- scoped_refptr<PlatformSharedBuffer> platform_shared_buffer =
- shm_dispatcher->PassPlatformSharedBuffer();
- CHECK(platform_shared_buffer);
-
- CHECK(size);
- *size = platform_shared_buffer->GetNumBytes();
-
- CHECK(flags);
- *flags = MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
- if (platform_shared_buffer->IsReadOnly())
- *flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_READ_ONLY;
-
- ScopedPlatformHandle handle = platform_shared_buffer->PassPlatformHandle();
- return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle),
- platform_handle);
-}
-
-void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
- base::AutoLock lock(handles_lock_);
- handles_.GetActiveHandlesForTest(handles);
-}
-
-// static
-void Core::PassNodeControllerToIOThread(
- std::unique_ptr<NodeController> node_controller) {
- // It's OK to leak this reference. At this point we know the IO loop is still
- // running, and we know the NodeController will observe its eventual
- // destruction. This tells the NodeController to delete itself when that
- // happens.
- node_controller.release()->DestroyOnIOThreadShutdown();
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/core.h b/mojo/edk/system/core.h
deleted file mode 100644
index 1f6d865..0000000
--- a/mojo/edk/system/core.h
+++ /dev/null
@@ -1,297 +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_CORE_H_
-#define MOJO_EDK_SYSTEM_CORE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory_handle.h"
-#include "base/synchronization/lock.h"
-#include "base/task_runner.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/handle_table.h"
-#include "mojo/edk/system/mapping_table.h"
-#include "mojo/edk/system/node_controller.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/c/system/buffer.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/message_pipe.h"
-#include "mojo/public/c/system/platform_handle.h"
-#include "mojo/public/c/system/types.h"
-#include "mojo/public/c/system/watcher.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-
-namespace base {
-class PortProvider;
-}
-
-namespace mojo {
-namespace edk {
-
-// |Core| is an object that implements the Mojo system calls. All public methods
-// are thread-safe.
-class MOJO_SYSTEM_IMPL_EXPORT Core {
- public:
- Core();
- virtual ~Core();
-
- // Called exactly once, shortly after construction, and before any other
- // methods are called on this object.
- void SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner);
-
- // Retrieves the NodeController for the current process.
- NodeController* GetNodeController();
-
- scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle);
-
- void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback);
-
- // Called in the parent process any time a new child is launched.
- void AddChild(base::ProcessHandle process_handle,
- ConnectionParams connection_params,
- const std::string& child_token,
- const ProcessErrorCallback& process_error_callback);
-
- // Called in the parent process when a child process fails to launch.
- void ChildLaunchFailed(const std::string& child_token);
-
- // Called to connect to a peer process. This should be called only if there
- // is no common ancestor for the processes involved within this mojo system.
- // Both processes must call this function, each passing one end of a platform
- // channel. This returns one end of a message pipe to each process.
- ScopedMessagePipeHandle ConnectToPeerProcess(ScopedPlatformHandle pipe_handle,
- const std::string& peer_token);
- void ClosePeerConnection(const std::string& peer_token);
-
- // Called in a child process exactly once during early initialization.
- void InitChild(ConnectionParams connection_params);
-
- // Creates a message pipe endpoint associated with |token|, which a child
- // holding the token can later locate and connect to.
- ScopedMessagePipeHandle CreateParentMessagePipe(
- const std::string& token, const std::string& child_token);
-
- // Creates a message pipe endpoint and connects it to a pipe the parent has
- // associated with |token|.
- ScopedMessagePipeHandle CreateChildMessagePipe(const std::string& token);
-
- // Sets the mach port provider for this process.
- void SetMachPortProvider(base::PortProvider* port_provider);
-
- MojoHandle AddDispatcher(scoped_refptr<Dispatcher> dispatcher);
-
- // Adds new dispatchers for non-message-pipe handles received in a message.
- // |dispatchers| and |handles| should be the same size.
- bool AddDispatchersFromTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
- MojoHandle* handles);
-
- // See "mojo/edk/embedder/embedder.h" for more information on these functions.
- MojoResult CreatePlatformHandleWrapper(ScopedPlatformHandle platform_handle,
- MojoHandle* wrapper_handle);
-
- MojoResult PassWrappedPlatformHandle(MojoHandle wrapper_handle,
- ScopedPlatformHandle* platform_handle);
-
- MojoResult CreateSharedBufferWrapper(
- base::SharedMemoryHandle shared_memory_handle,
- size_t num_bytes,
- bool read_only,
- MojoHandle* mojo_wrapper_handle);
-
- MojoResult PassSharedMemoryHandle(
- MojoHandle mojo_handle,
- base::SharedMemoryHandle* shared_memory_handle,
- size_t* num_bytes,
- bool* read_only);
-
- // Requests that the EDK tear itself down. |callback| will be called once
- // the shutdown process is complete. Note that |callback| is always called
- // asynchronously on the calling thread if said thread is running a message
- // loop, and the calling thread must continue running a MessageLoop at least
- // until the callback is called. If there is no running loop, the |callback|
- // may be called from any thread. Beware!
- void RequestShutdown(const base::Closure& callback);
-
- MojoResult SetProperty(MojoPropertyType type, const void* value);
-
- // ---------------------------------------------------------------------------
-
- // The following methods are essentially implementations of the Mojo Core
- // functions of the Mojo API, with the C interface translated to C++ by
- // "mojo/edk/embedder/entrypoints.cc". The best way to understand the contract
- // of these methods is to look at the header files defining the corresponding
- // API functions, referenced below.
-
- // These methods correspond to the API functions defined in
- // "mojo/public/c/system/functions.h":
- MojoTimeTicks GetTimeTicksNow();
- MojoResult Close(MojoHandle handle);
- MojoResult QueryHandleSignalsState(MojoHandle handle,
- MojoHandleSignalsState* signals_state);
- MojoResult CreateWatcher(MojoWatcherCallback callback,
- MojoHandle* watcher_handle);
- MojoResult Watch(MojoHandle watcher_handle,
- MojoHandle handle,
- MojoHandleSignals signals,
- uintptr_t context);
- MojoResult CancelWatch(MojoHandle watcher_handle, uintptr_t context);
- MojoResult ArmWatcher(MojoHandle watcher_handle,
- uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states);
- MojoResult AllocMessage(uint32_t num_bytes,
- const MojoHandle* handles,
- uint32_t num_handles,
- MojoAllocMessageFlags flags,
- MojoMessageHandle* message);
- MojoResult FreeMessage(MojoMessageHandle message);
- MojoResult GetMessageBuffer(MojoMessageHandle message, void** buffer);
- MojoResult GetProperty(MojoPropertyType type, void* value);
-
- // These methods correspond to the API functions defined in
- // "mojo/public/c/system/message_pipe.h":
- MojoResult CreateMessagePipe(
- const MojoCreateMessagePipeOptions* options,
- MojoHandle* message_pipe_handle0,
- MojoHandle* message_pipe_handle1);
- MojoResult WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
- uint32_t num_bytes,
- const MojoHandle* handles,
- uint32_t num_handles,
- MojoWriteMessageFlags flags);
- MojoResult WriteMessageNew(MojoHandle message_pipe_handle,
- MojoMessageHandle message,
- MojoWriteMessageFlags flags);
- MojoResult ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags);
- MojoResult ReadMessageNew(MojoHandle message_pipe_handle,
- MojoMessageHandle* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags);
- MojoResult FuseMessagePipes(MojoHandle handle0, MojoHandle handle1);
- MojoResult NotifyBadMessage(MojoMessageHandle message,
- const char* error,
- size_t error_num_bytes);
-
- // These methods correspond to the API functions defined in
- // "mojo/public/c/system/data_pipe.h":
- MojoResult CreateDataPipe(
- const MojoCreateDataPipeOptions* options,
- MojoHandle* data_pipe_producer_handle,
- MojoHandle* data_pipe_consumer_handle);
- MojoResult WriteData(MojoHandle data_pipe_producer_handle,
- const void* elements,
- uint32_t* num_bytes,
- MojoWriteDataFlags flags);
- MojoResult BeginWriteData(MojoHandle data_pipe_producer_handle,
- void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags);
- MojoResult EndWriteData(MojoHandle data_pipe_producer_handle,
- uint32_t num_bytes_written);
- MojoResult ReadData(MojoHandle data_pipe_consumer_handle,
- void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags);
- MojoResult BeginReadData(MojoHandle data_pipe_consumer_handle,
- const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags);
- MojoResult EndReadData(MojoHandle data_pipe_consumer_handle,
- uint32_t num_bytes_read);
-
- // These methods correspond to the API functions defined in
- // "mojo/public/c/system/buffer.h":
- MojoResult CreateSharedBuffer(
- const MojoCreateSharedBufferOptions* options,
- uint64_t num_bytes,
- MojoHandle* shared_buffer_handle);
- MojoResult DuplicateBufferHandle(
- MojoHandle buffer_handle,
- const MojoDuplicateBufferHandleOptions* options,
- MojoHandle* new_buffer_handle);
- MojoResult MapBuffer(MojoHandle buffer_handle,
- uint64_t offset,
- uint64_t num_bytes,
- void** buffer,
- MojoMapBufferFlags flags);
- MojoResult UnmapBuffer(void* buffer);
-
- // These methods correspond to the API functions defined in
- // "mojo/public/c/system/platform_handle.h".
- MojoResult WrapPlatformHandle(const MojoPlatformHandle* platform_handle,
- MojoHandle* mojo_handle);
- MojoResult UnwrapPlatformHandle(MojoHandle mojo_handle,
- MojoPlatformHandle* platform_handle);
- MojoResult WrapPlatformSharedBufferHandle(
- const MojoPlatformHandle* platform_handle,
- size_t size,
- MojoPlatformSharedBufferHandleFlags flags,
- MojoHandle* mojo_handle);
- MojoResult UnwrapPlatformSharedBufferHandle(
- MojoHandle mojo_handle,
- MojoPlatformHandle* platform_handle,
- size_t* size,
- MojoPlatformSharedBufferHandleFlags* flags);
-
- void GetActiveHandlesForTest(std::vector<MojoHandle>* handles);
-
- private:
- // Used to pass ownership of our NodeController over to the IO thread in the
- // event that we're torn down before said thread.
- static void PassNodeControllerToIOThread(
- std::unique_ptr<NodeController> node_controller);
-
- // Guards node_controller_.
- //
- // TODO(rockot): Consider removing this. It's only needed because we
- // initialize node_controller_ lazily and that may happen on any thread.
- // Otherwise it's effectively const and shouldn't need to be guarded.
- //
- // We can get rid of lazy initialization if we defer Mojo initialization far
- // enough that zygotes don't do it. The zygote can't create a NodeController.
- base::Lock node_controller_lock_;
-
- // This is lazily initialized on first access. Always use GetNodeController()
- // to access it.
- std::unique_ptr<NodeController> node_controller_;
-
- // The default callback to invoke, if any, when a process error is reported
- // but cannot be associated with a specific process.
- ProcessErrorCallback default_process_error_callback_;
-
- base::Lock handles_lock_;
- HandleTable handles_;
-
- base::Lock mapping_table_lock_; // Protects |mapping_table_|.
- MappingTable mapping_table_;
-
- base::Lock property_lock_;
- // Properties that can be read using the MojoGetProperty() API.
- bool property_sync_call_allowed_ = true;
-
- DISALLOW_COPY_AND_ASSIGN(Core);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_CORE_H_
diff --git a/mojo/edk/system/core_test_base.cc b/mojo/edk/system/core_test_base.cc
deleted file mode 100644
index 7751612..0000000
--- a/mojo/edk/system/core_test_base.cc
+++ /dev/null
@@ -1,272 +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/core_test_base.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/configuration.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/message_for_transit.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-namespace {
-
-// MockDispatcher --------------------------------------------------------------
-
-class MockDispatcher : public Dispatcher {
- public:
- static scoped_refptr<MockDispatcher> Create(
- CoreTestBase::MockHandleInfo* info) {
- return make_scoped_refptr(new MockDispatcher(info));
- }
-
- // Dispatcher:
- Type GetType() const override { return Type::UNKNOWN; }
-
- MojoResult Close() override {
- info_->IncrementCloseCallCount();
- return MOJO_RESULT_OK;
- }
-
- MojoResult WriteMessage(
- std::unique_ptr<MessageForTransit> message,
- MojoWriteMessageFlags /*flags*/) override {
- info_->IncrementWriteMessageCallCount();
-
- if (message->num_bytes() > GetConfiguration().max_message_num_bytes)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- if (message->num_handles())
- return MOJO_RESULT_UNIMPLEMENTED;
-
- return MOJO_RESULT_OK;
- }
-
- MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message,
- uint32_t* num_bytes,
- MojoHandle* handle,
- uint32_t* num_handles,
- MojoReadMessageFlags /*flags*/,
- bool ignore_num_bytes) override {
- info_->IncrementReadMessageCallCount();
-
- if (num_handles)
- *num_handles = 1;
-
- return MOJO_RESULT_OK;
- }
-
- MojoResult WriteData(const void* elements,
- uint32_t* num_bytes,
- MojoWriteDataFlags flags) override {
- info_->IncrementWriteDataCallCount();
- return MOJO_RESULT_UNIMPLEMENTED;
- }
-
- MojoResult BeginWriteData(void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags) override {
- info_->IncrementBeginWriteDataCallCount();
- return MOJO_RESULT_UNIMPLEMENTED;
- }
-
- MojoResult EndWriteData(uint32_t num_bytes_written) override {
- info_->IncrementEndWriteDataCallCount();
- return MOJO_RESULT_UNIMPLEMENTED;
- }
-
- MojoResult ReadData(void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags) override {
- info_->IncrementReadDataCallCount();
- return MOJO_RESULT_UNIMPLEMENTED;
- }
-
- MojoResult BeginReadData(const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags) override {
- info_->IncrementBeginReadDataCallCount();
- return MOJO_RESULT_UNIMPLEMENTED;
- }
-
- MojoResult EndReadData(uint32_t num_bytes_read) override {
- info_->IncrementEndReadDataCallCount();
- return MOJO_RESULT_UNIMPLEMENTED;
- }
-
- private:
- explicit MockDispatcher(CoreTestBase::MockHandleInfo* info) : info_(info) {
- CHECK(info_);
- info_->IncrementCtorCallCount();
- }
-
- ~MockDispatcher() override { info_->IncrementDtorCallCount(); }
-
- CoreTestBase::MockHandleInfo* const info_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDispatcher);
-};
-
-} // namespace
-
-// CoreTestBase ----------------------------------------------------------------
-
-CoreTestBase::CoreTestBase() {
-}
-
-CoreTestBase::~CoreTestBase() {
-}
-
-MojoHandle CoreTestBase::CreateMockHandle(CoreTestBase::MockHandleInfo* info) {
- scoped_refptr<MockDispatcher> dispatcher = MockDispatcher::Create(info);
- return core()->AddDispatcher(dispatcher);
-}
-
-Core* CoreTestBase::core() {
- return mojo::edk::internal::g_core;
-}
-
-// CoreTestBase_MockHandleInfo -------------------------------------------------
-
-CoreTestBase_MockHandleInfo::CoreTestBase_MockHandleInfo()
- : ctor_call_count_(0),
- dtor_call_count_(0),
- close_call_count_(0),
- write_message_call_count_(0),
- read_message_call_count_(0),
- write_data_call_count_(0),
- begin_write_data_call_count_(0),
- end_write_data_call_count_(0),
- read_data_call_count_(0),
- begin_read_data_call_count_(0),
- end_read_data_call_count_(0) {}
-
-CoreTestBase_MockHandleInfo::~CoreTestBase_MockHandleInfo() {
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetCtorCallCount() const {
- base::AutoLock locker(lock_);
- return ctor_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetDtorCallCount() const {
- base::AutoLock locker(lock_);
- return dtor_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetCloseCallCount() const {
- base::AutoLock locker(lock_);
- return close_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetWriteMessageCallCount() const {
- base::AutoLock locker(lock_);
- return write_message_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetReadMessageCallCount() const {
- base::AutoLock locker(lock_);
- return read_message_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetWriteDataCallCount() const {
- base::AutoLock locker(lock_);
- return write_data_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetBeginWriteDataCallCount() const {
- base::AutoLock locker(lock_);
- return begin_write_data_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetEndWriteDataCallCount() const {
- base::AutoLock locker(lock_);
- return end_write_data_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetReadDataCallCount() const {
- base::AutoLock locker(lock_);
- return read_data_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetBeginReadDataCallCount() const {
- base::AutoLock locker(lock_);
- return begin_read_data_call_count_;
-}
-
-unsigned CoreTestBase_MockHandleInfo::GetEndReadDataCallCount() const {
- base::AutoLock locker(lock_);
- return end_read_data_call_count_;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementCtorCallCount() {
- base::AutoLock locker(lock_);
- ctor_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementDtorCallCount() {
- base::AutoLock locker(lock_);
- dtor_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementCloseCallCount() {
- base::AutoLock locker(lock_);
- close_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementWriteMessageCallCount() {
- base::AutoLock locker(lock_);
- write_message_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementReadMessageCallCount() {
- base::AutoLock locker(lock_);
- read_message_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementWriteDataCallCount() {
- base::AutoLock locker(lock_);
- write_data_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementBeginWriteDataCallCount() {
- base::AutoLock locker(lock_);
- begin_write_data_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementEndWriteDataCallCount() {
- base::AutoLock locker(lock_);
- end_write_data_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementReadDataCallCount() {
- base::AutoLock locker(lock_);
- read_data_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementBeginReadDataCallCount() {
- base::AutoLock locker(lock_);
- begin_read_data_call_count_++;
-}
-
-void CoreTestBase_MockHandleInfo::IncrementEndReadDataCallCount() {
- base::AutoLock locker(lock_);
- end_read_data_call_count_++;
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/core_test_base.h b/mojo/edk/system/core_test_base.h
deleted file mode 100644
index 3d156e3..0000000
--- a/mojo/edk/system/core_test_base.h
+++ /dev/null
@@ -1,94 +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_CORE_TEST_BASE_H_
-#define MOJO_EDK_SYSTEM_CORE_TEST_BASE_H_
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/public/c/system/types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-
-class Core;
-
-namespace test {
-
-class CoreTestBase_MockHandleInfo;
-
-class CoreTestBase : public testing::Test {
- public:
- using MockHandleInfo = CoreTestBase_MockHandleInfo;
-
- CoreTestBase();
- ~CoreTestBase() override;
-
- protected:
- // |info| must remain alive until the returned handle is closed.
- MojoHandle CreateMockHandle(MockHandleInfo* info);
-
- Core* core();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CoreTestBase);
-};
-
-class CoreTestBase_MockHandleInfo {
- public:
- CoreTestBase_MockHandleInfo();
- ~CoreTestBase_MockHandleInfo();
-
- unsigned GetCtorCallCount() const;
- unsigned GetDtorCallCount() const;
- unsigned GetCloseCallCount() const;
- unsigned GetWriteMessageCallCount() const;
- unsigned GetReadMessageCallCount() const;
- unsigned GetWriteDataCallCount() const;
- unsigned GetBeginWriteDataCallCount() const;
- unsigned GetEndWriteDataCallCount() const;
- unsigned GetReadDataCallCount() const;
- unsigned GetBeginReadDataCallCount() const;
- unsigned GetEndReadDataCallCount() const;
-
- // For use by |MockDispatcher|:
- void IncrementCtorCallCount();
- void IncrementDtorCallCount();
- void IncrementCloseCallCount();
- void IncrementWriteMessageCallCount();
- void IncrementReadMessageCallCount();
- void IncrementWriteDataCallCount();
- void IncrementBeginWriteDataCallCount();
- void IncrementEndWriteDataCallCount();
- void IncrementReadDataCallCount();
- void IncrementBeginReadDataCallCount();
- void IncrementEndReadDataCallCount();
-
- private:
- mutable base::Lock lock_; // Protects the following members.
- unsigned ctor_call_count_;
- unsigned dtor_call_count_;
- unsigned close_call_count_;
- unsigned write_message_call_count_;
- unsigned read_message_call_count_;
- unsigned write_data_call_count_;
- unsigned begin_write_data_call_count_;
- unsigned end_write_data_call_count_;
- unsigned read_data_call_count_;
- unsigned begin_read_data_call_count_;
- unsigned end_read_data_call_count_;
-
- DISALLOW_COPY_AND_ASSIGN(CoreTestBase_MockHandleInfo);
-};
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_CORE_TEST_BASE_H_
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc
deleted file mode 100644
index 0d60b48..0000000
--- a/mojo/edk/system/core_unittest.cc
+++ /dev/null
@@ -1,971 +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/core.h"
-
-#include <stdint.h>
-
-#include <limits>
-
-#include "base/bind.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/core_test_base.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/public/cpp/system/wait.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-namespace mojo {
-namespace edk {
-namespace {
-
-const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u};
-const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u};
-const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED;
-
-using CoreTest = test::CoreTestBase;
-
-TEST_F(CoreTest, GetTimeTicksNow) {
- const MojoTimeTicks start = core()->GetTimeTicksNow();
- ASSERT_NE(static_cast<MojoTimeTicks>(0), start)
- << "GetTimeTicksNow should return nonzero value";
- test::Sleep(test::DeadlineFromMilliseconds(15));
- const MojoTimeTicks finish = core()->GetTimeTicksNow();
- // Allow for some fuzz in sleep.
- ASSERT_GE((finish - start), static_cast<MojoTimeTicks>(8000))
- << "Sleeping should result in increasing time ticks";
-}
-
-TEST_F(CoreTest, Basic) {
- MockHandleInfo info;
-
- ASSERT_EQ(0u, info.GetCtorCallCount());
- MojoHandle h = CreateMockHandle(&info);
- ASSERT_EQ(1u, info.GetCtorCallCount());
- ASSERT_NE(h, MOJO_HANDLE_INVALID);
-
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h, nullptr, 0, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, info.GetWriteMessageCallCount());
-
- ASSERT_EQ(0u, info.GetReadMessageCallCount());
- uint32_t num_bytes = 0;
- ASSERT_EQ(
- MOJO_RESULT_OK,
- core()->ReadMessage(h, nullptr, &num_bytes, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, info.GetReadMessageCallCount());
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(h, nullptr, nullptr, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(2u, info.GetReadMessageCallCount());
-
- ASSERT_EQ(0u, info.GetWriteDataCallCount());
- ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->WriteData(h, nullptr, nullptr, MOJO_WRITE_DATA_FLAG_NONE));
- ASSERT_EQ(1u, info.GetWriteDataCallCount());
-
- ASSERT_EQ(0u, info.GetBeginWriteDataCallCount());
- ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->BeginWriteData(h, nullptr, nullptr,
- MOJO_WRITE_DATA_FLAG_NONE));
- ASSERT_EQ(1u, info.GetBeginWriteDataCallCount());
-
- ASSERT_EQ(0u, info.GetEndWriteDataCallCount());
- ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndWriteData(h, 0));
- ASSERT_EQ(1u, info.GetEndWriteDataCallCount());
-
- ASSERT_EQ(0u, info.GetReadDataCallCount());
- ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->ReadData(h, nullptr, nullptr, MOJO_READ_DATA_FLAG_NONE));
- ASSERT_EQ(1u, info.GetReadDataCallCount());
-
- ASSERT_EQ(0u, info.GetBeginReadDataCallCount());
- ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- core()->BeginReadData(h, nullptr, nullptr,
- MOJO_READ_DATA_FLAG_NONE));
- ASSERT_EQ(1u, info.GetBeginReadDataCallCount());
-
- ASSERT_EQ(0u, info.GetEndReadDataCallCount());
- ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndReadData(h, 0));
- ASSERT_EQ(1u, info.GetEndReadDataCallCount());
-
- ASSERT_EQ(0u, info.GetDtorCallCount());
- ASSERT_EQ(0u, info.GetCloseCallCount());
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
- ASSERT_EQ(1u, info.GetCloseCallCount());
- ASSERT_EQ(1u, info.GetDtorCallCount());
-}
-
-TEST_F(CoreTest, InvalidArguments) {
- // |Close()|:
- {
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(MOJO_HANDLE_INVALID));
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(10));
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(1000000000));
-
- // Test a double-close.
- MockHandleInfo info;
- MojoHandle h = CreateMockHandle(&info);
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
- ASSERT_EQ(1u, info.GetCloseCallCount());
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h));
- ASSERT_EQ(1u, info.GetCloseCallCount());
- }
-
- // |CreateMessagePipe()|: Nothing to check (apart from things that cause
- // death).
-
- // |WriteMessage()|:
- // Only check arguments checked by |Core|, namely |handle|, |handles|, and
- // |num_handles|.
- {
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(MOJO_HANDLE_INVALID, nullptr, 0,
- nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- MockHandleInfo info;
- MojoHandle h = CreateMockHandle(&info);
- MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
-
- // Huge handle count (implausibly big on some systems -- more than can be
- // stored in a 32-bit address space).
- // Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or
- // |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or
- // not.
- ASSERT_NE(
- MOJO_RESULT_OK,
- core()->WriteMessage(h, nullptr, 0, handles,
- std::numeric_limits<uint32_t>::max(),
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- // Null |bytes| with non-zero message size.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 1, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- // Null |handles| with non-zero handle count.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 0, nullptr, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- // Huge handle count (plausibly big).
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->WriteMessage(
- h, nullptr, 0, handles,
- std::numeric_limits<uint32_t>::max() / sizeof(handles[0]),
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- // Invalid handle in |handles|.
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 0, handles, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- // Two invalid handles in |handles|.
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 0, handles, 2,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- // Can't send a handle over itself. Note that this will also cause |h| to be
- // closed.
- handles[0] = h;
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 0, handles, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(0u, info.GetWriteMessageCallCount());
-
- h = CreateMockHandle(&info);
-
- MockHandleInfo info2;
-
- // This is "okay", but |MockDispatcher| doesn't implement it.
- handles[0] = CreateMockHandle(&info2);
- ASSERT_EQ(
- MOJO_RESULT_UNIMPLEMENTED,
- core()->WriteMessage(h, nullptr, 0, handles, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, info.GetWriteMessageCallCount());
-
- // One of the |handles| is still invalid.
- handles[0] = CreateMockHandle(&info2);
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 0, handles, 2,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, info.GetWriteMessageCallCount());
-
- // One of the |handles| is the same as |h|. Both handles are closed.
- handles[0] = CreateMockHandle(&info2);
- handles[1] = h;
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h, nullptr, 0, handles, 2,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, info.GetWriteMessageCallCount());
-
- h = CreateMockHandle(&info);
-
- // Can't send a handle twice in the same message.
- handles[0] = CreateMockHandle(&info2);
- handles[1] = handles[0];
- ASSERT_EQ(
- MOJO_RESULT_BUSY,
- core()->WriteMessage(h, nullptr, 0, handles, 2,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, info.GetWriteMessageCallCount());
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
- }
-
- // |ReadMessage()|:
- // Only check arguments checked by |Core|, namely |handle|, |handles|, and
- // |num_handles|.
- {
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadMessage(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr,
- nullptr, MOJO_READ_MESSAGE_FLAG_NONE));
-
- MockHandleInfo info;
- MojoHandle h = CreateMockHandle(&info);
-
- // Okay.
- uint32_t handle_count = 0;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h, nullptr, nullptr, nullptr, &handle_count,
- MOJO_READ_MESSAGE_FLAG_NONE));
- // Checked by |Core|, shouldn't go through to the dispatcher.
- ASSERT_EQ(1u, info.GetReadMessageCallCount());
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
- }
-}
-
-// These test invalid arguments that should cause death if we're being paranoid
-// about checking arguments (which we would want to do if, e.g., we were in a
-// true "kernel" situation, but we might not want to do otherwise for
-// performance reasons). Probably blatant errors like passing in null pointers
-// (for required pointer arguments) will still cause death, but perhaps not
-// predictably.
-TEST_F(CoreTest, InvalidArgumentsDeath) {
-#if defined(OFFICIAL_BUILD)
- const char kMemoryCheckFailedRegex[] = "";
-#else
- const char kMemoryCheckFailedRegex[] = "Check failed";
-#endif
-
- // |CreateMessagePipe()|:
- {
- MojoHandle h;
- ASSERT_DEATH_IF_SUPPORTED(
- core()->CreateMessagePipe(nullptr, nullptr, nullptr),
- kMemoryCheckFailedRegex);
- ASSERT_DEATH_IF_SUPPORTED(
- core()->CreateMessagePipe(nullptr, &h, nullptr),
- kMemoryCheckFailedRegex);
- ASSERT_DEATH_IF_SUPPORTED(
- core()->CreateMessagePipe(nullptr, nullptr, &h),
- kMemoryCheckFailedRegex);
- }
-
- // |ReadMessage()|:
- // Only check arguments checked by |Core|, namely |handle|, |handles|, and
- // |num_handles|.
- {
- MockHandleInfo info;
- MojoHandle h = CreateMockHandle(&info);
-
- uint32_t handle_count = 1;
- ASSERT_DEATH_IF_SUPPORTED(
- core()->ReadMessage(h, nullptr, nullptr, nullptr, &handle_count,
- MOJO_READ_MESSAGE_FLAG_NONE),
- kMemoryCheckFailedRegex);
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h));
- }
-}
-
-TEST_F(CoreTest, MessagePipe) {
- MojoHandle h[2];
- MojoHandleSignalsState hss[2];
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessagePipe(nullptr, &h[0], &h[1]));
- // Should get two distinct, valid handles.
- ASSERT_NE(h[0], MOJO_HANDLE_INVALID);
- ASSERT_NE(h[1], MOJO_HANDLE_INVALID);
- ASSERT_NE(h[0], h[1]);
-
- // Neither should be readable.
- hss[0] = kEmptyMojoHandleSignalsState;
- hss[1] = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[0], &hss[0]));
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[1], &hss[1]));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
- ASSERT_EQ(kAllSignals, hss[0].satisfiable_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals);
- ASSERT_EQ(kAllSignals, hss[1].satisfiable_signals);
-
- // Try to read anyway.
- char buffer[1] = {'a'};
- uint32_t buffer_size = 1;
- ASSERT_EQ(
- MOJO_RESULT_SHOULD_WAIT,
- core()->ReadMessage(h[0], buffer, &buffer_size, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE));
- // Check that it left its inputs alone.
- ASSERT_EQ('a', buffer[0]);
- ASSERT_EQ(1u, buffer_size);
-
- // Write to |h[1]|.
- buffer[0] = 'b';
- ASSERT_EQ(
- MOJO_RESULT_OK,
- core()->WriteMessage(h[1], buffer, 1, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for |h[0]| to become readable.
- EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h[0]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss[0]));
-
- // Read from |h[0]|.
- // First, get only the size.
- buffer_size = 0;
- ASSERT_EQ(
- MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->ReadMessage(h[0], nullptr, &buffer_size, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, buffer_size);
- // Then actually read it.
- buffer[0] = 'c';
- buffer_size = 1;
- ASSERT_EQ(
- MOJO_RESULT_OK,
- core()->ReadMessage(h[0], buffer, &buffer_size, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ('b', buffer[0]);
- ASSERT_EQ(1u, buffer_size);
-
- // |h[0]| should no longer be readable.
- hss[0] = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[0], &hss[0]));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
- ASSERT_EQ(kAllSignals, hss[0].satisfiable_signals);
-
- // Write to |h[0]|.
- buffer[0] = 'd';
- ASSERT_EQ(
- MOJO_RESULT_OK,
- core()->WriteMessage(h[0], buffer, 1, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Close |h[0]|.
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h[0]));
-
- // Wait for |h[1]| to learn about the other end's closure.
- EXPECT_EQ(
- MOJO_RESULT_OK,
- mojo::Wait(mojo::Handle(h[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss[1]));
-
- // Check that |h[1]| is no longer writable (and will never be).
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss[1].satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss[1].satisfiable_signals);
-
- // Check that |h[1]| is still readable (for the moment).
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss[1].satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss[1].satisfiable_signals);
-
- // Discard a message from |h[1]|.
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- core()->ReadMessage(h[1], nullptr, nullptr, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_MAY_DISCARD));
-
- // |h[1]| is no longer readable (and will never be).
- hss[1] = kFullMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(h[1], &hss[1]));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[1].satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[1].satisfiable_signals);
-
- // Try writing to |h[1]|.
- buffer[0] = 'e';
- ASSERT_EQ(
- MOJO_RESULT_FAILED_PRECONDITION,
- core()->WriteMessage(h[1], buffer, 1, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h[1]));
-}
-
-// Tests passing a message pipe handle.
-TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
- const char kHello[] = "hello";
- const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
- const char kWorld[] = "world!!!";
- const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
- char buffer[100];
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
- uint32_t num_bytes;
- MojoHandle handles[10];
- uint32_t num_handles;
- MojoHandleSignalsState hss;
- MojoHandle h_received;
-
- MojoHandle h_passing[2];
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(nullptr, &h_passing[0], &h_passing[1]));
-
- // Make sure that |h_passing[]| work properly.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passing[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kHelloSize, num_bytes);
- ASSERT_STREQ(kHello, buffer);
- ASSERT_EQ(0u, num_handles);
-
- // Make sure that you can't pass either of the message pipe's handles over
- // itself.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize,
- &h_passing[0], 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(nullptr, &h_passing[0], &h_passing[1]));
-
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize,
- &h_passing[1], 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(nullptr, &h_passing[0], &h_passing[1]));
-
- MojoHandle h_passed[2];
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(nullptr, &h_passed[0], &h_passed[1]));
-
- // Make sure that |h_passed[]| work properly.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passed[0], kHello, kHelloSize, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- hss = kEmptyMojoHandleSignalsState;
- ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passed[1]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passed[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kHelloSize, num_bytes);
- ASSERT_STREQ(kHello, buffer);
- ASSERT_EQ(0u, num_handles);
-
- // Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0], kWorld, kWorldSize,
- &h_passed[1], 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- hss = kEmptyMojoHandleSignalsState;
- ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passing[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kWorldSize, num_bytes);
- ASSERT_STREQ(kWorld, buffer);
- ASSERT_EQ(1u, num_handles);
- h_received = handles[0];
- ASSERT_NE(h_received, MOJO_HANDLE_INVALID);
- ASSERT_NE(h_received, h_passing[0]);
- ASSERT_NE(h_received, h_passing[1]);
- ASSERT_NE(h_received, h_passed[0]);
-
- // Note: We rely on the Mojo system not re-using handle values very often.
- ASSERT_NE(h_received, h_passed[1]);
-
- // |h_passed[1]| should no longer be valid; check that trying to close it
- // fails. See above note.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h_passed[1]));
-
- // Write to |h_passed[0]|. Should receive on |h_received|.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passed[0], kHello, kHelloSize, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- hss = kEmptyMojoHandleSignalsState;
- ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_received),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_received, buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kHelloSize, num_bytes);
- ASSERT_STREQ(kHello, buffer);
- ASSERT_EQ(0u, num_handles);
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passed[0]));
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_received));
-}
-
-TEST_F(CoreTest, DataPipe) {
- MojoHandle ph, ch; // p is for producer and c is for consumer.
- MojoHandleSignalsState hss;
-
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateDataPipe(nullptr, &ph, &ch));
- // Should get two distinct, valid handles.
- ASSERT_NE(ph, MOJO_HANDLE_INVALID);
- ASSERT_NE(ch, MOJO_HANDLE_INVALID);
- ASSERT_NE(ph, ch);
-
- // Producer should be never-readable, but already writable.
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ph, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // Consumer should be never-writable, and not yet readable.
- hss = kFullMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
- EXPECT_EQ(0u, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Write.
- signed char elements[2] = {'A', 'B'};
- uint32_t num_bytes = 2u;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph, elements, &num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE));
- ASSERT_EQ(2u, num_bytes);
-
- // Wait for the data to arrive to the consumer.
- EXPECT_EQ(MOJO_RESULT_OK,
- mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
-
- // Consumer should now be readable.
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Peek one character.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = 1u;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadData(
- ch, elements, &num_bytes,
- MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_PEEK));
- ASSERT_EQ('A', elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Read one character.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = 1u;
- ASSERT_EQ(MOJO_RESULT_OK, core()->ReadData(ch, elements, &num_bytes,
- MOJO_READ_DATA_FLAG_NONE));
- ASSERT_EQ('A', elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Two-phase write.
- void* write_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginWriteData(ph, &write_ptr, &num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE));
- // We count on the default options providing a decent buffer size.
- ASSERT_GE(num_bytes, 3u);
-
- // Trying to do a normal write during a two-phase write should fail.
- elements[0] = 'X';
- num_bytes = 1u;
- ASSERT_EQ(MOJO_RESULT_BUSY,
- core()->WriteData(ph, elements, &num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE));
-
- // Actually write the data, and complete it now.
- static_cast<char*>(write_ptr)[0] = 'C';
- static_cast<char*>(write_ptr)[1] = 'D';
- static_cast<char*>(write_ptr)[2] = 'E';
- ASSERT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u));
-
- // Wait for the data to arrive to the consumer.
- ASSERT_EQ(MOJO_RESULT_OK,
- mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
-
- // Query how much data we have.
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_QUERY));
- ASSERT_GE(num_bytes, 1u);
-
- // Try to query with peek. Should fail.
- num_bytes = 0;
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadData(ch, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_QUERY | MOJO_READ_DATA_FLAG_PEEK));
- ASSERT_EQ(0u, num_bytes);
-
- // Try to discard ten characters, in all-or-none mode. Should fail.
- num_bytes = 10;
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- core()->ReadData(
- ch, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE));
-
- // Try to discard two characters, in peek mode. Should fail.
- num_bytes = 2;
- ASSERT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- core()->ReadData(ch, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_PEEK));
-
- // Discard a character.
- num_bytes = 1;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadData(
- ch, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE));
-
- // Ensure the 3 bytes were read.
- ASSERT_EQ(MOJO_RESULT_OK,
- mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
-
- // Try a two-phase read of the remaining three bytes with peek. Should fail.
- const void* read_ptr = nullptr;
- num_bytes = 3;
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
- MOJO_READ_DATA_FLAG_PEEK));
-
- // Read the remaining two characters, in two-phase mode (all-or-none).
- num_bytes = 3;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE));
- // Note: Count on still being able to do the contiguous read here.
- ASSERT_EQ(3u, num_bytes);
-
- // Discarding right now should fail.
- num_bytes = 1;
- ASSERT_EQ(MOJO_RESULT_BUSY,
- core()->ReadData(ch, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_DISCARD));
-
- // Actually check our data and end the two-phase read.
- ASSERT_EQ('C', static_cast<const char*>(read_ptr)[0]);
- ASSERT_EQ('D', static_cast<const char*>(read_ptr)[1]);
- ASSERT_EQ('E', static_cast<const char*>(read_ptr)[2]);
- ASSERT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 3u));
-
- // Consumer should now be no longer readable.
- hss = kFullMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
- EXPECT_EQ(0u, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // TODO(vtl): More.
-
- // Close the producer.
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(ph));
-
- // Wait for this to get to the consumer.
- EXPECT_EQ(MOJO_RESULT_OK,
- mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
-
- // The consumer should now be never-readable.
- hss = kFullMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, core()->QueryHandleSignalsState(ch, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(ch));
-}
-
-// Tests passing data pipe producer and consumer handles.
-TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
- const char kHello[] = "hello";
- const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
- const char kWorld[] = "world!!!";
- const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
- char buffer[100];
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
- uint32_t num_bytes;
- MojoHandle handles[10];
- uint32_t num_handles;
- MojoHandleSignalsState hss;
-
- MojoHandle h_passing[2];
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateMessagePipe(nullptr, &h_passing[0], &h_passing[1]));
-
- MojoHandle ph, ch;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->CreateDataPipe(nullptr, &ph, &ch));
-
- // Send |ch| from |h_passing[0]| to |h_passing[1]|.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize, &ch, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- hss = kEmptyMojoHandleSignalsState;
- ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passing[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kHelloSize, num_bytes);
- ASSERT_STREQ(kHello, buffer);
- ASSERT_EQ(1u, num_handles);
- MojoHandle ch_received = handles[0];
- ASSERT_NE(ch_received, MOJO_HANDLE_INVALID);
- ASSERT_NE(ch_received, h_passing[0]);
- ASSERT_NE(ch_received, h_passing[1]);
- ASSERT_NE(ch_received, ph);
-
- // Note: We rely on the Mojo system not re-using handle values very often.
- ASSERT_NE(ch_received, ch);
-
- // |ch| should no longer be valid; check that trying to close it fails. See
- // above note.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ch));
-
- // Write to |ph|. Should receive on |ch_received|.
- num_bytes = kWorldSize;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph, kWorld, &num_bytes,
- MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(ch_received),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
- num_bytes = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch_received, buffer, &num_bytes,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kWorldSize, num_bytes);
- ASSERT_STREQ(kWorld, buffer);
-
- // Now pass |ph| in the same direction.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0], kWorld, kWorldSize, &ph, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- hss = kEmptyMojoHandleSignalsState;
- ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passing[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kWorldSize, num_bytes);
- ASSERT_STREQ(kWorld, buffer);
- ASSERT_EQ(1u, num_handles);
- MojoHandle ph_received = handles[0];
- ASSERT_NE(ph_received, MOJO_HANDLE_INVALID);
- ASSERT_NE(ph_received, h_passing[0]);
- ASSERT_NE(ph_received, h_passing[1]);
- ASSERT_NE(ph_received, ch_received);
-
- // Again, rely on the Mojo system not re-using handle values very often.
- ASSERT_NE(ph_received, ph);
-
- // |ph| should no longer be valid; check that trying to close it fails. See
- // above note.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ph));
-
- // Write to |ph_received|. Should receive on |ch_received|.
- num_bytes = kHelloSize;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteData(ph_received, kHello, &num_bytes,
- MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(ch_received),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
- num_bytes = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadData(ch_received, buffer, &num_bytes,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kHelloSize, num_bytes);
- ASSERT_STREQ(kHello, buffer);
-
- ph = ph_received;
- ph_received = MOJO_HANDLE_INVALID;
- ch = ch_received;
- ch_received = MOJO_HANDLE_INVALID;
-
- // Make sure that |ph| can't be sent if it's in a two-phase write.
- void* write_ptr = nullptr;
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginWriteData(ph, &write_ptr, &num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE));
- ASSERT_GE(num_bytes, 1u);
- ASSERT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize, &ph, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // But |ch| can, even if |ph| is in a two-phase write.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize, &ch, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ch = MOJO_HANDLE_INVALID;
- EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
- MOJO_HANDLE_SIGNAL_READABLE));
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passing[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kHelloSize, num_bytes);
- ASSERT_STREQ(kHello, buffer);
- ASSERT_EQ(1u, num_handles);
- ch = handles[0];
- ASSERT_NE(ch, MOJO_HANDLE_INVALID);
-
- // Complete the two-phase write.
- static_cast<char*>(write_ptr)[0] = 'x';
- ASSERT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 1));
-
- // Wait for |ch| to be readable.
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK,
- mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Make sure that |ch| can't be sent if it's in a two-phase read.
- const void* read_ptr = nullptr;
- num_bytes = 1;
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->BeginReadData(ch, &read_ptr, &num_bytes,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE));
- ASSERT_EQ(MOJO_RESULT_BUSY,
- core()->WriteMessage(h_passing[0], kHello, kHelloSize, &ch, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // But |ph| can, even if |ch| is in a two-phase read.
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->WriteMessage(h_passing[0], kWorld, kWorldSize, &ph, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ph = MOJO_HANDLE_INVALID;
- hss = kEmptyMojoHandleSignalsState;
- EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]),
- MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- num_bytes = kBufferSize;
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- core()->ReadMessage(
- h_passing[1], buffer, &num_bytes, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(kWorldSize, num_bytes);
- ASSERT_STREQ(kWorld, buffer);
- ASSERT_EQ(1u, num_handles);
- ph = handles[0];
- ASSERT_NE(ph, MOJO_HANDLE_INVALID);
-
- // Complete the two-phase read.
- ASSERT_EQ('x', static_cast<const char*>(read_ptr)[0]);
- ASSERT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 1));
-
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(ph));
- ASSERT_EQ(MOJO_RESULT_OK, core()->Close(ch));
-}
-
-struct TestAsyncWaiter {
- TestAsyncWaiter() : result(MOJO_RESULT_UNKNOWN) {}
-
- void Awake(MojoResult r) { result = r; }
-
- MojoResult result;
-};
-
-// TODO(vtl): Test |DuplicateBufferHandle()| and |MapBuffer()|.
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/mojo/edk/system/data_pipe_consumer_dispatcher.cc
deleted file mode 100644
index f338732..0000000
--- a/mojo/edk/system/data_pipe_consumer_dispatcher.cc
+++ /dev/null
@@ -1,562 +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/data_pipe_consumer_dispatcher.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <limits>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/data_pipe_control_message.h"
-#include "mojo/edk/system/node_controller.h"
-#include "mojo/edk/system/ports_message.h"
-#include "mojo/edk/system/request_context.h"
-#include "mojo/public/c/system/data_pipe.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-const uint8_t kFlagPeerClosed = 0x01;
-
-#pragma pack(push, 1)
-
-struct SerializedState {
- MojoCreateDataPipeOptions options;
- uint64_t pipe_id;
- uint32_t read_offset;
- uint32_t bytes_available;
- uint8_t flags;
- char padding[7];
-};
-
-static_assert(sizeof(SerializedState) % 8 == 0,
- "Invalid SerializedState size.");
-
-#pragma pack(pop)
-
-} // namespace
-
-// A PortObserver which forwards to a DataPipeConsumerDispatcher. This owns a
-// reference to the dispatcher to ensure it lives as long as the observed port.
-class DataPipeConsumerDispatcher::PortObserverThunk
- : public NodeController::PortObserver {
- public:
- explicit PortObserverThunk(
- scoped_refptr<DataPipeConsumerDispatcher> dispatcher)
- : dispatcher_(dispatcher) {}
-
- private:
- ~PortObserverThunk() override {}
-
- // NodeController::PortObserver:
- void OnPortStatusChanged() override { dispatcher_->OnPortStatusChanged(); }
-
- scoped_refptr<DataPipeConsumerDispatcher> dispatcher_;
-
- DISALLOW_COPY_AND_ASSIGN(PortObserverThunk);
-};
-
-DataPipeConsumerDispatcher::DataPipeConsumerDispatcher(
- NodeController* node_controller,
- const ports::PortRef& control_port,
- scoped_refptr<PlatformSharedBuffer> shared_ring_buffer,
- const MojoCreateDataPipeOptions& options,
- bool initialized,
- uint64_t pipe_id)
- : options_(options),
- node_controller_(node_controller),
- control_port_(control_port),
- pipe_id_(pipe_id),
- watchers_(this),
- shared_ring_buffer_(shared_ring_buffer) {
- if (initialized) {
- base::AutoLock lock(lock_);
- InitializeNoLock();
- }
-}
-
-Dispatcher::Type DataPipeConsumerDispatcher::GetType() const {
- return Type::DATA_PIPE_CONSUMER;
-}
-
-MojoResult DataPipeConsumerDispatcher::Close() {
- base::AutoLock lock(lock_);
- DVLOG(1) << "Closing data pipe consumer " << pipe_id_;
- return CloseNoLock();
-}
-
-MojoResult DataPipeConsumerDispatcher::ReadData(void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags) {
- base::AutoLock lock(lock_);
-
- if (!shared_ring_buffer_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (in_two_phase_read_)
- return MOJO_RESULT_BUSY;
-
- const bool had_new_data = new_data_available_;
- new_data_available_ = false;
-
- if ((flags & MOJO_READ_DATA_FLAG_QUERY)) {
- if ((flags & MOJO_READ_DATA_FLAG_PEEK) ||
- (flags & MOJO_READ_DATA_FLAG_DISCARD))
- return MOJO_RESULT_INVALID_ARGUMENT;
- DCHECK(!(flags & MOJO_READ_DATA_FLAG_DISCARD)); // Handled above.
- DVLOG_IF(2, elements)
- << "Query mode: ignoring non-null |elements|";
- *num_bytes = static_cast<uint32_t>(bytes_available_);
-
- if (had_new_data)
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- return MOJO_RESULT_OK;
- }
-
- bool discard = false;
- if ((flags & MOJO_READ_DATA_FLAG_DISCARD)) {
- // These flags are mutally exclusive.
- if (flags & MOJO_READ_DATA_FLAG_PEEK)
- return MOJO_RESULT_INVALID_ARGUMENT;
- DVLOG_IF(2, elements)
- << "Discard mode: ignoring non-null |elements|";
- discard = true;
- }
-
- uint32_t max_num_bytes_to_read = *num_bytes;
- if (max_num_bytes_to_read % options_.element_num_bytes != 0)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- bool all_or_none = flags & MOJO_READ_DATA_FLAG_ALL_OR_NONE;
- uint32_t min_num_bytes_to_read =
- all_or_none ? max_num_bytes_to_read : 0;
-
- if (min_num_bytes_to_read > bytes_available_) {
- if (had_new_data)
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION
- : MOJO_RESULT_OUT_OF_RANGE;
- }
-
- uint32_t bytes_to_read = std::min(max_num_bytes_to_read, bytes_available_);
- if (bytes_to_read == 0) {
- if (had_new_data)
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION
- : MOJO_RESULT_SHOULD_WAIT;
- }
-
- if (!discard) {
- uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase());
- CHECK(data);
-
- uint8_t* destination = static_cast<uint8_t*>(elements);
- CHECK(destination);
-
- DCHECK_LE(read_offset_, options_.capacity_num_bytes);
- uint32_t tail_bytes_to_copy =
- std::min(options_.capacity_num_bytes - read_offset_, bytes_to_read);
- uint32_t head_bytes_to_copy = bytes_to_read - tail_bytes_to_copy;
- if (tail_bytes_to_copy > 0)
- memcpy(destination, data + read_offset_, tail_bytes_to_copy);
- if (head_bytes_to_copy > 0)
- memcpy(destination + tail_bytes_to_copy, data, head_bytes_to_copy);
- }
- *num_bytes = bytes_to_read;
-
- bool peek = !!(flags & MOJO_READ_DATA_FLAG_PEEK);
- if (discard || !peek) {
- read_offset_ = (read_offset_ + bytes_to_read) % options_.capacity_num_bytes;
- bytes_available_ -= bytes_to_read;
-
- base::AutoUnlock unlock(lock_);
- NotifyRead(bytes_to_read);
- }
-
- // We may have just read the last available data and thus changed the signals
- // state.
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult DataPipeConsumerDispatcher::BeginReadData(const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags) {
- base::AutoLock lock(lock_);
- if (!shared_ring_buffer_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (in_two_phase_read_)
- return MOJO_RESULT_BUSY;
-
- // These flags may not be used in two-phase mode.
- if ((flags & MOJO_READ_DATA_FLAG_DISCARD) ||
- (flags & MOJO_READ_DATA_FLAG_QUERY) ||
- (flags & MOJO_READ_DATA_FLAG_PEEK))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- const bool had_new_data = new_data_available_;
- new_data_available_ = false;
-
- if (bytes_available_ == 0) {
- if (had_new_data)
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION
- : MOJO_RESULT_SHOULD_WAIT;
- }
-
- DCHECK_LT(read_offset_, options_.capacity_num_bytes);
- uint32_t bytes_to_read = std::min(bytes_available_,
- options_.capacity_num_bytes - read_offset_);
-
- CHECK(ring_buffer_mapping_);
- uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase());
- CHECK(data);
-
- in_two_phase_read_ = true;
- *buffer = data + read_offset_;
- *buffer_num_bytes = bytes_to_read;
- two_phase_max_bytes_read_ = bytes_to_read;
-
- if (had_new_data)
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult DataPipeConsumerDispatcher::EndReadData(uint32_t num_bytes_read) {
- base::AutoLock lock(lock_);
- if (!in_two_phase_read_)
- return MOJO_RESULT_FAILED_PRECONDITION;
-
- if (in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- CHECK(shared_ring_buffer_);
-
- MojoResult rv;
- if (num_bytes_read > two_phase_max_bytes_read_ ||
- num_bytes_read % options_.element_num_bytes != 0) {
- rv = MOJO_RESULT_INVALID_ARGUMENT;
- } else {
- rv = MOJO_RESULT_OK;
- read_offset_ =
- (read_offset_ + num_bytes_read) % options_.capacity_num_bytes;
-
- DCHECK_GE(bytes_available_, num_bytes_read);
- bytes_available_ -= num_bytes_read;
-
- base::AutoUnlock unlock(lock_);
- NotifyRead(num_bytes_read);
- }
-
- in_two_phase_read_ = false;
- two_phase_max_bytes_read_ = 0;
-
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-
- return rv;
-}
-
-HandleSignalsState DataPipeConsumerDispatcher::GetHandleSignalsState() const {
- base::AutoLock lock(lock_);
- return GetHandleSignalsStateNoLock();
-}
-
-MojoResult DataPipeConsumerDispatcher::AddWatcherRef(
- const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) {
- base::AutoLock lock(lock_);
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watchers_.Add(watcher, context, GetHandleSignalsStateNoLock());
-}
-
-MojoResult DataPipeConsumerDispatcher::RemoveWatcherRef(
- WatcherDispatcher* watcher,
- uintptr_t context) {
- base::AutoLock lock(lock_);
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watchers_.Remove(watcher, context);
-}
-
-void DataPipeConsumerDispatcher::StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) {
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- *num_bytes = static_cast<uint32_t>(sizeof(SerializedState));
- *num_ports = 1;
- *num_handles = 1;
-}
-
-bool DataPipeConsumerDispatcher::EndSerialize(
- void* destination,
- ports::PortName* ports,
- PlatformHandle* platform_handles) {
- SerializedState* state = static_cast<SerializedState*>(destination);
- memcpy(&state->options, &options_, sizeof(MojoCreateDataPipeOptions));
- memset(state->padding, 0, sizeof(state->padding));
-
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- state->pipe_id = pipe_id_;
- state->read_offset = read_offset_;
- state->bytes_available = bytes_available_;
- state->flags = peer_closed_ ? kFlagPeerClosed : 0;
-
- ports[0] = control_port_.name();
-
- buffer_handle_for_transit_ = shared_ring_buffer_->DuplicatePlatformHandle();
- platform_handles[0] = buffer_handle_for_transit_.get();
-
- return true;
-}
-
-bool DataPipeConsumerDispatcher::BeginTransit() {
- base::AutoLock lock(lock_);
- if (in_transit_)
- return false;
- in_transit_ = !in_two_phase_read_;
- return in_transit_;
-}
-
-void DataPipeConsumerDispatcher::CompleteTransitAndClose() {
- node_controller_->SetPortObserver(control_port_, nullptr);
-
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- in_transit_ = false;
- transferred_ = true;
- ignore_result(buffer_handle_for_transit_.release());
- CloseNoLock();
-}
-
-void DataPipeConsumerDispatcher::CancelTransit() {
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- in_transit_ = false;
- buffer_handle_for_transit_.reset();
- UpdateSignalsStateNoLock();
-}
-
-// static
-scoped_refptr<DataPipeConsumerDispatcher>
-DataPipeConsumerDispatcher::Deserialize(const void* data,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles) {
- if (num_ports != 1 || num_handles != 1 ||
- num_bytes != sizeof(SerializedState)) {
- return nullptr;
- }
-
- const SerializedState* state = static_cast<const SerializedState*>(data);
-
- NodeController* node_controller = internal::g_core->GetNodeController();
- ports::PortRef port;
- if (node_controller->node()->GetPort(ports[0], &port) != ports::OK)
- return nullptr;
-
- PlatformHandle buffer_handle;
- std::swap(buffer_handle, handles[0]);
- scoped_refptr<PlatformSharedBuffer> ring_buffer =
- PlatformSharedBuffer::CreateFromPlatformHandle(
- state->options.capacity_num_bytes,
- false /* read_only */,
- ScopedPlatformHandle(buffer_handle));
- if (!ring_buffer) {
- DLOG(ERROR) << "Failed to deserialize shared buffer handle.";
- return nullptr;
- }
-
- scoped_refptr<DataPipeConsumerDispatcher> dispatcher =
- new DataPipeConsumerDispatcher(node_controller, port, ring_buffer,
- state->options, false /* initialized */,
- state->pipe_id);
-
- {
- base::AutoLock lock(dispatcher->lock_);
- dispatcher->read_offset_ = state->read_offset;
- dispatcher->bytes_available_ = state->bytes_available;
- dispatcher->new_data_available_ = state->bytes_available > 0;
- dispatcher->peer_closed_ = state->flags & kFlagPeerClosed;
- dispatcher->InitializeNoLock();
- dispatcher->UpdateSignalsStateNoLock();
- }
-
- return dispatcher;
-}
-
-DataPipeConsumerDispatcher::~DataPipeConsumerDispatcher() {
- DCHECK(is_closed_ && !shared_ring_buffer_ && !ring_buffer_mapping_ &&
- !in_transit_);
-}
-
-void DataPipeConsumerDispatcher::InitializeNoLock() {
- lock_.AssertAcquired();
-
- if (shared_ring_buffer_) {
- DCHECK(!ring_buffer_mapping_);
- ring_buffer_mapping_ =
- shared_ring_buffer_->Map(0, options_.capacity_num_bytes);
- if (!ring_buffer_mapping_) {
- DLOG(ERROR) << "Failed to map shared buffer.";
- shared_ring_buffer_ = nullptr;
- }
- }
-
- base::AutoUnlock unlock(lock_);
- node_controller_->SetPortObserver(
- control_port_,
- make_scoped_refptr(new PortObserverThunk(this)));
-}
-
-MojoResult DataPipeConsumerDispatcher::CloseNoLock() {
- lock_.AssertAcquired();
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- is_closed_ = true;
- ring_buffer_mapping_.reset();
- shared_ring_buffer_ = nullptr;
-
- watchers_.NotifyClosed();
- if (!transferred_) {
- base::AutoUnlock unlock(lock_);
- node_controller_->ClosePort(control_port_);
- }
-
- return MOJO_RESULT_OK;
-}
-
-HandleSignalsState
-DataPipeConsumerDispatcher::GetHandleSignalsStateNoLock() const {
- lock_.AssertAcquired();
-
- HandleSignalsState rv;
- if (shared_ring_buffer_ && bytes_available_) {
- if (!in_two_phase_read_) {
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- if (new_data_available_)
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE;
- }
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- } else if (!peer_closed_ && shared_ring_buffer_) {
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- }
-
- if (shared_ring_buffer_) {
- if (new_data_available_ || !peer_closed_)
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE;
- }
-
- if (peer_closed_)
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
-
- return rv;
-}
-
-void DataPipeConsumerDispatcher::NotifyRead(uint32_t num_bytes) {
- DVLOG(1) << "Data pipe consumer " << pipe_id_ << " notifying peer: "
- << num_bytes << " bytes read. [control_port="
- << control_port_.name() << "]";
-
- SendDataPipeControlMessage(node_controller_, control_port_,
- DataPipeCommand::DATA_WAS_READ, num_bytes);
-}
-
-void DataPipeConsumerDispatcher::OnPortStatusChanged() {
- DCHECK(RequestContext::current());
-
- base::AutoLock lock(lock_);
-
- // We stop observing the control port as soon it's transferred, but this can
- // race with events which are raised right before that happens. This is fine
- // to ignore.
- if (transferred_)
- return;
-
- DVLOG(1) << "Control port status changed for data pipe producer " << pipe_id_;
-
- UpdateSignalsStateNoLock();
-}
-
-void DataPipeConsumerDispatcher::UpdateSignalsStateNoLock() {
- lock_.AssertAcquired();
-
- bool was_peer_closed = peer_closed_;
- size_t previous_bytes_available = bytes_available_;
-
- ports::PortStatus port_status;
- int rv = node_controller_->node()->GetStatus(control_port_, &port_status);
- if (rv != ports::OK || !port_status.receiving_messages) {
- DVLOG(1) << "Data pipe consumer " << pipe_id_ << " is aware of peer closure"
- << " [control_port=" << control_port_.name() << "]";
- peer_closed_ = true;
- } else if (rv == ports::OK && port_status.has_messages && !in_transit_) {
- ports::ScopedMessage message;
- do {
- int rv = node_controller_->node()->GetMessage(
- control_port_, &message, nullptr);
- if (rv != ports::OK)
- peer_closed_ = true;
- if (message) {
- if (message->num_payload_bytes() < sizeof(DataPipeControlMessage)) {
- peer_closed_ = true;
- break;
- }
-
- const DataPipeControlMessage* m =
- static_cast<const DataPipeControlMessage*>(
- message->payload_bytes());
-
- if (m->command != DataPipeCommand::DATA_WAS_WRITTEN) {
- DLOG(ERROR) << "Unexpected control message from producer.";
- peer_closed_ = true;
- break;
- }
-
- if (static_cast<size_t>(bytes_available_) + m->num_bytes >
- options_.capacity_num_bytes) {
- DLOG(ERROR) << "Producer claims to have written too many bytes.";
- peer_closed_ = true;
- break;
- }
-
- DVLOG(1) << "Data pipe consumer " << pipe_id_ << " is aware that "
- << m->num_bytes << " bytes were written. [control_port="
- << control_port_.name() << "]";
-
- bytes_available_ += m->num_bytes;
- }
- } while (message);
- }
-
- bool has_new_data = bytes_available_ != previous_bytes_available;
- if (has_new_data)
- new_data_available_ = true;
-
- if (peer_closed_ != was_peer_closed || has_new_data)
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/data_pipe_consumer_dispatcher.h b/mojo/edk/system/data_pipe_consumer_dispatcher.h
deleted file mode 100644
index 120c7a3..0000000
--- a/mojo/edk/system/data_pipe_consumer_dispatcher.h
+++ /dev/null
@@ -1,123 +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_DATA_PIPE_CONSUMER_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_DATA_PIPE_CONSUMER_DISPATCHER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/ports/port_ref.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/edk/system/watcher_set.h"
-
-namespace mojo {
-namespace edk {
-
-class NodeController;
-
-// This is the Dispatcher implementation for the consumer handle for data
-// pipes created by the Mojo primitive MojoCreateDataPipe(). This class is
-// thread-safe.
-class MOJO_SYSTEM_IMPL_EXPORT DataPipeConsumerDispatcher final
- : public Dispatcher {
- public:
- DataPipeConsumerDispatcher(
- NodeController* node_controller,
- const ports::PortRef& control_port,
- scoped_refptr<PlatformSharedBuffer> shared_ring_buffer,
- const MojoCreateDataPipeOptions& options,
- bool initialized,
- uint64_t pipe_id);
-
- // Dispatcher:
- Type GetType() const override;
- MojoResult Close() override;
- MojoResult ReadData(void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags) override;
- MojoResult BeginReadData(const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags) override;
- MojoResult EndReadData(uint32_t num_bytes_read) override;
- HandleSignalsState GetHandleSignalsState() const override;
- MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) override;
- MojoResult RemoveWatcherRef(WatcherDispatcher* watcher,
- uintptr_t context) override;
- void StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) override;
- bool EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) override;
- bool BeginTransit() override;
- void CompleteTransitAndClose() override;
- void CancelTransit() override;
-
- static scoped_refptr<DataPipeConsumerDispatcher>
- Deserialize(const void* data,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles);
-
- private:
- class PortObserverThunk;
- friend class PortObserverThunk;
-
- ~DataPipeConsumerDispatcher() override;
-
- void InitializeNoLock();
- MojoResult CloseNoLock();
- HandleSignalsState GetHandleSignalsStateNoLock() const;
- void NotifyRead(uint32_t num_bytes);
- void OnPortStatusChanged();
- void UpdateSignalsStateNoLock();
-
- const MojoCreateDataPipeOptions options_;
- NodeController* const node_controller_;
- const ports::PortRef control_port_;
- const uint64_t pipe_id_;
-
- // Guards access to the fields below.
- mutable base::Lock lock_;
-
- WatcherSet watchers_;
-
- scoped_refptr<PlatformSharedBuffer> shared_ring_buffer_;
- std::unique_ptr<PlatformSharedBufferMapping> ring_buffer_mapping_;
- ScopedPlatformHandle buffer_handle_for_transit_;
-
- bool in_two_phase_read_ = false;
- uint32_t two_phase_max_bytes_read_ = 0;
-
- bool in_transit_ = false;
- bool is_closed_ = false;
- bool peer_closed_ = false;
- bool transferred_ = false;
-
- uint32_t read_offset_ = 0;
- uint32_t bytes_available_ = 0;
-
- // Indicates whether any new data is available since the last read attempt.
- bool new_data_available_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(DataPipeConsumerDispatcher);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_DATA_PIPE_CONSUMER_DISPATCHER_H_
diff --git a/mojo/edk/system/data_pipe_control_message.cc b/mojo/edk/system/data_pipe_control_message.cc
deleted file mode 100644
index 23873b8..0000000
--- a/mojo/edk/system/data_pipe_control_message.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/data_pipe_control_message.h"
-
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/system/node_controller.h"
-#include "mojo/edk/system/ports_message.h"
-
-namespace mojo {
-namespace edk {
-
-void SendDataPipeControlMessage(NodeController* node_controller,
- const ports::PortRef& port,
- DataPipeCommand command,
- uint32_t num_bytes) {
- std::unique_ptr<PortsMessage> message =
- PortsMessage::NewUserMessage(sizeof(DataPipeControlMessage), 0, 0);
- CHECK(message);
-
- DataPipeControlMessage* data =
- static_cast<DataPipeControlMessage*>(message->mutable_payload_bytes());
- data->command = command;
- data->num_bytes = num_bytes;
-
- int rv = node_controller->SendMessage(port, std::move(message));
- if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) {
- DLOG(ERROR) << "Unexpected failure sending data pipe control message: "
- << rv;
- }
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/data_pipe_control_message.h b/mojo/edk/system/data_pipe_control_message.h
deleted file mode 100644
index ec84ea3..0000000
--- a/mojo/edk/system/data_pipe_control_message.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_DATA_PIPE_CONTROL_MESSAGE_H_
-#define MOJO_EDK_SYSTEM_DATA_PIPE_CONTROL_MESSAGE_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/ports/port_ref.h"
-#include "mojo/public/c/system/macros.h"
-
-namespace mojo {
-namespace edk {
-
-class NodeController;
-
-enum DataPipeCommand : uint32_t {
- // Signal to the consumer that new data is available.
- DATA_WAS_WRITTEN,
-
- // Signal to the producer that data has been consumed.
- DATA_WAS_READ,
-};
-
-// Message header for messages sent over a data pipe control port.
-struct MOJO_ALIGNAS(8) DataPipeControlMessage {
- DataPipeCommand command;
- uint32_t num_bytes;
-};
-
-void SendDataPipeControlMessage(NodeController* node_controller,
- const ports::PortRef& port,
- DataPipeCommand command,
- uint32_t num_bytes);
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_DATA_PIPE_CONTROL_MESSAGE_H_
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.cc b/mojo/edk/system/data_pipe_producer_dispatcher.cc
deleted file mode 100644
index b0102a6..0000000
--- a/mojo/edk/system/data_pipe_producer_dispatcher.cc
+++ /dev/null
@@ -1,507 +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/data_pipe_producer_dispatcher.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/configuration.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/data_pipe_control_message.h"
-#include "mojo/edk/system/node_controller.h"
-#include "mojo/edk/system/ports_message.h"
-#include "mojo/edk/system/request_context.h"
-#include "mojo/public/c/system/data_pipe.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-const uint8_t kFlagPeerClosed = 0x01;
-
-#pragma pack(push, 1)
-
-struct SerializedState {
- MojoCreateDataPipeOptions options;
- uint64_t pipe_id;
- uint32_t write_offset;
- uint32_t available_capacity;
- uint8_t flags;
- char padding[7];
-};
-
-static_assert(sizeof(SerializedState) % 8 == 0,
- "Invalid SerializedState size.");
-
-#pragma pack(pop)
-
-} // namespace
-
-// A PortObserver which forwards to a DataPipeProducerDispatcher. This owns a
-// reference to the dispatcher to ensure it lives as long as the observed port.
-class DataPipeProducerDispatcher::PortObserverThunk
- : public NodeController::PortObserver {
- public:
- explicit PortObserverThunk(
- scoped_refptr<DataPipeProducerDispatcher> dispatcher)
- : dispatcher_(dispatcher) {}
-
- private:
- ~PortObserverThunk() override {}
-
- // NodeController::PortObserver:
- void OnPortStatusChanged() override { dispatcher_->OnPortStatusChanged(); }
-
- scoped_refptr<DataPipeProducerDispatcher> dispatcher_;
-
- DISALLOW_COPY_AND_ASSIGN(PortObserverThunk);
-};
-
-DataPipeProducerDispatcher::DataPipeProducerDispatcher(
- NodeController* node_controller,
- const ports::PortRef& control_port,
- scoped_refptr<PlatformSharedBuffer> shared_ring_buffer,
- const MojoCreateDataPipeOptions& options,
- bool initialized,
- uint64_t pipe_id)
- : options_(options),
- node_controller_(node_controller),
- control_port_(control_port),
- pipe_id_(pipe_id),
- watchers_(this),
- shared_ring_buffer_(shared_ring_buffer),
- available_capacity_(options_.capacity_num_bytes) {
- if (initialized) {
- base::AutoLock lock(lock_);
- InitializeNoLock();
- }
-}
-
-Dispatcher::Type DataPipeProducerDispatcher::GetType() const {
- return Type::DATA_PIPE_PRODUCER;
-}
-
-MojoResult DataPipeProducerDispatcher::Close() {
- base::AutoLock lock(lock_);
- DVLOG(1) << "Closing data pipe producer " << pipe_id_;
- return CloseNoLock();
-}
-
-MojoResult DataPipeProducerDispatcher::WriteData(const void* elements,
- uint32_t* num_bytes,
- MojoWriteDataFlags flags) {
- base::AutoLock lock(lock_);
- if (!shared_ring_buffer_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (in_two_phase_write_)
- return MOJO_RESULT_BUSY;
-
- if (peer_closed_)
- return MOJO_RESULT_FAILED_PRECONDITION;
-
- if (*num_bytes % options_.element_num_bytes != 0)
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (*num_bytes == 0)
- return MOJO_RESULT_OK; // Nothing to do.
-
- if ((flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) &&
- (*num_bytes > available_capacity_)) {
- // Don't return "should wait" since you can't wait for a specified amount of
- // data.
- return MOJO_RESULT_OUT_OF_RANGE;
- }
-
- DCHECK_LE(available_capacity_, options_.capacity_num_bytes);
- uint32_t num_bytes_to_write = std::min(*num_bytes, available_capacity_);
- if (num_bytes_to_write == 0)
- return MOJO_RESULT_SHOULD_WAIT;
-
- *num_bytes = num_bytes_to_write;
-
- CHECK(ring_buffer_mapping_);
- uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase());
- CHECK(data);
-
- const uint8_t* source = static_cast<const uint8_t*>(elements);
- CHECK(source);
-
- DCHECK_LE(write_offset_, options_.capacity_num_bytes);
- uint32_t tail_bytes_to_write =
- std::min(options_.capacity_num_bytes - write_offset_,
- num_bytes_to_write);
- uint32_t head_bytes_to_write = num_bytes_to_write - tail_bytes_to_write;
-
- DCHECK_GT(tail_bytes_to_write, 0u);
- memcpy(data + write_offset_, source, tail_bytes_to_write);
- if (head_bytes_to_write > 0)
- memcpy(data, source + tail_bytes_to_write, head_bytes_to_write);
-
- DCHECK_LE(num_bytes_to_write, available_capacity_);
- available_capacity_ -= num_bytes_to_write;
- write_offset_ = (write_offset_ + num_bytes_to_write) %
- options_.capacity_num_bytes;
-
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-
- base::AutoUnlock unlock(lock_);
- NotifyWrite(num_bytes_to_write);
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult DataPipeProducerDispatcher::BeginWriteData(
- void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags) {
- base::AutoLock lock(lock_);
- if (!shared_ring_buffer_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- // These flags may not be used in two-phase mode.
- if (flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (in_two_phase_write_)
- return MOJO_RESULT_BUSY;
- if (peer_closed_)
- return MOJO_RESULT_FAILED_PRECONDITION;
-
- if (available_capacity_ == 0) {
- return peer_closed_ ? MOJO_RESULT_FAILED_PRECONDITION
- : MOJO_RESULT_SHOULD_WAIT;
- }
-
- in_two_phase_write_ = true;
- *buffer_num_bytes = std::min(options_.capacity_num_bytes - write_offset_,
- available_capacity_);
- DCHECK_GT(*buffer_num_bytes, 0u);
-
- CHECK(ring_buffer_mapping_);
- uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase());
- *buffer = data + write_offset_;
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult DataPipeProducerDispatcher::EndWriteData(
- uint32_t num_bytes_written) {
- base::AutoLock lock(lock_);
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (!in_two_phase_write_)
- return MOJO_RESULT_FAILED_PRECONDITION;
-
- DCHECK(shared_ring_buffer_);
- DCHECK(ring_buffer_mapping_);
-
- // Note: Allow successful completion of the two-phase write even if the other
- // side has been closed.
- MojoResult rv = MOJO_RESULT_OK;
- if (num_bytes_written > available_capacity_ ||
- num_bytes_written % options_.element_num_bytes != 0 ||
- write_offset_ + num_bytes_written > options_.capacity_num_bytes) {
- rv = MOJO_RESULT_INVALID_ARGUMENT;
- } else {
- DCHECK_LE(num_bytes_written + write_offset_, options_.capacity_num_bytes);
- available_capacity_ -= num_bytes_written;
- write_offset_ = (write_offset_ + num_bytes_written) %
- options_.capacity_num_bytes;
-
- base::AutoUnlock unlock(lock_);
- NotifyWrite(num_bytes_written);
- }
-
- in_two_phase_write_ = false;
-
- // If we're now writable, we *became* writable (since we weren't writable
- // during the two-phase write), so notify watchers.
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-
- return rv;
-}
-
-HandleSignalsState DataPipeProducerDispatcher::GetHandleSignalsState() const {
- base::AutoLock lock(lock_);
- return GetHandleSignalsStateNoLock();
-}
-
-MojoResult DataPipeProducerDispatcher::AddWatcherRef(
- const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) {
- base::AutoLock lock(lock_);
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watchers_.Add(watcher, context, GetHandleSignalsStateNoLock());
-}
-
-MojoResult DataPipeProducerDispatcher::RemoveWatcherRef(
- WatcherDispatcher* watcher,
- uintptr_t context) {
- base::AutoLock lock(lock_);
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watchers_.Remove(watcher, context);
-}
-
-void DataPipeProducerDispatcher::StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) {
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- *num_bytes = sizeof(SerializedState);
- *num_ports = 1;
- *num_handles = 1;
-}
-
-bool DataPipeProducerDispatcher::EndSerialize(
- void* destination,
- ports::PortName* ports,
- PlatformHandle* platform_handles) {
- SerializedState* state = static_cast<SerializedState*>(destination);
- memcpy(&state->options, &options_, sizeof(MojoCreateDataPipeOptions));
- memset(state->padding, 0, sizeof(state->padding));
-
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- state->pipe_id = pipe_id_;
- state->write_offset = write_offset_;
- state->available_capacity = available_capacity_;
- state->flags = peer_closed_ ? kFlagPeerClosed : 0;
-
- ports[0] = control_port_.name();
-
- buffer_handle_for_transit_ = shared_ring_buffer_->DuplicatePlatformHandle();
- platform_handles[0] = buffer_handle_for_transit_.get();
-
- return true;
-}
-
-bool DataPipeProducerDispatcher::BeginTransit() {
- base::AutoLock lock(lock_);
- if (in_transit_)
- return false;
- in_transit_ = !in_two_phase_write_;
- return in_transit_;
-}
-
-void DataPipeProducerDispatcher::CompleteTransitAndClose() {
- node_controller_->SetPortObserver(control_port_, nullptr);
-
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- transferred_ = true;
- in_transit_ = false;
- ignore_result(buffer_handle_for_transit_.release());
- CloseNoLock();
-}
-
-void DataPipeProducerDispatcher::CancelTransit() {
- base::AutoLock lock(lock_);
- DCHECK(in_transit_);
- in_transit_ = false;
- buffer_handle_for_transit_.reset();
-
- HandleSignalsState state = GetHandleSignalsStateNoLock();
- watchers_.NotifyState(state);
-}
-
-// static
-scoped_refptr<DataPipeProducerDispatcher>
-DataPipeProducerDispatcher::Deserialize(const void* data,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles) {
- if (num_ports != 1 || num_handles != 1 ||
- num_bytes != sizeof(SerializedState)) {
- return nullptr;
- }
-
- const SerializedState* state = static_cast<const SerializedState*>(data);
-
- NodeController* node_controller = internal::g_core->GetNodeController();
- ports::PortRef port;
- if (node_controller->node()->GetPort(ports[0], &port) != ports::OK)
- return nullptr;
-
- PlatformHandle buffer_handle;
- std::swap(buffer_handle, handles[0]);
- scoped_refptr<PlatformSharedBuffer> ring_buffer =
- PlatformSharedBuffer::CreateFromPlatformHandle(
- state->options.capacity_num_bytes,
- false /* read_only */,
- ScopedPlatformHandle(buffer_handle));
- if (!ring_buffer) {
- DLOG(ERROR) << "Failed to deserialize shared buffer handle.";
- return nullptr;
- }
-
- scoped_refptr<DataPipeProducerDispatcher> dispatcher =
- new DataPipeProducerDispatcher(node_controller, port, ring_buffer,
- state->options, false /* initialized */,
- state->pipe_id);
-
- {
- base::AutoLock lock(dispatcher->lock_);
- dispatcher->write_offset_ = state->write_offset;
- dispatcher->available_capacity_ = state->available_capacity;
- dispatcher->peer_closed_ = state->flags & kFlagPeerClosed;
- dispatcher->InitializeNoLock();
- dispatcher->UpdateSignalsStateNoLock();
- }
-
- return dispatcher;
-}
-
-DataPipeProducerDispatcher::~DataPipeProducerDispatcher() {
- DCHECK(is_closed_ && !in_transit_ && !shared_ring_buffer_ &&
- !ring_buffer_mapping_);
-}
-
-void DataPipeProducerDispatcher::InitializeNoLock() {
- lock_.AssertAcquired();
-
- if (shared_ring_buffer_) {
- ring_buffer_mapping_ =
- shared_ring_buffer_->Map(0, options_.capacity_num_bytes);
- if (!ring_buffer_mapping_) {
- DLOG(ERROR) << "Failed to map shared buffer.";
- shared_ring_buffer_ = nullptr;
- }
- }
-
- base::AutoUnlock unlock(lock_);
- node_controller_->SetPortObserver(
- control_port_,
- make_scoped_refptr(new PortObserverThunk(this)));
-}
-
-MojoResult DataPipeProducerDispatcher::CloseNoLock() {
- lock_.AssertAcquired();
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- is_closed_ = true;
- ring_buffer_mapping_.reset();
- shared_ring_buffer_ = nullptr;
-
- watchers_.NotifyClosed();
- if (!transferred_) {
- base::AutoUnlock unlock(lock_);
- node_controller_->ClosePort(control_port_);
- }
-
- return MOJO_RESULT_OK;
-}
-
-HandleSignalsState DataPipeProducerDispatcher::GetHandleSignalsStateNoLock()
- const {
- lock_.AssertAcquired();
- HandleSignalsState rv;
- if (!peer_closed_) {
- if (!in_two_phase_write_ && shared_ring_buffer_ && available_capacity_ > 0)
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
- } else {
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
- }
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
- return rv;
-}
-
-void DataPipeProducerDispatcher::NotifyWrite(uint32_t num_bytes) {
- DVLOG(1) << "Data pipe producer " << pipe_id_ << " notifying peer: "
- << num_bytes << " bytes written. [control_port="
- << control_port_.name() << "]";
-
- SendDataPipeControlMessage(node_controller_, control_port_,
- DataPipeCommand::DATA_WAS_WRITTEN, num_bytes);
-}
-
-void DataPipeProducerDispatcher::OnPortStatusChanged() {
- DCHECK(RequestContext::current());
-
- base::AutoLock lock(lock_);
-
- // We stop observing the control port as soon it's transferred, but this can
- // race with events which are raised right before that happens. This is fine
- // to ignore.
- if (transferred_)
- return;
-
- DVLOG(1) << "Control port status changed for data pipe producer " << pipe_id_;
-
- UpdateSignalsStateNoLock();
-}
-
-void DataPipeProducerDispatcher::UpdateSignalsStateNoLock() {
- lock_.AssertAcquired();
-
- bool was_peer_closed = peer_closed_;
- size_t previous_capacity = available_capacity_;
-
- ports::PortStatus port_status;
- int rv = node_controller_->node()->GetStatus(control_port_, &port_status);
- if (rv != ports::OK || !port_status.receiving_messages) {
- DVLOG(1) << "Data pipe producer " << pipe_id_ << " is aware of peer closure"
- << " [control_port=" << control_port_.name() << "]";
- peer_closed_ = true;
- } else if (rv == ports::OK && port_status.has_messages && !in_transit_) {
- ports::ScopedMessage message;
- do {
- int rv = node_controller_->node()->GetMessage(
- control_port_, &message, nullptr);
- if (rv != ports::OK)
- peer_closed_ = true;
- if (message) {
- if (message->num_payload_bytes() < sizeof(DataPipeControlMessage)) {
- peer_closed_ = true;
- break;
- }
-
- const DataPipeControlMessage* m =
- static_cast<const DataPipeControlMessage*>(
- message->payload_bytes());
-
- if (m->command != DataPipeCommand::DATA_WAS_READ) {
- DLOG(ERROR) << "Unexpected message from consumer.";
- peer_closed_ = true;
- break;
- }
-
- if (static_cast<size_t>(available_capacity_) + m->num_bytes >
- options_.capacity_num_bytes) {
- DLOG(ERROR) << "Consumer claims to have read too many bytes.";
- break;
- }
-
- DVLOG(1) << "Data pipe producer " << pipe_id_ << " is aware that "
- << m->num_bytes << " bytes were read. [control_port="
- << control_port_.name() << "]";
-
- available_capacity_ += m->num_bytes;
- }
- } while (message);
- }
-
- if (peer_closed_ != was_peer_closed ||
- available_capacity_ != previous_capacity) {
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- }
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/data_pipe_producer_dispatcher.h b/mojo/edk/system/data_pipe_producer_dispatcher.h
deleted file mode 100644
index 1eddd5d..0000000
--- a/mojo/edk/system/data_pipe_producer_dispatcher.h
+++ /dev/null
@@ -1,123 +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_DATA_PIPE_PRODUCER_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_DATA_PIPE_PRODUCER_DISPATCHER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/ports/port_ref.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/edk/system/watcher_set.h"
-
-namespace mojo {
-namespace edk {
-
-struct DataPipeControlMessage;
-class NodeController;
-
-// This is the Dispatcher implementation for the producer handle for data
-// pipes created by the Mojo primitive MojoCreateDataPipe(). This class is
-// thread-safe.
-class MOJO_SYSTEM_IMPL_EXPORT DataPipeProducerDispatcher final
- : public Dispatcher {
- public:
- DataPipeProducerDispatcher(
- NodeController* node_controller,
- const ports::PortRef& port,
- scoped_refptr<PlatformSharedBuffer> shared_ring_buffer,
- const MojoCreateDataPipeOptions& options,
- bool initialized,
- uint64_t pipe_id);
-
- // Dispatcher:
- Type GetType() const override;
- MojoResult Close() override;
- MojoResult WriteData(const void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags) override;
- MojoResult BeginWriteData(void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags) override;
- MojoResult EndWriteData(uint32_t num_bytes_written) override;
- HandleSignalsState GetHandleSignalsState() const override;
- MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) override;
- MojoResult RemoveWatcherRef(WatcherDispatcher* watcher,
- uintptr_t context) override;
- void StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) override;
- bool EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) override;
- bool BeginTransit() override;
- void CompleteTransitAndClose() override;
- void CancelTransit() override;
-
- static scoped_refptr<DataPipeProducerDispatcher>
- Deserialize(const void* data,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles);
-
- private:
- class PortObserverThunk;
- friend class PortObserverThunk;
-
- ~DataPipeProducerDispatcher() override;
-
- void OnSharedBufferCreated(const scoped_refptr<PlatformSharedBuffer>& buffer);
- void InitializeNoLock();
- MojoResult CloseNoLock();
- HandleSignalsState GetHandleSignalsStateNoLock() const;
- void NotifyWrite(uint32_t num_bytes);
- void OnPortStatusChanged();
- void UpdateSignalsStateNoLock();
- bool ProcessMessageNoLock(const DataPipeControlMessage& message,
- ScopedPlatformHandleVectorPtr handles);
-
- const MojoCreateDataPipeOptions options_;
- NodeController* const node_controller_;
- const ports::PortRef control_port_;
- const uint64_t pipe_id_;
-
- // Guards access to the fields below.
- mutable base::Lock lock_;
-
- WatcherSet watchers_;
-
- bool buffer_requested_ = false;
-
- scoped_refptr<PlatformSharedBuffer> shared_ring_buffer_;
- std::unique_ptr<PlatformSharedBufferMapping> ring_buffer_mapping_;
- ScopedPlatformHandle buffer_handle_for_transit_;
-
- bool in_transit_ = false;
- bool is_closed_ = false;
- bool peer_closed_ = false;
- bool transferred_ = false;
- bool in_two_phase_write_ = false;
-
- uint32_t write_offset_ = 0;
- uint32_t available_capacity_;
-
- DISALLOW_COPY_AND_ASSIGN(DataPipeProducerDispatcher);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_DATA_PIPE_PRODUCER_DISPATCHER_H_
diff --git a/mojo/edk/system/data_pipe_unittest.cc b/mojo/edk/system/data_pipe_unittest.cc
deleted file mode 100644
index 79c1f75..0000000
--- a/mojo/edk/system/data_pipe_unittest.cc
+++ /dev/null
@@ -1,2034 +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 <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/functions.h"
-#include "mojo/public/c/system/message_pipe.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-const uint32_t kSizeOfOptions =
- static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions));
-
-// In various places, we have to poll (since, e.g., we can't yet wait for a
-// certain amount of data to be available). This is the maximum number of
-// iterations (separated by a short sleep).
-// TODO(vtl): Get rid of this.
-const size_t kMaxPoll = 100;
-
-// Used in Multiprocess test.
-const size_t kMultiprocessCapacity = 37;
-const char kMultiprocessTestData[] = "hello i'm a string that is 36 bytes";
-const int kMultiprocessMaxIter = 5;
-
-// TODO(rockot): There are many uses of ASSERT where EXPECT would be more
-// appropriate. Fix this.
-
-class DataPipeTest : public test::MojoTestBase {
- public:
- DataPipeTest() : producer_(MOJO_HANDLE_INVALID),
- consumer_(MOJO_HANDLE_INVALID) {}
-
- ~DataPipeTest() override {
- if (producer_ != MOJO_HANDLE_INVALID)
- CHECK_EQ(MOJO_RESULT_OK, MojoClose(producer_));
- if (consumer_ != MOJO_HANDLE_INVALID)
- CHECK_EQ(MOJO_RESULT_OK, MojoClose(consumer_));
- }
-
- MojoResult Create(const MojoCreateDataPipeOptions* options) {
- return MojoCreateDataPipe(options, &producer_, &consumer_);
- }
-
- MojoResult WriteData(const void* elements,
- uint32_t* num_bytes,
- bool all_or_none = false) {
- return MojoWriteData(producer_, elements, num_bytes,
- all_or_none ? MOJO_WRITE_DATA_FLAG_ALL_OR_NONE
- : MOJO_WRITE_DATA_FLAG_NONE);
- }
-
- MojoResult ReadData(void* elements,
- uint32_t* num_bytes,
- bool all_or_none = false,
- bool peek = false) {
- MojoReadDataFlags flags = MOJO_READ_DATA_FLAG_NONE;
- if (all_or_none)
- flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE;
- if (peek)
- flags |= MOJO_READ_DATA_FLAG_PEEK;
- return MojoReadData(consumer_, elements, num_bytes, flags);
- }
-
- MojoResult QueryData(uint32_t* num_bytes) {
- return MojoReadData(consumer_, nullptr, num_bytes,
- MOJO_READ_DATA_FLAG_QUERY);
- }
-
- MojoResult DiscardData(uint32_t* num_bytes, bool all_or_none = false) {
- MojoReadDataFlags flags = MOJO_READ_DATA_FLAG_DISCARD;
- if (all_or_none)
- flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE;
- return MojoReadData(consumer_, nullptr, num_bytes, flags);
- }
-
- MojoResult BeginReadData(const void** elements,
- uint32_t* num_bytes,
- bool all_or_none = false) {
- MojoReadDataFlags flags = MOJO_READ_DATA_FLAG_NONE;
- if (all_or_none)
- flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE;
- return MojoBeginReadData(consumer_, elements, num_bytes, flags);
- }
-
- MojoResult EndReadData(uint32_t num_bytes_read) {
- return MojoEndReadData(consumer_, num_bytes_read);
- }
-
- MojoResult BeginWriteData(void** elements,
- uint32_t* num_bytes,
- bool all_or_none = false) {
- MojoReadDataFlags flags = MOJO_WRITE_DATA_FLAG_NONE;
- if (all_or_none)
- flags |= MOJO_WRITE_DATA_FLAG_ALL_OR_NONE;
- return MojoBeginWriteData(producer_, elements, num_bytes, flags);
- }
-
- MojoResult EndWriteData(uint32_t num_bytes_written) {
- return MojoEndWriteData(producer_, num_bytes_written);
- }
-
- MojoResult CloseProducer() {
- MojoResult rv = MojoClose(producer_);
- producer_ = MOJO_HANDLE_INVALID;
- return rv;
- }
-
- MojoResult CloseConsumer() {
- MojoResult rv = MojoClose(consumer_);
- consumer_ = MOJO_HANDLE_INVALID;
- return rv;
- }
-
- MojoHandle producer_, consumer_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DataPipeTest);
-};
-
-TEST_F(DataPipeTest, Basic) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
-
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
-
- // We can write to a data pipe handle immediately.
- int32_t elements[10] = {};
- uint32_t num_bytes = 0;
-
- num_bytes =
- static_cast<uint32_t>(arraysize(elements) * sizeof(elements[0]));
-
- elements[0] = 123;
- elements[1] = 456;
- num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(&elements[0], &num_bytes));
-
- // Now wait for the other side to become readable.
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- state.satisfied_signals);
-
- elements[0] = -1;
- elements[1] = -1;
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(&elements[0], &num_bytes));
- ASSERT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes);
- ASSERT_EQ(elements[0], 123);
- ASSERT_EQ(elements[1], 456);
-}
-
-// Tests creation of data pipes with various (valid) options.
-TEST_F(DataPipeTest, CreateAndMaybeTransfer) {
- MojoCreateDataPipeOptions test_options[] = {
- // Default options.
- {},
- // Trivial element size, non-default capacity.
- {kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1, // |element_num_bytes|.
- 1000}, // |capacity_num_bytes|.
- // Nontrivial element size, non-default capacity.
- {kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 4, // |element_num_bytes|.
- 4000}, // |capacity_num_bytes|.
- // Nontrivial element size, default capacity.
- {kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 100, // |element_num_bytes|.
- 0} // |capacity_num_bytes|.
- };
- for (size_t i = 0; i < arraysize(test_options); i++) {
- MojoHandle producer_handle, consumer_handle;
- MojoCreateDataPipeOptions* options =
- i ? &test_options[i] : nullptr;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateDataPipe(options, &producer_handle, &consumer_handle));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(producer_handle));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(consumer_handle));
- }
-}
-
-TEST_F(DataPipeTest, SimpleReadWrite) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
-
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- int32_t elements[10] = {};
- uint32_t num_bytes = 0;
-
- // Try reading; nothing there yet.
- num_bytes =
- static_cast<uint32_t>(arraysize(elements) * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadData(elements, &num_bytes));
-
- // Query; nothing there yet.
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-
- // Discard; nothing there yet.
- num_bytes = static_cast<uint32_t>(5u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, DiscardData(&num_bytes));
-
- // Read with invalid |num_bytes|.
- num_bytes = sizeof(elements[0]) + 1;
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, ReadData(elements, &num_bytes));
-
- // Write two elements.
- elements[0] = 123;
- elements[1] = 456;
- num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes));
- // It should have written everything (even without "all or none").
- ASSERT_EQ(2u * sizeof(elements[0]), num_bytes);
-
- // Wait.
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Query.
- // TODO(vtl): It's theoretically possible (though not with the current
- // implementation/configured limits) that not all the data has arrived yet.
- // (The theoretically-correct assertion here is that |num_bytes| is |1 * ...|
- // or |2 * ...|.)
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(2 * sizeof(elements[0]), num_bytes);
-
- // Read one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes));
- ASSERT_EQ(1u * sizeof(elements[0]), num_bytes);
- ASSERT_EQ(123, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Query.
- // TODO(vtl): See previous TODO. (If we got 2 elements there, however, we
- // should get 1 here.)
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(1 * sizeof(elements[0]), num_bytes);
-
- // Peek one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, false, true));
- ASSERT_EQ(1u * sizeof(elements[0]), num_bytes);
- ASSERT_EQ(456, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Query. Still has 1 element remaining.
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(1 * sizeof(elements[0]), num_bytes);
-
- // Try to read two elements, with "all or none".
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- ReadData(elements, &num_bytes, true, false));
- ASSERT_EQ(-1, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Try to read two elements, without "all or none".
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, false, false));
- ASSERT_EQ(1u * sizeof(elements[0]), num_bytes);
- ASSERT_EQ(456, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Query.
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-}
-
-// Note: The "basic" waiting tests test that the "wait states" are correct in
-// various situations; they don't test that waiters are properly awoken on state
-// changes. (For that, we need to use multiple threads.)
-TEST_F(DataPipeTest, BasicProducerWaiting) {
- // Note: We take advantage of the fact that current for current
- // implementations capacities are strict maximums. This is not guaranteed by
- // the API.
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 2 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- Create(&options);
- MojoHandleSignalsState hss;
-
- // Never readable. Already writable.
- hss = GetSignalsState(producer_);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // Write two elements.
- int32_t elements[2] = {123, 456};
- uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
- ASSERT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes);
-
- // Wait for data to become available to the consumer.
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Peek one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, true, true));
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
- ASSERT_EQ(123, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Read one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, true, false));
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
- ASSERT_EQ(123, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Try writing, using a two-phase write.
- void* buffer = nullptr;
- num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&buffer, &num_bytes));
- EXPECT_TRUE(buffer);
- ASSERT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(elements[0])));
-
- static_cast<int32_t*>(buffer)[0] = 789;
- ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(static_cast<uint32_t>(
- 1u * sizeof(elements[0]))));
-
- // Read one element, using a two-phase read.
- const void* read_buffer = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginReadData(&read_buffer, &num_bytes, false));
- EXPECT_TRUE(read_buffer);
- // The two-phase read should be able to read at least one element.
- ASSERT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(elements[0])));
- ASSERT_EQ(456, static_cast<const int32_t*>(read_buffer)[0]);
- ASSERT_EQ(MOJO_RESULT_OK, EndReadData(static_cast<uint32_t>(
- 1u * sizeof(elements[0]))));
-
- // Write one element.
- elements[0] = 123;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes));
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
-
- // Close the consumer.
- CloseConsumer();
-
- // It should now be never-writable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(producer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-}
-
-TEST_F(DataPipeTest, PeerClosedProducerWaiting) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 2 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Close the consumer.
- CloseConsumer();
-
- // It should be signaled.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(producer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-}
-
-TEST_F(DataPipeTest, PeerClosedConsumerWaiting) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 2 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Close the producer.
- CloseProducer();
-
- // It should be signaled.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-}
-
-TEST_F(DataPipeTest, BasicConsumerWaiting) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Never writable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
- EXPECT_EQ(0u, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Write two elements.
- int32_t elements[2] = {123, 456};
- uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
-
- // Wait for readability.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Discard one element.
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, DiscardData(&num_bytes, true));
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
-
- // Should still be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Peek one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, true, true));
- ASSERT_EQ(456, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Should still be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Read one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, true));
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
- ASSERT_EQ(456, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Write one element.
- elements[0] = 789;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
-
- // Waiting should now succeed.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Close the producer.
- CloseProducer();
-
- // Should still be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_TRUE(hss.satisfied_signals & (MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Wait for the peer closed signal.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Read one element.
- elements[0] = -1;
- elements[1] = -1;
- num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(elements, &num_bytes, true));
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
- ASSERT_EQ(789, elements[0]);
- ASSERT_EQ(-1, elements[1]);
-
- // Should be never-readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-}
-
-TEST_F(DataPipeTest, ConsumerNewDataReadable) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- EXPECT_EQ(MOJO_RESULT_OK, Create(&options));
-
- int32_t elements[2] = {123, 456};
- uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- EXPECT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
-
- // The consumer handle should appear to be readable and have new data.
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE));
- EXPECT_TRUE(GetSignalsState(consumer_).satisfied_signals &
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE);
-
- // Now try to read a minimum of 6 elements.
- int32_t read_elements[6];
- uint32_t num_read_bytes = sizeof(read_elements);
- EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- MojoReadData(consumer_, read_elements, &num_read_bytes,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE));
-
- // The consumer should still appear to be readable but not with new data.
- EXPECT_TRUE(GetSignalsState(consumer_).satisfied_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
- EXPECT_FALSE(GetSignalsState(consumer_).satisfied_signals &
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE);
-
- // Write four more elements.
- EXPECT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
- EXPECT_EQ(MOJO_RESULT_OK, WriteData(elements, &num_bytes, true));
-
- // The consumer handle should once again appear to be readable.
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE));
-
- // Try again to read a minimum of 6 elements. Should succeed this time.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoReadData(consumer_, read_elements, &num_read_bytes,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE));
-
- // And now the consumer is unreadable.
- EXPECT_FALSE(GetSignalsState(consumer_).satisfied_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
- EXPECT_FALSE(GetSignalsState(consumer_).satisfied_signals &
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE);
-}
-
-// Test with two-phase APIs and also closing the producer with an active
-// consumer waiter.
-TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Write two elements.
- int32_t* elements = nullptr;
- void* buffer = nullptr;
- // Request room for three (but we'll only write two).
- uint32_t num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&buffer, &num_bytes, false));
- EXPECT_TRUE(buffer);
- EXPECT_GE(num_bytes, static_cast<uint32_t>(3u * sizeof(elements[0])));
- elements = static_cast<int32_t*>(buffer);
- elements[0] = 123;
- elements[1] = 456;
- ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(2u * sizeof(elements[0])));
-
- // Wait for readability.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Read one element.
- // Request two in all-or-none mode, but only read one.
- const void* read_buffer = nullptr;
- num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_buffer, &num_bytes, true));
- EXPECT_TRUE(read_buffer);
- ASSERT_EQ(static_cast<uint32_t>(2u * sizeof(elements[0])), num_bytes);
- const int32_t* read_elements = static_cast<const int32_t*>(read_buffer);
- ASSERT_EQ(123, read_elements[0]);
- ASSERT_EQ(MOJO_RESULT_OK, EndReadData(1u * sizeof(elements[0])));
-
- // Should still be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Read one element.
- // Request three, but not in all-or-none mode.
- read_buffer = nullptr;
- num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0]));
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_buffer, &num_bytes));
- EXPECT_TRUE(read_buffer);
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(elements[0])), num_bytes);
- read_elements = static_cast<const int32_t*>(read_buffer);
- ASSERT_EQ(456, read_elements[0]);
- ASSERT_EQ(MOJO_RESULT_OK, EndReadData(1u * sizeof(elements[0])));
-
- // Close the producer.
- CloseProducer();
-
- // Should be never-readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-}
-
-// Tests that data pipes aren't writable/readable during two-phase writes/reads.
-TEST_F(DataPipeTest, BasicTwoPhaseWaiting) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // It should be writable.
- hss = GetSignalsState(producer_);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- uint32_t num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
- void* write_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_ptr, &num_bytes));
- EXPECT_TRUE(write_ptr);
- EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t)));
-
- // At this point, it shouldn't be writable.
- hss = GetSignalsState(producer_);
- ASSERT_EQ(0u, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // It shouldn't be readable yet either (we'll wait later).
- hss = GetSignalsState(consumer_);
- ASSERT_EQ(0u, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- static_cast<int32_t*>(write_ptr)[0] = 123;
- ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(1u * sizeof(int32_t)));
-
- // It should immediately be writable again.
- hss = GetSignalsState(producer_);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // It should become readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Start another two-phase write and check that it's readable even in the
- // middle of it.
- num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
- write_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_ptr, &num_bytes));
- EXPECT_TRUE(write_ptr);
- EXPECT_GE(num_bytes, static_cast<uint32_t>(1u * sizeof(int32_t)));
-
- // It should be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // End the two-phase write without writing anything.
- ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(0u));
-
- // Start a two-phase read.
- num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t));
- const void* read_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_ptr, &num_bytes));
- EXPECT_TRUE(read_ptr);
- ASSERT_EQ(static_cast<uint32_t>(1u * sizeof(int32_t)), num_bytes);
-
- // At this point, it should still be writable.
- hss = GetSignalsState(producer_);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // But not readable.
- hss = GetSignalsState(consumer_);
- ASSERT_EQ(0u, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // End the two-phase read without reading anything.
- ASSERT_EQ(MOJO_RESULT_OK, EndReadData(0u));
-
- // It should be readable again.
- hss = GetSignalsState(consumer_);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-}
-
-void Seq(int32_t start, size_t count, int32_t* out) {
- for (size_t i = 0; i < count; i++)
- out[i] = start + static_cast<int32_t>(i);
-}
-
-TEST_F(DataPipeTest, AllOrNone) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 10 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Try writing more than the total capacity of the pipe.
- uint32_t num_bytes = 20u * sizeof(int32_t);
- int32_t buffer[100];
- Seq(0, arraysize(buffer), buffer);
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, WriteData(buffer, &num_bytes, true));
-
- // Should still be empty.
- num_bytes = ~0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-
- // Write some data.
- num_bytes = 5u * sizeof(int32_t);
- Seq(100, arraysize(buffer), buffer);
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(buffer, &num_bytes, true));
- ASSERT_EQ(5u * sizeof(int32_t), num_bytes);
-
- // Wait for data.
- // TODO(vtl): There's no real guarantee that all the data will become
- // 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.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // Half full.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(5u * sizeof(int32_t), num_bytes);
-
- // Try writing more than the available capacity of the pipe, but less than the
- // total capacity.
- num_bytes = 6u * sizeof(int32_t);
- Seq(200, arraysize(buffer), buffer);
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, WriteData(buffer, &num_bytes, true));
-
- // Try reading too much.
- num_bytes = 11u * sizeof(int32_t);
- memset(buffer, 0xab, sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, ReadData(buffer, &num_bytes, true));
- int32_t expected_buffer[100];
- memset(expected_buffer, 0xab, sizeof(expected_buffer));
- ASSERT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
-
- // Try discarding too much.
- num_bytes = 11u * sizeof(int32_t);
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, DiscardData(&num_bytes, true));
-
- // Just a little.
- num_bytes = 2u * sizeof(int32_t);
- Seq(300, arraysize(buffer), buffer);
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(buffer, &num_bytes, true));
- ASSERT_EQ(2u * sizeof(int32_t), num_bytes);
-
- // Just right.
- num_bytes = 3u * sizeof(int32_t);
- Seq(400, arraysize(buffer), buffer);
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(buffer, &num_bytes, true));
- ASSERT_EQ(3u * sizeof(int32_t), num_bytes);
-
- // TODO(vtl): Hack (see also the TODO above): We can't currently wait for a
- // specified amount of data to be available, so poll.
- for (size_t i = 0; i < kMaxPoll; i++) {
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- if (num_bytes >= 10u * sizeof(int32_t))
- break;
-
- test::Sleep(test::EpsilonDeadline());
- }
- ASSERT_EQ(10u * sizeof(int32_t), num_bytes);
-
- // Read half.
- num_bytes = 5u * sizeof(int32_t);
- memset(buffer, 0xab, sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(buffer, &num_bytes, true));
- ASSERT_EQ(5u * sizeof(int32_t), num_bytes);
- memset(expected_buffer, 0xab, sizeof(expected_buffer));
- Seq(100, 5, expected_buffer);
- ASSERT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
-
- // Try reading too much again.
- num_bytes = 6u * sizeof(int32_t);
- memset(buffer, 0xab, sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, ReadData(buffer, &num_bytes, true));
- memset(expected_buffer, 0xab, sizeof(expected_buffer));
- ASSERT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
-
- // Try discarding too much again.
- num_bytes = 6u * sizeof(int32_t);
- ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, DiscardData(&num_bytes, true));
-
- // Discard a little.
- num_bytes = 2u * sizeof(int32_t);
- ASSERT_EQ(MOJO_RESULT_OK, DiscardData(&num_bytes, true));
- ASSERT_EQ(2u * sizeof(int32_t), num_bytes);
-
- // Three left.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(3u * sizeof(int32_t), num_bytes);
-
- // Close the producer, then test producer-closed cases.
- CloseProducer();
-
- // Wait.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // Try reading too much; "failed precondition" since the producer is closed.
- num_bytes = 4u * sizeof(int32_t);
- memset(buffer, 0xab, sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- ReadData(buffer, &num_bytes, true));
- memset(expected_buffer, 0xab, sizeof(expected_buffer));
- ASSERT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
-
- // Try discarding too much; "failed precondition" again.
- num_bytes = 4u * sizeof(int32_t);
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, DiscardData(&num_bytes, true));
-
- // Read a little.
- num_bytes = 2u * sizeof(int32_t);
- memset(buffer, 0xab, sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(buffer, &num_bytes, true));
- ASSERT_EQ(2u * sizeof(int32_t), num_bytes);
- memset(expected_buffer, 0xab, sizeof(expected_buffer));
- Seq(400, 2, expected_buffer);
- ASSERT_EQ(0, memcmp(buffer, expected_buffer, sizeof(buffer)));
-
- // Discard the remaining element.
- num_bytes = 1u * sizeof(int32_t);
- ASSERT_EQ(MOJO_RESULT_OK, DiscardData(&num_bytes, true));
- ASSERT_EQ(1u * sizeof(int32_t), num_bytes);
-
- // Empty again.
- num_bytes = ~0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-}
-
-// Tests that |ProducerWriteData()| and |ConsumerReadData()| writes and reads,
-// respectively, as much as possible, even if it may have to "wrap around" the
-// internal circular buffer. (Note that the two-phase write and read need not do
-// this.)
-TEST_F(DataPipeTest, WrapAround) {
- unsigned char test_data[1000];
- for (size_t i = 0; i < arraysize(test_data); i++)
- test_data[i] = static_cast<unsigned char>(i);
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 100u // |capacity_num_bytes|.
- };
-
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Write 20 bytes.
- uint32_t num_bytes = 20u;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(&test_data[0], &num_bytes, true));
- ASSERT_EQ(20u, num_bytes);
-
- // Wait for data.
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_TRUE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Read 10 bytes.
- unsigned char read_buffer[1000] = {0};
- num_bytes = 10u;
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(read_buffer, &num_bytes, true));
- ASSERT_EQ(10u, num_bytes);
- ASSERT_EQ(0, memcmp(read_buffer, &test_data[0], 10u));
-
- // Check that a two-phase write can now only write (at most) 80 bytes. (This
- // checks an implementation detail; this behavior is not guaranteed.)
- void* write_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginWriteData(&write_buffer_ptr, &num_bytes, false));
- EXPECT_TRUE(write_buffer_ptr);
- ASSERT_EQ(80u, num_bytes);
- ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(0));
-
- size_t total_num_bytes = 0;
- while (total_num_bytes < 90) {
- // Wait to write.
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(producer_, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
- ASSERT_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_WRITABLE);
- ASSERT_EQ(hss.satisfiable_signals,
- MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- // Write as much as we can.
- num_bytes = 100;
- ASSERT_EQ(MOJO_RESULT_OK,
- WriteData(&test_data[20 + total_num_bytes], &num_bytes, false));
- total_num_bytes += num_bytes;
- }
-
- ASSERT_EQ(90u, total_num_bytes);
-
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(100u, num_bytes);
-
- // Check that a two-phase read can now only read (at most) 90 bytes. (This
- // checks an implementation detail; this behavior is not guaranteed.)
- const void* read_buffer_ptr = nullptr;
- num_bytes = 0;
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_buffer_ptr, &num_bytes, false));
- EXPECT_TRUE(read_buffer_ptr);
- ASSERT_EQ(90u, num_bytes);
- ASSERT_EQ(MOJO_RESULT_OK, EndReadData(0));
-
- // Read as much as possible. We should read 100 bytes.
- num_bytes = static_cast<uint32_t>(arraysize(read_buffer) *
- sizeof(read_buffer[0]));
- memset(read_buffer, 0, num_bytes);
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(read_buffer, &num_bytes));
- ASSERT_EQ(100u, num_bytes);
- ASSERT_EQ(0, memcmp(read_buffer, &test_data[10], 100u));
-}
-
-// Tests the behavior of writing (simple and two-phase), closing the producer,
-// then reading (simple and two-phase).
-TEST_F(DataPipeTest, WriteCloseProducerRead) {
- const char kTestData[] = "hello world";
- const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData));
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 1000u // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
-
- // Write some data, so we'll have something to read.
- uint32_t num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kTestData, &num_bytes, false));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Write it again, so we'll have something left over.
- num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kTestData, &num_bytes, false));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Start two-phase write.
- void* write_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginWriteData(&write_buffer_ptr, &num_bytes, false));
- EXPECT_TRUE(write_buffer_ptr);
- EXPECT_GT(num_bytes, 0u);
-
- // TODO(vtl): (See corresponding TODO in TwoPhaseAllOrNone.)
- for (size_t i = 0; i < kMaxPoll; i++) {
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- if (num_bytes >= 2u * kTestDataSize)
- break;
-
- test::Sleep(test::EpsilonDeadline());
- }
- ASSERT_EQ(2u * kTestDataSize, num_bytes);
-
- // Start two-phase read.
- const void* read_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginReadData(&read_buffer_ptr, &num_bytes));
- EXPECT_TRUE(read_buffer_ptr);
- ASSERT_EQ(2u * kTestDataSize, num_bytes);
-
- // Close the producer.
- CloseProducer();
-
- // The consumer can finish its two-phase read.
- ASSERT_EQ(0, memcmp(read_buffer_ptr, kTestData, kTestDataSize));
- ASSERT_EQ(MOJO_RESULT_OK, EndReadData(kTestDataSize));
-
- // And start another.
- read_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginReadData(&read_buffer_ptr, &num_bytes));
- EXPECT_TRUE(read_buffer_ptr);
- ASSERT_EQ(kTestDataSize, num_bytes);
-}
-
-
-// Tests the behavior of interrupting a two-phase read and write by closing the
-// consumer.
-TEST_F(DataPipeTest, TwoPhaseWriteReadCloseConsumer) {
- const char kTestData[] = "hello world";
- const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData));
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 1000u // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Write some data, so we'll have something to read.
- uint32_t num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kTestData, &num_bytes));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Start two-phase write.
- void* write_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_buffer_ptr, &num_bytes));
- EXPECT_TRUE(write_buffer_ptr);
- ASSERT_GT(num_bytes, kTestDataSize);
-
- // Wait for data.
- // TODO(vtl): (See corresponding TODO in AllOrNone.)
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Start two-phase read.
- const void* read_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_buffer_ptr, &num_bytes));
- EXPECT_TRUE(read_buffer_ptr);
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Close the consumer.
- CloseConsumer();
-
- // Wait for producer to know that the consumer is closed.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(producer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-
- // Actually write some data. (Note: Premature freeing of the buffer would
- // probably only be detected under ASAN or similar.)
- memcpy(write_buffer_ptr, kTestData, kTestDataSize);
- // Note: Even though the consumer has been closed, ending the two-phase
- // write will report success.
- ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(kTestDataSize));
-
- // But trying to write should result in failure.
- num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, WriteData(kTestData, &num_bytes));
-
- // As will trying to start another two-phase write.
- write_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- BeginWriteData(&write_buffer_ptr, &num_bytes));
-}
-
-// Tests the behavior of "interrupting" a two-phase write by closing both the
-// producer and the consumer.
-TEST_F(DataPipeTest, TwoPhaseWriteCloseBoth) {
- const uint32_t kTestDataSize = 15u;
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 1000u // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
-
- // Start two-phase write.
- void* write_buffer_ptr = nullptr;
- uint32_t num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_buffer_ptr, &num_bytes));
- EXPECT_TRUE(write_buffer_ptr);
- ASSERT_GT(num_bytes, kTestDataSize);
-}
-
-// Tests the behavior of writing, closing the producer, and then reading (with
-// and without data remaining).
-TEST_F(DataPipeTest, WriteCloseProducerReadNoData) {
- const char kTestData[] = "hello world";
- const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData));
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 1000u // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Write some data, so we'll have something to read.
- uint32_t num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kTestData, &num_bytes));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Close the producer.
- CloseProducer();
-
- // Wait. (Note that once the consumer knows that the producer is closed, it
- // must also know about all the data that was sent.)
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Peek that data.
- char buffer[1000];
- num_bytes = static_cast<uint32_t>(sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(buffer, &num_bytes, false, true));
- ASSERT_EQ(kTestDataSize, num_bytes);
- ASSERT_EQ(0, memcmp(buffer, kTestData, kTestDataSize));
-
- // Read that data.
- memset(buffer, 0, 1000);
- num_bytes = static_cast<uint32_t>(sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(buffer, &num_bytes));
- ASSERT_EQ(kTestDataSize, num_bytes);
- ASSERT_EQ(0, memcmp(buffer, kTestData, kTestDataSize));
-
- // A second read should fail.
- num_bytes = static_cast<uint32_t>(sizeof(buffer));
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ReadData(buffer, &num_bytes));
-
- // A two-phase read should also fail.
- const void* read_buffer_ptr = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- BeginReadData(&read_buffer_ptr, &num_bytes));
-
- // Ditto for discard.
- num_bytes = 10u;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, DiscardData(&num_bytes));
-}
-
-// Test that during a two phase read the memory stays valid even if more data
-// comes in.
-TEST_F(DataPipeTest, TwoPhaseReadMemoryStable) {
- const char kTestData[] = "hello world";
- const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData));
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 1000u // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Write some data.
- uint32_t num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kTestData, &num_bytes));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Wait for the data.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Begin a two-phase read.
- const void* read_buffer_ptr = nullptr;
- uint32_t read_buffer_size = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_buffer_ptr, &read_buffer_size));
-
- // Write more data.
- const char kExtraData[] = "bye world";
- const uint32_t kExtraDataSize = static_cast<uint32_t>(sizeof(kExtraData));
- num_bytes = kExtraDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kExtraData, &num_bytes));
- ASSERT_EQ(kExtraDataSize, num_bytes);
-
- // Close the producer.
- CloseProducer();
-
- // Wait. (Note that once the consumer knows that the producer is closed, it
- // must also have received the extra data).
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Read the two phase memory to check it's still valid.
- ASSERT_EQ(0, memcmp(read_buffer_ptr, kTestData, kTestDataSize));
- EndReadData(read_buffer_size);
-}
-
-// Test that two-phase reads/writes behave correctly when given invalid
-// arguments.
-TEST_F(DataPipeTest, TwoPhaseMoreInvalidArguments) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 10 * sizeof(int32_t) // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // No data.
- uint32_t num_bytes = 1000u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-
- // Try "ending" a two-phase write when one isn't active.
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- EndWriteData(1u * sizeof(int32_t)));
-
- // Wait a bit, to make sure that if a signal were (incorrectly) sent, it'd
- // have time to propagate.
- test::Sleep(test::EpsilonDeadline());
-
- // Still no data.
- num_bytes = 1000u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-
- // Try ending a two-phase write with an invalid amount (too much).
- num_bytes = 0u;
- void* write_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_ptr, &num_bytes));
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- EndWriteData(num_bytes + static_cast<uint32_t>(sizeof(int32_t))));
-
- // But the two-phase write still ended.
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, EndWriteData(0u));
-
- // Wait a bit (as above).
- test::Sleep(test::EpsilonDeadline());
-
- // Still no data.
- num_bytes = 1000u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-
- // Try ending a two-phase write with an invalid amount (not a multiple of the
- // element size).
- num_bytes = 0u;
- write_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_ptr, &num_bytes));
- EXPECT_GE(num_bytes, 1u);
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, EndWriteData(1u));
-
- // But the two-phase write still ended.
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, EndWriteData(0u));
-
- // Wait a bit (as above).
- test::Sleep(test::EpsilonDeadline());
-
- // Still no data.
- num_bytes = 1000u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(0u, num_bytes);
-
- // Now write some data, so we'll be able to try reading.
- int32_t element = 123;
- num_bytes = 1u * sizeof(int32_t);
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(&element, &num_bytes));
-
- // Wait for data.
- // TODO(vtl): (See corresponding TODO in AllOrNone.)
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // One element available.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(1u * sizeof(int32_t), num_bytes);
-
- // Try "ending" a two-phase read when one isn't active.
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, EndReadData(1u * sizeof(int32_t)));
-
- // Still one element available.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(1u * sizeof(int32_t), num_bytes);
-
- // Try ending a two-phase read with an invalid amount (too much).
- num_bytes = 0u;
- const void* read_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_ptr, &num_bytes));
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- EndReadData(num_bytes + static_cast<uint32_t>(sizeof(int32_t))));
-
- // Still one element available.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(1u * sizeof(int32_t), num_bytes);
-
- // Try ending a two-phase read with an invalid amount (not a multiple of the
- // element size).
- num_bytes = 0u;
- read_ptr = nullptr;
- ASSERT_EQ(MOJO_RESULT_OK, BeginReadData(&read_ptr, &num_bytes));
- ASSERT_EQ(1u * sizeof(int32_t), num_bytes);
- ASSERT_EQ(123, static_cast<const int32_t*>(read_ptr)[0]);
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, EndReadData(1u));
-
- // Still one element available.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK, QueryData(&num_bytes));
- ASSERT_EQ(1u * sizeof(int32_t), num_bytes);
-}
-
-// Test that a producer can be sent over a MP.
-TEST_F(DataPipeTest, SendProducer) {
- const char kTestData[] = "hello world";
- const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData));
-
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1u, // |element_num_bytes|.
- 1000u // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
- MojoHandleSignalsState hss;
-
- // Write some data.
- uint32_t num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kTestData, &num_bytes));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Wait for the data.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Check the data.
- const void* read_buffer = nullptr;
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginReadData(&read_buffer, &num_bytes, false));
- ASSERT_EQ(0, memcmp(read_buffer, kTestData, kTestDataSize));
- EndReadData(num_bytes);
-
- // Now send the producer over a MP so that it's serialized.
- MojoHandle pipe0, pipe1;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateMessagePipe(nullptr, &pipe0, &pipe1));
-
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(pipe0, nullptr, 0, &producer_, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- producer_ = MOJO_HANDLE_INVALID;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- uint32_t num_handles = 1;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessage(pipe1, nullptr, 0, &producer_, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(num_handles, 1u);
-
- // Write more data.
- const char kExtraData[] = "bye world";
- const uint32_t kExtraDataSize = static_cast<uint32_t>(sizeof(kExtraData));
- num_bytes = kExtraDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kExtraData, &num_bytes));
- ASSERT_EQ(kExtraDataSize, num_bytes);
-
- // Wait for it.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- hss.satisfiable_signals);
-
- // Check the second write.
- num_bytes = 0u;
- ASSERT_EQ(MOJO_RESULT_OK,
- BeginReadData(&read_buffer, &num_bytes, false));
- ASSERT_EQ(0, memcmp(read_buffer, kExtraData, kExtraDataSize));
- EndReadData(num_bytes);
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipe0));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipe1));
-}
-
-// Ensures that if a data pipe consumer whose producer has closed is passed over
-// a message pipe, the deserialized dispatcher is also marked as having a closed
-// peer.
-TEST_F(DataPipeTest, ConsumerWithClosedProducerSent) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|.
- 1000 * sizeof(int32_t) // |capacity_num_bytes|.
- };
-
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
-
- // We can write to a data pipe handle immediately.
- int32_t data = 123;
- uint32_t num_bytes = sizeof(data);
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(&data, &num_bytes));
- ASSERT_EQ(MOJO_RESULT_OK, CloseProducer());
-
- // Now wait for the other side to become readable and to see the peer closed.
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- state.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- state.satisfiable_signals);
-
- // Now send the consumer over a MP so that it's serialized.
- MojoHandle pipe0, pipe1;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateMessagePipe(nullptr, &pipe0, &pipe1));
-
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(pipe0, nullptr, 0, &consumer_, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- consumer_ = MOJO_HANDLE_INVALID;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1, MOJO_HANDLE_SIGNAL_READABLE, &state));
- uint32_t num_handles = 1;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessage(pipe1, nullptr, 0, &consumer_, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(num_handles, 1u);
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED |
- MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- state.satisfiable_signals);
-
- int32_t read_data;
- ASSERT_EQ(MOJO_RESULT_OK, ReadData(&read_data, &num_bytes));
- ASSERT_EQ(sizeof(read_data), num_bytes);
- ASSERT_EQ(data, read_data);
-
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipe0));
- ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipe1));
-}
-
-bool WriteAllData(MojoHandle producer,
- const void* elements,
- uint32_t num_bytes) {
- for (size_t i = 0; i < kMaxPoll; i++) {
- // Write as much data as we can.
- uint32_t write_bytes = num_bytes;
- MojoResult result = MojoWriteData(producer, elements, &write_bytes,
- MOJO_WRITE_DATA_FLAG_NONE);
- if (result == MOJO_RESULT_OK) {
- num_bytes -= write_bytes;
- elements = static_cast<const uint8_t*>(elements) + write_bytes;
- if (num_bytes == 0)
- return true;
- } else {
- EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, result);
- }
-
- MojoHandleSignalsState hss = MojoHandleSignalsState();
- EXPECT_EQ(MOJO_RESULT_OK, test::MojoTestBase::WaitForSignals(
- producer, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
- }
-
- return false;
-}
-
-// If |expect_empty| is true, expect |consumer| to be empty after reading.
-bool ReadAllData(MojoHandle consumer,
- void* elements,
- uint32_t num_bytes,
- bool expect_empty) {
- for (size_t i = 0; i < kMaxPoll; i++) {
- // Read as much data as we can.
- uint32_t read_bytes = num_bytes;
- MojoResult result =
- MojoReadData(consumer, elements, &read_bytes, MOJO_READ_DATA_FLAG_NONE);
- if (result == MOJO_RESULT_OK) {
- num_bytes -= read_bytes;
- elements = static_cast<uint8_t*>(elements) + read_bytes;
- if (num_bytes == 0) {
- if (expect_empty) {
- // Expect no more data.
- test::Sleep(test::TinyDeadline());
- MojoReadData(consumer, nullptr, &num_bytes,
- MOJO_READ_DATA_FLAG_QUERY);
- EXPECT_EQ(0u, num_bytes);
- }
- return true;
- }
- } else {
- EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, result);
- }
-
- MojoHandleSignalsState hss = MojoHandleSignalsState();
- EXPECT_EQ(MOJO_RESULT_OK, test::MojoTestBase::WaitForSignals(
- consumer, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- // Peer could have become closed while we're still waiting for data.
- EXPECT_TRUE(MOJO_HANDLE_SIGNAL_READABLE & hss.satisfied_signals);
- EXPECT_TRUE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
- EXPECT_TRUE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- }
-
- return num_bytes == 0;
-}
-
-#if !defined(OS_IOS)
-
-TEST_F(DataPipeTest, Multiprocess) {
- const uint32_t kTestDataSize =
- static_cast<uint32_t>(sizeof(kMultiprocessTestData));
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1, // |element_num_bytes|.
- kMultiprocessCapacity // |capacity_num_bytes|.
- };
- ASSERT_EQ(MOJO_RESULT_OK, Create(&options));
-
- RUN_CHILD_ON_PIPE(MultiprocessClient, server_mp)
- // Send some data before serialising and sending the data pipe over.
- // This is the first write so we don't need to use WriteAllData.
- uint32_t num_bytes = kTestDataSize;
- ASSERT_EQ(MOJO_RESULT_OK, WriteData(kMultiprocessTestData, &num_bytes,
- MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
- ASSERT_EQ(kTestDataSize, num_bytes);
-
- // Send child process the data pipe.
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(server_mp, nullptr, 0, &consumer_, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Send a bunch of data of varying sizes.
- uint8_t buffer[100];
- int seq = 0;
- for (int i = 0; i < kMultiprocessMaxIter; ++i) {
- for (uint32_t size = 1; size <= kMultiprocessCapacity; size++) {
- for (unsigned int j = 0; j < size; ++j)
- buffer[j] = seq + j;
- EXPECT_TRUE(WriteAllData(producer_, buffer, size));
- seq += size;
- }
- }
-
- // Write the test string in again.
- ASSERT_TRUE(WriteAllData(producer_, kMultiprocessTestData, kTestDataSize));
-
- // Swap ends.
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(server_mp, nullptr, 0, &producer_, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Receive the consumer from the other side.
- producer_ = MOJO_HANDLE_INVALID;
- MojoHandleSignalsState hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(server_mp, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- MojoHandle handles[2];
- uint32_t num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessage(server_mp, nullptr, 0, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, num_handles);
- consumer_ = handles[0];
-
- // Read the test string twice. Once for when we sent it, and once for the
- // other end sending it.
- for (int i = 0; i < 2; ++i) {
- EXPECT_TRUE(ReadAllData(consumer_, buffer, kTestDataSize, i == 1));
- EXPECT_EQ(0, memcmp(buffer, kMultiprocessTestData, kTestDataSize));
- }
-
- WriteMessage(server_mp, "quit");
-
- // Don't have to close the consumer here because it will be done for us.
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessClient, DataPipeTest, client_mp) {
- const uint32_t kTestDataSize =
- static_cast<uint32_t>(sizeof(kMultiprocessTestData));
-
- // Receive the data pipe from the other side.
- MojoHandle consumer = MOJO_HANDLE_INVALID;
- MojoHandleSignalsState hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(client_mp, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- MojoHandle handles[2];
- uint32_t num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessage(client_mp, nullptr, 0, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, num_handles);
- consumer = handles[0];
-
- // Read the initial string that was sent.
- int32_t buffer[100];
- EXPECT_TRUE(ReadAllData(consumer, buffer, kTestDataSize, false));
- EXPECT_EQ(0, memcmp(buffer, kMultiprocessTestData, kTestDataSize));
-
- // Receive the main data and check it is correct.
- int seq = 0;
- uint8_t expected_buffer[100];
- for (int i = 0; i < kMultiprocessMaxIter; ++i) {
- for (uint32_t size = 1; size <= kMultiprocessCapacity; ++size) {
- for (unsigned int j = 0; j < size; ++j)
- expected_buffer[j] = seq + j;
- EXPECT_TRUE(ReadAllData(consumer, buffer, size, false));
- EXPECT_EQ(0, memcmp(buffer, expected_buffer, size));
-
- seq += size;
- }
- }
-
- // Swap ends.
- ASSERT_EQ(MOJO_RESULT_OK, MojoWriteMessage(client_mp, nullptr, 0, &consumer,
- 1, MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Receive the producer from the other side.
- MojoHandle producer = MOJO_HANDLE_INVALID;
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(client_mp, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- num_handles = arraysize(handles);
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessage(client_mp, nullptr, 0, handles, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_EQ(1u, num_handles);
- producer = handles[0];
-
- // Write the test string one more time.
- EXPECT_TRUE(WriteAllData(producer, kMultiprocessTestData, kTestDataSize));
-
- // We swapped ends, so close the producer.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
-
- // Wait to receive a "quit" message before exiting.
- EXPECT_EQ("quit", ReadMessage(client_mp));
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteAndCloseProducer, DataPipeTest, h) {
- MojoHandle p;
- std::string message = ReadMessageWithHandles(h, &p, 1);
-
- // Write some data to the producer and close it.
- uint32_t num_bytes = static_cast<uint32_t>(message.size());
- EXPECT_EQ(MOJO_RESULT_OK, MojoWriteData(p, message.data(), &num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE));
- EXPECT_EQ(num_bytes, static_cast<uint32_t>(message.size()));
-
- // Close the producer before quitting.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(p));
-
- // Wait for a quit message.
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndCloseConsumer, DataPipeTest, h) {
- MojoHandle c;
- std::string expected_message = ReadMessageWithHandles(h, &c, 1);
-
- // Wait for the consumer to become readable.
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(c, MOJO_HANDLE_SIGNAL_READABLE));
-
- // Drain the consumer and expect to find the given message.
- uint32_t num_bytes = static_cast<uint32_t>(expected_message.size());
- std::vector<char> bytes(expected_message.size());
- EXPECT_EQ(MOJO_RESULT_OK, MojoReadData(c, bytes.data(), &num_bytes,
- MOJO_READ_DATA_FLAG_NONE));
- EXPECT_EQ(num_bytes, static_cast<uint32_t>(bytes.size()));
-
- std::string message(bytes.data(), bytes.size());
- EXPECT_EQ(expected_message, message);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
-
- // Wait for a quit message.
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_F(DataPipeTest, SendConsumerAndCloseProducer) {
- // Create a new data pipe.
- MojoHandle p, c;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(nullptr, &p ,&c));
-
- RUN_CHILD_ON_PIPE(WriteAndCloseProducer, producer_client)
- RUN_CHILD_ON_PIPE(ReadAndCloseConsumer, consumer_client)
- const std::string kMessage = "Hello, world!";
- WriteMessageWithHandles(producer_client, kMessage, &p, 1);
- WriteMessageWithHandles(consumer_client, kMessage, &c, 1);
-
- WriteMessage(consumer_client, "quit");
- END_CHILD()
-
- WriteMessage(producer_client, "quit");
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndWrite, DataPipeTest, h) {
- const MojoCreateDataPipeOptions options = {
- kSizeOfOptions, // |struct_size|.
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|.
- 1, // |element_num_bytes|.
- kMultiprocessCapacity // |capacity_num_bytes|.
- };
-
- MojoHandle p, c;
- ASSERT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(&options, &p, &c));
-
- const std::string kMessage = "Hello, world!";
- WriteMessageWithHandles(h, kMessage, &c, 1);
-
- // Write some data to the producer and close it.
- uint32_t num_bytes = static_cast<uint32_t>(kMessage.size());
- EXPECT_EQ(MOJO_RESULT_OK, MojoWriteData(p, kMessage.data(), &num_bytes,
- MOJO_WRITE_DATA_FLAG_NONE));
- EXPECT_EQ(num_bytes, static_cast<uint32_t>(kMessage.size()));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(p));
-
- // Wait for a quit message.
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_F(DataPipeTest, CreateInChild) {
- RUN_CHILD_ON_PIPE(CreateAndWrite, child)
- MojoHandle c;
- std::string expected_message = ReadMessageWithHandles(child, &c, 1);
-
- // Wait for the consumer to become readable.
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(c, MOJO_HANDLE_SIGNAL_READABLE));
-
- // Drain the consumer and expect to find the given message.
- uint32_t num_bytes = static_cast<uint32_t>(expected_message.size());
- std::vector<char> bytes(expected_message.size());
- EXPECT_EQ(MOJO_RESULT_OK, MojoReadData(c, bytes.data(), &num_bytes,
- MOJO_READ_DATA_FLAG_NONE));
- EXPECT_EQ(num_bytes, static_cast<uint32_t>(bytes.size()));
-
- std::string message(bytes.data(), bytes.size());
- EXPECT_EQ(expected_message, message);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- WriteMessage(child, "quit");
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(DataPipeStatusChangeInTransitClient,
- DataPipeTest, parent) {
- // This test verifies that peer closure is detectable through various
- // mechanisms when it races with handle transfer.
-
- MojoHandle handles[6];
- EXPECT_EQ("o_O", ReadMessageWithHandles(parent, handles, 6));
- MojoHandle* producers = &handles[0];
- MojoHandle* consumers = &handles[3];
-
- // Wait on producer 0
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(producers[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- // Wait on consumer 0
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(consumers[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- base::MessageLoop message_loop;
-
- // Wait on producer 1 and consumer 1 using SimpleWatchers.
- {
- base::RunLoop run_loop;
- int count = 0;
- auto callback = base::Bind(
- [] (base::RunLoop* loop, int* count, MojoResult result) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- if (++*count == 2)
- loop->Quit();
- },
- &run_loop, &count);
- SimpleWatcher producer_watcher(FROM_HERE,
- SimpleWatcher::ArmingPolicy::AUTOMATIC);
- SimpleWatcher consumer_watcher(FROM_HERE,
- SimpleWatcher::ArmingPolicy::AUTOMATIC);
- producer_watcher.Watch(Handle(producers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- callback);
- consumer_watcher.Watch(Handle(consumers[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- callback);
- run_loop.Run();
- EXPECT_EQ(2, count);
- }
-
- // Wait on producer 2 by polling with MojoWriteData.
- MojoResult result;
- do {
- uint32_t num_bytes = 0;
- result = MojoWriteData(
- producers[2], nullptr, &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
- } while (result == MOJO_RESULT_OK);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
-
- // Wait on consumer 2 by polling with MojoReadData.
- do {
- char byte;
- uint32_t num_bytes = 1;
- result = MojoReadData(
- consumers[2], &byte, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
- } while (result == MOJO_RESULT_SHOULD_WAIT);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
-
- for (size_t i = 0; i < 6; ++i)
- CloseHandle(handles[i]);
-}
-
-TEST_F(DataPipeTest, StatusChangeInTransit) {
- MojoHandle producers[6];
- MojoHandle consumers[6];
- for (size_t i = 0; i < 6; ++i)
- CreateDataPipe(&producers[i], &consumers[i], 1);
-
- RUN_CHILD_ON_PIPE(DataPipeStatusChangeInTransitClient, child)
- MojoHandle handles[] = { producers[0], producers[1], producers[2],
- consumers[3], consumers[4], consumers[5] };
-
- // Send 3 producers and 3 consumers, and let their transfer race with their
- // peers' closure.
- WriteMessageWithHandles(child, "o_O", handles, 6);
-
- for (size_t i = 0; i < 3; ++i)
- CloseHandle(consumers[i]);
- for (size_t i = 3; i < 6; ++i)
- CloseHandle(producers[i]);
- END_CHILD()
-}
-
-#endif // !defined(OS_IOS)
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/dispatcher.cc b/mojo/edk/system/dispatcher.cc
deleted file mode 100644
index 7cdbe91..0000000
--- a/mojo/edk/system/dispatcher.cc
+++ /dev/null
@@ -1,198 +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/dispatcher.h"
-
-#include "base/logging.h"
-#include "mojo/edk/system/configuration.h"
-#include "mojo/edk/system/data_pipe_consumer_dispatcher.h"
-#include "mojo/edk/system/data_pipe_producer_dispatcher.h"
-#include "mojo/edk/system/message_pipe_dispatcher.h"
-#include "mojo/edk/system/platform_handle_dispatcher.h"
-#include "mojo/edk/system/shared_buffer_dispatcher.h"
-
-namespace mojo {
-namespace edk {
-
-Dispatcher::DispatcherInTransit::DispatcherInTransit() {}
-
-Dispatcher::DispatcherInTransit::DispatcherInTransit(
- const DispatcherInTransit& other) = default;
-
-Dispatcher::DispatcherInTransit::~DispatcherInTransit() {}
-
-MojoResult Dispatcher::WatchDispatcher(scoped_refptr<Dispatcher> dispatcher,
- MojoHandleSignals signals,
- uintptr_t context) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::CancelWatch(uintptr_t context) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::Arm(uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::WriteMessage(std::unique_ptr<MessageForTransit> message,
- MojoWriteMessageFlags flags) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::ReadMessage(std::unique_ptr<MessageForTransit>* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags,
- bool read_any_size) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::DuplicateBufferHandle(
- const MojoDuplicateBufferHandleOptions* options,
- scoped_refptr<Dispatcher>* new_dispatcher) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::MapBuffer(
- uint64_t offset,
- uint64_t num_bytes,
- MojoMapBufferFlags flags,
- std::unique_ptr<PlatformSharedBufferMapping>* mapping) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::ReadData(void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::BeginReadData(const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::EndReadData(uint32_t num_bytes_read) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::WriteData(const void* elements,
- uint32_t* num_bytes,
- MojoWriteDataFlags flags) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::BeginWriteData(void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::EndWriteData(uint32_t num_bytes_written) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::AddWaitingDispatcher(
- const scoped_refptr<Dispatcher>& dispatcher,
- MojoHandleSignals signals,
- uintptr_t context) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::RemoveWaitingDispatcher(
- const scoped_refptr<Dispatcher>& dispatcher) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::GetReadyDispatchers(uint32_t* count,
- DispatcherVector* dispatchers,
- MojoResult* results,
- uintptr_t* contexts) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-HandleSignalsState Dispatcher::GetHandleSignalsState() const {
- return HandleSignalsState();
-}
-
-MojoResult Dispatcher::AddWatcherRef(
- const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-MojoResult Dispatcher::RemoveWatcherRef(WatcherDispatcher* watcher,
- uintptr_t context) {
- return MOJO_RESULT_INVALID_ARGUMENT;
-}
-
-void Dispatcher::StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_platform_handles) {
- *num_bytes = 0;
- *num_ports = 0;
- *num_platform_handles = 0;
-}
-
-bool Dispatcher::EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) {
- LOG(ERROR) << "Attempting to serialize a non-transferrable dispatcher.";
- return true;
-}
-
-bool Dispatcher::BeginTransit() { return true; }
-
-void Dispatcher::CompleteTransitAndClose() {}
-
-void Dispatcher::CancelTransit() {}
-
-// static
-scoped_refptr<Dispatcher> Dispatcher::Deserialize(
- Type type,
- const void* bytes,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* platform_handles,
- size_t num_platform_handles) {
- switch (type) {
- case Type::MESSAGE_PIPE:
- return MessagePipeDispatcher::Deserialize(
- bytes, num_bytes, ports, num_ports, platform_handles,
- num_platform_handles);
- case Type::SHARED_BUFFER:
- return SharedBufferDispatcher::Deserialize(
- bytes, num_bytes, ports, num_ports, platform_handles,
- num_platform_handles);
- case Type::DATA_PIPE_CONSUMER:
- return DataPipeConsumerDispatcher::Deserialize(
- bytes, num_bytes, ports, num_ports, platform_handles,
- num_platform_handles);
- case Type::DATA_PIPE_PRODUCER:
- return DataPipeProducerDispatcher::Deserialize(
- bytes, num_bytes, ports, num_ports, platform_handles,
- num_platform_handles);
- case Type::PLATFORM_HANDLE:
- return PlatformHandleDispatcher::Deserialize(
- bytes, num_bytes, ports, num_ports, platform_handles,
- num_platform_handles);
- default:
- LOG(ERROR) << "Deserializing invalid dispatcher type.";
- return nullptr;
- }
-}
-
-Dispatcher::Dispatcher() {}
-
-Dispatcher::~Dispatcher() {}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/dispatcher.h b/mojo/edk/system/dispatcher.h
deleted file mode 100644
index db1f1f1..0000000
--- a/mojo/edk/system/dispatcher.h
+++ /dev/null
@@ -1,245 +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_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_DISPATCHER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <ostream>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/ports/name.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/edk/system/watch.h"
-#include "mojo/public/c/system/buffer.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/message_pipe.h"
-#include "mojo/public/c/system/types.h"
-
-namespace mojo {
-namespace edk {
-
-class Dispatcher;
-class MessageForTransit;
-
-using DispatcherVector = std::vector<scoped_refptr<Dispatcher>>;
-
-// A |Dispatcher| implements Mojo EDK calls that are associated with a
-// particular MojoHandle.
-class MOJO_SYSTEM_IMPL_EXPORT Dispatcher
- : public base::RefCountedThreadSafe<Dispatcher> {
- public:
- struct DispatcherInTransit {
- DispatcherInTransit();
- DispatcherInTransit(const DispatcherInTransit& other);
- ~DispatcherInTransit();
-
- scoped_refptr<Dispatcher> dispatcher;
- MojoHandle local_handle;
- };
-
- enum class Type {
- UNKNOWN = 0,
- MESSAGE_PIPE,
- DATA_PIPE_PRODUCER,
- DATA_PIPE_CONSUMER,
- SHARED_BUFFER,
- WATCHER,
-
- // "Private" types (not exposed via the public interface):
- PLATFORM_HANDLE = -1,
- };
-
- // All Dispatchers must minimally implement these methods.
-
- virtual Type GetType() const = 0;
- virtual MojoResult Close() = 0;
-
- ///////////// Watcher API ////////////////////
-
- virtual MojoResult WatchDispatcher(scoped_refptr<Dispatcher> dispatcher,
- MojoHandleSignals signals,
- uintptr_t context);
- virtual MojoResult CancelWatch(uintptr_t context);
- virtual MojoResult Arm(uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states);
-
- ///////////// Message pipe API /////////////
-
- virtual MojoResult WriteMessage(std::unique_ptr<MessageForTransit> message,
- MojoWriteMessageFlags flags);
-
- virtual MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags,
- bool read_any_size);
-
- ///////////// Shared buffer API /////////////
-
- // |options| may be null. |new_dispatcher| must not be null, but
- // |*new_dispatcher| should be null (and will contain the dispatcher for the
- // new handle on success).
- virtual MojoResult DuplicateBufferHandle(
- const MojoDuplicateBufferHandleOptions* options,
- scoped_refptr<Dispatcher>* new_dispatcher);
-
- virtual MojoResult MapBuffer(
- uint64_t offset,
- uint64_t num_bytes,
- MojoMapBufferFlags flags,
- std::unique_ptr<PlatformSharedBufferMapping>* mapping);
-
- ///////////// Data pipe consumer API /////////////
-
- virtual MojoResult ReadData(void* elements,
- uint32_t* num_bytes,
- MojoReadDataFlags flags);
-
- virtual MojoResult BeginReadData(const void** buffer,
- uint32_t* buffer_num_bytes,
- MojoReadDataFlags flags);
-
- virtual MojoResult EndReadData(uint32_t num_bytes_read);
-
- ///////////// Data pipe producer API /////////////
-
- virtual MojoResult WriteData(const void* elements,
- uint32_t* num_bytes,
- MojoWriteDataFlags flags);
-
- virtual MojoResult BeginWriteData(void** buffer,
- uint32_t* buffer_num_bytes,
- MojoWriteDataFlags flags);
-
- virtual MojoResult EndWriteData(uint32_t num_bytes_written);
-
- ///////////// Wait set API /////////////
-
- // Adds a dispatcher to wait on. When the dispatcher satisfies |signals|, it
- // will be returned in the next call to |GetReadyDispatchers()|. If
- // |dispatcher| has been added, it must be removed before adding again,
- // otherwise |MOJO_RESULT_ALREADY_EXISTS| will be returned.
- virtual MojoResult AddWaitingDispatcher(
- const scoped_refptr<Dispatcher>& dispatcher,
- MojoHandleSignals signals,
- uintptr_t context);
-
- // Removes a dispatcher to wait on. If |dispatcher| has not been added,
- // |MOJO_RESULT_NOT_FOUND| will be returned.
- virtual MojoResult RemoveWaitingDispatcher(
- const scoped_refptr<Dispatcher>& dispatcher);
-
- // Returns a set of ready dispatchers. |*count| is the maximum number of
- // dispatchers to return, and will contain the number of dispatchers returned
- // in |dispatchers| on completion.
- virtual MojoResult GetReadyDispatchers(uint32_t* count,
- DispatcherVector* dispatchers,
- MojoResult* results,
- uintptr_t* contexts);
-
- ///////////// General-purpose API for all handle types /////////
-
- // Gets the current handle signals state. (The default implementation simply
- // returns a default-constructed |HandleSignalsState|, i.e., no signals
- // satisfied or satisfiable.) Note: The state is subject to change from other
- // threads.
- virtual HandleSignalsState GetHandleSignalsState() const;
-
- // Adds a WatcherDispatcher reference to this dispatcher, to be notified of
- // all subsequent changes to handle state including signal changes or closure.
- // The reference is associated with a |context| for disambiguation of
- // removals.
- virtual MojoResult AddWatcherRef(
- const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context);
-
- // Removes a WatcherDispatcher reference from this dispatcher.
- virtual MojoResult RemoveWatcherRef(WatcherDispatcher* watcher,
- uintptr_t context);
-
- // Informs the caller of the total serialized size (in bytes) and the total
- // number of platform handles and ports needed to transfer this dispatcher
- // across a message pipe.
- //
- // Must eventually be followed by a call to EndSerializeAndClose(). Note that
- // StartSerialize() and EndSerialize() are always called in sequence, and
- // only between calls to BeginTransit() and either (but not both)
- // CompleteTransitAndClose() or CancelTransit().
- //
- // For this reason it is IMPERATIVE that the implementation ensure a
- // consistent serializable state between BeginTransit() and
- // CompleteTransitAndClose()/CancelTransit().
- virtual void StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_platform_handles);
-
- // Serializes this dispatcher into |destination|, |ports|, and |handles|.
- // Returns true iff successful, false otherwise. In either case the dispatcher
- // will close.
- //
- // NOTE: Transit MAY still fail after this call returns. Implementations
- // should not assume PlatformHandle ownership has transferred until
- // CompleteTransitAndClose() is called. In other words, if CancelTransit() is
- // called, the implementation should retain its PlatformHandles in working
- // condition.
- virtual bool EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles);
-
- // Does whatever is necessary to begin transit of the dispatcher. This
- // should return |true| if transit is OK, or false if the underlying resource
- // is deemed busy by the implementation.
- virtual bool BeginTransit();
-
- // Does whatever is necessary to complete transit of the dispatcher, including
- // closure. This is only called upon successfully transmitting an outgoing
- // message containing this serialized dispatcher.
- virtual void CompleteTransitAndClose();
-
- // Does whatever is necessary to cancel transit of the dispatcher. The
- // dispatcher should remain in a working state and resume normal operation.
- virtual void CancelTransit();
-
- // Deserializes a specific dispatcher type from an incoming message.
- static scoped_refptr<Dispatcher> Deserialize(
- Type type,
- const void* bytes,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* platform_handles,
- size_t num_platform_handles);
-
- protected:
- friend class base::RefCountedThreadSafe<Dispatcher>;
-
- Dispatcher();
- virtual ~Dispatcher();
-
- DISALLOW_COPY_AND_ASSIGN(Dispatcher);
-};
-
-// So logging macros and |DCHECK_EQ()|, etc. work.
-MOJO_SYSTEM_IMPL_EXPORT inline std::ostream& operator<<(std::ostream& out,
- Dispatcher::Type type) {
- return out << static_cast<int>(type);
-}
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_DISPATCHER_H_
diff --git a/mojo/edk/system/handle_signals_state.h b/mojo/edk/system/handle_signals_state.h
deleted file mode 100644
index f241278..0000000
--- a/mojo/edk/system/handle_signals_state.h
+++ /dev/null
@@ -1,13 +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_SYSTEM_HANDLE_SIGNALS_STATE_H_
-#define MOJO_EDK_SYSTEM_HANDLE_SIGNALS_STATE_H_
-
-#include "mojo/public/cpp/system/handle_signals_state.h"
-
-// TODO(rockot): Remove this header and use the C++ system library type
-// directly inside the EDK.
-
-#endif // MOJO_EDK_SYSTEM_HANDLE_SIGNALS_STATE_H_
diff --git a/mojo/edk/system/handle_table.cc b/mojo/edk/system/handle_table.cc
deleted file mode 100644
index b570793..0000000
--- a/mojo/edk/system/handle_table.cc
+++ /dev/null
@@ -1,135 +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/handle_table.h"
-
-#include <stdint.h>
-
-#include <limits>
-
-namespace mojo {
-namespace edk {
-
-HandleTable::HandleTable() {}
-
-HandleTable::~HandleTable() {}
-
-MojoHandle HandleTable::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
- // Oops, we're out of handles.
- if (next_available_handle_ == MOJO_HANDLE_INVALID)
- return MOJO_HANDLE_INVALID;
-
- MojoHandle handle = next_available_handle_++;
- auto result =
- handles_.insert(std::make_pair(handle, Entry(std::move(dispatcher))));
- DCHECK(result.second);
-
- return handle;
-}
-
-bool HandleTable::AddDispatchersFromTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
- MojoHandle* handles) {
- // Oops, we're out of handles.
- if (next_available_handle_ == MOJO_HANDLE_INVALID)
- return false;
-
- DCHECK_LE(dispatchers.size(), std::numeric_limits<uint32_t>::max());
- // If this insertion would cause handle overflow, we're out of handles.
- if (next_available_handle_ + dispatchers.size() < next_available_handle_)
- return false;
-
- for (size_t i = 0; i < dispatchers.size(); ++i) {
- MojoHandle handle = next_available_handle_++;
- auto result = handles_.insert(
- std::make_pair(handle, Entry(dispatchers[i].dispatcher)));
- DCHECK(result.second);
- handles[i] = handle;
- }
-
- return true;
-}
-
-scoped_refptr<Dispatcher> HandleTable::GetDispatcher(MojoHandle handle) const {
- auto it = handles_.find(handle);
- if (it == handles_.end())
- return nullptr;
- return it->second.dispatcher;
-}
-
-MojoResult HandleTable::GetAndRemoveDispatcher(
- MojoHandle handle,
- scoped_refptr<Dispatcher>* dispatcher) {
- auto it = handles_.find(handle);
- if (it == handles_.end())
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (it->second.busy)
- return MOJO_RESULT_BUSY;
-
- *dispatcher = std::move(it->second.dispatcher);
- handles_.erase(it);
- return MOJO_RESULT_OK;
-}
-
-MojoResult HandleTable::BeginTransit(
- const MojoHandle* handles,
- uint32_t num_handles,
- std::vector<Dispatcher::DispatcherInTransit>* dispatchers) {
- dispatchers->clear();
- dispatchers->reserve(num_handles);
- for (size_t i = 0; i < num_handles; ++i) {
- auto it = handles_.find(handles[i]);
- if (it == handles_.end())
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (it->second.busy)
- return MOJO_RESULT_BUSY;
-
- Dispatcher::DispatcherInTransit d;
- d.local_handle = handles[i];
- d.dispatcher = it->second.dispatcher;
- if (!d.dispatcher->BeginTransit())
- return MOJO_RESULT_BUSY;
- it->second.busy = true;
- dispatchers->push_back(d);
- }
- return MOJO_RESULT_OK;
-}
-
-void HandleTable::CompleteTransitAndClose(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
- for (const auto& dispatcher : dispatchers) {
- auto it = handles_.find(dispatcher.local_handle);
- DCHECK(it != handles_.end() && it->second.busy);
- handles_.erase(it);
- dispatcher.dispatcher->CompleteTransitAndClose();
- }
-}
-
-void HandleTable::CancelTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
- for (const auto& dispatcher : dispatchers) {
- auto it = handles_.find(dispatcher.local_handle);
- DCHECK(it != handles_.end() && it->second.busy);
- it->second.busy = false;
- dispatcher.dispatcher->CancelTransit();
- }
-}
-
-void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
- handles->clear();
- for (const auto& entry : handles_)
- handles->push_back(entry.first);
-}
-
-HandleTable::Entry::Entry() {}
-
-HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher)
- : dispatcher(std::move(dispatcher)) {}
-
-HandleTable::Entry::Entry(const Entry& other) = default;
-
-HandleTable::Entry::~Entry() {}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/handle_table.h b/mojo/edk/system/handle_table.h
deleted file mode 100644
index 882d540..0000000
--- a/mojo/edk/system/handle_table.h
+++ /dev/null
@@ -1,75 +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_SYSTEM_HANDLE_TABLE_H_
-#define MOJO_EDK_SYSTEM_HANDLE_TABLE_H_
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/public/c/system/types.h"
-
-namespace mojo {
-namespace edk {
-
-class HandleTable {
- public:
- HandleTable();
- ~HandleTable();
-
- MojoHandle AddDispatcher(scoped_refptr<Dispatcher> dispatcher);
-
- // Inserts multiple dispatchers received from message transit, populating
- // |handles| with their newly allocated handles. Returns |true| on success.
- bool AddDispatchersFromTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
- MojoHandle* handles);
-
- scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle) const;
- MojoResult GetAndRemoveDispatcher(MojoHandle,
- scoped_refptr<Dispatcher>* dispatcher);
-
- // Marks handles as busy and populates |dispatchers|. Returns MOJO_RESULT_BUSY
- // if any of the handles are already in transit; MOJO_RESULT_INVALID_ARGUMENT
- // if any of the handles are invalid; or MOJO_RESULT_OK if successful.
- MojoResult BeginTransit(
- const MojoHandle* handles,
- uint32_t num_handles,
- std::vector<Dispatcher::DispatcherInTransit>* dispatchers);
-
- void CompleteTransitAndClose(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers);
- void CancelTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers);
-
- void GetActiveHandlesForTest(std::vector<MojoHandle> *handles);
-
- private:
- struct Entry {
- Entry();
- explicit Entry(scoped_refptr<Dispatcher> dispatcher);
- Entry(const Entry& other);
- ~Entry();
-
- scoped_refptr<Dispatcher> dispatcher;
- bool busy = false;
- };
-
- using HandleMap = base::hash_map<MojoHandle, Entry>;
-
- HandleMap handles_;
-
- uint32_t next_available_handle_ = 1;
-
- DISALLOW_COPY_AND_ASSIGN(HandleTable);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_HANDLE_TABLE_H_
diff --git a/mojo/edk/system/mach_port_relay.cc b/mojo/edk/system/mach_port_relay.cc
deleted file mode 100644
index f05cf22..0000000
--- a/mojo/edk/system/mach_port_relay.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/mach_port_relay.h"
-
-#include <mach/mach.h>
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/mac/mach_port_util.h"
-#include "base/mac/scoped_mach_port.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/process/process.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-// Errors that can occur in the broker (privileged parent) process.
-// These match tools/metrics/histograms.xml.
-// This enum is append-only.
-enum class BrokerUMAError : int {
- SUCCESS = 0,
- // Couldn't get a task port for the process with a given pid.
- ERROR_TASK_FOR_PID = 1,
- // Couldn't make a port with receive rights in the destination process.
- ERROR_MAKE_RECEIVE_PORT = 2,
- // Couldn't change the attributes of a Mach port.
- ERROR_SET_ATTRIBUTES = 3,
- // Couldn't extract a right from the destination.
- ERROR_EXTRACT_DEST_RIGHT = 4,
- // Couldn't send a Mach port in a call to mach_msg().
- ERROR_SEND_MACH_PORT = 5,
- // Couldn't extract a right from the source.
- ERROR_EXTRACT_SOURCE_RIGHT = 6,
- ERROR_MAX
-};
-
-// Errors that can occur in a child process.
-// These match tools/metrics/histograms.xml.
-// This enum is append-only.
-enum class ChildUMAError : int {
- SUCCESS = 0,
- // An error occurred while trying to receive a Mach port with mach_msg().
- ERROR_RECEIVE_MACH_MESSAGE = 1,
- ERROR_MAX
-};
-
-void ReportBrokerError(BrokerUMAError error) {
- UMA_HISTOGRAM_ENUMERATION("Mojo.MachPortRelay.BrokerError",
- static_cast<int>(error),
- static_cast<int>(BrokerUMAError::ERROR_MAX));
-}
-
-void ReportChildError(ChildUMAError error) {
- UMA_HISTOGRAM_ENUMERATION("Mojo.MachPortRelay.ChildError",
- static_cast<int>(error),
- static_cast<int>(ChildUMAError::ERROR_MAX));
-}
-
-} // namespace
-
-// static
-bool MachPortRelay::ReceivePorts(PlatformHandleVector* handles) {
- DCHECK(handles);
-
- for (size_t i = 0; i < handles->size(); i++) {
- PlatformHandle* handle = handles->data() + i;
- DCHECK(handle->type != PlatformHandle::Type::MACH);
- if (handle->type != PlatformHandle::Type::MACH_NAME)
- continue;
-
- if (handle->port == MACH_PORT_NULL) {
- handle->type = PlatformHandle::Type::MACH;
- continue;
- }
-
- base::mac::ScopedMachReceiveRight message_port(handle->port);
- base::mac::ScopedMachSendRight received_port(
- base::ReceiveMachPort(message_port.get()));
- if (received_port.get() == MACH_PORT_NULL) {
- ReportChildError(ChildUMAError::ERROR_RECEIVE_MACH_MESSAGE);
- handle->port = MACH_PORT_NULL;
- LOG(ERROR) << "Error receiving mach port";
- return false;
- }
-
- ReportChildError(ChildUMAError::SUCCESS);
- handle->port = received_port.release();
- handle->type = PlatformHandle::Type::MACH;
- }
-
- return true;
-}
-
-MachPortRelay::MachPortRelay(base::PortProvider* port_provider)
- : port_provider_(port_provider) {
- DCHECK(port_provider);
- port_provider_->AddObserver(this);
-}
-
-MachPortRelay::~MachPortRelay() {
- port_provider_->RemoveObserver(this);
-}
-
-bool MachPortRelay::SendPortsToProcess(Channel::Message* message,
- base::ProcessHandle process) {
- DCHECK(message);
- mach_port_t task_port = port_provider_->TaskForPid(process);
- if (task_port == MACH_PORT_NULL) {
- // Callers check the port provider for the task port before calling this
- // function, in order to queue pending messages. Therefore, if this fails,
- // it should be considered a genuine, bona fide, electrified, six-car error.
- ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
- return false;
- }
-
- size_t num_sent = 0;
- bool error = false;
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- // Message should have handles, otherwise there's no point in calling this
- // function.
- DCHECK(handles);
- for (size_t i = 0; i < handles->size(); i++) {
- PlatformHandle* handle = &(*handles)[i];
- DCHECK(handle->type != PlatformHandle::Type::MACH_NAME);
- if (handle->type != PlatformHandle::Type::MACH)
- continue;
-
- if (handle->port == MACH_PORT_NULL) {
- handle->type = PlatformHandle::Type::MACH_NAME;
- num_sent++;
- continue;
- }
-
- mach_port_name_t intermediate_port;
- base::MachCreateError error_code;
- intermediate_port = base::CreateIntermediateMachPort(
- task_port, base::mac::ScopedMachSendRight(handle->port), &error_code);
- if (intermediate_port == MACH_PORT_NULL) {
- BrokerUMAError uma_error;
- switch (error_code) {
- case base::MachCreateError::ERROR_MAKE_RECEIVE_PORT:
- uma_error = BrokerUMAError::ERROR_MAKE_RECEIVE_PORT;
- break;
- case base::MachCreateError::ERROR_SET_ATTRIBUTES:
- uma_error = BrokerUMAError::ERROR_SET_ATTRIBUTES;
- break;
- case base::MachCreateError::ERROR_EXTRACT_DEST_RIGHT:
- uma_error = BrokerUMAError::ERROR_EXTRACT_DEST_RIGHT;
- break;
- case base::MachCreateError::ERROR_SEND_MACH_PORT:
- uma_error = BrokerUMAError::ERROR_SEND_MACH_PORT;
- break;
- }
- ReportBrokerError(uma_error);
- handle->port = MACH_PORT_NULL;
- error = true;
- break;
- }
-
- ReportBrokerError(BrokerUMAError::SUCCESS);
- handle->port = intermediate_port;
- handle->type = PlatformHandle::Type::MACH_NAME;
- num_sent++;
- }
- DCHECK(error || num_sent);
- message->SetHandles(std::move(handles));
-
- return !error;
-}
-
-bool MachPortRelay::ExtractPortRights(Channel::Message* message,
- base::ProcessHandle process) {
- DCHECK(message);
-
- mach_port_t task_port = port_provider_->TaskForPid(process);
- if (task_port == MACH_PORT_NULL) {
- ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
- return false;
- }
-
- size_t num_received = 0;
- bool error = false;
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- // Message should have handles, otherwise there's no point in calling this
- // function.
- DCHECK(handles);
- for (size_t i = 0; i < handles->size(); i++) {
- PlatformHandle* handle = handles->data() + i;
- DCHECK(handle->type != PlatformHandle::Type::MACH);
- if (handle->type != PlatformHandle::Type::MACH_NAME)
- continue;
-
- if (handle->port == MACH_PORT_NULL) {
- handle->type = PlatformHandle::Type::MACH;
- num_received++;
- continue;
- }
-
- mach_port_t extracted_right = MACH_PORT_NULL;
- mach_msg_type_name_t extracted_right_type;
- kern_return_t kr =
- mach_port_extract_right(task_port, handle->port,
- MACH_MSG_TYPE_MOVE_SEND,
- &extracted_right, &extracted_right_type);
- if (kr != KERN_SUCCESS) {
- ReportBrokerError(BrokerUMAError::ERROR_EXTRACT_SOURCE_RIGHT);
- error = true;
- break;
- }
-
- ReportBrokerError(BrokerUMAError::SUCCESS);
- DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
- extracted_right_type);
- handle->port = extracted_right;
- handle->type = PlatformHandle::Type::MACH;
- num_received++;
- }
- DCHECK(error || num_received);
- message->SetHandles(std::move(handles));
-
- return !error;
-}
-
-void MachPortRelay::AddObserver(Observer* observer) {
- base::AutoLock locker(observers_lock_);
- bool inserted = observers_.insert(observer).second;
- DCHECK(inserted);
-}
-
-void MachPortRelay::RemoveObserver(Observer* observer) {
- base::AutoLock locker(observers_lock_);
- observers_.erase(observer);
-}
-
-void MachPortRelay::OnReceivedTaskPort(base::ProcessHandle process) {
- base::AutoLock locker(observers_lock_);
- for (auto* observer : observers_)
- observer->OnProcessReady(process);
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/mach_port_relay.h b/mojo/edk/system/mach_port_relay.h
deleted file mode 100644
index 87bc56c..0000000
--- a/mojo/edk/system/mach_port_relay.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_MACH_PORT_RELAY_H_
-#define MOJO_EDK_SYSTEM_MACH_PORT_RELAY_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "base/process/port_provider_mac.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/channel.h"
-
-namespace mojo {
-namespace edk {
-
-// The MachPortRelay is used by a privileged process, usually the root process,
-// to manipulate Mach ports in a child process. Ports can be added to and
-// extracted from a child process that has registered itself with the
-// |base::PortProvider| used by this class.
-class MachPortRelay : public base::PortProvider::Observer {
- public:
- class Observer {
- public:
- // Called by the MachPortRelay to notify observers that a new process is
- // ready for Mach ports to be sent/received. There are no guarantees about
- // the thread this is called on, including the presence of a MessageLoop.
- // Implementations must not call AddObserver() or RemoveObserver() during
- // this function, as doing so will deadlock.
- virtual void OnProcessReady(base::ProcessHandle process) = 0;
- };
-
- // Used by a child process to receive Mach ports from a sender (privileged)
- // process. Each Mach port in |handles| is interpreted as an intermediate Mach
- // port. It replaces each Mach port with the final Mach port received from the
- // intermediate port. This method takes ownership of the intermediate Mach
- // port and gives ownership of the final Mach port to the caller. Any handles
- // that are not Mach ports will remain unchanged, and the number and ordering
- // of handles is preserved.
- // Returns |false| on failure and there is no guarantee about whether a Mach
- // port is intermediate or final.
- //
- // See SendPortsToProcess() for the definition of intermediate and final Mach
- // ports.
- static bool ReceivePorts(PlatformHandleVector* handles);
-
- explicit MachPortRelay(base::PortProvider* port_provider);
- ~MachPortRelay() override;
-
- // Sends the Mach ports attached to |message| to |process|.
- // For each Mach port attached to |message|, a new Mach port, the intermediate
- // port, is created in |process|. The message's Mach port is then sent over
- // this intermediate port and the message is modified to refer to the name of
- // the intermediate port. The Mach port received over the intermediate port in
- // the child is referred to as the final Mach port.
- // Returns |false| on failure and |message| may contain a mix of actual Mach
- // ports and names.
- bool SendPortsToProcess(Channel::Message* message,
- base::ProcessHandle process);
-
- // Extracts the Mach ports attached to |message| from |process|.
- // Any Mach ports attached to |message| are names and not actual Mach ports
- // that are valid in this process. For each of those Mach port names, a send
- // right is extracted from |process| and the port name is replaced with the
- // send right.
- // Returns |false| on failure and |message| may contain a mix of actual Mach
- // ports and names.
- bool ExtractPortRights(Channel::Message* message,
- base::ProcessHandle process);
-
- // Observer interface.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- base::PortProvider* port_provider() const { return port_provider_; }
-
- private:
- // base::PortProvider::Observer implementation.
- void OnReceivedTaskPort(base::ProcessHandle process) override;
-
- base::PortProvider* const port_provider_;
-
- base::Lock observers_lock_;
- std::set<Observer*> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(MachPortRelay);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_MACH_PORT_RELAY_H_
diff --git a/mojo/edk/system/mapping_table.cc b/mojo/edk/system/mapping_table.cc
deleted file mode 100644
index 8509443..0000000
--- a/mojo/edk/system/mapping_table.cc
+++ /dev/null
@@ -1,48 +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/mapping_table.h"
-
-#include "base/logging.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/configuration.h"
-
-namespace mojo {
-namespace edk {
-
-MappingTable::MappingTable() {
-}
-
-MappingTable::~MappingTable() {
- // This should usually not be reached (the only instance should be owned by
- // the singleton |Core|, which lives forever), except in tests.
-}
-
-MojoResult MappingTable::AddMapping(
- std::unique_ptr<PlatformSharedBufferMapping> mapping) {
- DCHECK(mapping);
-
- if (address_to_mapping_map_.size() >=
- GetConfiguration().max_mapping_table_sze)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- void* address = mapping->GetBase();
- DCHECK(address_to_mapping_map_.find(address) ==
- address_to_mapping_map_.end());
- address_to_mapping_map_[address] = mapping.release();
- return MOJO_RESULT_OK;
-}
-
-MojoResult MappingTable::RemoveMapping(void* address) {
- AddressToMappingMap::iterator it = address_to_mapping_map_.find(address);
- if (it == address_to_mapping_map_.end())
- return MOJO_RESULT_INVALID_ARGUMENT;
- PlatformSharedBufferMapping* mapping_to_delete = it->second;
- address_to_mapping_map_.erase(it);
- delete mapping_to_delete;
- return MOJO_RESULT_OK;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/mapping_table.h b/mojo/edk/system/mapping_table.h
deleted file mode 100644
index 00167e3..0000000
--- a/mojo/edk/system/mapping_table.h
+++ /dev/null
@@ -1,57 +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_SYSTEM_MAPPING_TABLE_H_
-#define MOJO_EDK_SYSTEM_MAPPING_TABLE_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/c/system/types.h"
-
-namespace mojo {
-
-namespace edk {
-class Core;
-class PlatformSharedBufferMapping;
-
-// Test-only function (defined/used in embedder/test_embedder.cc). Declared here
-// so it can be friended.
-namespace internal {
-bool ShutdownCheckNoLeaks(Core*);
-}
-
-// This class provides the (global) table of memory mappings (owned by |Core|),
-// which maps mapping base addresses to |PlatformSharedBufferMapping|s.
-//
-// This class is NOT thread-safe; locking is left to |Core|.
-class MOJO_SYSTEM_IMPL_EXPORT MappingTable {
- public:
- MappingTable();
- ~MappingTable();
-
- // Tries to add a mapping. (Takes ownership of the mapping in all cases; on
- // failure, it will be destroyed.)
- MojoResult AddMapping(std::unique_ptr<PlatformSharedBufferMapping> mapping);
- MojoResult RemoveMapping(void* address);
-
- private:
- friend bool internal::ShutdownCheckNoLeaks(Core*);
-
- using AddressToMappingMap =
- base::hash_map<void*, PlatformSharedBufferMapping*>;
- AddressToMappingMap address_to_mapping_map_;
-
- DISALLOW_COPY_AND_ASSIGN(MappingTable);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_MAPPING_TABLE_H_
diff --git a/mojo/edk/system/message_for_transit.cc b/mojo/edk/system/message_for_transit.cc
deleted file mode 100644
index 26658e1..0000000
--- a/mojo/edk/system/message_for_transit.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/message_for_transit.h"
-
-#include <vector>
-
-#include "mojo/edk/embedder/platform_handle_vector.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-static_assert(sizeof(MessageForTransit::MessageHeader) % 8 == 0,
- "Invalid MessageHeader size.");
-static_assert(sizeof(MessageForTransit::DispatcherHeader) % 8 == 0,
- "Invalid DispatcherHeader size.");
-
-} // namespace
-
-MessageForTransit::~MessageForTransit() {}
-
-// static
-MojoResult MessageForTransit::Create(
- std::unique_ptr<MessageForTransit>* message,
- uint32_t num_bytes,
- const Dispatcher::DispatcherInTransit* dispatchers,
- uint32_t num_dispatchers) {
- // A structure for retaining information about every Dispatcher that will be
- // sent with this message.
- struct DispatcherInfo {
- uint32_t num_bytes;
- uint32_t num_ports;
- uint32_t num_handles;
- };
-
- // This is only the base header size. It will grow as we accumulate the
- // size of serialized state for each dispatcher.
- size_t header_size = sizeof(MessageHeader) +
- num_dispatchers * sizeof(DispatcherHeader);
- size_t num_ports = 0;
- size_t num_handles = 0;
-
- std::vector<DispatcherInfo> dispatcher_info(num_dispatchers);
- for (size_t i = 0; i < num_dispatchers; ++i) {
- Dispatcher* d = dispatchers[i].dispatcher.get();
- d->StartSerialize(&dispatcher_info[i].num_bytes,
- &dispatcher_info[i].num_ports,
- &dispatcher_info[i].num_handles);
- header_size += dispatcher_info[i].num_bytes;
- num_ports += dispatcher_info[i].num_ports;
- num_handles += dispatcher_info[i].num_handles;
- }
-
- // We now have enough information to fully allocate the message storage.
- std::unique_ptr<PortsMessage> msg = PortsMessage::NewUserMessage(
- header_size + num_bytes, num_ports, num_handles);
- if (!msg)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- // Populate the message header with information about serialized dispatchers.
- //
- // The front of the message is always a MessageHeader followed by a
- // DispatcherHeader for each dispatcher to be sent.
- MessageHeader* header =
- static_cast<MessageHeader*>(msg->mutable_payload_bytes());
- DispatcherHeader* dispatcher_headers =
- reinterpret_cast<DispatcherHeader*>(header + 1);
-
- // Serialized dispatcher state immediately follows the series of
- // DispatcherHeaders.
- char* dispatcher_data =
- reinterpret_cast<char*>(dispatcher_headers + num_dispatchers);
-
- header->num_dispatchers = num_dispatchers;
-
- // |header_size| is the total number of bytes preceding the message payload,
- // including all dispatcher headers and serialized dispatcher state.
- DCHECK_LE(header_size, std::numeric_limits<uint32_t>::max());
- header->header_size = static_cast<uint32_t>(header_size);
-
- if (num_dispatchers > 0) {
- ScopedPlatformHandleVectorPtr handles(
- new PlatformHandleVector(num_handles));
- size_t port_index = 0;
- size_t handle_index = 0;
- bool fail = false;
- for (size_t i = 0; i < num_dispatchers; ++i) {
- Dispatcher* d = dispatchers[i].dispatcher.get();
- DispatcherHeader* dh = &dispatcher_headers[i];
- const DispatcherInfo& info = dispatcher_info[i];
-
- // Fill in the header for this dispatcher.
- dh->type = static_cast<int32_t>(d->GetType());
- dh->num_bytes = info.num_bytes;
- dh->num_ports = info.num_ports;
- dh->num_platform_handles = info.num_handles;
-
- // Fill in serialized state, ports, and platform handles. We'll cancel
- // the send if the dispatcher implementation rejects for some reason.
- if (!d->EndSerialize(static_cast<void*>(dispatcher_data),
- msg->mutable_ports() + port_index,
- handles->data() + handle_index)) {
- fail = true;
- break;
- }
-
- dispatcher_data += info.num_bytes;
- port_index += info.num_ports;
- handle_index += info.num_handles;
- }
-
- if (fail) {
- // Release any platform handles we've accumulated. Their dispatchers
- // retain ownership when message creation fails, so these are not actually
- // leaking.
- handles->clear();
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- // Take ownership of all the handles and move them into message storage.
- msg->SetHandles(std::move(handles));
- }
-
- message->reset(new MessageForTransit(std::move(msg)));
- return MOJO_RESULT_OK;
-}
-
-MessageForTransit::MessageForTransit(std::unique_ptr<PortsMessage> message)
- : message_(std::move(message)) {
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/message_for_transit.h b/mojo/edk/system/message_for_transit.h
deleted file mode 100644
index 6103a77..0000000
--- a/mojo/edk/system/message_for_transit.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_MESSAGE_FOR_TRANSIT_H_
-#define MOJO_EDK_SYSTEM_MESSAGE_FOR_TRANSIT_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/ports_message.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-// MessageForTransit holds onto a PortsMessage which may be sent via
-// |MojoWriteMessage()| or which may have been received on a pipe endpoint.
-// Instances of this class are exposed to Mojo system API consumers via the
-// opaque pointers used with |MojoCreateMessage()|, |MojoDestroyMessage()|,
-// |MojoWriteMessageNew()|, and |MojoReadMessageNew()|.
-class MOJO_SYSTEM_IMPL_EXPORT MessageForTransit {
- public:
-#pragma pack(push, 1)
- // Header attached to every message.
- struct MessageHeader {
- // The number of serialized dispatchers included in this header.
- uint32_t num_dispatchers;
-
- // Total size of the header, including serialized dispatcher data.
- uint32_t header_size;
- };
-
- // Header for each dispatcher in a message, immediately following the message
- // header.
- struct DispatcherHeader {
- // The type of the dispatcher, correpsonding to the Dispatcher::Type enum.
- int32_t type;
-
- // The size of the serialized dispatcher, not including this header.
- uint32_t num_bytes;
-
- // The number of ports needed to deserialize this dispatcher.
- uint32_t num_ports;
-
- // The number of platform handles needed to deserialize this dispatcher.
- uint32_t num_platform_handles;
- };
-#pragma pack(pop)
-
- ~MessageForTransit();
-
- // A static constructor for building outbound messages.
- static MojoResult Create(
- std::unique_ptr<MessageForTransit>* message,
- uint32_t num_bytes,
- const Dispatcher::DispatcherInTransit* dispatchers,
- uint32_t num_dispatchers);
-
- // A static constructor for wrapping inbound messages.
- static std::unique_ptr<MessageForTransit> WrapPortsMessage(
- std::unique_ptr<PortsMessage> message) {
- return base::WrapUnique(new MessageForTransit(std::move(message)));
- }
-
- const void* bytes() const {
- DCHECK(message_);
- return static_cast<const void*>(
- static_cast<const char*>(message_->payload_bytes()) +
- header()->header_size);
- }
-
- void* mutable_bytes() {
- DCHECK(message_);
- return static_cast<void*>(
- static_cast<char*>(message_->mutable_payload_bytes()) +
- header()->header_size);
- }
-
- size_t num_bytes() const {
- size_t header_size = header()->header_size;
- DCHECK_GE(message_->num_payload_bytes(), header_size);
- return message_->num_payload_bytes() - header_size;
- }
-
- size_t num_handles() const { return header()->num_dispatchers; }
-
- const PortsMessage& ports_message() const { return *message_; }
-
- std::unique_ptr<PortsMessage> TakePortsMessage() {
- return std::move(message_);
- }
-
- private:
- explicit MessageForTransit(std::unique_ptr<PortsMessage> message);
-
- const MessageForTransit::MessageHeader* header() const {
- DCHECK(message_);
- return static_cast<const MessageForTransit::MessageHeader*>(
- message_->payload_bytes());
- }
-
- std::unique_ptr<PortsMessage> message_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageForTransit);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_MESSAGE_FOR_TRANSIT_H_
diff --git a/mojo/edk/system/message_pipe_dispatcher.cc b/mojo/edk/system/message_pipe_dispatcher.cc
deleted file mode 100644
index 1db56c0..0000000
--- a/mojo/edk/system/message_pipe_dispatcher.cc
+++ /dev/null
@@ -1,554 +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/message_pipe_dispatcher.h"
-
-#include <limits>
-#include <memory>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/message_for_transit.h"
-#include "mojo/edk/system/node_controller.h"
-#include "mojo/edk/system/ports/message_filter.h"
-#include "mojo/edk/system/ports_message.h"
-#include "mojo/edk/system/request_context.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-using DispatcherHeader = MessageForTransit::DispatcherHeader;
-using MessageHeader = MessageForTransit::MessageHeader;
-
-#pragma pack(push, 1)
-
-struct SerializedState {
- uint64_t pipe_id;
- int8_t endpoint;
- char padding[7];
-};
-
-static_assert(sizeof(SerializedState) % 8 == 0,
- "Invalid SerializedState size.");
-
-#pragma pack(pop)
-
-} // namespace
-
-// A PortObserver which forwards to a MessagePipeDispatcher. This owns a
-// reference to the MPD to ensure it lives as long as the observed port.
-class MessagePipeDispatcher::PortObserverThunk
- : public NodeController::PortObserver {
- public:
- explicit PortObserverThunk(scoped_refptr<MessagePipeDispatcher> dispatcher)
- : dispatcher_(dispatcher) {}
-
- private:
- ~PortObserverThunk() override {}
-
- // NodeController::PortObserver:
- void OnPortStatusChanged() override { dispatcher_->OnPortStatusChanged(); }
-
- scoped_refptr<MessagePipeDispatcher> dispatcher_;
-
- DISALLOW_COPY_AND_ASSIGN(PortObserverThunk);
-};
-
-// A MessageFilter used by ReadMessage to determine whether a message should
-// actually be consumed yet.
-class ReadMessageFilter : public ports::MessageFilter {
- public:
- // Creates a new ReadMessageFilter which captures and potentially modifies
- // various (unowned) local state within MessagePipeDispatcher::ReadMessage.
- ReadMessageFilter(bool read_any_size,
- bool may_discard,
- uint32_t* num_bytes,
- uint32_t* num_handles,
- bool* no_space,
- bool* invalid_message)
- : read_any_size_(read_any_size),
- may_discard_(may_discard),
- num_bytes_(num_bytes),
- num_handles_(num_handles),
- no_space_(no_space),
- invalid_message_(invalid_message) {}
-
- ~ReadMessageFilter() override {}
-
- // ports::MessageFilter:
- bool Match(const ports::Message& m) override {
- const PortsMessage& message = static_cast<const PortsMessage&>(m);
- if (message.num_payload_bytes() < sizeof(MessageHeader)) {
- *invalid_message_ = true;
- return true;
- }
-
- const MessageHeader* header =
- static_cast<const MessageHeader*>(message.payload_bytes());
- if (header->header_size > message.num_payload_bytes()) {
- *invalid_message_ = true;
- return true;
- }
-
- uint32_t bytes_to_read = 0;
- uint32_t bytes_available =
- static_cast<uint32_t>(message.num_payload_bytes()) -
- header->header_size;
- if (num_bytes_) {
- bytes_to_read = std::min(*num_bytes_, bytes_available);
- *num_bytes_ = bytes_available;
- }
-
- uint32_t handles_to_read = 0;
- uint32_t handles_available = header->num_dispatchers;
- if (num_handles_) {
- handles_to_read = std::min(*num_handles_, handles_available);
- *num_handles_ = handles_available;
- }
-
- if (handles_to_read < handles_available ||
- (!read_any_size_ && bytes_to_read < bytes_available)) {
- *no_space_ = true;
- return may_discard_;
- }
-
- return true;
- }
-
- private:
- const bool read_any_size_;
- const bool may_discard_;
- uint32_t* const num_bytes_;
- uint32_t* const num_handles_;
- bool* const no_space_;
- bool* const invalid_message_;
-
- DISALLOW_COPY_AND_ASSIGN(ReadMessageFilter);
-};
-
-#if DCHECK_IS_ON()
-
-// A MessageFilter which never matches a message. Used to peek at the size of
-// the next available message on a port, for debug logging only.
-class PeekSizeMessageFilter : public ports::MessageFilter {
- public:
- PeekSizeMessageFilter() {}
- ~PeekSizeMessageFilter() override {}
-
- // ports::MessageFilter:
- bool Match(const ports::Message& message) override {
- message_size_ = message.num_payload_bytes();
- return false;
- }
-
- size_t message_size() const { return message_size_; }
-
- private:
- size_t message_size_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(PeekSizeMessageFilter);
-};
-
-#endif // DCHECK_IS_ON()
-
-MessagePipeDispatcher::MessagePipeDispatcher(NodeController* node_controller,
- const ports::PortRef& port,
- uint64_t pipe_id,
- int endpoint)
- : node_controller_(node_controller),
- port_(port),
- pipe_id_(pipe_id),
- endpoint_(endpoint),
- watchers_(this) {
- DVLOG(2) << "Creating new MessagePipeDispatcher for port " << port.name()
- << " [pipe_id=" << pipe_id << "; endpoint=" << endpoint << "]";
-
- node_controller_->SetPortObserver(
- port_,
- make_scoped_refptr(new PortObserverThunk(this)));
-}
-
-bool MessagePipeDispatcher::Fuse(MessagePipeDispatcher* other) {
- node_controller_->SetPortObserver(port_, nullptr);
- node_controller_->SetPortObserver(other->port_, nullptr);
-
- ports::PortRef port0;
- {
- base::AutoLock lock(signal_lock_);
- port0 = port_;
- port_closed_.Set(true);
- watchers_.NotifyClosed();
- }
-
- ports::PortRef port1;
- {
- base::AutoLock lock(other->signal_lock_);
- port1 = other->port_;
- other->port_closed_.Set(true);
- other->watchers_.NotifyClosed();
- }
-
- // Both ports are always closed by this call.
- int rv = node_controller_->MergeLocalPorts(port0, port1);
- return rv == ports::OK;
-}
-
-Dispatcher::Type MessagePipeDispatcher::GetType() const {
- return Type::MESSAGE_PIPE;
-}
-
-MojoResult MessagePipeDispatcher::Close() {
- base::AutoLock lock(signal_lock_);
- DVLOG(2) << "Closing message pipe " << pipe_id_ << " endpoint " << endpoint_
- << " [port=" << port_.name() << "]";
- return CloseNoLock();
-}
-
-MojoResult MessagePipeDispatcher::WriteMessage(
- std::unique_ptr<MessageForTransit> message,
- MojoWriteMessageFlags flags) {
- if (port_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- size_t num_bytes = message->num_bytes();
- int rv = node_controller_->SendMessage(port_, message->TakePortsMessage());
-
- DVLOG(4) << "Sent message on pipe " << pipe_id_ << " endpoint " << endpoint_
- << " [port=" << port_.name() << "; rv=" << rv
- << "; num_bytes=" << num_bytes << "]";
-
- if (rv != ports::OK) {
- if (rv == ports::ERROR_PORT_UNKNOWN ||
- rv == ports::ERROR_PORT_STATE_UNEXPECTED ||
- rv == ports::ERROR_PORT_CANNOT_SEND_PEER) {
- return MOJO_RESULT_INVALID_ARGUMENT;
- } else if (rv == ports::ERROR_PORT_PEER_CLOSED) {
- return MOJO_RESULT_FAILED_PRECONDITION;
- }
-
- NOTREACHED();
- return MOJO_RESULT_UNKNOWN;
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult MessagePipeDispatcher::ReadMessage(
- std::unique_ptr<MessageForTransit>* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags,
- bool read_any_size) {
- // We can't read from a port that's closed or in transit!
- if (port_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- bool no_space = false;
- bool may_discard = flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD;
- bool invalid_message = false;
-
- // Grab a message if the provided handles buffer is large enough. If the input
- // |num_bytes| is provided and |read_any_size| is false, we also ensure
- // that it specifies a size at least as large as the next available payload.
- //
- // If |read_any_size| is true, the input value of |*num_bytes| is ignored.
- // This flag exists to support both new and old API behavior.
-
- ports::ScopedMessage ports_message;
- ReadMessageFilter filter(read_any_size, may_discard, num_bytes, num_handles,
- &no_space, &invalid_message);
- int rv = node_controller_->node()->GetMessage(port_, &ports_message, &filter);
-
- if (invalid_message)
- return MOJO_RESULT_UNKNOWN;
-
- if (rv != ports::OK && rv != ports::ERROR_PORT_PEER_CLOSED) {
- if (rv == ports::ERROR_PORT_UNKNOWN ||
- rv == ports::ERROR_PORT_STATE_UNEXPECTED)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- NOTREACHED();
- return MOJO_RESULT_UNKNOWN; // TODO: Add a better error code here?
- }
-
- if (no_space) {
- if (may_discard) {
- // May have been the last message on the pipe. Need to update signals just
- // in case.
- base::AutoLock lock(signal_lock_);
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- }
- // |*num_handles| (and/or |*num_bytes| if |read_any_size| is false) wasn't
- // sufficient to hold this message's data. The message will still be in
- // queue unless MOJO_READ_MESSAGE_FLAG_MAY_DISCARD was set.
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- if (!ports_message) {
- // No message was available in queue.
-
- if (rv == ports::OK)
- return MOJO_RESULT_SHOULD_WAIT;
-
- // Peer is closed and there are no more messages to read.
- DCHECK_EQ(rv, ports::ERROR_PORT_PEER_CLOSED);
- return MOJO_RESULT_FAILED_PRECONDITION;
- }
-
- // Alright! We have a message and the caller has provided sufficient storage
- // in which to receive it.
-
- {
- // We need to update anyone watching our signals in case that was the last
- // available message.
- base::AutoLock lock(signal_lock_);
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
- }
-
- std::unique_ptr<PortsMessage> msg(
- static_cast<PortsMessage*>(ports_message.release()));
-
- const MessageHeader* header =
- static_cast<const MessageHeader*>(msg->payload_bytes());
- const DispatcherHeader* dispatcher_headers =
- reinterpret_cast<const DispatcherHeader*>(header + 1);
-
- if (header->num_dispatchers > std::numeric_limits<uint16_t>::max())
- return MOJO_RESULT_UNKNOWN;
-
- // Deserialize dispatchers.
- if (header->num_dispatchers > 0) {
- CHECK(handles);
- std::vector<DispatcherInTransit> dispatchers(header->num_dispatchers);
- size_t data_payload_index = sizeof(MessageHeader) +
- header->num_dispatchers * sizeof(DispatcherHeader);
- if (data_payload_index > header->header_size)
- return MOJO_RESULT_UNKNOWN;
- const char* dispatcher_data = reinterpret_cast<const char*>(
- dispatcher_headers + header->num_dispatchers);
- size_t port_index = 0;
- size_t platform_handle_index = 0;
- ScopedPlatformHandleVectorPtr msg_handles = msg->TakeHandles();
- const size_t num_msg_handles = msg_handles ? msg_handles->size() : 0;
- for (size_t i = 0; i < header->num_dispatchers; ++i) {
- const DispatcherHeader& dh = dispatcher_headers[i];
- Type type = static_cast<Type>(dh.type);
-
- size_t next_payload_index = data_payload_index + dh.num_bytes;
- if (msg->num_payload_bytes() < next_payload_index ||
- next_payload_index < data_payload_index) {
- return MOJO_RESULT_UNKNOWN;
- }
-
- size_t next_port_index = port_index + dh.num_ports;
- if (msg->num_ports() < next_port_index || next_port_index < port_index)
- return MOJO_RESULT_UNKNOWN;
-
- size_t next_platform_handle_index =
- platform_handle_index + dh.num_platform_handles;
- if (num_msg_handles < next_platform_handle_index ||
- next_platform_handle_index < platform_handle_index) {
- return MOJO_RESULT_UNKNOWN;
- }
-
- PlatformHandle* out_handles =
- num_msg_handles ? msg_handles->data() + platform_handle_index
- : nullptr;
- dispatchers[i].dispatcher = Dispatcher::Deserialize(
- type, dispatcher_data, dh.num_bytes, msg->ports() + port_index,
- dh.num_ports, out_handles, dh.num_platform_handles);
- if (!dispatchers[i].dispatcher)
- return MOJO_RESULT_UNKNOWN;
-
- dispatcher_data += dh.num_bytes;
- data_payload_index = next_payload_index;
- port_index = next_port_index;
- platform_handle_index = next_platform_handle_index;
- }
-
- if (!node_controller_->core()->AddDispatchersFromTransit(dispatchers,
- handles))
- return MOJO_RESULT_UNKNOWN;
- }
-
- CHECK(msg);
- *message = MessageForTransit::WrapPortsMessage(std::move(msg));
- return MOJO_RESULT_OK;
-}
-
-HandleSignalsState
-MessagePipeDispatcher::GetHandleSignalsState() const {
- base::AutoLock lock(signal_lock_);
- return GetHandleSignalsStateNoLock();
-}
-
-MojoResult MessagePipeDispatcher::AddWatcherRef(
- const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) {
- base::AutoLock lock(signal_lock_);
- if (port_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watchers_.Add(watcher, context, GetHandleSignalsStateNoLock());
-}
-
-MojoResult MessagePipeDispatcher::RemoveWatcherRef(WatcherDispatcher* watcher,
- uintptr_t context) {
- base::AutoLock lock(signal_lock_);
- if (port_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- return watchers_.Remove(watcher, context);
-}
-
-void MessagePipeDispatcher::StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) {
- *num_bytes = static_cast<uint32_t>(sizeof(SerializedState));
- *num_ports = 1;
- *num_handles = 0;
-}
-
-bool MessagePipeDispatcher::EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) {
- SerializedState* state = static_cast<SerializedState*>(destination);
- state->pipe_id = pipe_id_;
- state->endpoint = static_cast<int8_t>(endpoint_);
- memset(state->padding, 0, sizeof(state->padding));
- ports[0] = port_.name();
- return true;
-}
-
-bool MessagePipeDispatcher::BeginTransit() {
- base::AutoLock lock(signal_lock_);
- if (in_transit_ || port_closed_)
- return false;
- in_transit_.Set(true);
- return in_transit_;
-}
-
-void MessagePipeDispatcher::CompleteTransitAndClose() {
- node_controller_->SetPortObserver(port_, nullptr);
-
- base::AutoLock lock(signal_lock_);
- port_transferred_ = true;
- in_transit_.Set(false);
- CloseNoLock();
-}
-
-void MessagePipeDispatcher::CancelTransit() {
- base::AutoLock lock(signal_lock_);
- in_transit_.Set(false);
-
- // Something may have happened while we were waiting for potential transit.
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-}
-
-// static
-scoped_refptr<Dispatcher> MessagePipeDispatcher::Deserialize(
- const void* data,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles) {
- if (num_ports != 1 || num_handles || num_bytes != sizeof(SerializedState))
- return nullptr;
-
- const SerializedState* state = static_cast<const SerializedState*>(data);
-
- ports::PortRef port;
- CHECK_EQ(
- ports::OK,
- internal::g_core->GetNodeController()->node()->GetPort(ports[0], &port));
-
- return new MessagePipeDispatcher(internal::g_core->GetNodeController(), port,
- state->pipe_id, state->endpoint);
-}
-
-MessagePipeDispatcher::~MessagePipeDispatcher() {
- DCHECK(port_closed_ && !in_transit_);
-}
-
-MojoResult MessagePipeDispatcher::CloseNoLock() {
- signal_lock_.AssertAcquired();
- if (port_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- port_closed_.Set(true);
- watchers_.NotifyClosed();
-
- if (!port_transferred_) {
- base::AutoUnlock unlock(signal_lock_);
- node_controller_->ClosePort(port_);
- }
-
- return MOJO_RESULT_OK;
-}
-
-HandleSignalsState MessagePipeDispatcher::GetHandleSignalsStateNoLock() const {
- HandleSignalsState rv;
-
- ports::PortStatus port_status;
- if (node_controller_->node()->GetStatus(port_, &port_status) != ports::OK) {
- CHECK(in_transit_ || port_transferred_ || port_closed_);
- return HandleSignalsState();
- }
-
- if (port_status.has_messages) {
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- }
- if (port_status.receiving_messages)
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- if (!port_status.peer_closed) {
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE;
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE;
- } else {
- rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
- }
- rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED;
- return rv;
-}
-
-void MessagePipeDispatcher::OnPortStatusChanged() {
- DCHECK(RequestContext::current());
-
- base::AutoLock lock(signal_lock_);
-
- // We stop observing our port as soon as it's transferred, but this can race
- // with events which are raised right before that happens. This is fine to
- // ignore.
- if (port_transferred_)
- return;
-
-#if DCHECK_IS_ON()
- ports::PortStatus port_status;
- if (node_controller_->node()->GetStatus(port_, &port_status) == ports::OK) {
- if (port_status.has_messages) {
- ports::ScopedMessage unused;
- PeekSizeMessageFilter filter;
- node_controller_->node()->GetMessage(port_, &unused, &filter);
- DVLOG(4) << "New message detected on message pipe " << pipe_id_
- << " endpoint " << endpoint_ << " [port=" << port_.name()
- << "; size=" << filter.message_size() << "]";
- }
- if (port_status.peer_closed) {
- DVLOG(2) << "Peer closure detected on message pipe " << pipe_id_
- << " endpoint " << endpoint_ << " [port=" << port_.name() << "]";
- }
- }
-#endif
-
- watchers_.NotifyState(GetHandleSignalsStateNoLock());
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/message_pipe_dispatcher.h b/mojo/edk/system/message_pipe_dispatcher.h
deleted file mode 100644
index 574ad66..0000000
--- a/mojo/edk/system/message_pipe_dispatcher.h
+++ /dev/null
@@ -1,115 +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_EDK_SYSTEM_MESSAGE_PIPE_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_MESSAGE_PIPE_DISPATCHER_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <queue>
-
-#include "base/macros.h"
-#include "mojo/edk/system/atomic_flag.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/message_for_transit.h"
-#include "mojo/edk/system/ports/port_ref.h"
-#include "mojo/edk/system/watcher_set.h"
-
-namespace mojo {
-namespace edk {
-
-class NodeController;
-
-class MessagePipeDispatcher : public Dispatcher {
- public:
- // Constructs a MessagePipeDispatcher permanently tied to a specific port.
- // |connected| must indicate the state of the port at construction time; if
- // the port is initialized with a peer, |connected| must be true. Otherwise it
- // must be false.
- //
- // A MessagePipeDispatcher may not be transferred while in a disconnected
- // state, and one can never return to a disconnected once connected.
- //
- // |pipe_id| is a unique identifier which can be used to track pipe endpoints
- // as they're passed around. |endpoint| is either 0 or 1 and again is only
- // used for tracking pipes (one side is always 0, the other is always 1.)
- MessagePipeDispatcher(NodeController* node_controller,
- const ports::PortRef& port,
- uint64_t pipe_id,
- int endpoint);
-
- // Fuses this pipe with |other|. Returns |true| on success or |false| on
- // failure. Regardless of the return value, both dispatchers are closed by
- // this call.
- bool Fuse(MessagePipeDispatcher* other);
-
- // Dispatcher:
- Type GetType() const override;
- MojoResult Close() override;
- MojoResult WriteMessage(std::unique_ptr<MessageForTransit> message,
- MojoWriteMessageFlags flags) override;
- MojoResult ReadMessage(std::unique_ptr<MessageForTransit>* message,
- uint32_t* num_bytes,
- MojoHandle* handles,
- uint32_t* num_handles,
- MojoReadMessageFlags flags,
- bool read_any_size) override;
- HandleSignalsState GetHandleSignalsState() const override;
- MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context) override;
- MojoResult RemoveWatcherRef(WatcherDispatcher* watcher,
- uintptr_t context) override;
- void StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) override;
- bool EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) override;
- bool BeginTransit() override;
- void CompleteTransitAndClose() override;
- void CancelTransit() override;
-
- static scoped_refptr<Dispatcher> Deserialize(
- const void* data,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles);
-
- private:
- class PortObserverThunk;
- friend class PortObserverThunk;
-
- ~MessagePipeDispatcher() override;
-
- MojoResult CloseNoLock();
- HandleSignalsState GetHandleSignalsStateNoLock() const;
- void OnPortStatusChanged();
-
- // These are safe to access from any thread without locking.
- NodeController* const node_controller_;
- const ports::PortRef port_;
- const uint64_t pipe_id_;
- const int endpoint_;
-
- // Guards access to all the fields below.
- mutable base::Lock signal_lock_;
-
- // This is not the same is |port_transferred_|. It's only held true between
- // BeginTransit() and Complete/CancelTransit().
- AtomicFlag in_transit_;
-
- bool port_transferred_ = false;
- AtomicFlag port_closed_;
- WatcherSet watchers_;
-
- DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_MESSAGE_PIPE_DISPATCHER_H_
diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc
deleted file mode 100644
index 9866c47..0000000
--- a/mojo/edk/system/message_pipe_perftest.cc
+++ /dev/null
@@ -1,167 +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 <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/perf_time_logger.h"
-#include "base/threading/thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/edk/test/test_utils.h"
-#include "mojo/public/c/system/functions.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-class MessagePipePerfTest : public test::MojoTestBase {
- public:
- MessagePipePerfTest() : message_count_(0), message_size_(0) {}
-
- void SetUpMeasurement(int message_count, size_t message_size) {
- message_count_ = message_count;
- message_size_ = message_size;
- payload_ = std::string(message_size, '*');
- read_buffer_.resize(message_size * 2);
- }
-
- protected:
- void WriteWaitThenRead(MojoHandle mp) {
- CHECK_EQ(MojoWriteMessage(mp, payload_.data(),
- static_cast<uint32_t>(payload_.size()), nullptr,
- 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- HandleSignalsState hss;
- CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer_.size());
- CHECK_EQ(MojoReadMessage(mp, &read_buffer_[0], &read_buffer_size, nullptr,
- nullptr, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(read_buffer_size, static_cast<uint32_t>(payload_.size()));
- }
-
- void SendQuitMessage(MojoHandle mp) {
- CHECK_EQ(MojoWriteMessage(mp, "", 0, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- }
-
- void Measure(MojoHandle mp) {
- // Have one ping-pong to ensure channel being established.
- WriteWaitThenRead(mp);
-
- std::string test_name =
- base::StringPrintf("IPC_Perf_%dx_%u", message_count_,
- static_cast<unsigned>(message_size_));
- base::PerfTimeLogger logger(test_name.c_str());
-
- for (int i = 0; i < message_count_; ++i)
- WriteWaitThenRead(mp);
-
- logger.Done();
- }
-
- protected:
- void RunPingPongServer(MojoHandle mp) {
- // This values are set to align with one at ipc_pertests.cc for comparison.
- const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
- const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
-
- for (size_t i = 0; i < 5; i++) {
- SetUpMeasurement(kMessageCount[i], kMsgSize[i]);
- Measure(mp);
- }
-
- SendQuitMessage(mp);
- }
-
- static int RunPingPongClient(MojoHandle mp) {
- std::string buffer(1000000, '\0');
- int rv = 0;
- while (true) {
- // Wait for our end of the message pipe to be readable.
- HandleSignalsState hss;
- MojoResult result = WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss);
- if (result != MOJO_RESULT_OK) {
- rv = result;
- break;
- }
-
- uint32_t read_size = static_cast<uint32_t>(buffer.size());
- CHECK_EQ(MojoReadMessage(mp, &buffer[0],
- &read_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
-
- // Empty message indicates quit.
- if (read_size == 0)
- break;
-
- CHECK_EQ(MojoWriteMessage(mp, &buffer[0],
- read_size,
- nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- }
-
- return rv;
- }
-
- private:
- int message_count_;
- size_t message_size_;
- std::string payload_;
- std::string read_buffer_;
- std::unique_ptr<base::PerfTimeLogger> perf_logger_;
-
- DISALLOW_COPY_AND_ASSIGN(MessagePipePerfTest);
-};
-
-TEST_F(MessagePipePerfTest, PingPong) {
- MojoHandle server_handle, client_handle;
- CreateMessagePipe(&server_handle, &client_handle);
-
- base::Thread client_thread("PingPongClient");
- client_thread.Start();
- client_thread.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&RunPingPongClient), client_handle));
-
- RunPingPongServer(server_handle);
-}
-
-// For each message received, sends a reply message with the same contents
-// repeated twice, until the other end is closed or it receives "quitquitquit"
-// (which it doesn't reply to). It'll return the number of messages received,
-// not including any "quitquitquit" message, modulo 100.
-DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MessagePipePerfTest, h) {
- return RunPingPongClient(h);
-}
-
-// Repeatedly sends messages as previous one got replied by the child.
-// Waits for the child to close its end before quitting once specified
-// number of messages has been sent.
-TEST_F(MessagePipePerfTest, MultiprocessPingPong) {
- RUN_CHILD_ON_PIPE(PingPongClient, h)
- RunPingPongServer(h);
- END_CHILD()
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc
deleted file mode 100644
index e6f1ff6..0000000
--- a/mojo/edk/system/message_pipe_unittest.cc
+++ /dev/null
@@ -1,699 +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 <stdint.h>
-#include <string.h>
-
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/core.h"
-#include "mojo/public/c/system/types.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED;
-static const char kHelloWorld[] = "hello world";
-
-class MessagePipeTest : public test::MojoTestBase {
- public:
- MessagePipeTest() {
- CHECK_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &pipe0_, &pipe1_));
- }
-
- ~MessagePipeTest() override {
- if (pipe0_ != MOJO_HANDLE_INVALID)
- CHECK_EQ(MOJO_RESULT_OK, MojoClose(pipe0_));
- if (pipe1_ != MOJO_HANDLE_INVALID)
- CHECK_EQ(MOJO_RESULT_OK, MojoClose(pipe1_));
- }
-
- MojoResult WriteMessage(MojoHandle message_pipe_handle,
- const void* bytes,
- uint32_t num_bytes) {
- return MojoWriteMessage(message_pipe_handle, bytes, num_bytes, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE);
- }
-
- MojoResult ReadMessage(MojoHandle message_pipe_handle,
- void* bytes,
- uint32_t* num_bytes,
- bool may_discard = false) {
- return MojoReadMessage(message_pipe_handle, bytes, num_bytes, nullptr, 0,
- may_discard ? MOJO_READ_MESSAGE_FLAG_MAY_DISCARD :
- MOJO_READ_MESSAGE_FLAG_NONE);
- }
-
- MojoHandle pipe0_, pipe1_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MessagePipeTest);
-};
-
-using FuseMessagePipeTest = test::MojoTestBase;
-
-TEST_F(MessagePipeTest, WriteData) {
- ASSERT_EQ(MOJO_RESULT_OK,
- WriteMessage(pipe0_, kHelloWorld, sizeof(kHelloWorld)));
-}
-
-// Tests:
-// - only default flags
-// - reading messages from a port
-// - when there are no/one/two messages available for that port
-// - with buffer size 0 (and null buffer) -- should get size
-// - with too-small buffer -- should get size
-// - also verify that buffers aren't modified when/where they shouldn't be
-// - writing messages to a port
-// - in the obvious scenarios (as above)
-// - to a port that's been closed
-// - writing a message to a port, closing the other (would be the source) port,
-// and reading it
-TEST_F(MessagePipeTest, Basic) {
- int32_t buffer[2];
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
- uint32_t buffer_size;
-
- // Nothing to read yet on port 0.
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe0_, buffer, &buffer_size));
- ASSERT_EQ(kBufferSize, buffer_size);
- ASSERT_EQ(123, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- // Ditto for port 1.
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe1_, buffer, &buffer_size));
-
- // Write from port 1 (to port 0).
- buffer[0] = 789012345;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
-
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Read from port 0.
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe0_, buffer, &buffer_size));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
- ASSERT_EQ(789012345, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- // Read again from port 0 -- it should be empty.
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe0_, buffer, &buffer_size));
-
- // Write two messages from port 0 (to port 1).
- buffer[0] = 123456789;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, sizeof(buffer[0])));
- buffer[0] = 234567890;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, sizeof(buffer[0])));
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Read from port 1 with buffer size 0 (should get the size of next message).
- // Also test that giving a null buffer is okay when the buffer size is 0.
- buffer_size = 0;
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- ReadMessage(pipe1_, nullptr, &buffer_size));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
-
- // Read from port 1 with buffer size 1 (too small; should get the size of next
- // message).
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = 1;
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- ReadMessage(pipe1_, buffer, &buffer_size));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
- ASSERT_EQ(123, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- // Read from port 1.
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
- ASSERT_EQ(123456789, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Read again from port 1.
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
- ASSERT_EQ(234567890, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- // Read again from port 1 -- it should be empty.
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, ReadMessage(pipe1_, buffer, &buffer_size));
-
- // Write from port 0 (to port 1).
- buffer[0] = 345678901;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, sizeof(buffer[0])));
-
- // Close port 0.
- MojoClose(pipe0_);
- pipe0_ = MOJO_HANDLE_INVALID;
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &state));
-
- // Try to write from port 1 (to port 0).
- buffer[0] = 456789012;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
-
- // Read from port 1; should still get message (even though port 0 was closed).
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
- ASSERT_EQ(345678901, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- // Read again from port 1 -- it should be empty (and port 0 is closed).
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- ReadMessage(pipe1_, buffer, &buffer_size));
-}
-
-TEST_F(MessagePipeTest, CloseWithQueuedIncomingMessages) {
- int32_t buffer[1];
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
- uint32_t buffer_size;
-
- // Write some messages from port 1 (to port 0).
- for (int32_t i = 0; i < 5; i++) {
- buffer[0] = i;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, kBufferSize));
- }
-
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Port 0 shouldn't be empty.
- buffer_size = 0;
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- ReadMessage(pipe0_, nullptr, &buffer_size));
- ASSERT_EQ(kBufferSize, buffer_size);
-
- // Close port 0 first, which should have outstanding (incoming) messages.
- MojoClose(pipe0_);
- MojoClose(pipe1_);
- pipe0_ = pipe1_ = MOJO_HANDLE_INVALID;
-}
-
-TEST_F(MessagePipeTest, DiscardMode) {
- int32_t buffer[2];
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
- uint32_t buffer_size;
-
- // Write from port 1 (to port 0).
- buffer[0] = 789012345;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
-
- MojoHandleSignalsState state;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Read/discard from port 0 (no buffer); get size.
- buffer_size = 0;
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- ReadMessage(pipe0_, nullptr, &buffer_size, true));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
-
- // Read again from port 0 -- it should be empty.
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT,
- ReadMessage(pipe0_, buffer, &buffer_size, true));
-
- // Write from port 1 (to port 0).
- buffer[0] = 890123456;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK,
- WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Read from port 0 (buffer big enough).
- buffer[0] = 123;
- buffer[1] = 456;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe0_, buffer, &buffer_size, true));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
- ASSERT_EQ(890123456, buffer[0]);
- ASSERT_EQ(456, buffer[1]);
-
- // Read again from port 0 -- it should be empty.
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT,
- ReadMessage(pipe0_, buffer, &buffer_size, true));
-
- // Write from port 1 (to port 0).
- buffer[0] = 901234567;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Read/discard from port 0 (buffer too small); get size.
- buffer_size = 1;
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- ReadMessage(pipe0_, buffer, &buffer_size, true));
- ASSERT_EQ(static_cast<uint32_t>(sizeof(buffer[0])), buffer_size);
-
- // Read again from port 0 -- it should be empty.
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT,
- ReadMessage(pipe0_, buffer, &buffer_size, true));
-
- // Write from port 1 (to port 0).
- buffer[0] = 123456789;
- buffer[1] = 0;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe1_, buffer, sizeof(buffer[0])));
-
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe0_, MOJO_HANDLE_SIGNAL_READABLE, &state));
-
- // Discard from port 0.
- buffer_size = 1;
- ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- ReadMessage(pipe0_, nullptr, 0, true));
-
- // Read again from port 0 -- it should be empty.
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT,
- ReadMessage(pipe0_, buffer, &buffer_size, true));
-}
-
-TEST_F(MessagePipeTest, BasicWaiting) {
- MojoHandleSignalsState hss;
-
- int32_t buffer[1];
- const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
- uint32_t buffer_size;
-
- // Always writable (until the other port is closed). Not yet readable. Peer
- // not closed.
- hss = GetSignalsState(pipe0_);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- hss = MojoHandleSignalsState();
-
- // Write from port 0 (to port 1), to make port 1 readable.
- buffer[0] = 123456789;
- ASSERT_EQ(MOJO_RESULT_OK, WriteMessage(pipe0_, buffer, kBufferSize));
-
- // Port 1 should already be readable now.
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
- // ... and still writable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- hss.satisfied_signals);
- ASSERT_EQ(kAllSignals, hss.satisfiable_signals);
-
- // Close port 0.
- MojoClose(pipe0_);
- pipe0_ = MOJO_HANDLE_INVALID;
-
- // Port 1 should be signaled with peer closed.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_PEER_CLOSED, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // Port 1 should not be writable.
- hss = MojoHandleSignalsState();
-
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_WRITABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // But it should still be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- hss.satisfiable_signals);
-
- // Read from port 1.
- buffer[0] = 0;
- buffer_size = kBufferSize;
- ASSERT_EQ(MOJO_RESULT_OK, ReadMessage(pipe1_, buffer, &buffer_size));
- ASSERT_EQ(123456789, buffer[0]);
-
- // Now port 1 should no longer be readable.
- hss = MojoHandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(pipe1_, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
-}
-
-TEST_F(MessagePipeTest, InvalidMessageObjects) {
- // null message
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoFreeMessage(MOJO_MESSAGE_HANDLE_INVALID));
-
- // null message
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoGetMessageBuffer(MOJO_MESSAGE_HANDLE_INVALID, nullptr));
-
- // Non-zero num_handles with null handles array.
- ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoAllocMessage(0, nullptr, 1, MOJO_ALLOC_MESSAGE_FLAG_NONE,
- nullptr));
-}
-
-TEST_F(MessagePipeTest, AllocAndFreeMessage) {
- const std::string kMessage = "Hello, world.";
- MojoMessageHandle message = MOJO_MESSAGE_HANDLE_INVALID;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoAllocMessage(static_cast<uint32_t>(kMessage.size()), nullptr, 0,
- MOJO_ALLOC_MESSAGE_FLAG_NONE, &message));
- ASSERT_NE(MOJO_MESSAGE_HANDLE_INVALID, message);
- ASSERT_EQ(MOJO_RESULT_OK, MojoFreeMessage(message));
-}
-
-TEST_F(MessagePipeTest, WriteAndReadMessageObject) {
- const std::string kMessage = "Hello, world.";
- MojoMessageHandle message = MOJO_MESSAGE_HANDLE_INVALID;
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoAllocMessage(static_cast<uint32_t>(kMessage.size()), nullptr, 0,
- MOJO_ALLOC_MESSAGE_FLAG_NONE, &message));
- ASSERT_NE(MOJO_MESSAGE_HANDLE_INVALID, message);
-
- void* buffer = nullptr;
- EXPECT_EQ(MOJO_RESULT_OK, MojoGetMessageBuffer(message, &buffer));
- ASSERT_TRUE(buffer);
- memcpy(buffer, kMessage.data(), kMessage.size());
-
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWriteMessageNew(a, message, MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE));
- uint32_t num_bytes = 0;
- uint32_t num_handles = 0;
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoReadMessageNew(b, &message, &num_bytes, nullptr, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE));
- ASSERT_NE(MOJO_MESSAGE_HANDLE_INVALID, message);
- EXPECT_EQ(static_cast<uint32_t>(kMessage.size()), num_bytes);
- EXPECT_EQ(0u, num_handles);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoGetMessageBuffer(message, &buffer));
- ASSERT_TRUE(buffer);
-
- EXPECT_EQ(0, strncmp(static_cast<const char*>(buffer), kMessage.data(),
- num_bytes));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoFreeMessage(message));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-#if !defined(OS_IOS)
-
-const size_t kPingPongHandlesPerIteration = 50;
-const size_t kPingPongIterations = 500;
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(HandlePingPong, MessagePipeTest, h) {
- // Waits for a handle to become readable and writes it back to the sender.
- for (size_t i = 0; i < kPingPongIterations; i++) {
- MojoHandle handles[kPingPongHandlesPerIteration];
- ReadMessageWithHandles(h, handles, kPingPongHandlesPerIteration);
- WriteMessageWithHandles(h, "", handles, kPingPongHandlesPerIteration);
- }
-
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE));
- char msg[4];
- uint32_t num_bytes = 4;
- EXPECT_EQ(MOJO_RESULT_OK, ReadMessage(h, msg, &num_bytes));
-}
-
-// This test is flaky: http://crbug.com/585784
-TEST_F(MessagePipeTest, DISABLED_DataPipeConsumerHandlePingPong) {
- MojoHandle p, c[kPingPongHandlesPerIteration];
- for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i) {
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(nullptr, &p, &c[i]));
- MojoClose(p);
- }
-
- RUN_CHILD_ON_PIPE(HandlePingPong, h)
- for (size_t i = 0; i < kPingPongIterations; i++) {
- WriteMessageWithHandles(h, "", c, kPingPongHandlesPerIteration);
- ReadMessageWithHandles(h, c, kPingPongHandlesPerIteration);
- }
- WriteMessage(h, "quit", 4);
- END_CHILD()
- for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
- MojoClose(c[i]);
-}
-
-// This test is flaky: http://crbug.com/585784
-TEST_F(MessagePipeTest, DISABLED_DataPipeProducerHandlePingPong) {
- MojoHandle p[kPingPongHandlesPerIteration], c;
- for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i) {
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateDataPipe(nullptr, &p[i], &c));
- MojoClose(c);
- }
-
- RUN_CHILD_ON_PIPE(HandlePingPong, h)
- for (size_t i = 0; i < kPingPongIterations; i++) {
- WriteMessageWithHandles(h, "", p, kPingPongHandlesPerIteration);
- ReadMessageWithHandles(h, p, kPingPongHandlesPerIteration);
- }
- WriteMessage(h, "quit", 4);
- END_CHILD()
- for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
- MojoClose(p[i]);
-}
-
-TEST_F(MessagePipeTest, SharedBufferHandlePingPong) {
- MojoHandle buffers[kPingPongHandlesPerIteration];
- for (size_t i = 0; i <kPingPongHandlesPerIteration; ++i)
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(nullptr, 1, &buffers[i]));
-
- RUN_CHILD_ON_PIPE(HandlePingPong, h)
- for (size_t i = 0; i < kPingPongIterations; i++) {
- WriteMessageWithHandles(h, "", buffers, kPingPongHandlesPerIteration);
- ReadMessageWithHandles(h, buffers, kPingPongHandlesPerIteration);
- }
- WriteMessage(h, "quit", 4);
- END_CHILD()
- for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i)
- MojoClose(buffers[i]);
-}
-
-#endif // !defined(OS_IOS)
-
-TEST_F(FuseMessagePipeTest, Basic) {
- // Test that we can fuse pipes and they still work.
-
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c));
-
- // Handles b and c should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
-
- const std::string kTestMessage1 = "Hello, world!";
- const std::string kTestMessage2 = "Goodbye, world!";
-
- WriteMessage(a, kTestMessage1);
- EXPECT_EQ(kTestMessage1, ReadMessage(d));
-
- WriteMessage(d, kTestMessage2);
- EXPECT_EQ(kTestMessage2, ReadMessage(a));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(FuseMessagePipeTest, FuseAfterPeerWrite) {
- // Test that messages written before fusion are eventually delivered.
-
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
-
- const std::string kTestMessage1 = "Hello, world!";
- const std::string kTestMessage2 = "Goodbye, world!";
- WriteMessage(a, kTestMessage1);
- WriteMessage(d, kTestMessage2);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c));
-
- // Handles b and c should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
-
- EXPECT_EQ(kTestMessage1, ReadMessage(d));
- EXPECT_EQ(kTestMessage2, ReadMessage(a));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(FuseMessagePipeTest, NoFuseAfterWrite) {
- // Test that a pipe endpoint which has been written to cannot be fused.
-
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
-
- WriteMessage(b, "shouldn't have done that!");
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, MojoFuseMessagePipes(b, c));
-
- // Handles b and c should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(FuseMessagePipeTest, NoFuseSelf) {
- // Test that a pipe's own endpoints can't be fused together.
-
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, MojoFuseMessagePipes(a, b));
-
- // Handles a and b should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
-}
-
-TEST_F(FuseMessagePipeTest, FuseInvalidArguments) {
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-
- // Can't fuse an invalid handle.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(b, c));
-
- // Handle c should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
-
- // Can't fuse a non-message pipe handle.
- MojoHandle e, f;
- CreateDataPipe(&e, &f, 16);
-
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(e, d));
-
- // Handles d and e should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(d));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(e));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(f));
-}
-
-TEST_F(FuseMessagePipeTest, FuseAfterPeerClosure) {
- // Test that peer closure prior to fusion can still be detected after fusion.
-
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c));
-
- // Handles b and c should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
-
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(d, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(FuseMessagePipeTest, FuseAfterPeerWriteAndClosure) {
- // Test that peer write and closure prior to fusion still results in the
- // both message arrival and awareness of peer closure.
-
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
-
- const std::string kTestMessage = "ayyy lmao";
- WriteMessage(a, kTestMessage);
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c));
-
- // Handles b and c should be closed.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c));
-
- EXPECT_EQ(kTestMessage, ReadMessage(d));
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(d, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(MessagePipeTest, ClosePipesStressTest) {
- // Stress test to exercise https://crbug.com/665869.
- const size_t kNumPipes = 100000;
- for (size_t i = 0; i < kNumPipes; ++i) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
- MojoClose(a);
- MojoClose(b);
- }
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
deleted file mode 100644
index 37248d1..0000000
--- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc
+++ /dev/null
@@ -1,1366 +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 <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/containers/hash_tables.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/string_split.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/edk/test/test_utils.h"
-#include "mojo/public/c/system/buffer.h"
-#include "mojo/public/c/system/functions.h"
-#include "mojo/public/c/system/types.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-#include "mojo/public/cpp/system/wait.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-
-namespace mojo {
-namespace edk {
-namespace {
-
-class MultiprocessMessagePipeTest : public test::MojoTestBase {
- protected:
- // Convenience class for tests which will control command-driven children.
- // See the CommandDrivenClient definition below.
- class CommandDrivenClientController {
- public:
- explicit CommandDrivenClientController(MojoHandle h) : h_(h) {}
-
- void Send(const std::string& command) {
- WriteMessage(h_, command);
- EXPECT_EQ("ok", ReadMessage(h_));
- }
-
- void SendHandle(const std::string& name, MojoHandle p) {
- WriteMessageWithHandles(h_, "take:" + name, &p, 1);
- EXPECT_EQ("ok", ReadMessage(h_));
- }
-
- MojoHandle RetrieveHandle(const std::string& name) {
- WriteMessage(h_, "return:" + name);
- MojoHandle p;
- EXPECT_EQ("ok", ReadMessageWithHandles(h_, &p, 1));
- return p;
- }
-
- void Exit() { WriteMessage(h_, "exit"); }
-
- private:
- MojoHandle h_;
- };
-};
-
-class MultiprocessMessagePipeTestWithPeerSupport
- : public MultiprocessMessagePipeTest,
- public testing::WithParamInterface<test::MojoTestBase::LaunchType> {
- protected:
- void SetUp() override {
- test::MojoTestBase::SetUp();
- set_launch_type(GetParam());
- }
-};
-
-// For each message received, sends a reply message with the same contents
-// repeated twice, until the other end is closed or it receives "quitquitquit"
-// (which it doesn't reply to). It'll return the number of messages received,
-// not including any "quitquitquit" message, modulo 100.
-DEFINE_TEST_CLIENT_WITH_PIPE(EchoEcho, MultiprocessMessagePipeTest, h) {
- const std::string quitquitquit("quitquitquit");
- int rv = 0;
- for (;; rv = (rv + 1) % 100) {
- // Wait for our end of the message pipe to be readable.
- HandleSignalsState hss;
- MojoResult result = WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss);
- if (result != MOJO_RESULT_OK) {
- // It was closed, probably.
- CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION);
- CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- break;
- } else {
- CHECK((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- CHECK((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
- }
-
- std::string read_buffer(1000, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(h, &read_buffer[0],
- &read_buffer_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- VLOG(2) << "Child got: " << read_buffer;
-
- if (read_buffer == quitquitquit) {
- VLOG(2) << "Child quitting.";
- break;
- }
-
- std::string write_buffer = read_buffer + read_buffer;
- CHECK_EQ(MojoWriteMessage(h, write_buffer.data(),
- static_cast<uint32_t>(write_buffer.size()),
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- }
-
- return rv;
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, Basic) {
- RUN_CHILD_ON_PIPE(EchoEcho, h)
- std::string hello("hello");
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, hello.data(),
- static_cast<uint32_t>(hello.size()), nullptr, 0u,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- // The child may or may not have closed its end of the message pipe and died
- // (and we may or may not know it yet), so our end may or may not appear as
- // writable.
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
-
- std::string read_buffer(1000, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(h, &read_buffer[0],
- &read_buffer_size, nullptr, 0,
- MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- VLOG(2) << "Parent got: " << read_buffer;
- ASSERT_EQ(hello + hello, read_buffer);
-
- std::string quitquitquit("quitquitquit");
- CHECK_EQ(MojoWriteMessage(h, quitquitquit.data(),
- static_cast<uint32_t>(quitquitquit.size()),
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- END_CHILD_AND_EXPECT_EXIT_CODE(1 % 100);
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, QueueMessages) {
- static const size_t kNumMessages = 1001;
- RUN_CHILD_ON_PIPE(EchoEcho, h)
- for (size_t i = 0; i < kNumMessages; i++) {
- std::string write_buffer(i, 'A' + (i % 26));
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, write_buffer.data(),
- static_cast<uint32_t>(write_buffer.size()),
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
- }
-
- for (size_t i = 0; i < kNumMessages; i++) {
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- // The child may or may not have closed its end of the message pipe and
- // died (and we may or may not know it yet), so our end may or may not
- // appear as writable.
- ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- ASSERT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
-
- std::string read_buffer(kNumMessages * 2, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- ASSERT_EQ(MojoReadMessage(h, &read_buffer[0],
- &read_buffer_size, nullptr, 0,
- MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
-
- ASSERT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer);
- }
-
- const std::string quitquitquit("quitquitquit");
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, quitquitquit.data(),
- static_cast<uint32_t>(quitquitquit.size()),
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for it to become readable, which should fail (since we sent
- // "quitquitquit").
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
- END_CHILD_AND_EXPECT_EXIT_CODE(static_cast<int>(kNumMessages % 100));
-}
-
-DEFINE_TEST_CLIENT_WITH_PIPE(CheckSharedBuffer, MultiprocessMessagePipeTest,
- h) {
- // Wait for the first message from our parent.
- HandleSignalsState hss;
- CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- // In this test, the parent definitely doesn't close its end of the message
- // pipe before we do.
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- // It should have a shared buffer.
- std::string read_buffer(100, '\0');
- uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
- MojoHandle handles[10];
- uint32_t num_handlers = arraysize(handles); // Maximum number to receive
- CHECK_EQ(MojoReadMessage(h, &read_buffer[0],
- &num_bytes, &handles[0],
- &num_handlers, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(num_bytes);
- CHECK_EQ(read_buffer, std::string("go 1"));
- CHECK_EQ(num_handlers, 1u);
-
- // Make a mapping.
- void* buffer;
- CHECK_EQ(MojoMapBuffer(handles[0], 0, 100, &buffer,
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE),
- MOJO_RESULT_OK);
-
- // Write some stuff to the shared buffer.
- static const char kHello[] = "hello";
- memcpy(buffer, kHello, sizeof(kHello));
-
- // We should be able to close the dispatcher now.
- MojoClose(handles[0]);
-
- // And send a message to signal that we've written stuff.
- const std::string go2("go 2");
- CHECK_EQ(MojoWriteMessage(h, go2.data(),
- static_cast<uint32_t>(go2.size()), nullptr, 0u,
- MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
-
- // Now wait for our parent to send us a message.
- hss = HandleSignalsState();
- CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- read_buffer = std::string(100, '\0');
- num_bytes = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &num_bytes,
- nullptr, 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(num_bytes);
- CHECK_EQ(read_buffer, std::string("go 3"));
-
- // It should have written something to the shared buffer.
- static const char kWorld[] = "world!!!";
- CHECK_EQ(memcmp(buffer, kWorld, sizeof(kWorld)), 0);
-
- // And we're done.
-
- return 0;
-}
-
-TEST_F(MultiprocessMessagePipeTest, SharedBufferPassing) {
- RUN_CHILD_ON_PIPE(CheckSharedBuffer, h)
- // Make a shared buffer.
- MojoCreateSharedBufferOptions options;
- options.struct_size = sizeof(options);
- options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
-
- MojoHandle shared_buffer;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateSharedBuffer(&options, 100, &shared_buffer));
-
- // Send the shared buffer.
- const std::string go1("go 1");
-
- MojoHandle duplicated_shared_buffer;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoDuplicateBufferHandle(
- shared_buffer,
- nullptr,
- &duplicated_shared_buffer));
- MojoHandle handles[1];
- handles[0] = duplicated_shared_buffer;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, &go1[0],
- static_cast<uint32_t>(go1.size()), &handles[0],
- arraysize(handles),
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for a message from the child.
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
-
- std::string read_buffer(100, '\0');
- uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessage(h, &read_buffer[0],
- &num_bytes, nullptr, 0,
- MOJO_READ_MESSAGE_FLAG_NONE));
- read_buffer.resize(num_bytes);
- ASSERT_EQ(std::string("go 2"), read_buffer);
-
- // After we get it, the child should have written something to the shared
- // buffer.
- static const char kHello[] = "hello";
- void* buffer;
- CHECK_EQ(MojoMapBuffer(shared_buffer, 0, 100, &buffer,
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE),
- MOJO_RESULT_OK);
- ASSERT_EQ(0, memcmp(buffer, kHello, sizeof(kHello)));
-
- // Now we'll write some stuff to the shared buffer.
- static const char kWorld[] = "world!!!";
- memcpy(buffer, kWorld, sizeof(kWorld));
-
- // And send a message to signal that we've written stuff.
- const std::string go3("go 3");
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, &go3[0],
- static_cast<uint32_t>(go3.size()), nullptr, 0u,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for |h| to become readable, which should fail.
- hss = HandleSignalsState();
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_WITH_PIPE(CheckPlatformHandleFile,
- MultiprocessMessagePipeTest, h) {
- HandleSignalsState hss;
- CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- std::string read_buffer(100, '\0');
- uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
- MojoHandle handles[255]; // Maximum number to receive.
- uint32_t num_handlers = arraysize(handles);
-
- CHECK_EQ(MojoReadMessage(h, &read_buffer[0],
- &num_bytes, &handles[0],
- &num_handlers, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
-
- read_buffer.resize(num_bytes);
- char hello[32];
- int num_handles = 0;
- sscanf(read_buffer.c_str(), "%s %d", hello, &num_handles);
- CHECK_EQ(std::string("hello"), std::string(hello));
- CHECK_GT(num_handles, 0);
-
- for (int i = 0; i < num_handles; ++i) {
- ScopedPlatformHandle h;
- CHECK_EQ(PassWrappedPlatformHandle(handles[i], &h), MOJO_RESULT_OK);
- CHECK(h.is_valid());
- MojoClose(handles[i]);
-
- base::ScopedFILE fp(test::FILEFromPlatformHandle(std::move(h), "r"));
- CHECK(fp);
- std::string fread_buffer(100, '\0');
- size_t bytes_read =
- fread(&fread_buffer[0], 1, fread_buffer.size(), fp.get());
- fread_buffer.resize(bytes_read);
- CHECK_EQ(fread_buffer, "world");
- }
-
- return 0;
-}
-
-class MultiprocessMessagePipeTestWithPipeCount
- : public MultiprocessMessagePipeTest,
- public testing::WithParamInterface<size_t> {};
-
-TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- RUN_CHILD_ON_PIPE(CheckPlatformHandleFile, h)
- std::vector<MojoHandle> handles;
-
- size_t pipe_count = GetParam();
- for (size_t i = 0; i < pipe_count; ++i) {
- base::FilePath unused;
- base::ScopedFILE fp(
- CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
- const std::string world("world");
- CHECK_EQ(fwrite(&world[0], 1, world.size(), fp.get()), world.size());
- fflush(fp.get());
- rewind(fp.get());
- MojoHandle handle;
- ASSERT_EQ(
- CreatePlatformHandleWrapper(
- ScopedPlatformHandle(test::PlatformHandleFromFILE(std::move(fp))),
- &handle),
- MOJO_RESULT_OK);
- handles.push_back(handle);
- }
-
- char message[128];
- snprintf(message, sizeof(message), "hello %d",
- static_cast<int>(pipe_count));
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, message,
- static_cast<uint32_t>(strlen(message)),
- &handles[0],
- static_cast<uint32_t>(handles.size()),
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for it to become readable, which should fail.
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals);
- ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals);
- END_CHILD()
-}
-
-// Android multi-process tests are not executing the new process. This is flaky.
-#if !defined(OS_ANDROID)
-INSTANTIATE_TEST_CASE_P(PipeCount,
- MultiprocessMessagePipeTestWithPipeCount,
- // TODO(rockot): Re-enable the 140-pipe case when
- // ChannelPosix has support for sending lots of handles.
- testing::Values(1u, 128u /*, 140u*/));
-#endif
-
-DEFINE_TEST_CLIENT_WITH_PIPE(CheckMessagePipe, MultiprocessMessagePipeTest, h) {
- // Wait for the first message from our parent.
- HandleSignalsState hss;
- CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- // In this test, the parent definitely doesn't close its end of the message
- // pipe before we do.
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- // It should have a message pipe.
- MojoHandle handles[10];
- uint32_t num_handlers = arraysize(handles);
- CHECK_EQ(MojoReadMessage(h, nullptr,
- nullptr, &handles[0],
- &num_handlers, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(num_handlers, 1u);
-
- // Read data from the received message pipe.
- CHECK_EQ(WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- std::string read_buffer(100, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(handles[0], &read_buffer[0],
- &read_buffer_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- CHECK_EQ(read_buffer, std::string("hello"));
-
- // Now write some data into the message pipe.
- std::string write_buffer = "world";
- CHECK_EQ(MojoWriteMessage(handles[0], write_buffer.data(),
- static_cast<uint32_t>(write_buffer.size()), nullptr,
- 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- MojoClose(handles[0]);
- return 0;
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipePassing) {
- RUN_CHILD_ON_PIPE(CheckMessagePipe, h)
- MojoCreateSharedBufferOptions options;
- options.struct_size = sizeof(options);
- options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
-
- MojoHandle mp1, mp2;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateMessagePipe(nullptr, &mp1, &mp2));
-
- // Write a string into one end of the new message pipe and send the other
- // end.
- const std::string hello("hello");
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(mp1, &hello[0],
- static_cast<uint32_t>(hello.size()), nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, nullptr, 0, &mp2, 1,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for a message from the child.
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
-
- std::string read_buffer(100, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0],
- &read_buffer_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- CHECK_EQ(read_buffer, std::string("world"));
-
- MojoClose(mp1);
- END_CHILD()
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipeTwoPassing) {
- RUN_CHILD_ON_PIPE(CheckMessagePipe, h)
- MojoHandle mp1, mp2;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateMessagePipe(nullptr, &mp2, &mp1));
-
- // Write a string into one end of the new message pipe and send the other
- // end.
- const std::string hello("hello");
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(mp1, &hello[0],
- static_cast<uint32_t>(hello.size()), nullptr, 0u,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, nullptr, 0u, &mp2, 1u,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for a message from the child.
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
-
- std::string read_buffer(100, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0],
- &read_buffer_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- CHECK_EQ(read_buffer, std::string("world"));
- END_CHILD();
-}
-
-DEFINE_TEST_CLIENT_WITH_PIPE(DataPipeConsumer, MultiprocessMessagePipeTest, h) {
- // Wait for the first message from our parent.
- HandleSignalsState hss;
- CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- // In this test, the parent definitely doesn't close its end of the message
- // pipe before we do.
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- // It should have a message pipe.
- MojoHandle handles[10];
- uint32_t num_handlers = arraysize(handles);
- CHECK_EQ(MojoReadMessage(h, nullptr,
- nullptr, &handles[0],
- &num_handlers, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(num_handlers, 1u);
-
- // Read data from the received message pipe.
- CHECK_EQ(WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_READABLE, &hss),
- MOJO_RESULT_OK);
- CHECK_EQ(hss.satisfied_signals,
- MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE);
- CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE |
- MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
-
- std::string read_buffer(100, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(handles[0], &read_buffer[0],
- &read_buffer_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- CHECK_EQ(read_buffer, std::string("hello"));
-
- // Now write some data into the message pipe.
- std::string write_buffer = "world";
- CHECK_EQ(MojoWriteMessage(handles[0], write_buffer.data(),
- static_cast<uint32_t>(write_buffer.size()),
- nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- MojoClose(handles[0]);
- return 0;
-}
-
-TEST_F(MultiprocessMessagePipeTest, DataPipeConsumer) {
- RUN_CHILD_ON_PIPE(DataPipeConsumer, h)
- MojoCreateSharedBufferOptions options;
- options.struct_size = sizeof(options);
- options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
-
- MojoHandle mp1, mp2;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoCreateMessagePipe(nullptr, &mp2, &mp1));
-
- // Write a string into one end of the new message pipe and send the other
- // end.
- const std::string hello("hello");
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(mp1, &hello[0],
- static_cast<uint32_t>(hello.size()), nullptr, 0u,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWriteMessage(h, nullptr, 0, &mp2, 1u,
- MOJO_WRITE_MESSAGE_FLAG_NONE));
-
- // Wait for a message from the child.
- HandleSignalsState hss;
- ASSERT_EQ(MOJO_RESULT_OK,
- WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
- EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
- EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
-
- std::string read_buffer(100, '\0');
- uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
- CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0],
- &read_buffer_size, nullptr,
- 0, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- read_buffer.resize(read_buffer_size);
- CHECK_EQ(read_buffer, std::string("world"));
-
- MojoClose(mp1);
- END_CHILD();
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, CreateMessagePipe) {
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
- VerifyTransmission(p0, p1, std::string(10 * 1024 * 1024, 'a'));
- VerifyTransmission(p1, p0, std::string(10 * 1024 * 1024, 'e'));
-
- CloseHandle(p0);
- CloseHandle(p1);
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PassMessagePipeLocal) {
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
- VerifyTransmission(p0, p1, "testing testing");
- VerifyTransmission(p1, p0, "one two three");
-
- MojoHandle p2, p3;
-
- CreateMessagePipe(&p2, &p3);
- VerifyTransmission(p2, p3, "testing testing");
- VerifyTransmission(p3, p2, "one two three");
-
- // Pass p2 over p0 to p1.
- const std::string message = "ceci n'est pas une pipe";
- WriteMessageWithHandles(p0, message, &p2, 1);
- EXPECT_EQ(message, ReadMessageWithHandles(p1, &p2, 1));
-
- CloseHandle(p0);
- CloseHandle(p1);
-
- // Verify that the received handle (now in p2) still works.
- VerifyTransmission(p2, p3, "Easy come, easy go; will you let me go?");
- VerifyTransmission(p3, p2, "Bismillah! NO! We will not let you go!");
-
- CloseHandle(p2);
- CloseHandle(p3);
-}
-
-// Echos the primordial channel until "exit".
-DEFINE_TEST_CLIENT_WITH_PIPE(ChannelEchoClient, MultiprocessMessagePipeTest,
- h) {
- for (;;) {
- std::string message = ReadMessage(h);
- if (message == "exit")
- break;
- WriteMessage(h, message);
- }
- return 0;
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MultiprocessChannelPipe) {
- RUN_CHILD_ON_PIPE(ChannelEchoClient, h)
- VerifyEcho(h, "in an interstellar burst");
- VerifyEcho(h, "i am back to save the universe");
- VerifyEcho(h, std::string(10 * 1024 * 1024, 'o'));
-
- WriteMessage(h, "exit");
- END_CHILD()
-}
-
-// Receives a pipe handle from the primordial channel and echos on it until
-// "exit". Used to test simple pipe transfer across processes via channels.
-DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceClient, MultiprocessMessagePipeTest,
- h) {
- MojoHandle p;
- ReadMessageWithHandles(h, &p, 1);
- for (;;) {
- std::string message = ReadMessage(p);
- if (message == "exit")
- break;
- WriteMessage(p, message);
- }
- return 0;
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
- PassMessagePipeCrossProcess) {
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
- RUN_CHILD_ON_PIPE(EchoServiceClient, h)
-
- // Pass one end of the pipe to the other process.
- WriteMessageWithHandles(h, "here take this", &p1, 1);
-
- VerifyEcho(p0, "and you may ask yourself");
- VerifyEcho(p0, "where does that highway go?");
- VerifyEcho(p0, std::string(20 * 1024 * 1024, 'i'));
-
- WriteMessage(p0, "exit");
- END_CHILD()
- CloseHandle(p0);
-}
-
-// Receives a pipe handle from the primordial channel and reads new handles
-// from it. Each read handle establishes a new echo channel.
-DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceFactoryClient,
- MultiprocessMessagePipeTest, h) {
- MojoHandle p;
- ReadMessageWithHandles(h, &p, 1);
-
- std::vector<Handle> handles(2);
- handles[0] = Handle(h);
- handles[1] = Handle(p);
- std::vector<MojoHandleSignals> signals(2, MOJO_HANDLE_SIGNAL_READABLE);
- for (;;) {
- size_t index;
- CHECK_EQ(
- mojo::WaitMany(handles.data(), signals.data(), handles.size(), &index),
- MOJO_RESULT_OK);
- DCHECK_LE(index, handles.size());
- if (index == 0) {
- // If data is available on the first pipe, it should be an exit command.
- EXPECT_EQ(std::string("exit"), ReadMessage(h));
- break;
- } else if (index == 1) {
- // If the second pipe, it should be a new handle requesting echo service.
- MojoHandle echo_request;
- ReadMessageWithHandles(p, &echo_request, 1);
- handles.push_back(Handle(echo_request));
- signals.push_back(MOJO_HANDLE_SIGNAL_READABLE);
- } else {
- // Otherwise it was one of our established echo pipes. Echo!
- WriteMessage(handles[index].value(), ReadMessage(handles[index].value()));
- }
- }
-
- for (size_t i = 1; i < handles.size(); ++i)
- CloseHandle(handles[i].value());
-
- return 0;
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
- PassMoarMessagePipesCrossProcess) {
- MojoHandle echo_factory_proxy, echo_factory_request;
- CreateMessagePipe(&echo_factory_proxy, &echo_factory_request);
-
- MojoHandle echo_proxy_a, echo_request_a;
- CreateMessagePipe(&echo_proxy_a, &echo_request_a);
-
- MojoHandle echo_proxy_b, echo_request_b;
- CreateMessagePipe(&echo_proxy_b, &echo_request_b);
-
- MojoHandle echo_proxy_c, echo_request_c;
- CreateMessagePipe(&echo_proxy_c, &echo_request_c);
-
- RUN_CHILD_ON_PIPE(EchoServiceFactoryClient, h)
- WriteMessageWithHandles(
- h, "gief factory naow plz", &echo_factory_request, 1);
-
- WriteMessageWithHandles(echo_factory_proxy, "give me an echo service plz!",
- &echo_request_a, 1);
- WriteMessageWithHandles(echo_factory_proxy, "give me one too!",
- &echo_request_b, 1);
-
- VerifyEcho(echo_proxy_a, "i came here for an argument");
- VerifyEcho(echo_proxy_a, "shut your festering gob");
- VerifyEcho(echo_proxy_a, "mumble mumble mumble");
-
- VerifyEcho(echo_proxy_b, "wubalubadubdub");
- VerifyEcho(echo_proxy_b, "wubalubadubdub");
-
- WriteMessageWithHandles(echo_factory_proxy, "hook me up also thanks",
- &echo_request_c, 1);
-
- VerifyEcho(echo_proxy_a, "the frobinators taste like frobinators");
- VerifyEcho(echo_proxy_b, "beep bop boop");
- VerifyEcho(echo_proxy_c, "zzzzzzzzzzzzzzzzzzzzzzzzzz");
-
- WriteMessage(h, "exit");
- END_CHILD()
-
- CloseHandle(echo_factory_proxy);
- CloseHandle(echo_proxy_a);
- CloseHandle(echo_proxy_b);
- CloseHandle(echo_proxy_c);
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
- ChannelPipesWithMultipleChildren) {
- RUN_CHILD_ON_PIPE(ChannelEchoClient, a)
- RUN_CHILD_ON_PIPE(ChannelEchoClient, b)
- VerifyEcho(a, "hello child 0");
- VerifyEcho(b, "hello child 1");
-
- WriteMessage(a, "exit");
- WriteMessage(b, "exit");
- END_CHILD()
- END_CHILD()
-}
-
-// Reads and turns a pipe handle some number of times to create lots of
-// transient proxies.
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingPongPipeClient,
- MultiprocessMessagePipeTest, h) {
- const size_t kNumBounces = 50;
- MojoHandle p0, p1;
- ReadMessageWithHandles(h, &p0, 1);
- ReadMessageWithHandles(h, &p1, 1);
- for (size_t i = 0; i < kNumBounces; ++i) {
- WriteMessageWithHandles(h, "", &p1, 1);
- ReadMessageWithHandles(h, &p1, 1);
- }
- WriteMessageWithHandles(h, "", &p0, 1);
- WriteMessage(p1, "bye");
- MojoClose(p1);
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PingPongPipe) {
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
-
- RUN_CHILD_ON_PIPE(PingPongPipeClient, h)
- const size_t kNumBounces = 50;
- WriteMessageWithHandles(h, "", &p0, 1);
- WriteMessageWithHandles(h, "", &p1, 1);
- for (size_t i = 0; i < kNumBounces; ++i) {
- ReadMessageWithHandles(h, &p1, 1);
- WriteMessageWithHandles(h, "", &p1, 1);
- }
- ReadMessageWithHandles(h, &p0, 1);
- WriteMessage(h, "quit");
- END_CHILD()
-
- EXPECT_EQ("bye", ReadMessage(p0));
-
- // We should still be able to observe peer closure from the other end.
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(p0, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-// Parses commands from the parent pipe and does whatever it's asked to do.
-DEFINE_TEST_CLIENT_WITH_PIPE(CommandDrivenClient, MultiprocessMessagePipeTest,
- h) {
- base::hash_map<std::string, MojoHandle> named_pipes;
- for (;;) {
- MojoHandle p;
- auto parts = base::SplitString(ReadMessageWithOptionalHandle(h, &p), ":",
- base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
- CHECK(!parts.empty());
- std::string command = parts[0];
- if (command == "take") {
- // Take a pipe.
- CHECK_EQ(parts.size(), 2u);
- CHECK_NE(p, MOJO_HANDLE_INVALID);
- named_pipes[parts[1]] = p;
- WriteMessage(h, "ok");
- } else if (command == "return") {
- // Return a pipe.
- CHECK_EQ(parts.size(), 2u);
- CHECK_EQ(p, MOJO_HANDLE_INVALID);
- p = named_pipes[parts[1]];
- CHECK_NE(p, MOJO_HANDLE_INVALID);
- named_pipes.erase(parts[1]);
- WriteMessageWithHandles(h, "ok", &p, 1);
- } else if (command == "say") {
- // Say something to a named pipe.
- CHECK_EQ(parts.size(), 3u);
- CHECK_EQ(p, MOJO_HANDLE_INVALID);
- p = named_pipes[parts[1]];
- CHECK_NE(p, MOJO_HANDLE_INVALID);
- CHECK(!parts[2].empty());
- WriteMessage(p, parts[2]);
- WriteMessage(h, "ok");
- } else if (command == "hear") {
- // Expect to read something from a named pipe.
- CHECK_EQ(parts.size(), 3u);
- CHECK_EQ(p, MOJO_HANDLE_INVALID);
- p = named_pipes[parts[1]];
- CHECK_NE(p, MOJO_HANDLE_INVALID);
- CHECK(!parts[2].empty());
- CHECK_EQ(parts[2], ReadMessage(p));
- WriteMessage(h, "ok");
- } else if (command == "pass") {
- // Pass one named pipe over another named pipe.
- CHECK_EQ(parts.size(), 3u);
- CHECK_EQ(p, MOJO_HANDLE_INVALID);
- p = named_pipes[parts[1]];
- MojoHandle carrier = named_pipes[parts[2]];
- CHECK_NE(p, MOJO_HANDLE_INVALID);
- CHECK_NE(carrier, MOJO_HANDLE_INVALID);
- named_pipes.erase(parts[1]);
- WriteMessageWithHandles(carrier, "got a pipe for ya", &p, 1);
- WriteMessage(h, "ok");
- } else if (command == "catch") {
- // Expect to receive one named pipe from another named pipe.
- CHECK_EQ(parts.size(), 3u);
- CHECK_EQ(p, MOJO_HANDLE_INVALID);
- MojoHandle carrier = named_pipes[parts[2]];
- CHECK_NE(carrier, MOJO_HANDLE_INVALID);
- ReadMessageWithHandles(carrier, &p, 1);
- CHECK_NE(p, MOJO_HANDLE_INVALID);
- named_pipes[parts[1]] = p;
- WriteMessage(h, "ok");
- } else if (command == "exit") {
- CHECK_EQ(parts.size(), 1u);
- break;
- }
- }
-
- for (auto& pipe : named_pipes)
- CloseHandle(pipe.second);
-
- return 0;
-}
-
-TEST_F(MultiprocessMessagePipeTest, ChildToChildPipes) {
- RUN_CHILD_ON_PIPE(CommandDrivenClient, h0)
- RUN_CHILD_ON_PIPE(CommandDrivenClient, h1)
- CommandDrivenClientController a(h0);
- CommandDrivenClientController b(h1);
-
- // Create a pipe and pass each end to a different client.
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
- a.SendHandle("x", p0);
- b.SendHandle("y", p1);
-
- // Make sure they can talk.
- a.Send("say:x:hello");
- b.Send("hear:y:hello");
-
- b.Send("say:y:i love multiprocess pipes!");
- a.Send("hear:x:i love multiprocess pipes!");
-
- a.Exit();
- b.Exit();
- END_CHILD()
- END_CHILD()
-}
-
-TEST_F(MultiprocessMessagePipeTest, MoreChildToChildPipes) {
- RUN_CHILD_ON_PIPE(CommandDrivenClient, h0)
- RUN_CHILD_ON_PIPE(CommandDrivenClient, h1)
- RUN_CHILD_ON_PIPE(CommandDrivenClient, h2)
- RUN_CHILD_ON_PIPE(CommandDrivenClient, h3)
- CommandDrivenClientController a(h0), b(h1), c(h2), d(h3);
-
- // Connect a to b and c to d
-
- MojoHandle p0, p1;
-
- CreateMessagePipe(&p0, &p1);
- a.SendHandle("b_pipe", p0);
- b.SendHandle("a_pipe", p1);
-
- MojoHandle p2, p3;
-
- CreateMessagePipe(&p2, &p3);
- c.SendHandle("d_pipe", p2);
- d.SendHandle("c_pipe", p3);
-
- // Connect b to c via a and d
- MojoHandle p4, p5;
- CreateMessagePipe(&p4, &p5);
- a.SendHandle("d_pipe", p4);
- d.SendHandle("a_pipe", p5);
-
- // Have |a| pass its new |d|-pipe to |b|. It will eventually connect
- // to |c|.
- a.Send("pass:d_pipe:b_pipe");
- b.Send("catch:c_pipe:a_pipe");
-
- // Have |d| pass its new |a|-pipe to |c|. It will now be connected to
- // |b|.
- d.Send("pass:a_pipe:c_pipe");
- c.Send("catch:b_pipe:d_pipe");
-
- // Make sure b and c and talk.
- b.Send("say:c_pipe:it's a beautiful day");
- c.Send("hear:b_pipe:it's a beautiful day");
-
- // Create x and y and have b and c exchange them.
- MojoHandle x, y;
- CreateMessagePipe(&x, &y);
- b.SendHandle("x", x);
- c.SendHandle("y", y);
- b.Send("pass:x:c_pipe");
- c.Send("pass:y:b_pipe");
- b.Send("catch:y:c_pipe");
- c.Send("catch:x:b_pipe");
-
- // Make sure the pipe still works in both directions.
- b.Send("say:y:hello");
- c.Send("hear:x:hello");
- c.Send("say:x:goodbye");
- b.Send("hear:y:goodbye");
-
- // Take both pipes back.
- y = c.RetrieveHandle("x");
- x = b.RetrieveHandle("y");
-
- VerifyTransmission(x, y, "still works");
- VerifyTransmission(y, x, "in both directions");
-
- CloseHandle(x);
- CloseHandle(y);
-
- a.Exit();
- b.Exit();
- c.Exit();
- d.Exit();
- END_CHILD()
- END_CHILD()
- END_CHILD()
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeer,
- MultiprocessMessagePipeTest, h) {
- MojoHandle p;
- EXPECT_EQ("foo", ReadMessageWithHandles(h, &p, 1));
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendPipeThenClosePeer) {
- RUN_CHILD_ON_PIPE(ReceivePipeWithClosedPeer, h)
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- // Send |a| and immediately close |b|. The child should observe closure.
- WriteMessageWithHandles(h, "foo", &a, 1);
- MojoClose(b);
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(SendOtherChildPipeWithClosedPeer,
- MultiprocessMessagePipeTest, h) {
- // Create a new pipe and send one end to the parent, who will connect it to
- // a client running ReceivePipeWithClosedPeerFromOtherChild.
- MojoHandle application_proxy, application_request;
- CreateMessagePipe(&application_proxy, &application_request);
- WriteMessageWithHandles(h, "c2a plz", &application_request, 1);
-
- // Create another pipe and send one end to the remote "application".
- MojoHandle service_proxy, service_request;
- CreateMessagePipe(&service_proxy, &service_request);
- WriteMessageWithHandles(application_proxy, "c2s lol", &service_request, 1);
-
- // Immediately close the service proxy. The "application" should detect this.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(service_proxy));
-
- // Wait for quit.
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeerFromOtherChild,
- MultiprocessMessagePipeTest, h) {
- // Receive a pipe from the parent. This is akin to an "application request".
- MojoHandle application_client;
- EXPECT_EQ("c2a", ReadMessageWithHandles(h, &application_client, 1));
-
- // Receive a pipe from the "application" "client".
- MojoHandle service_client;
- EXPECT_EQ("c2s lol",
- ReadMessageWithHandles(application_client, &service_client, 1));
-
- // Wait for the service client to signal closure.
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(service_client, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(service_client));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(application_client));
-}
-
-#if defined(OS_ANDROID)
-// Android multi-process tests are not executing the new process. This is flaky.
-#define MAYBE_SendPipeWithClosedPeerBetweenChildren \
- DISABLED_SendPipeWithClosedPeerBetweenChildren
-#else
-#define MAYBE_SendPipeWithClosedPeerBetweenChildren \
- SendPipeWithClosedPeerBetweenChildren
-#endif
-TEST_F(MultiprocessMessagePipeTest,
- MAYBE_SendPipeWithClosedPeerBetweenChildren) {
- RUN_CHILD_ON_PIPE(SendOtherChildPipeWithClosedPeer, kid_a)
- RUN_CHILD_ON_PIPE(ReceivePipeWithClosedPeerFromOtherChild, kid_b)
- // Receive an "application request" from the first child and forward it
- // to the second child.
- MojoHandle application_request;
- EXPECT_EQ("c2a plz",
- ReadMessageWithHandles(kid_a, &application_request, 1));
-
- WriteMessageWithHandles(kid_b, "c2a", &application_request, 1);
- END_CHILD()
-
- WriteMessage(kid_a, "quit");
- END_CHILD()
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendClosePeerSend) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- // Send |a| over |c|, immediately close |b|, then send |a| back over |d|.
- WriteMessageWithHandles(c, "foo", &a, 1);
- EXPECT_EQ("foo", ReadMessageWithHandles(d, &a, 1));
- WriteMessageWithHandles(d, "bar", &a, 1);
- EXPECT_EQ("bar", ReadMessageWithHandles(c, &a, 1));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-
- // We should be able to detect peer closure on |a|.
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(a, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteCloseSendPeerClient,
- MultiprocessMessagePipeTest, h) {
- MojoHandle pipe[2];
- EXPECT_EQ("foo", ReadMessageWithHandles(h, pipe, 2));
-
- // Write some messages to the first endpoint and then close it.
- WriteMessage(pipe[0], "baz");
- WriteMessage(pipe[0], "qux");
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe[0]));
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- // Pass the orphaned endpoint over another pipe before passing it back to
- // the parent, just for some extra proxying goodness.
- WriteMessageWithHandles(c, "foo", &pipe[1], 1);
- EXPECT_EQ("foo", ReadMessageWithHandles(d, &pipe[1], 1));
-
- // And finally pass it back to the parent.
- WriteMessageWithHandles(h, "bar", &pipe[1], 1);
-
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_P(MultiprocessMessagePipeTestWithPeerSupport, WriteCloseSendPeer) {
- MojoHandle pipe[2];
- CreateMessagePipe(&pipe[0], &pipe[1]);
-
- RUN_CHILD_ON_PIPE(WriteCloseSendPeerClient, h)
- // Pass the pipe to the child.
- WriteMessageWithHandles(h, "foo", pipe, 2);
-
- // Read back an endpoint which should have messages on it.
- MojoHandle p;
- EXPECT_EQ("bar", ReadMessageWithHandles(h, &p, 1));
-
- EXPECT_EQ("baz", ReadMessage(p));
- EXPECT_EQ("qux", ReadMessage(p));
-
- // Expect to have peer closure signaled.
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- WriteMessage(h, "quit");
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MessagePipeStatusChangeInTransitClient,
- MultiprocessMessagePipeTest, parent) {
- // This test verifies that peer closure is detectable through various
- // mechanisms when it races with handle transfer.
- MojoHandle handles[4];
- EXPECT_EQ("o_O", ReadMessageWithHandles(parent, handles, 4));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- base::MessageLoop message_loop;
-
- // Wait on handle 1 using a SimpleWatcher.
- {
- base::RunLoop run_loop;
- SimpleWatcher watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC);
- watcher.Watch(Handle(handles[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- base::Bind(
- [](base::RunLoop* loop, MojoResult result) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- loop->Quit();
- },
- &run_loop));
- run_loop.Run();
- }
-
- // Wait on handle 2 by polling with MojoReadMessage.
- MojoResult result;
- do {
- result = MojoReadMessage(handles[2], nullptr, nullptr, nullptr, nullptr,
- MOJO_READ_MESSAGE_FLAG_NONE);
- } while (result == MOJO_RESULT_SHOULD_WAIT);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
-
- // Wait on handle 3 by polling with MojoWriteMessage.
- do {
- result = MojoWriteMessage(handles[3], nullptr, 0, nullptr, 0,
- MOJO_WRITE_MESSAGE_FLAG_NONE);
- } while (result == MOJO_RESULT_OK);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
-
- for (size_t i = 0; i < 4; ++i)
- CloseHandle(handles[i]);
-}
-
-TEST_F(MultiprocessMessagePipeTest, MessagePipeStatusChangeInTransit) {
- MojoHandle local_handles[4];
- MojoHandle sent_handles[4];
- for (size_t i = 0; i < 4; ++i)
- CreateMessagePipe(&local_handles[i], &sent_handles[i]);
-
- RUN_CHILD_ON_PIPE(MessagePipeStatusChangeInTransitClient, child)
- // Send 4 handles and let their transfer race with their peers' closure.
- WriteMessageWithHandles(child, "o_O", sent_handles, 4);
- for (size_t i = 0; i < 4; ++i)
- CloseHandle(local_handles[i]);
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(BadMessageClient, MultiprocessMessagePipeTest,
- parent) {
- MojoHandle pipe;
- EXPECT_EQ("hi", ReadMessageWithHandles(parent, &pipe, 1));
- WriteMessage(pipe, "derp");
- EXPECT_EQ("bye", ReadMessage(parent));
-}
-
-void OnProcessError(std::string* out_error, const std::string& error) {
- *out_error = error;
-}
-
-TEST_F(MultiprocessMessagePipeTest, NotifyBadMessage) {
- const std::string kFirstErrorMessage = "everything is terrible!";
- const std::string kSecondErrorMessage = "not the bits you're looking for";
-
- std::string first_process_error;
- std::string second_process_error;
-
- set_process_error_callback(base::Bind(&OnProcessError, &first_process_error));
- RUN_CHILD_ON_PIPE(BadMessageClient, child1)
- set_process_error_callback(base::Bind(&OnProcessError,
- &second_process_error));
- RUN_CHILD_ON_PIPE(BadMessageClient, child2)
- MojoHandle a, b, c, d;
- CreateMessagePipe(&a, &b);
- CreateMessagePipe(&c, &d);
- WriteMessageWithHandles(child1, "hi", &b, 1);
- WriteMessageWithHandles(child2, "hi", &d, 1);
-
- // Read a message from the pipe we sent to child1 and flag it as bad.
- ASSERT_EQ(MOJO_RESULT_OK, WaitForSignals(a, MOJO_HANDLE_SIGNAL_READABLE));
- uint32_t num_bytes = 0;
- MojoMessageHandle message;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessageNew(a, &message, &num_bytes, nullptr, 0,
- MOJO_READ_MESSAGE_FLAG_NONE));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoNotifyBadMessage(message, kFirstErrorMessage.data(),
- kFirstErrorMessage.size()));
- EXPECT_EQ(MOJO_RESULT_OK, MojoFreeMessage(message));
-
- // Read a message from the pipe we sent to child2 and flag it as bad.
- ASSERT_EQ(MOJO_RESULT_OK, WaitForSignals(c, MOJO_HANDLE_SIGNAL_READABLE));
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoReadMessageNew(c, &message, &num_bytes, nullptr, 0,
- MOJO_READ_MESSAGE_FLAG_NONE));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoNotifyBadMessage(message, kSecondErrorMessage.data(),
- kSecondErrorMessage.size()));
- EXPECT_EQ(MOJO_RESULT_OK, MojoFreeMessage(message));
-
- WriteMessage(child2, "bye");
- END_CHILD();
-
- WriteMessage(child1, "bye");
- END_CHILD()
-
- // The error messages should match the processes which triggered them.
- EXPECT_NE(std::string::npos, first_process_error.find(kFirstErrorMessage));
- EXPECT_NE(std::string::npos, second_process_error.find(kSecondErrorMessage));
-}
-INSTANTIATE_TEST_CASE_P(
- ,
- MultiprocessMessagePipeTestWithPeerSupport,
- testing::Values(test::MojoTestBase::LaunchType::CHILD,
- test::MojoTestBase::LaunchType::PEER,
- test::MojoTestBase::LaunchType::NAMED_CHILD,
- test::MojoTestBase::LaunchType::NAMED_PEER));
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/node_channel.cc b/mojo/edk/system/node_channel.cc
deleted file mode 100644
index b0f770d..0000000
--- a/mojo/edk/system/node_channel.cc
+++ /dev/null
@@ -1,905 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/node_channel.h"
-
-#include <cstring>
-#include <limits>
-#include <sstream>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "mojo/edk/system/channel.h"
-#include "mojo/edk/system/request_context.h"
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "mojo/edk/system/mach_port_relay.h"
-#endif
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-template <typename T>
-T Align(T t) {
- const auto k = kChannelMessageAlignment;
- return t + (k - (t % k)) % k;
-}
-
-// NOTE: Please ONLY append messages to the end of this enum.
-enum class MessageType : uint32_t {
- ACCEPT_CHILD,
- ACCEPT_PARENT,
- ADD_BROKER_CLIENT,
- BROKER_CLIENT_ADDED,
- ACCEPT_BROKER_CLIENT,
- PORTS_MESSAGE,
- REQUEST_PORT_MERGE,
- REQUEST_INTRODUCTION,
- INTRODUCE,
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- RELAY_PORTS_MESSAGE,
-#endif
- BROADCAST,
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- PORTS_MESSAGE_FROM_RELAY,
-#endif
- ACCEPT_PEER,
-};
-
-struct Header {
- MessageType type;
- uint32_t padding;
-};
-
-static_assert(IsAlignedForChannelMessage(sizeof(Header)),
- "Invalid header size.");
-
-struct AcceptChildData {
- ports::NodeName parent_name;
- ports::NodeName token;
-};
-
-struct AcceptParentData {
- ports::NodeName token;
- ports::NodeName child_name;
-};
-
-struct AcceptPeerData {
- ports::NodeName token;
- ports::NodeName peer_name;
- ports::PortName port_name;
-};
-
-// This message may include a process handle on plaforms that require it.
-struct AddBrokerClientData {
- ports::NodeName client_name;
-#if !defined(OS_WIN)
- uint32_t process_handle;
- uint32_t padding;
-#endif
-};
-
-#if !defined(OS_WIN)
-static_assert(sizeof(base::ProcessHandle) == sizeof(uint32_t),
- "Unexpected pid size");
-static_assert(sizeof(AddBrokerClientData) % kChannelMessageAlignment == 0,
- "Invalid AddBrokerClientData size.");
-#endif
-
-// This data is followed by a platform channel handle to the broker.
-struct BrokerClientAddedData {
- ports::NodeName client_name;
-};
-
-// This data may be followed by a platform channel handle to the broker. If not,
-// then the parent is the broker and its channel should be used as such.
-struct AcceptBrokerClientData {
- ports::NodeName broker_name;
-};
-
-// This is followed by arbitrary payload data which is interpreted as a token
-// string for port location.
-struct RequestPortMergeData {
- ports::PortName connector_port_name;
-};
-
-// Used for both REQUEST_INTRODUCTION and INTRODUCE.
-//
-// For INTRODUCE the message also includes a valid platform handle for a channel
-// the receiver may use to communicate with the named node directly, or an
-// invalid platform handle if the node is unknown to the sender or otherwise
-// cannot be introduced.
-struct IntroductionData {
- ports::NodeName name;
-};
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
-// This struct is followed by the full payload of a message to be relayed.
-struct RelayPortsMessageData {
- ports::NodeName destination;
-};
-
-// This struct is followed by the full payload of a relayed message.
-struct PortsMessageFromRelayData {
- ports::NodeName source;
-};
-#endif
-
-template <typename DataType>
-Channel::MessagePtr CreateMessage(MessageType type,
- size_t payload_size,
- size_t num_handles,
- DataType** out_data) {
- Channel::MessagePtr message(
- new Channel::Message(sizeof(Header) + payload_size, num_handles));
- Header* header = reinterpret_cast<Header*>(message->mutable_payload());
- header->type = type;
- header->padding = 0;
- *out_data = reinterpret_cast<DataType*>(&header[1]);
- return message;
-}
-
-template <typename DataType>
-bool GetMessagePayload(const void* bytes,
- size_t num_bytes,
- DataType** out_data) {
- static_assert(sizeof(DataType) > 0, "DataType must have non-zero size.");
- if (num_bytes < sizeof(Header) + sizeof(DataType))
- return false;
- *out_data = reinterpret_cast<const DataType*>(
- static_cast<const char*>(bytes) + sizeof(Header));
- return true;
-}
-
-} // namespace
-
-// static
-scoped_refptr<NodeChannel> NodeChannel::Create(
- Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner,
- const ProcessErrorCallback& process_error_callback) {
-#if defined(OS_NACL_SFI)
- LOG(FATAL) << "Multi-process not yet supported on NaCl-SFI";
- return nullptr;
-#else
- return new NodeChannel(delegate, std::move(connection_params), io_task_runner,
- process_error_callback);
-#endif
-}
-
-// static
-Channel::MessagePtr NodeChannel::CreatePortsMessage(size_t payload_size,
- void** payload,
- size_t num_handles) {
- return CreateMessage(MessageType::PORTS_MESSAGE, payload_size, num_handles,
- payload);
-}
-
-// static
-void NodeChannel::GetPortsMessageData(Channel::Message* message,
- void** data,
- size_t* num_data_bytes) {
- *data = reinterpret_cast<Header*>(message->mutable_payload()) + 1;
- *num_data_bytes = message->payload_size() - sizeof(Header);
-}
-
-void NodeChannel::Start() {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- MachPortRelay* relay = delegate_->GetMachPortRelay();
- if (relay)
- relay->AddObserver(this);
-#endif
-
- base::AutoLock lock(channel_lock_);
- // ShutDown() may have already been called, in which case |channel_| is null.
- if (channel_)
- channel_->Start();
-}
-
-void NodeChannel::ShutDown() {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- MachPortRelay* relay = delegate_->GetMachPortRelay();
- if (relay)
- relay->RemoveObserver(this);
-#endif
-
- base::AutoLock lock(channel_lock_);
- if (channel_) {
- channel_->ShutDown();
- channel_ = nullptr;
- }
-}
-
-void NodeChannel::LeakHandleOnShutdown() {
- base::AutoLock lock(channel_lock_);
- if (channel_) {
- channel_->LeakHandle();
- }
-}
-
-void NodeChannel::NotifyBadMessage(const std::string& error) {
- if (!process_error_callback_.is_null())
- process_error_callback_.Run("Received bad user message: " + error);
-}
-
-void NodeChannel::SetRemoteProcessHandle(base::ProcessHandle process_handle) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
- base::AutoLock lock(remote_process_handle_lock_);
- DCHECK_EQ(base::kNullProcessHandle, remote_process_handle_);
- CHECK_NE(remote_process_handle_, base::GetCurrentProcessHandle());
- remote_process_handle_ = process_handle;
-#if defined(OS_WIN)
- DCHECK(!scoped_remote_process_handle_.is_valid());
- scoped_remote_process_handle_.reset(PlatformHandle(process_handle));
-#endif
-}
-
-bool NodeChannel::HasRemoteProcessHandle() {
- base::AutoLock lock(remote_process_handle_lock_);
- return remote_process_handle_ != base::kNullProcessHandle;
-}
-
-base::ProcessHandle NodeChannel::CopyRemoteProcessHandle() {
- base::AutoLock lock(remote_process_handle_lock_);
-#if defined(OS_WIN)
- if (remote_process_handle_ != base::kNullProcessHandle) {
- // Privileged nodes use this to pass their childrens' process handles to the
- // broker on launch.
- HANDLE handle = remote_process_handle_;
- BOOL result = DuplicateHandle(
- base::GetCurrentProcessHandle(), remote_process_handle_,
- base::GetCurrentProcessHandle(), &handle, 0, FALSE,
- DUPLICATE_SAME_ACCESS);
- DPCHECK(result);
- return handle;
- }
- return base::kNullProcessHandle;
-#else
- return remote_process_handle_;
-#endif
-}
-
-void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
- remote_node_name_ = name;
-}
-
-void NodeChannel::AcceptChild(const ports::NodeName& parent_name,
- const ports::NodeName& token) {
- AcceptChildData* data;
- Channel::MessagePtr message = CreateMessage(
- MessageType::ACCEPT_CHILD, sizeof(AcceptChildData), 0, &data);
- data->parent_name = parent_name;
- data->token = token;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::AcceptParent(const ports::NodeName& token,
- const ports::NodeName& child_name) {
- AcceptParentData* data;
- Channel::MessagePtr message = CreateMessage(
- MessageType::ACCEPT_PARENT, sizeof(AcceptParentData), 0, &data);
- data->token = token;
- data->child_name = child_name;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::AcceptPeer(const ports::NodeName& sender_name,
- const ports::NodeName& token,
- const ports::PortName& port_name) {
- AcceptPeerData* data;
- Channel::MessagePtr message =
- CreateMessage(MessageType::ACCEPT_PEER, sizeof(AcceptPeerData), 0, &data);
- data->token = token;
- data->peer_name = sender_name;
- data->port_name = port_name;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::AddBrokerClient(const ports::NodeName& client_name,
- base::ProcessHandle process_handle) {
- AddBrokerClientData* data;
- ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector());
-#if defined(OS_WIN)
- handles->push_back(PlatformHandle(process_handle));
-#endif
- Channel::MessagePtr message = CreateMessage(
- MessageType::ADD_BROKER_CLIENT, sizeof(AddBrokerClientData),
- handles->size(), &data);
- message->SetHandles(std::move(handles));
- data->client_name = client_name;
-#if !defined(OS_WIN)
- data->process_handle = process_handle;
- data->padding = 0;
-#endif
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::BrokerClientAdded(const ports::NodeName& client_name,
- ScopedPlatformHandle broker_channel) {
- BrokerClientAddedData* data;
- ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector());
- if (broker_channel.is_valid())
- handles->push_back(broker_channel.release());
- Channel::MessagePtr message = CreateMessage(
- MessageType::BROKER_CLIENT_ADDED, sizeof(BrokerClientAddedData),
- handles->size(), &data);
- message->SetHandles(std::move(handles));
- data->client_name = client_name;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::AcceptBrokerClient(const ports::NodeName& broker_name,
- ScopedPlatformHandle broker_channel) {
- AcceptBrokerClientData* data;
- ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector());
- if (broker_channel.is_valid())
- handles->push_back(broker_channel.release());
- Channel::MessagePtr message = CreateMessage(
- MessageType::ACCEPT_BROKER_CLIENT, sizeof(AcceptBrokerClientData),
- handles->size(), &data);
- message->SetHandles(std::move(handles));
- data->broker_name = broker_name;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::PortsMessage(Channel::MessagePtr message) {
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::RequestPortMerge(const ports::PortName& connector_port_name,
- const std::string& token) {
- RequestPortMergeData* data;
- Channel::MessagePtr message = CreateMessage(
- MessageType::REQUEST_PORT_MERGE,
- sizeof(RequestPortMergeData) + token.size(), 0, &data);
- data->connector_port_name = connector_port_name;
- memcpy(data + 1, token.data(), token.size());
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::RequestIntroduction(const ports::NodeName& name) {
- IntroductionData* data;
- Channel::MessagePtr message = CreateMessage(
- MessageType::REQUEST_INTRODUCTION, sizeof(IntroductionData), 0, &data);
- data->name = name;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::Introduce(const ports::NodeName& name,
- ScopedPlatformHandle channel_handle) {
- IntroductionData* data;
- ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector());
- if (channel_handle.is_valid())
- handles->push_back(channel_handle.release());
- Channel::MessagePtr message = CreateMessage(
- MessageType::INTRODUCE, sizeof(IntroductionData), handles->size(), &data);
- message->SetHandles(std::move(handles));
- data->name = name;
- WriteChannelMessage(std::move(message));
-}
-
-void NodeChannel::Broadcast(Channel::MessagePtr message) {
- DCHECK(!message->has_handles());
- void* data;
- Channel::MessagePtr broadcast_message = CreateMessage(
- MessageType::BROADCAST, message->data_num_bytes(), 0, &data);
- memcpy(data, message->data(), message->data_num_bytes());
- WriteChannelMessage(std::move(broadcast_message));
-}
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
-void NodeChannel::RelayPortsMessage(const ports::NodeName& destination,
- Channel::MessagePtr message) {
-#if defined(OS_WIN)
- DCHECK(message->has_handles());
-
- // Note that this is only used on Windows, and on Windows all platform
- // handles are included in the message data. We blindly copy all the data
- // here and the relay node (the parent) will duplicate handles as needed.
- size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes();
- RelayPortsMessageData* data;
- Channel::MessagePtr relay_message = CreateMessage(
- MessageType::RELAY_PORTS_MESSAGE, num_bytes, 0, &data);
- data->destination = destination;
- memcpy(data + 1, message->data(), message->data_num_bytes());
-
- // When the handles are duplicated in the parent, the source handles will
- // be closed. If the parent never receives this message then these handles
- // will leak, but that means something else has probably broken and the
- // sending process won't likely be around much longer.
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- handles->clear();
-
-#else
- DCHECK(message->has_mach_ports());
-
- // On OSX, the handles are extracted from the relayed message and attached to
- // the wrapper. The broker then takes the handles attached to the wrapper and
- // moves them back to the relayed message. This is necessary because the
- // message may contain fds which need to be attached to the outer message so
- // that they can be transferred to the broker.
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- size_t num_bytes = sizeof(RelayPortsMessageData) + message->data_num_bytes();
- RelayPortsMessageData* data;
- Channel::MessagePtr relay_message = CreateMessage(
- MessageType::RELAY_PORTS_MESSAGE, num_bytes, handles->size(), &data);
- data->destination = destination;
- memcpy(data + 1, message->data(), message->data_num_bytes());
- relay_message->SetHandles(std::move(handles));
-#endif // defined(OS_WIN)
-
- WriteChannelMessage(std::move(relay_message));
-}
-
-void NodeChannel::PortsMessageFromRelay(const ports::NodeName& source,
- Channel::MessagePtr message) {
- size_t num_bytes = sizeof(PortsMessageFromRelayData) +
- message->payload_size();
- PortsMessageFromRelayData* data;
- Channel::MessagePtr relayed_message = CreateMessage(
- MessageType::PORTS_MESSAGE_FROM_RELAY, num_bytes, message->num_handles(),
- &data);
- data->source = source;
- if (message->payload_size())
- memcpy(data + 1, message->payload(), message->payload_size());
- relayed_message->SetHandles(message->TakeHandles());
- WriteChannelMessage(std::move(relayed_message));
-}
-#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
-
-NodeChannel::NodeChannel(Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner,
- const ProcessErrorCallback& process_error_callback)
- : delegate_(delegate),
- io_task_runner_(io_task_runner),
- process_error_callback_(process_error_callback)
-#if !defined(OS_NACL_SFI)
- ,
- channel_(
- Channel::Create(this, std::move(connection_params), io_task_runner_))
-#endif
-{
-}
-
-NodeChannel::~NodeChannel() {
- ShutDown();
-}
-
-void NodeChannel::OnChannelMessage(const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- RequestContext request_context(RequestContext::Source::SYSTEM);
-
- // Ensure this NodeChannel stays alive through the extent of this method. The
- // delegate may have the only other reference to this object and it may choose
- // to drop it here in response to, e.g., a malformed message.
- scoped_refptr<NodeChannel> keepalive = this;
-
-#if defined(OS_WIN)
- // If we receive handles from a known process, rewrite them to our own
- // process. This can occur when a privileged node receives handles directly
- // from a privileged descendant.
- {
- base::AutoLock lock(remote_process_handle_lock_);
- if (handles && remote_process_handle_ != base::kNullProcessHandle) {
- // Note that we explicitly mark the handles as being owned by the sending
- // process before rewriting them, in order to accommodate RewriteHandles'
- // internal sanity checks.
- for (auto& handle : *handles)
- handle.owning_process = remote_process_handle_;
- if (!Channel::Message::RewriteHandles(remote_process_handle_,
- base::GetCurrentProcessHandle(),
- handles.get())) {
- DLOG(ERROR) << "Received one or more invalid handles.";
- }
- } else if (handles) {
- // Handles received by an unknown process must already be owned by us.
- for (auto& handle : *handles)
- handle.owning_process = base::GetCurrentProcessHandle();
- }
- }
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- // If we're not the root, receive any mach ports from the message. If we're
- // the root, the only message containing mach ports should be a
- // RELAY_PORTS_MESSAGE.
- {
- MachPortRelay* relay = delegate_->GetMachPortRelay();
- if (handles && !relay) {
- if (!MachPortRelay::ReceivePorts(handles.get())) {
- LOG(ERROR) << "Error receiving mach ports.";
- }
- }
- }
-#endif // defined(OS_WIN)
-
-
- if (payload_size <= sizeof(Header)) {
- delegate_->OnChannelError(remote_node_name_, this);
- return;
- }
-
- const Header* header = static_cast<const Header*>(payload);
- switch (header->type) {
- case MessageType::ACCEPT_CHILD: {
- const AcceptChildData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- delegate_->OnAcceptChild(remote_node_name_, data->parent_name,
- data->token);
- return;
- }
- break;
- }
-
- case MessageType::ACCEPT_PARENT: {
- const AcceptParentData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- delegate_->OnAcceptParent(remote_node_name_, data->token,
- data->child_name);
- return;
- }
- break;
- }
-
- case MessageType::ADD_BROKER_CLIENT: {
- const AddBrokerClientData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- ScopedPlatformHandle process_handle;
-#if defined(OS_WIN)
- if (!handles || handles->size() != 1) {
- DLOG(ERROR) << "Dropping invalid AddBrokerClient message.";
- break;
- }
- process_handle = ScopedPlatformHandle(handles->at(0));
- handles->clear();
- delegate_->OnAddBrokerClient(remote_node_name_, data->client_name,
- process_handle.release().handle);
-#else
- if (handles && handles->size() != 0) {
- DLOG(ERROR) << "Dropping invalid AddBrokerClient message.";
- break;
- }
- delegate_->OnAddBrokerClient(remote_node_name_, data->client_name,
- data->process_handle);
-#endif
- return;
- }
- break;
- }
-
- case MessageType::BROKER_CLIENT_ADDED: {
- const BrokerClientAddedData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- ScopedPlatformHandle broker_channel;
- if (!handles || handles->size() != 1) {
- DLOG(ERROR) << "Dropping invalid BrokerClientAdded message.";
- break;
- }
- broker_channel = ScopedPlatformHandle(handles->at(0));
- handles->clear();
- delegate_->OnBrokerClientAdded(remote_node_name_, data->client_name,
- std::move(broker_channel));
- return;
- }
- break;
- }
-
- case MessageType::ACCEPT_BROKER_CLIENT: {
- const AcceptBrokerClientData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- ScopedPlatformHandle broker_channel;
- if (handles && handles->size() > 1) {
- DLOG(ERROR) << "Dropping invalid AcceptBrokerClient message.";
- break;
- }
- if (handles && handles->size() == 1) {
- broker_channel = ScopedPlatformHandle(handles->at(0));
- handles->clear();
- }
- delegate_->OnAcceptBrokerClient(remote_node_name_, data->broker_name,
- std::move(broker_channel));
- return;
- }
- break;
- }
-
- case MessageType::PORTS_MESSAGE: {
- size_t num_handles = handles ? handles->size() : 0;
- Channel::MessagePtr message(
- new Channel::Message(payload_size, num_handles));
- message->SetHandles(std::move(handles));
- memcpy(message->mutable_payload(), payload, payload_size);
- delegate_->OnPortsMessage(remote_node_name_, std::move(message));
- return;
- }
-
- case MessageType::REQUEST_PORT_MERGE: {
- const RequestPortMergeData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- // Don't accept an empty token.
- size_t token_size = payload_size - sizeof(*data) - sizeof(Header);
- if (token_size == 0)
- break;
- std::string token(reinterpret_cast<const char*>(data + 1), token_size);
- delegate_->OnRequestPortMerge(remote_node_name_,
- data->connector_port_name, token);
- return;
- }
- break;
- }
-
- case MessageType::REQUEST_INTRODUCTION: {
- const IntroductionData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- delegate_->OnRequestIntroduction(remote_node_name_, data->name);
- return;
- }
- break;
- }
-
- case MessageType::INTRODUCE: {
- const IntroductionData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- if (handles && handles->size() > 1) {
- DLOG(ERROR) << "Dropping invalid introduction message.";
- break;
- }
- ScopedPlatformHandle channel_handle;
- if (handles && handles->size() == 1) {
- channel_handle = ScopedPlatformHandle(handles->at(0));
- handles->clear();
- }
- delegate_->OnIntroduce(remote_node_name_, data->name,
- std::move(channel_handle));
- return;
- }
- break;
- }
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- case MessageType::RELAY_PORTS_MESSAGE: {
- base::ProcessHandle from_process;
- {
- base::AutoLock lock(remote_process_handle_lock_);
- from_process = remote_process_handle_;
- }
- const RelayPortsMessageData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- // Don't try to relay an empty message.
- if (payload_size <= sizeof(Header) + sizeof(RelayPortsMessageData))
- break;
-
- const void* message_start = data + 1;
- Channel::MessagePtr message = Channel::Message::Deserialize(
- message_start, payload_size - sizeof(Header) - sizeof(*data));
- if (!message) {
- DLOG(ERROR) << "Dropping invalid relay message.";
- break;
- }
- #if defined(OS_MACOSX) && !defined(OS_IOS)
- message->SetHandles(std::move(handles));
- MachPortRelay* relay = delegate_->GetMachPortRelay();
- if (!relay) {
- LOG(ERROR) << "Receiving mach ports without a port relay from "
- << remote_node_name_ << ". Dropping message.";
- break;
- }
- {
- base::AutoLock lock(pending_mach_messages_lock_);
- if (relay->port_provider()->TaskForPid(from_process) ==
- MACH_PORT_NULL) {
- pending_relay_messages_.push(
- std::make_pair(data->destination, std::move(message)));
- break;
- }
- }
- #endif
- delegate_->OnRelayPortsMessage(remote_node_name_, from_process,
- data->destination, std::move(message));
- return;
- }
- break;
- }
-#endif
-
- case MessageType::BROADCAST: {
- if (payload_size <= sizeof(Header))
- break;
- const void* data = static_cast<const void*>(
- reinterpret_cast<const Header*>(payload) + 1);
- Channel::MessagePtr message =
- Channel::Message::Deserialize(data, payload_size - sizeof(Header));
- if (!message || message->has_handles()) {
- DLOG(ERROR) << "Dropping invalid broadcast message.";
- break;
- }
- delegate_->OnBroadcast(remote_node_name_, std::move(message));
- return;
- }
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- case MessageType::PORTS_MESSAGE_FROM_RELAY:
- const PortsMessageFromRelayData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- size_t num_bytes = payload_size - sizeof(*data);
- if (num_bytes < sizeof(Header))
- break;
- num_bytes -= sizeof(Header);
-
- size_t num_handles = handles ? handles->size() : 0;
- Channel::MessagePtr message(
- new Channel::Message(num_bytes, num_handles));
- message->SetHandles(std::move(handles));
- if (num_bytes)
- memcpy(message->mutable_payload(), data + 1, num_bytes);
- delegate_->OnPortsMessageFromRelay(
- remote_node_name_, data->source, std::move(message));
- return;
- }
- break;
-
-#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
-
- case MessageType::ACCEPT_PEER: {
- const AcceptPeerData* data;
- if (GetMessagePayload(payload, payload_size, &data)) {
- delegate_->OnAcceptPeer(remote_node_name_, data->token, data->peer_name,
- data->port_name);
- return;
- }
- break;
- }
-
- default:
- break;
- }
-
- DLOG(ERROR) << "Received invalid message. Closing channel.";
- delegate_->OnChannelError(remote_node_name_, this);
-}
-
-void NodeChannel::OnChannelError() {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- RequestContext request_context(RequestContext::Source::SYSTEM);
-
- ShutDown();
- // |OnChannelError()| may cause |this| to be destroyed, but still need access
- // to the name name after that destruction. So may a copy of
- // |remote_node_name_| so it can be used if |this| becomes destroyed.
- ports::NodeName node_name = remote_node_name_;
- delegate_->OnChannelError(node_name, this);
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-void NodeChannel::OnProcessReady(base::ProcessHandle process) {
- io_task_runner_->PostTask(FROM_HERE, base::Bind(
- &NodeChannel::ProcessPendingMessagesWithMachPorts, this));
-}
-
-void NodeChannel::ProcessPendingMessagesWithMachPorts() {
- MachPortRelay* relay = delegate_->GetMachPortRelay();
- DCHECK(relay);
-
- base::ProcessHandle remote_process_handle;
- {
- base::AutoLock lock(remote_process_handle_lock_);
- remote_process_handle = remote_process_handle_;
- }
- PendingMessageQueue pending_writes;
- PendingRelayMessageQueue pending_relays;
- {
- base::AutoLock lock(pending_mach_messages_lock_);
- pending_writes.swap(pending_write_messages_);
- pending_relays.swap(pending_relay_messages_);
- }
-
- while (!pending_writes.empty()) {
- Channel::MessagePtr message = std::move(pending_writes.front());
- pending_writes.pop();
- if (!relay->SendPortsToProcess(message.get(), remote_process_handle)) {
- LOG(ERROR) << "Error on sending mach ports. Remote process is likely "
- << "gone. Dropping message.";
- return;
- }
-
- base::AutoLock lock(channel_lock_);
- if (!channel_) {
- DLOG(ERROR) << "Dropping message on closed channel.";
- break;
- } else {
- channel_->Write(std::move(message));
- }
- }
-
- // Ensure this NodeChannel stays alive while flushing relay messages.
- scoped_refptr<NodeChannel> keepalive = this;
-
- while (!pending_relays.empty()) {
- ports::NodeName destination = pending_relays.front().first;
- Channel::MessagePtr message = std::move(pending_relays.front().second);
- pending_relays.pop();
- delegate_->OnRelayPortsMessage(remote_node_name_, remote_process_handle,
- destination, std::move(message));
- }
-}
-#endif
-
-void NodeChannel::WriteChannelMessage(Channel::MessagePtr message) {
-#if defined(OS_WIN)
- // Map handles to the destination process. Note: only messages from a
- // privileged node should contain handles on Windows. If an unprivileged
- // node needs to send handles, it should do so via RelayPortsMessage which
- // stashes the handles in the message in such a way that they go undetected
- // here (they'll be unpacked and duplicated by a privileged parent.)
-
- if (message->has_handles()) {
- base::ProcessHandle remote_process_handle;
- {
- base::AutoLock lock(remote_process_handle_lock_);
- remote_process_handle = remote_process_handle_;
- }
-
- // Rewrite outgoing handles if we have a handle to the destination process.
- if (remote_process_handle != base::kNullProcessHandle) {
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- if (!Channel::Message::RewriteHandles(base::GetCurrentProcessHandle(),
- remote_process_handle,
- handles.get())) {
- DLOG(ERROR) << "Failed to duplicate one or more outgoing handles.";
- }
- message->SetHandles(std::move(handles));
- }
- }
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- // On OSX, we need to transfer mach ports to the destination process before
- // transferring the message itself.
- if (message->has_mach_ports()) {
- MachPortRelay* relay = delegate_->GetMachPortRelay();
- if (relay) {
- base::ProcessHandle remote_process_handle;
- {
- base::AutoLock lock(remote_process_handle_lock_);
- // Expect that the receiving node is a child.
- DCHECK(remote_process_handle_ != base::kNullProcessHandle);
- remote_process_handle = remote_process_handle_;
- }
- {
- base::AutoLock lock(pending_mach_messages_lock_);
- if (relay->port_provider()->TaskForPid(remote_process_handle) ==
- MACH_PORT_NULL) {
- // It is also possible for TaskForPid() to return MACH_PORT_NULL when
- // the process has started, then died. In that case, the queued
- // message will never be processed. But that's fine since we're about
- // to die anyway.
- pending_write_messages_.push(std::move(message));
- return;
- }
- }
-
- if (!relay->SendPortsToProcess(message.get(), remote_process_handle)) {
- LOG(ERROR) << "Error on sending mach ports. Remote process is likely "
- << "gone. Dropping message.";
- return;
- }
- }
- }
-#endif
-
- base::AutoLock lock(channel_lock_);
- if (!channel_)
- DLOG(ERROR) << "Dropping message on closed channel.";
- else
- channel_->Write(std::move(message));
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/node_channel.h b/mojo/edk/system/node_channel.h
deleted file mode 100644
index 95dc341..0000000
--- a/mojo/edk/system/node_channel.h
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_NODE_CHANNEL_H_
-#define MOJO_EDK_SYSTEM_NODE_CHANNEL_H_
-
-#include <queue>
-#include <unordered_map>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/process/process_handle.h"
-#include "base/synchronization/lock.h"
-#include "base/task_runner.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/connection_params.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/channel.h"
-#include "mojo/edk/system/ports/name.h"
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "mojo/edk/system/mach_port_relay.h"
-#endif
-
-namespace mojo {
-namespace edk {
-
-// Wraps a Channel to send and receive Node control messages.
-class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
- public Channel::Delegate
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- , public MachPortRelay::Observer
-#endif
- {
- public:
- class Delegate {
- public:
- virtual ~Delegate() {}
- virtual void OnAcceptChild(const ports::NodeName& from_node,
- const ports::NodeName& parent_name,
- const ports::NodeName& token) = 0;
- virtual void OnAcceptParent(const ports::NodeName& from_node,
- const ports::NodeName& token,
- const ports::NodeName& child_name) = 0;
- virtual void OnAddBrokerClient(const ports::NodeName& from_node,
- const ports::NodeName& client_name,
- base::ProcessHandle process_handle) = 0;
- virtual void OnBrokerClientAdded(const ports::NodeName& from_node,
- const ports::NodeName& client_name,
- ScopedPlatformHandle broker_channel) = 0;
- virtual void OnAcceptBrokerClient(const ports::NodeName& from_node,
- const ports::NodeName& broker_name,
- ScopedPlatformHandle broker_channel) = 0;
- virtual void OnPortsMessage(const ports::NodeName& from_node,
- Channel::MessagePtr message) = 0;
- virtual void OnRequestPortMerge(const ports::NodeName& from_node,
- const ports::PortName& connector_port_name,
- const std::string& token) = 0;
- virtual void OnRequestIntroduction(const ports::NodeName& from_node,
- const ports::NodeName& name) = 0;
- virtual void OnIntroduce(const ports::NodeName& from_node,
- const ports::NodeName& name,
- ScopedPlatformHandle channel_handle) = 0;
- virtual void OnBroadcast(const ports::NodeName& from_node,
- Channel::MessagePtr message) = 0;
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- virtual void OnRelayPortsMessage(const ports::NodeName& from_node,
- base::ProcessHandle from_process,
- const ports::NodeName& destination,
- Channel::MessagePtr message) = 0;
- virtual void OnPortsMessageFromRelay(const ports::NodeName& from_node,
- const ports::NodeName& source_node,
- Channel::MessagePtr message) = 0;
-#endif
- virtual void OnAcceptPeer(const ports::NodeName& from_node,
- const ports::NodeName& token,
- const ports::NodeName& peer_name,
- const ports::PortName& port_name) = 0;
- virtual void OnChannelError(const ports::NodeName& node,
- NodeChannel* channel) = 0;
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- virtual MachPortRelay* GetMachPortRelay() = 0;
-#endif
- };
-
- static scoped_refptr<NodeChannel> Create(
- Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner,
- const ProcessErrorCallback& process_error_callback);
-
- static Channel::MessagePtr CreatePortsMessage(size_t payload_size,
- void** payload,
- size_t num_handles);
-
- static void GetPortsMessageData(Channel::Message* message, void** data,
- size_t* num_data_bytes);
-
- // Start receiving messages.
- void Start();
-
- // Permanently stop the channel from sending or receiving messages.
- void ShutDown();
-
- // Leaks the pipe handle instead of closing it on shutdown.
- void LeakHandleOnShutdown();
-
- // Invokes the bad message callback for this channel, if any.
- void NotifyBadMessage(const std::string& error);
-
- // Note: On Windows, we take ownership of the remote process handle.
- void SetRemoteProcessHandle(base::ProcessHandle process_handle);
- bool HasRemoteProcessHandle();
- // Note: The returned |ProcessHandle| is owned by the caller and should be
- // freed if necessary.
- base::ProcessHandle CopyRemoteProcessHandle();
-
- // Used for context in Delegate calls (via |from_node| arguments.)
- void SetRemoteNodeName(const ports::NodeName& name);
-
- void AcceptChild(const ports::NodeName& parent_name,
- const ports::NodeName& token);
- void AcceptParent(const ports::NodeName& token,
- const ports::NodeName& child_name);
- void AcceptPeer(const ports::NodeName& sender_name,
- const ports::NodeName& token,
- const ports::PortName& port_name);
- void AddBrokerClient(const ports::NodeName& client_name,
- base::ProcessHandle process_handle);
- void BrokerClientAdded(const ports::NodeName& client_name,
- ScopedPlatformHandle broker_channel);
- void AcceptBrokerClient(const ports::NodeName& broker_name,
- ScopedPlatformHandle broker_channel);
- void PortsMessage(Channel::MessagePtr message);
- void RequestPortMerge(const ports::PortName& connector_port_name,
- const std::string& token);
- void RequestIntroduction(const ports::NodeName& name);
- void Introduce(const ports::NodeName& name,
- ScopedPlatformHandle channel_handle);
- void Broadcast(Channel::MessagePtr message);
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- // Relay the message to the specified node via this channel. This is used to
- // pass windows handles between two processes that do not have permission to
- // duplicate handles into the other's address space. The relay process is
- // assumed to have that permission.
- void RelayPortsMessage(const ports::NodeName& destination,
- Channel::MessagePtr message);
-
- // Sends a message to its destination from a relay. This is interpreted by the
- // receiver similarly to PortsMessage, but the original source node is
- // provided as additional message metadata from the (trusted) relay node.
- void PortsMessageFromRelay(const ports::NodeName& source,
- Channel::MessagePtr message);
-#endif
-
- private:
- friend class base::RefCountedThreadSafe<NodeChannel>;
-
- using PendingMessageQueue = std::queue<Channel::MessagePtr>;
- using PendingRelayMessageQueue =
- std::queue<std::pair<ports::NodeName, Channel::MessagePtr>>;
-
- NodeChannel(Delegate* delegate,
- ConnectionParams connection_params,
- scoped_refptr<base::TaskRunner> io_task_runner,
- const ProcessErrorCallback& process_error_callback);
- ~NodeChannel() override;
-
- // Channel::Delegate:
- void OnChannelMessage(const void* payload,
- size_t payload_size,
- ScopedPlatformHandleVectorPtr handles) override;
- void OnChannelError() override;
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // MachPortRelay::Observer:
- void OnProcessReady(base::ProcessHandle process) override;
-
- void ProcessPendingMessagesWithMachPorts();
-#endif
-
- void WriteChannelMessage(Channel::MessagePtr message);
-
- Delegate* const delegate_;
- const scoped_refptr<base::TaskRunner> io_task_runner_;
- const ProcessErrorCallback process_error_callback_;
-
- base::Lock channel_lock_;
- scoped_refptr<Channel> channel_;
-
- // Must only be accessed from |io_task_runner_|'s thread.
- ports::NodeName remote_node_name_;
-
- base::Lock remote_process_handle_lock_;
- base::ProcessHandle remote_process_handle_ = base::kNullProcessHandle;
-#if defined(OS_WIN)
- ScopedPlatformHandle scoped_remote_process_handle_;
-#endif
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- base::Lock pending_mach_messages_lock_;
- PendingMessageQueue pending_write_messages_;
- PendingRelayMessageQueue pending_relay_messages_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(NodeChannel);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_NODE_CHANNEL_H_
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
deleted file mode 100644
index 73b16b1..0000000
--- a/mojo/edk/system/node_controller.cc
+++ /dev/null
@@ -1,1470 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/node_controller.h"
-
-#include <algorithm>
-#include <limits>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/process/process_handle.h"
-#include "base/rand_util.h"
-#include "base/time/time.h"
-#include "base/timer/elapsed_timer.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/embedder/named_platform_channel_pair.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "mojo/edk/system/broker.h"
-#include "mojo/edk/system/broker_host.h"
-#include "mojo/edk/system/core.h"
-#include "mojo/edk/system/ports_message.h"
-#include "mojo/edk/system/request_context.h"
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "mojo/edk/system/mach_port_relay.h"
-#endif
-
-#if !defined(OS_NACL)
-#include "crypto/random.h"
-#endif
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-#if defined(OS_NACL)
-template <typename T>
-void GenerateRandomName(T* out) { base::RandBytes(out, sizeof(T)); }
-#else
-template <typename T>
-void GenerateRandomName(T* out) { crypto::RandBytes(out, sizeof(T)); }
-#endif
-
-ports::NodeName GetRandomNodeName() {
- ports::NodeName name;
- GenerateRandomName(&name);
- return name;
-}
-
-void RecordPeerCount(size_t count) {
- DCHECK_LE(count, static_cast<size_t>(std::numeric_limits<int32_t>::max()));
-
- // 8k is the maximum number of file descriptors allowed in Chrome.
- UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.Node.ConnectedPeers",
- static_cast<int32_t>(count),
- 1 /* min */,
- 8000 /* max */,
- 50 /* bucket count */);
-}
-
-void RecordPendingChildCount(size_t count) {
- DCHECK_LE(count, static_cast<size_t>(std::numeric_limits<int32_t>::max()));
-
- // 8k is the maximum number of file descriptors allowed in Chrome.
- UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.Node.PendingChildren",
- static_cast<int32_t>(count),
- 1 /* min */,
- 8000 /* max */,
- 50 /* bucket count */);
-}
-
-bool ParsePortsMessage(Channel::Message* message,
- void** data,
- size_t* num_data_bytes,
- size_t* num_header_bytes,
- size_t* num_payload_bytes,
- size_t* num_ports_bytes) {
- DCHECK(data && num_data_bytes && num_header_bytes && num_payload_bytes &&
- num_ports_bytes);
-
- NodeChannel::GetPortsMessageData(message, data, num_data_bytes);
- if (!*num_data_bytes)
- return false;
-
- if (!ports::Message::Parse(*data, *num_data_bytes, num_header_bytes,
- num_payload_bytes, num_ports_bytes)) {
- return false;
- }
-
- return true;
-}
-
-// Used by NodeController to watch for shutdown. Since no IO can happen once
-// the IO thread is killed, the NodeController can cleanly drop all its peers
-// at that time.
-class ThreadDestructionObserver :
- public base::MessageLoop::DestructionObserver {
- public:
- static void Create(scoped_refptr<base::TaskRunner> task_runner,
- const base::Closure& callback) {
- if (task_runner->RunsTasksOnCurrentThread()) {
- // Owns itself.
- new ThreadDestructionObserver(callback);
- } else {
- task_runner->PostTask(FROM_HERE,
- base::Bind(&Create, task_runner, callback));
- }
- }
-
- private:
- explicit ThreadDestructionObserver(const base::Closure& callback)
- : callback_(callback) {
- base::MessageLoop::current()->AddDestructionObserver(this);
- }
-
- ~ThreadDestructionObserver() override {
- base::MessageLoop::current()->RemoveDestructionObserver(this);
- }
-
- // base::MessageLoop::DestructionObserver:
- void WillDestroyCurrentMessageLoop() override {
- callback_.Run();
- delete this;
- }
-
- const base::Closure callback_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadDestructionObserver);
-};
-
-} // namespace
-
-NodeController::~NodeController() {}
-
-NodeController::NodeController(Core* core)
- : core_(core),
- name_(GetRandomNodeName()),
- node_(new ports::Node(name_, this)) {
- DVLOG(1) << "Initializing node " << name_;
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-void NodeController::CreateMachPortRelay(
- base::PortProvider* port_provider) {
- base::AutoLock lock(mach_port_relay_lock_);
- DCHECK(!mach_port_relay_);
- mach_port_relay_.reset(new MachPortRelay(port_provider));
-}
-#endif
-
-void NodeController::SetIOTaskRunner(
- scoped_refptr<base::TaskRunner> task_runner) {
- io_task_runner_ = task_runner;
- ThreadDestructionObserver::Create(
- io_task_runner_,
- base::Bind(&NodeController::DropAllPeers, base::Unretained(this)));
-}
-
-void NodeController::ConnectToChild(
- base::ProcessHandle process_handle,
- ConnectionParams connection_params,
- const std::string& child_token,
- const ProcessErrorCallback& process_error_callback) {
- // Generate the temporary remote node name here so that it can be associated
- // with the embedder's child_token. If an error occurs in the child process
- // after it is launched, but before any reserved ports are connected, this can
- // be used to clean up any dangling ports.
- ports::NodeName node_name;
- GenerateRandomName(&node_name);
-
- {
- base::AutoLock lock(reserved_ports_lock_);
- bool inserted = pending_child_tokens_.insert(
- std::make_pair(node_name, child_token)).second;
- DCHECK(inserted);
- }
-
-#if defined(OS_WIN)
- // On Windows, we need to duplicate the process handle because we have no
- // control over its lifetime and it may become invalid by the time the posted
- // task runs.
- HANDLE dup_handle = INVALID_HANDLE_VALUE;
- BOOL ok = ::DuplicateHandle(
- base::GetCurrentProcessHandle(), process_handle,
- base::GetCurrentProcessHandle(), &dup_handle,
- 0, FALSE, DUPLICATE_SAME_ACCESS);
- DPCHECK(ok);
- process_handle = dup_handle;
-#endif
-
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&NodeController::ConnectToChildOnIOThread,
- base::Unretained(this), process_handle,
- base::Passed(&connection_params), node_name,
- process_error_callback));
-}
-
-void NodeController::CloseChildPorts(const std::string& child_token) {
- std::vector<ports::PortRef> ports_to_close;
- {
- std::vector<std::string> port_tokens;
- base::AutoLock lock(reserved_ports_lock_);
- for (const auto& port : reserved_ports_) {
- if (port.second.child_token == child_token) {
- DVLOG(1) << "Closing reserved port " << port.second.port.name();
- ports_to_close.push_back(port.second.port);
- port_tokens.push_back(port.first);
- }
- }
-
- for (const auto& token : port_tokens)
- reserved_ports_.erase(token);
- }
-
- for (const auto& port : ports_to_close)
- node_->ClosePort(port);
-
- // Ensure local port closure messages are processed.
- AcceptIncomingMessages();
-}
-
-void NodeController::ClosePeerConnection(const std::string& peer_token) {
- io_task_runner_->PostTask(
- FROM_HERE, base::Bind(&NodeController::ClosePeerConnectionOnIOThread,
- base::Unretained(this), peer_token));
-}
-
-void NodeController::ConnectToParent(ConnectionParams connection_params) {
-#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
- // Use the bootstrap channel for the broker and receive the node's channel
- // synchronously as the first message from the broker.
- base::ElapsedTimer timer;
- broker_.reset(new Broker(connection_params.TakeChannelHandle()));
- ScopedPlatformHandle platform_handle = broker_->GetParentPlatformHandle();
- UMA_HISTOGRAM_TIMES("Mojo.System.GetParentPlatformHandleSyncTime",
- timer.Elapsed());
-
- if (!platform_handle.is_valid()) {
- // Most likely the browser side of the channel has already been closed and
- // the broker was unable to negotiate a NodeChannel pipe. In this case we
- // can cancel parent connection.
- DVLOG(1) << "Cannot connect to invalid parent channel.";
- CancelPendingPortMerges();
- return;
- }
- connection_params = ConnectionParams(std::move(platform_handle));
-#endif
-
- io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&NodeController::ConnectToParentOnIOThread,
- base::Unretained(this), base::Passed(&connection_params)));
-}
-
-void NodeController::ConnectToPeer(ConnectionParams connection_params,
- const ports::PortRef& port,
- const std::string& peer_token) {
- ports::NodeName node_name;
- GenerateRandomName(&node_name);
- io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&NodeController::ConnectToPeerOnIOThread,
- base::Unretained(this), base::Passed(&connection_params),
- node_name, port, peer_token));
-}
-
-void NodeController::SetPortObserver(const ports::PortRef& port,
- scoped_refptr<PortObserver> observer) {
- node_->SetUserData(port, std::move(observer));
-}
-
-void NodeController::ClosePort(const ports::PortRef& port) {
- SetPortObserver(port, nullptr);
- int rv = node_->ClosePort(port);
- DCHECK_EQ(rv, ports::OK) << " Failed to close port: " << port.name();
-
- AcceptIncomingMessages();
-}
-
-int NodeController::SendMessage(const ports::PortRef& port,
- std::unique_ptr<PortsMessage> message) {
- ports::ScopedMessage ports_message(message.release());
- int rv = node_->SendMessage(port, std::move(ports_message));
-
- AcceptIncomingMessages();
- return rv;
-}
-
-void NodeController::ReservePort(const std::string& token,
- const ports::PortRef& port,
- const std::string& child_token) {
- DVLOG(2) << "Reserving port " << port.name() << "@" << name_ << " for token "
- << token;
-
- base::AutoLock lock(reserved_ports_lock_);
- auto result = reserved_ports_.insert(
- std::make_pair(token, ReservedPort{port, child_token}));
- DCHECK(result.second);
-}
-
-void NodeController::MergePortIntoParent(const std::string& token,
- const ports::PortRef& port) {
- bool was_merged = false;
- {
- // This request may be coming from within the process that reserved the
- // "parent" side (e.g. for Chrome single-process mode), so if this token is
- // reserved locally, merge locally instead.
- base::AutoLock lock(reserved_ports_lock_);
- auto it = reserved_ports_.find(token);
- if (it != reserved_ports_.end()) {
- node_->MergePorts(port, name_, it->second.port.name());
- reserved_ports_.erase(it);
- was_merged = true;
- }
- }
- if (was_merged) {
- AcceptIncomingMessages();
- return;
- }
-
- scoped_refptr<NodeChannel> parent;
- bool reject_merge = false;
- {
- // Hold |pending_port_merges_lock_| while getting |parent|. Otherwise,
- // there is a race where the parent can be set, and |pending_port_merges_|
- // be processed between retrieving |parent| and adding the merge to
- // |pending_port_merges_|.
- base::AutoLock lock(pending_port_merges_lock_);
- parent = GetParentChannel();
- if (reject_pending_merges_) {
- reject_merge = true;
- } else if (!parent) {
- pending_port_merges_.push_back(std::make_pair(token, port));
- return;
- }
- }
- if (reject_merge) {
- node_->ClosePort(port);
- DVLOG(2) << "Rejecting port merge for token " << token
- << " due to closed parent channel.";
- AcceptIncomingMessages();
- return;
- }
-
- parent->RequestPortMerge(port.name(), token);
-}
-
-int NodeController::MergeLocalPorts(const ports::PortRef& port0,
- const ports::PortRef& port1) {
- int rv = node_->MergeLocalPorts(port0, port1);
- AcceptIncomingMessages();
- return rv;
-}
-
-scoped_refptr<PlatformSharedBuffer> NodeController::CreateSharedBuffer(
- size_t num_bytes) {
-#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
- // Shared buffer creation failure is fatal, so always use the broker when we
- // have one. This does mean that a non-root process that has children will use
- // the broker for shared buffer creation even though that process is
- // privileged.
- if (broker_) {
- return broker_->GetSharedBuffer(num_bytes);
- }
-#endif
- return PlatformSharedBuffer::Create(num_bytes);
-}
-
-void NodeController::RequestShutdown(const base::Closure& callback) {
- {
- base::AutoLock lock(shutdown_lock_);
- shutdown_callback_ = callback;
- shutdown_callback_flag_.Set(true);
- }
-
- AttemptShutdownIfRequested();
-}
-
-void NodeController::NotifyBadMessageFrom(const ports::NodeName& source_node,
- const std::string& error) {
- scoped_refptr<NodeChannel> peer = GetPeerChannel(source_node);
- if (peer)
- peer->NotifyBadMessage(error);
-}
-
-void NodeController::ConnectToChildOnIOThread(
- base::ProcessHandle process_handle,
- ConnectionParams connection_params,
- ports::NodeName token,
- const ProcessErrorCallback& process_error_callback) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
- PlatformChannelPair node_channel;
- ScopedPlatformHandle server_handle = node_channel.PassServerHandle();
- // BrokerHost owns itself.
- BrokerHost* broker_host =
- new BrokerHost(process_handle, connection_params.TakeChannelHandle());
- bool channel_ok = broker_host->SendChannel(node_channel.PassClientHandle());
-
-#if defined(OS_WIN)
- if (!channel_ok) {
- // On Windows the above operation may fail if the channel is crossing a
- // session boundary. In that case we fall back to a named pipe.
- NamedPlatformChannelPair named_channel;
- server_handle = named_channel.PassServerHandle();
- broker_host->SendNamedChannel(named_channel.handle().name);
- }
-#else
- CHECK(channel_ok);
-#endif // defined(OS_WIN)
-
- scoped_refptr<NodeChannel> channel =
- NodeChannel::Create(this, ConnectionParams(std::move(server_handle)),
- io_task_runner_, process_error_callback);
-
-#else // !defined(OS_MACOSX) && !defined(OS_NACL)
- scoped_refptr<NodeChannel> channel =
- NodeChannel::Create(this, std::move(connection_params), io_task_runner_,
- process_error_callback);
-#endif // !defined(OS_MACOSX) && !defined(OS_NACL)
-
- // We set up the child channel with a temporary name so it can be identified
- // as a pending child if it writes any messages to the channel. We may start
- // receiving messages from it (though we shouldn't) as soon as Start() is
- // called below.
-
- pending_children_.insert(std::make_pair(token, channel));
- RecordPendingChildCount(pending_children_.size());
-
- channel->SetRemoteNodeName(token);
- channel->SetRemoteProcessHandle(process_handle);
- channel->Start();
-
- channel->AcceptChild(name_, token);
-}
-
-void NodeController::ConnectToParentOnIOThread(
- ConnectionParams connection_params) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- {
- base::AutoLock lock(parent_lock_);
- DCHECK(parent_name_ == ports::kInvalidNodeName);
-
- // At this point we don't know the parent's name, so we can't yet insert it
- // into our |peers_| map. That will happen as soon as we receive an
- // AcceptChild message from them.
- bootstrap_parent_channel_ =
- NodeChannel::Create(this, std::move(connection_params), io_task_runner_,
- ProcessErrorCallback());
- // Prevent the parent pipe handle from being closed on shutdown. Pipe
- // closure is used by the parent to detect the child process has exited.
- // Relying on message pipes to be closed is not enough because the parent
- // may see the message pipe closure before the child is dead, causing the
- // child process to be unexpectedly SIGKILL'd.
- bootstrap_parent_channel_->LeakHandleOnShutdown();
- }
- bootstrap_parent_channel_->Start();
-}
-
-void NodeController::ConnectToPeerOnIOThread(ConnectionParams connection_params,
- ports::NodeName token,
- ports::PortRef port,
- const std::string& peer_token) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- scoped_refptr<NodeChannel> channel = NodeChannel::Create(
- this, std::move(connection_params), io_task_runner_, {});
- peer_connections_.insert(
- {token, PeerConnection{channel, port, peer_token}});
- peers_by_token_.insert({peer_token, token});
-
- channel->SetRemoteNodeName(token);
- channel->Start();
-
- channel->AcceptPeer(name_, token, port.name());
-}
-
-void NodeController::ClosePeerConnectionOnIOThread(
- const std::string& peer_token) {
- RequestContext request_context(RequestContext::Source::SYSTEM);
- auto peer = peers_by_token_.find(peer_token);
- // The connection may already be closed.
- if (peer == peers_by_token_.end())
- return;
-
- // |peer| may be removed so make a copy of |name|.
- ports::NodeName name = peer->second;
- DropPeer(name, nullptr);
-}
-
-scoped_refptr<NodeChannel> NodeController::GetPeerChannel(
- const ports::NodeName& name) {
- base::AutoLock lock(peers_lock_);
- auto it = peers_.find(name);
- if (it == peers_.end())
- return nullptr;
- return it->second;
-}
-
-scoped_refptr<NodeChannel> NodeController::GetParentChannel() {
- ports::NodeName parent_name;
- {
- base::AutoLock lock(parent_lock_);
- parent_name = parent_name_;
- }
- return GetPeerChannel(parent_name);
-}
-
-scoped_refptr<NodeChannel> NodeController::GetBrokerChannel() {
- ports::NodeName broker_name;
- {
- base::AutoLock lock(broker_lock_);
- broker_name = broker_name_;
- }
- return GetPeerChannel(broker_name);
-}
-
-void NodeController::AddPeer(const ports::NodeName& name,
- scoped_refptr<NodeChannel> channel,
- bool start_channel) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- DCHECK(name != ports::kInvalidNodeName);
- DCHECK(channel);
-
- channel->SetRemoteNodeName(name);
-
- OutgoingMessageQueue pending_messages;
- {
- base::AutoLock lock(peers_lock_);
- if (peers_.find(name) != peers_.end()) {
- // This can happen normally if two nodes race to be introduced to each
- // other. The losing pipe will be silently closed and introduction should
- // not be affected.
- DVLOG(1) << "Ignoring duplicate peer name " << name;
- return;
- }
-
- auto result = peers_.insert(std::make_pair(name, channel));
- DCHECK(result.second);
-
- DVLOG(2) << "Accepting new peer " << name << " on node " << name_;
-
- RecordPeerCount(peers_.size());
-
- auto it = pending_peer_messages_.find(name);
- if (it != pending_peer_messages_.end()) {
- std::swap(pending_messages, it->second);
- pending_peer_messages_.erase(it);
- }
- }
-
- if (start_channel)
- channel->Start();
-
- // Flush any queued message we need to deliver to this node.
- while (!pending_messages.empty()) {
- channel->PortsMessage(std::move(pending_messages.front()));
- pending_messages.pop();
- }
-}
-
-void NodeController::DropPeer(const ports::NodeName& name,
- NodeChannel* channel) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- {
- base::AutoLock lock(peers_lock_);
- auto it = peers_.find(name);
-
- if (it != peers_.end()) {
- ports::NodeName peer = it->first;
- peers_.erase(it);
- DVLOG(1) << "Dropped peer " << peer;
- }
-
- pending_peer_messages_.erase(name);
- pending_children_.erase(name);
-
- RecordPeerCount(peers_.size());
- RecordPendingChildCount(pending_children_.size());
- }
-
- std::vector<ports::PortRef> ports_to_close;
- {
- // Clean up any reserved ports.
- base::AutoLock lock(reserved_ports_lock_);
- auto it = pending_child_tokens_.find(name);
- if (it != pending_child_tokens_.end()) {
- const std::string& child_token = it->second;
-
- std::vector<std::string> port_tokens;
- for (const auto& port : reserved_ports_) {
- if (port.second.child_token == child_token) {
- DVLOG(1) << "Closing reserved port: " << port.second.port.name();
- ports_to_close.push_back(port.second.port);
- port_tokens.push_back(port.first);
- }
- }
-
- // We have to erase reserved ports in a two-step manner because the usual
- // manner of using the returned iterator from map::erase isn't technically
- // valid in C++11 (although it is in C++14).
- for (const auto& token : port_tokens)
- reserved_ports_.erase(token);
-
- pending_child_tokens_.erase(it);
- }
- }
-
- bool is_parent;
- {
- base::AutoLock lock(parent_lock_);
- is_parent = (name == parent_name_ || channel == bootstrap_parent_channel_);
- }
-
- // If the error comes from the parent channel, we also need to cancel any
- // port merge requests, so that errors can be propagated to the message
- // pipes.
- if (is_parent)
- CancelPendingPortMerges();
-
- auto peer = peer_connections_.find(name);
- if (peer != peer_connections_.end()) {
- peers_by_token_.erase(peer->second.peer_token);
- ports_to_close.push_back(peer->second.local_port);
- peer_connections_.erase(peer);
- }
-
- for (const auto& port : ports_to_close)
- node_->ClosePort(port);
-
- node_->LostConnectionToNode(name);
-
- AcceptIncomingMessages();
-}
-
-void NodeController::SendPeerMessage(const ports::NodeName& name,
- ports::ScopedMessage message) {
- Channel::MessagePtr channel_message =
- static_cast<PortsMessage*>(message.get())->TakeChannelMessage();
-
- scoped_refptr<NodeChannel> peer = GetPeerChannel(name);
-#if defined(OS_WIN)
- if (channel_message->has_handles()) {
- // If we're sending a message with handles we aren't the destination
- // node's parent or broker (i.e. we don't know its process handle), ask
- // the broker to relay for us.
- scoped_refptr<NodeChannel> broker = GetBrokerChannel();
- if (!peer || !peer->HasRemoteProcessHandle()) {
- if (broker) {
- broker->RelayPortsMessage(name, std::move(channel_message));
- } else {
- base::AutoLock lock(broker_lock_);
- pending_relay_messages_[name].emplace(std::move(channel_message));
- }
- return;
- }
- }
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- if (channel_message->has_mach_ports()) {
- // Messages containing Mach ports are always routed through the broker, even
- // if the broker process is the intended recipient.
- bool use_broker = false;
- {
- base::AutoLock lock(parent_lock_);
- use_broker = (bootstrap_parent_channel_ ||
- parent_name_ != ports::kInvalidNodeName);
- }
- if (use_broker) {
- scoped_refptr<NodeChannel> broker = GetBrokerChannel();
- if (broker) {
- broker->RelayPortsMessage(name, std::move(channel_message));
- } else {
- base::AutoLock lock(broker_lock_);
- pending_relay_messages_[name].emplace(std::move(channel_message));
- }
- return;
- }
- }
-#endif // defined(OS_WIN)
-
- if (peer) {
- peer->PortsMessage(std::move(channel_message));
- return;
- }
-
- // If we don't know who the peer is and we are the broker, we can only assume
- // the peer is invalid, i.e., it's either a junk name or has already been
- // disconnected.
- scoped_refptr<NodeChannel> broker = GetBrokerChannel();
- if (!broker) {
- DVLOG(1) << "Dropping message for unknown peer: " << name;
- return;
- }
-
- // If we aren't the broker, assume we just need to be introduced and queue
- // until that can be either confirmed or denied by the broker.
- bool needs_introduction = false;
- {
- base::AutoLock lock(peers_lock_);
- auto& queue = pending_peer_messages_[name];
- needs_introduction = queue.empty();
- queue.emplace(std::move(channel_message));
- }
- if (needs_introduction)
- broker->RequestIntroduction(name);
-}
-
-void NodeController::AcceptIncomingMessages() {
- // This is an impactically large value which should never be reached in
- // practice. See the CHECK below for usage.
- constexpr size_t kMaxAcceptedMessages = 1000000;
-
- size_t num_messages_accepted = 0;
- while (incoming_messages_flag_) {
- // TODO: We may need to be more careful to avoid starving the rest of the
- // thread here. Revisit this if it turns out to be a problem. One
- // alternative would be to schedule a task to continue pumping messages
- // after flushing once.
-
- messages_lock_.Acquire();
- if (incoming_messages_.empty()) {
- messages_lock_.Release();
- break;
- }
-
- // libstdc++'s deque creates an internal buffer on construction, even when
- // the size is 0. So avoid creating it until it is necessary.
- std::queue<ports::ScopedMessage> messages;
- std::swap(messages, incoming_messages_);
- incoming_messages_flag_.Set(false);
- messages_lock_.Release();
-
- num_messages_accepted += messages.size();
- while (!messages.empty()) {
- node_->AcceptMessage(std::move(messages.front()));
- messages.pop();
- }
-
- // This is effectively a safeguard against potential bugs which might lead
- // to runaway message cycles. If any such cycles arise, we'll start seeing
- // crash reports from this location.
- CHECK_LE(num_messages_accepted, kMaxAcceptedMessages);
- }
-
- if (num_messages_accepted >= 4) {
- // Note: We avoid logging this histogram for the vast majority of cases.
- // See https://crbug.com/685763 for more context.
- UMA_HISTOGRAM_CUSTOM_COUNTS("Mojo.System.MessagesAcceptedPerEvent",
- static_cast<int32_t>(num_messages_accepted),
- 1 /* min */,
- 500 /* max */,
- 50 /* bucket count */);
- }
-
- AttemptShutdownIfRequested();
-}
-
-void NodeController::ProcessIncomingMessages() {
- RequestContext request_context(RequestContext::Source::SYSTEM);
-
- {
- base::AutoLock lock(messages_lock_);
- // Allow a new incoming messages processing task to be posted. This can't be
- // done after AcceptIncomingMessages() otherwise a message might be missed.
- // Doing it here may result in at most two tasks existing at the same time;
- // this running one, and one pending in the task runner.
- incoming_messages_task_posted_ = false;
- }
-
- AcceptIncomingMessages();
-}
-
-void NodeController::DropAllPeers() {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- std::vector<scoped_refptr<NodeChannel>> all_peers;
- {
- base::AutoLock lock(parent_lock_);
- if (bootstrap_parent_channel_) {
- // |bootstrap_parent_channel_| isn't null'd here becuase we rely on its
- // existence to determine whether or not this is the root node. Once
- // bootstrap_parent_channel_->ShutDown() has been called,
- // |bootstrap_parent_channel_| is essentially a dead object and it doesn't
- // matter if it's deleted now or when |this| is deleted.
- // Note: |bootstrap_parent_channel_| is only modified on the IO thread.
- all_peers.push_back(bootstrap_parent_channel_);
- }
- }
-
- {
- base::AutoLock lock(peers_lock_);
- for (const auto& peer : peers_)
- all_peers.push_back(peer.second);
- for (const auto& peer : pending_children_)
- all_peers.push_back(peer.second);
- peers_.clear();
- pending_children_.clear();
- pending_peer_messages_.clear();
- peer_connections_.clear();
- }
-
- for (const auto& peer : all_peers)
- peer->ShutDown();
-
- if (destroy_on_io_thread_shutdown_)
- delete this;
-}
-
-void NodeController::GenerateRandomPortName(ports::PortName* port_name) {
- GenerateRandomName(port_name);
-}
-
-void NodeController::AllocMessage(size_t num_header_bytes,
- ports::ScopedMessage* message) {
- message->reset(new PortsMessage(num_header_bytes, 0, 0, nullptr));
-}
-
-void NodeController::ForwardMessage(const ports::NodeName& node,
- ports::ScopedMessage message) {
- DCHECK(message);
- bool schedule_pump_task = false;
- if (node == name_) {
- // NOTE: We need to avoid re-entering the Node instance within
- // ForwardMessage. Because ForwardMessage is only ever called
- // (synchronously) in response to Node's ClosePort, SendMessage, or
- // AcceptMessage, we flush the queue after calling any of those methods.
- base::AutoLock lock(messages_lock_);
- // |io_task_runner_| may be null in tests or processes that don't require
- // multi-process Mojo.
- schedule_pump_task = incoming_messages_.empty() && io_task_runner_ &&
- !incoming_messages_task_posted_;
- incoming_messages_task_posted_ |= schedule_pump_task;
- incoming_messages_.emplace(std::move(message));
- incoming_messages_flag_.Set(true);
- } else {
- SendPeerMessage(node, std::move(message));
- }
-
- if (schedule_pump_task) {
- // Normally, the queue is processed after the action that added the local
- // message is done (i.e. SendMessage, ClosePort, etc). However, it's also
- // possible for a local message to be added as a result of a remote message,
- // and OnChannelMessage() doesn't process this queue (although
- // OnPortsMessage() does). There may also be other code paths, now or added
- // in the future, which cause local messages to be added but don't process
- // this message queue.
- //
- // Instead of adding a call to AcceptIncomingMessages() on every possible
- // code path, post a task to the IO thread to process the queue. If the
- // current call stack processes the queue, this may end up doing nothing.
- io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&NodeController::ProcessIncomingMessages,
- base::Unretained(this)));
- }
-}
-
-void NodeController::BroadcastMessage(ports::ScopedMessage message) {
- CHECK_EQ(message->num_ports(), 0u);
- Channel::MessagePtr channel_message =
- static_cast<PortsMessage*>(message.get())->TakeChannelMessage();
- CHECK(!channel_message->has_handles());
-
- scoped_refptr<NodeChannel> broker = GetBrokerChannel();
- if (broker)
- broker->Broadcast(std::move(channel_message));
- else
- OnBroadcast(name_, std::move(channel_message));
-}
-
-void NodeController::PortStatusChanged(const ports::PortRef& port) {
- scoped_refptr<ports::UserData> user_data;
- node_->GetUserData(port, &user_data);
-
- PortObserver* observer = static_cast<PortObserver*>(user_data.get());
- if (observer) {
- observer->OnPortStatusChanged();
- } else {
- DVLOG(2) << "Ignoring status change for " << port.name() << " because it "
- << "doesn't have an observer.";
- }
-}
-
-void NodeController::OnAcceptChild(const ports::NodeName& from_node,
- const ports::NodeName& parent_name,
- const ports::NodeName& token) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- scoped_refptr<NodeChannel> parent;
- {
- base::AutoLock lock(parent_lock_);
- if (bootstrap_parent_channel_ && parent_name_ == ports::kInvalidNodeName) {
- parent_name_ = parent_name;
- parent = bootstrap_parent_channel_;
- }
- }
-
- if (!parent) {
- DLOG(ERROR) << "Unexpected AcceptChild message from " << from_node;
- DropPeer(from_node, nullptr);
- return;
- }
-
- parent->SetRemoteNodeName(parent_name);
- parent->AcceptParent(token, name_);
-
- // NOTE: The child does not actually add its parent as a peer until
- // receiving an AcceptBrokerClient message from the broker. The parent
- // will request that said message be sent upon receiving AcceptParent.
-
- DVLOG(1) << "Child " << name_ << " accepting parent " << parent_name;
-}
-
-void NodeController::OnAcceptParent(const ports::NodeName& from_node,
- const ports::NodeName& token,
- const ports::NodeName& child_name) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- auto it = pending_children_.find(from_node);
- if (it == pending_children_.end() || token != from_node) {
- DLOG(ERROR) << "Received unexpected AcceptParent message from "
- << from_node;
- DropPeer(from_node, nullptr);
- return;
- }
-
- {
- base::AutoLock lock(reserved_ports_lock_);
- auto it = pending_child_tokens_.find(from_node);
- if (it != pending_child_tokens_.end()) {
- std::string token = std::move(it->second);
- pending_child_tokens_.erase(it);
- pending_child_tokens_[child_name] = std::move(token);
- }
- }
-
- scoped_refptr<NodeChannel> channel = it->second;
- pending_children_.erase(it);
-
- DCHECK(channel);
-
- DVLOG(1) << "Parent " << name_ << " accepted child " << child_name;
-
- AddPeer(child_name, channel, false /* start_channel */);
-
- // TODO(rockot/amistry): We could simplify child initialization if we could
- // synchronously get a new async broker channel from the broker. For now we do
- // it asynchronously since it's only used to facilitate handle passing, not
- // handle creation.
- scoped_refptr<NodeChannel> broker = GetBrokerChannel();
- if (broker) {
- // Inform the broker of this new child.
- broker->AddBrokerClient(child_name, channel->CopyRemoteProcessHandle());
- } else {
- // If we have no broker, either we need to wait for one, or we *are* the
- // broker.
- scoped_refptr<NodeChannel> parent = GetParentChannel();
- if (!parent) {
- base::AutoLock lock(parent_lock_);
- parent = bootstrap_parent_channel_;
- }
-
- if (!parent) {
- // Yes, we're the broker. We can initialize the child directly.
- channel->AcceptBrokerClient(name_, ScopedPlatformHandle());
- } else {
- // We aren't the broker, so wait for a broker connection.
- base::AutoLock lock(broker_lock_);
- pending_broker_clients_.push(child_name);
- }
- }
-}
-
-void NodeController::OnAddBrokerClient(const ports::NodeName& from_node,
- const ports::NodeName& client_name,
- base::ProcessHandle process_handle) {
-#if defined(OS_WIN)
- // Scoped handle to avoid leaks on error.
- ScopedPlatformHandle scoped_process_handle =
- ScopedPlatformHandle(PlatformHandle(process_handle));
-#endif
- scoped_refptr<NodeChannel> sender = GetPeerChannel(from_node);
- if (!sender) {
- DLOG(ERROR) << "Ignoring AddBrokerClient from unknown sender.";
- return;
- }
-
- if (GetPeerChannel(client_name)) {
- DLOG(ERROR) << "Ignoring AddBrokerClient for known client.";
- DropPeer(from_node, nullptr);
- return;
- }
-
- PlatformChannelPair broker_channel;
- ConnectionParams connection_params(broker_channel.PassServerHandle());
- scoped_refptr<NodeChannel> client =
- NodeChannel::Create(this, std::move(connection_params), io_task_runner_,
- ProcessErrorCallback());
-
-#if defined(OS_WIN)
- // The broker must have a working handle to the client process in order to
- // properly copy other handles to and from the client.
- if (!scoped_process_handle.is_valid()) {
- DLOG(ERROR) << "Broker rejecting client with invalid process handle.";
- return;
- }
- client->SetRemoteProcessHandle(scoped_process_handle.release().handle);
-#else
- client->SetRemoteProcessHandle(process_handle);
-#endif
-
- AddPeer(client_name, client, true /* start_channel */);
-
- DVLOG(1) << "Broker " << name_ << " accepting client " << client_name
- << " from peer " << from_node;
-
- sender->BrokerClientAdded(client_name, broker_channel.PassClientHandle());
-}
-
-void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node,
- const ports::NodeName& client_name,
- ScopedPlatformHandle broker_channel) {
- scoped_refptr<NodeChannel> client = GetPeerChannel(client_name);
- if (!client) {
- DLOG(ERROR) << "BrokerClientAdded for unknown child " << client_name;
- return;
- }
-
- // This should have come from our own broker.
- if (GetBrokerChannel() != GetPeerChannel(from_node)) {
- DLOG(ERROR) << "BrokerClientAdded from non-broker node " << from_node;
- return;
- }
-
- DVLOG(1) << "Child " << client_name << " accepted by broker " << from_node;
-
- client->AcceptBrokerClient(from_node, std::move(broker_channel));
-}
-
-void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node,
- const ports::NodeName& broker_name,
- ScopedPlatformHandle broker_channel) {
- // This node should already have a parent in bootstrap mode.
- ports::NodeName parent_name;
- scoped_refptr<NodeChannel> parent;
- {
- base::AutoLock lock(parent_lock_);
- parent_name = parent_name_;
- parent = bootstrap_parent_channel_;
- bootstrap_parent_channel_ = nullptr;
- }
- DCHECK(parent_name == from_node);
- DCHECK(parent);
-
- std::queue<ports::NodeName> pending_broker_clients;
- std::unordered_map<ports::NodeName, OutgoingMessageQueue>
- pending_relay_messages;
- {
- base::AutoLock lock(broker_lock_);
- broker_name_ = broker_name;
- std::swap(pending_broker_clients, pending_broker_clients_);
- std::swap(pending_relay_messages, pending_relay_messages_);
- }
- DCHECK(broker_name != ports::kInvalidNodeName);
-
- // It's now possible to add both the broker and the parent as peers.
- // Note that the broker and parent may be the same node.
- scoped_refptr<NodeChannel> broker;
- if (broker_name == parent_name) {
- DCHECK(!broker_channel.is_valid());
- broker = parent;
- } else {
- DCHECK(broker_channel.is_valid());
- broker =
- NodeChannel::Create(this, ConnectionParams(std::move(broker_channel)),
- io_task_runner_, ProcessErrorCallback());
- AddPeer(broker_name, broker, true /* start_channel */);
- }
-
- AddPeer(parent_name, parent, false /* start_channel */);
-
- {
- // Complete any port merge requests we have waiting for the parent.
- base::AutoLock lock(pending_port_merges_lock_);
- for (const auto& request : pending_port_merges_)
- parent->RequestPortMerge(request.second.name(), request.first);
- pending_port_merges_.clear();
- }
-
- // Feed the broker any pending children of our own.
- while (!pending_broker_clients.empty()) {
- const ports::NodeName& child_name = pending_broker_clients.front();
- auto it = pending_children_.find(child_name);
- DCHECK(it != pending_children_.end());
- broker->AddBrokerClient(child_name, it->second->CopyRemoteProcessHandle());
- pending_broker_clients.pop();
- }
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- // Have the broker relay any messages we have waiting.
- for (auto& entry : pending_relay_messages) {
- const ports::NodeName& destination = entry.first;
- auto& message_queue = entry.second;
- while (!message_queue.empty()) {
- broker->RelayPortsMessage(destination, std::move(message_queue.front()));
- message_queue.pop();
- }
- }
-#endif
-
- DVLOG(1) << "Child " << name_ << " accepted by broker " << broker_name;
-}
-
-void NodeController::OnPortsMessage(const ports::NodeName& from_node,
- Channel::MessagePtr channel_message) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- void* data;
- size_t num_data_bytes, num_header_bytes, num_payload_bytes, num_ports_bytes;
- if (!ParsePortsMessage(channel_message.get(), &data, &num_data_bytes,
- &num_header_bytes, &num_payload_bytes,
- &num_ports_bytes)) {
- DropPeer(from_node, nullptr);
- return;
- }
-
- CHECK(channel_message);
- std::unique_ptr<PortsMessage> ports_message(
- new PortsMessage(num_header_bytes,
- num_payload_bytes,
- num_ports_bytes,
- std::move(channel_message)));
- ports_message->set_source_node(from_node);
- node_->AcceptMessage(ports::ScopedMessage(ports_message.release()));
- AcceptIncomingMessages();
-}
-
-void NodeController::OnRequestPortMerge(
- const ports::NodeName& from_node,
- const ports::PortName& connector_port_name,
- const std::string& token) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- DVLOG(2) << "Node " << name_ << " received RequestPortMerge for token "
- << token << " and port " << connector_port_name << "@" << from_node;
-
- ports::PortRef local_port;
- {
- base::AutoLock lock(reserved_ports_lock_);
- auto it = reserved_ports_.find(token);
- if (it == reserved_ports_.end()) {
- DVLOG(1) << "Ignoring request to connect to port for unknown token "
- << token;
- return;
- }
- local_port = it->second.port;
- reserved_ports_.erase(it);
- }
-
- int rv = node_->MergePorts(local_port, from_node, connector_port_name);
- if (rv != ports::OK)
- DLOG(ERROR) << "MergePorts failed: " << rv;
-
- AcceptIncomingMessages();
-}
-
-void NodeController::OnRequestIntroduction(const ports::NodeName& from_node,
- const ports::NodeName& name) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- scoped_refptr<NodeChannel> requestor = GetPeerChannel(from_node);
- if (from_node == name || name == ports::kInvalidNodeName || !requestor) {
- DLOG(ERROR) << "Rejecting invalid OnRequestIntroduction message from "
- << from_node;
- DropPeer(from_node, nullptr);
- return;
- }
-
- scoped_refptr<NodeChannel> new_friend = GetPeerChannel(name);
- if (!new_friend) {
- // We don't know who they're talking about!
- requestor->Introduce(name, ScopedPlatformHandle());
- } else {
- PlatformChannelPair new_channel;
- requestor->Introduce(name, new_channel.PassServerHandle());
- new_friend->Introduce(from_node, new_channel.PassClientHandle());
- }
-}
-
-void NodeController::OnIntroduce(const ports::NodeName& from_node,
- const ports::NodeName& name,
- ScopedPlatformHandle channel_handle) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- if (!channel_handle.is_valid()) {
- node_->LostConnectionToNode(name);
-
- DVLOG(1) << "Could not be introduced to peer " << name;
- base::AutoLock lock(peers_lock_);
- pending_peer_messages_.erase(name);
- return;
- }
-
- scoped_refptr<NodeChannel> channel =
- NodeChannel::Create(this, ConnectionParams(std::move(channel_handle)),
- io_task_runner_, ProcessErrorCallback());
-
- DVLOG(1) << "Adding new peer " << name << " via parent introduction.";
- AddPeer(name, channel, true /* start_channel */);
-}
-
-void NodeController::OnBroadcast(const ports::NodeName& from_node,
- Channel::MessagePtr message) {
- DCHECK(!message->has_handles());
-
- void* data;
- size_t num_data_bytes, num_header_bytes, num_payload_bytes, num_ports_bytes;
- if (!ParsePortsMessage(message.get(), &data, &num_data_bytes,
- &num_header_bytes, &num_payload_bytes,
- &num_ports_bytes)) {
- DropPeer(from_node, nullptr);
- return;
- }
-
- // Broadcast messages must not contain ports.
- if (num_ports_bytes > 0) {
- DropPeer(from_node, nullptr);
- return;
- }
-
- base::AutoLock lock(peers_lock_);
- for (auto& iter : peers_) {
- // Copy and send the message to each known peer.
- Channel::MessagePtr peer_message(
- new Channel::Message(message->payload_size(), 0));
- memcpy(peer_message->mutable_payload(), message->payload(),
- message->payload_size());
- iter.second->PortsMessage(std::move(peer_message));
- }
-}
-
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
-void NodeController::OnRelayPortsMessage(const ports::NodeName& from_node,
- base::ProcessHandle from_process,
- const ports::NodeName& destination,
- Channel::MessagePtr message) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- if (GetBrokerChannel()) {
- // Only the broker should be asked to relay a message.
- LOG(ERROR) << "Non-broker refusing to relay message.";
- DropPeer(from_node, nullptr);
- return;
- }
-
- // The parent should always know which process this came from.
- DCHECK(from_process != base::kNullProcessHandle);
-
-#if defined(OS_WIN)
- // Rewrite the handles to this (the parent) process. If the message is
- // destined for another child process, the handles will be rewritten to that
- // process before going out (see NodeChannel::WriteChannelMessage).
- //
- // TODO: We could avoid double-duplication.
- //
- // Note that we explicitly mark the handles as being owned by the sending
- // process before rewriting them, in order to accommodate RewriteHandles'
- // internal sanity checks.
- ScopedPlatformHandleVectorPtr handles = message->TakeHandles();
- for (size_t i = 0; i < handles->size(); ++i)
- (*handles)[i].owning_process = from_process;
- if (!Channel::Message::RewriteHandles(from_process,
- base::GetCurrentProcessHandle(),
- handles.get())) {
- DLOG(ERROR) << "Failed to relay one or more handles.";
- }
- message->SetHandles(std::move(handles));
-#else
- MachPortRelay* relay = GetMachPortRelay();
- if (!relay) {
- LOG(ERROR) << "Receiving Mach ports without a port relay from "
- << from_node << ". Dropping message.";
- return;
- }
- if (!relay->ExtractPortRights(message.get(), from_process)) {
- // NodeChannel should ensure that MachPortRelay is ready for the remote
- // process. At this point, if the port extraction failed, either something
- // went wrong in the mach stuff, or the remote process died.
- LOG(ERROR) << "Error on receiving Mach ports " << from_node
- << ". Dropping message.";
- return;
- }
-#endif // defined(OS_WIN)
-
- if (destination == name_) {
- // Great, we can deliver this message locally.
- OnPortsMessage(from_node, std::move(message));
- return;
- }
-
- scoped_refptr<NodeChannel> peer = GetPeerChannel(destination);
- if (peer)
- peer->PortsMessageFromRelay(from_node, std::move(message));
- else
- DLOG(ERROR) << "Dropping relay message for unknown node " << destination;
-}
-
-void NodeController::OnPortsMessageFromRelay(const ports::NodeName& from_node,
- const ports::NodeName& source_node,
- Channel::MessagePtr message) {
- if (GetPeerChannel(from_node) != GetBrokerChannel()) {
- LOG(ERROR) << "Refusing relayed message from non-broker node.";
- DropPeer(from_node, nullptr);
- return;
- }
-
- OnPortsMessage(source_node, std::move(message));
-}
-#endif
-
-void NodeController::OnAcceptPeer(const ports::NodeName& from_node,
- const ports::NodeName& token,
- const ports::NodeName& peer_name,
- const ports::PortName& port_name) {
- DCHECK(io_task_runner_->RunsTasksOnCurrentThread());
-
- auto it = peer_connections_.find(from_node);
- if (it == peer_connections_.end()) {
- DLOG(ERROR) << "Received unexpected AcceptPeer message from " << from_node;
- DropPeer(from_node, nullptr);
- return;
- }
-
- scoped_refptr<NodeChannel> channel = std::move(it->second.channel);
- ports::PortRef local_port = it->second.local_port;
- std::string peer_token = std::move(it->second.peer_token);
- peer_connections_.erase(it);
- DCHECK(channel);
-
- // If the peer connection is a self connection (which is used in tests),
- // drop the channel to it and skip straight to merging the ports.
- if (name_ == peer_name) {
- peers_by_token_.erase(peer_token);
- } else {
- peers_by_token_[peer_token] = peer_name;
- peer_connections_.insert(
- {peer_name, PeerConnection{nullptr, local_port, peer_token}});
- DVLOG(1) << "Node " << name_ << " accepted peer " << peer_name;
-
- AddPeer(peer_name, channel, false /* start_channel */);
- }
-
- // We need to choose one side to initiate the port merge. It doesn't matter
- // who does it as long as they don't both try. Simple solution: pick the one
- // with the "smaller" port name.
- if (local_port.name() < port_name) {
- node()->MergePorts(local_port, peer_name, port_name);
- }
-}
-
-void NodeController::OnChannelError(const ports::NodeName& from_node,
- NodeChannel* channel) {
- if (io_task_runner_->RunsTasksOnCurrentThread()) {
- DropPeer(from_node, channel);
- // DropPeer may have caused local port closures, so be sure to process any
- // pending local messages.
- AcceptIncomingMessages();
- } else {
- io_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&NodeController::OnChannelError, base::Unretained(this),
- from_node, channel));
- }
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-MachPortRelay* NodeController::GetMachPortRelay() {
- {
- base::AutoLock lock(parent_lock_);
- // Return null if we're not the root.
- if (bootstrap_parent_channel_ || parent_name_ != ports::kInvalidNodeName)
- return nullptr;
- }
-
- base::AutoLock lock(mach_port_relay_lock_);
- return mach_port_relay_.get();
-}
-#endif
-
-void NodeController::CancelPendingPortMerges() {
- std::vector<ports::PortRef> ports_to_close;
-
- {
- base::AutoLock lock(pending_port_merges_lock_);
- reject_pending_merges_ = true;
- for (const auto& port : pending_port_merges_)
- ports_to_close.push_back(port.second);
- pending_port_merges_.clear();
- }
-
- for (const auto& port : ports_to_close)
- node_->ClosePort(port);
-}
-
-void NodeController::DestroyOnIOThreadShutdown() {
- destroy_on_io_thread_shutdown_ = true;
-}
-
-void NodeController::AttemptShutdownIfRequested() {
- if (!shutdown_callback_flag_)
- return;
-
- base::Closure callback;
- {
- base::AutoLock lock(shutdown_lock_);
- if (shutdown_callback_.is_null())
- return;
- if (!node_->CanShutdownCleanly(
- ports::Node::ShutdownPolicy::ALLOW_LOCAL_PORTS)) {
- DVLOG(2) << "Unable to cleanly shut down node " << name_;
- return;
- }
-
- callback = shutdown_callback_;
- shutdown_callback_.Reset();
- shutdown_callback_flag_.Set(false);
- }
-
- DCHECK(!callback.is_null());
-
- callback.Run();
-}
-
-NodeController::PeerConnection::PeerConnection() = default;
-
-NodeController::PeerConnection::PeerConnection(
- const PeerConnection& other) = default;
-
-NodeController::PeerConnection::PeerConnection(
- PeerConnection&& other) = default;
-
-NodeController::PeerConnection::PeerConnection(
- scoped_refptr<NodeChannel> channel,
- const ports::PortRef& local_port,
- const std::string& peer_token)
- : channel(std::move(channel)),
- local_port(local_port),
- peer_token(peer_token) {}
-
-NodeController::PeerConnection::~PeerConnection() = default;
-
-NodeController::PeerConnection& NodeController::PeerConnection::
-operator=(const PeerConnection& other) = default;
-
-NodeController::PeerConnection& NodeController::PeerConnection::
-operator=(PeerConnection&& other) = default;
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/node_controller.h b/mojo/edk/system/node_controller.h
deleted file mode 100644
index 46a2d61..0000000
--- a/mojo/edk/system/node_controller.h
+++ /dev/null
@@ -1,378 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_NODE_CONTROLLER_H_
-#define MOJO_EDK_SYSTEM_NODE_CONTROLLER_H_
-
-#include <memory>
-#include <queue>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/task_runner.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/atomic_flag.h"
-#include "mojo/edk/system/node_channel.h"
-#include "mojo/edk/system/ports/name.h"
-#include "mojo/edk/system/ports/node.h"
-#include "mojo/edk/system/ports/node_delegate.h"
-
-namespace base {
-class PortProvider;
-}
-
-namespace mojo {
-namespace edk {
-
-class Broker;
-class Core;
-class MachPortRelay;
-class PortsMessage;
-
-// The owner of ports::Node which facilitates core EDK implementation. All
-// public interface methods are safe to call from any thread.
-class NodeController : public ports::NodeDelegate,
- public NodeChannel::Delegate {
- public:
- class PortObserver : public ports::UserData {
- public:
- virtual void OnPortStatusChanged() = 0;
-
- protected:
- ~PortObserver() override {}
- };
-
- // |core| owns and out-lives us.
- explicit NodeController(Core* core);
- ~NodeController() override;
-
- const ports::NodeName& name() const { return name_; }
- Core* core() const { return core_; }
- ports::Node* node() const { return node_.get(); }
- scoped_refptr<base::TaskRunner> io_task_runner() const {
- return io_task_runner_;
- }
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // Create the relay used to transfer mach ports between processes.
- void CreateMachPortRelay(base::PortProvider* port_provider);
-#endif
-
- // Called exactly once, shortly after construction, and before any other
- // methods are called on this object.
- void SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner);
-
- // Connects this node to a child node. This node will initiate a handshake.
- void ConnectToChild(base::ProcessHandle process_handle,
- ConnectionParams connection_params,
- const std::string& child_token,
- const ProcessErrorCallback& process_error_callback);
-
- // Closes all reserved ports which associated with the child process
- // |child_token|.
- void CloseChildPorts(const std::string& child_token);
-
- // Close a connection to a peer associated with |peer_token|.
- void ClosePeerConnection(const std::string& peer_token);
-
- // Connects this node to a parent node. The parent node will initiate a
- // handshake.
- void ConnectToParent(ConnectionParams connection_params);
-
- // Connects this node to a peer node. On success, |port| will be merged with
- // the corresponding port in the peer node.
- void ConnectToPeer(ConnectionParams connection_params,
- const ports::PortRef& port,
- const std::string& peer_token);
-
- // Sets a port's observer. If |observer| is null the port's current observer
- // is removed.
- void SetPortObserver(const ports::PortRef& port,
- scoped_refptr<PortObserver> observer);
-
- // Closes a port. Use this in lieu of calling Node::ClosePort() directly, as
- // it ensures the port's observer has also been removed.
- void ClosePort(const ports::PortRef& port);
-
- // Sends a message on a port to its peer.
- int SendMessage(const ports::PortRef& port_ref,
- std::unique_ptr<PortsMessage> message);
-
- // Reserves a local port |port| associated with |token|. A peer holding a copy
- // of |token| can merge one of its own ports into this one.
- void ReservePort(const std::string& token, const ports::PortRef& port,
- const std::string& child_token);
-
- // Merges a local port |port| into a port reserved by |token| in the parent.
- void MergePortIntoParent(const std::string& token,
- const ports::PortRef& port);
-
- // Merges two local ports together.
- int MergeLocalPorts(const ports::PortRef& port0, const ports::PortRef& port1);
-
- // Creates a new shared buffer for use in the current process.
- scoped_refptr<PlatformSharedBuffer> CreateSharedBuffer(size_t num_bytes);
-
- // Request that the Node be shut down cleanly. This may take an arbitrarily
- // long time to complete, at which point |callback| will be called.
- //
- // Note that while it is safe to continue using the NodeController's public
- // interface after requesting shutdown, you do so at your own risk and there
- // is NO guarantee that new messages will be sent or ports will complete
- // transfer.
- void RequestShutdown(const base::Closure& callback);
-
- // Notifies the NodeController that we received a bad message from the given
- // node.
- void NotifyBadMessageFrom(const ports::NodeName& source_node,
- const std::string& error);
-
- private:
- friend Core;
-
- using NodeMap = std::unordered_map<ports::NodeName,
- scoped_refptr<NodeChannel>>;
- using OutgoingMessageQueue = std::queue<Channel::MessagePtr>;
-
- struct ReservedPort {
- ports::PortRef port;
- const std::string child_token;
- };
-
- struct PeerConnection {
- PeerConnection();
- PeerConnection(const PeerConnection& other);
- PeerConnection(PeerConnection&& other);
- PeerConnection(scoped_refptr<NodeChannel> channel,
- const ports::PortRef& local_port,
- const std::string& peer_token);
- ~PeerConnection();
-
- PeerConnection& operator=(const PeerConnection& other);
- PeerConnection& operator=(PeerConnection&& other);
-
-
- scoped_refptr<NodeChannel> channel;
- ports::PortRef local_port;
- std::string peer_token;
- };
-
- void ConnectToChildOnIOThread(
- base::ProcessHandle process_handle,
- ConnectionParams connection_params,
- ports::NodeName token,
- const ProcessErrorCallback& process_error_callback);
- void ConnectToParentOnIOThread(ConnectionParams connection_params);
-
- void ConnectToPeerOnIOThread(ConnectionParams connection_params,
- ports::NodeName token,
- ports::PortRef port,
- const std::string& peer_token);
- void ClosePeerConnectionOnIOThread(const std::string& node_name);
-
- scoped_refptr<NodeChannel> GetPeerChannel(const ports::NodeName& name);
- scoped_refptr<NodeChannel> GetParentChannel();
- scoped_refptr<NodeChannel> GetBrokerChannel();
-
- void AddPeer(const ports::NodeName& name,
- scoped_refptr<NodeChannel> channel,
- bool start_channel);
- void DropPeer(const ports::NodeName& name, NodeChannel* channel);
- void SendPeerMessage(const ports::NodeName& name,
- ports::ScopedMessage message);
- void AcceptIncomingMessages();
- void ProcessIncomingMessages();
- void DropAllPeers();
-
- // ports::NodeDelegate:
- void GenerateRandomPortName(ports::PortName* port_name) override;
- void AllocMessage(size_t num_header_bytes,
- ports::ScopedMessage* message) override;
- void ForwardMessage(const ports::NodeName& node,
- ports::ScopedMessage message) override;
- void BroadcastMessage(ports::ScopedMessage message) override;
- void PortStatusChanged(const ports::PortRef& port) override;
-
- // NodeChannel::Delegate:
- void OnAcceptChild(const ports::NodeName& from_node,
- const ports::NodeName& parent_name,
- const ports::NodeName& token) override;
- void OnAcceptParent(const ports::NodeName& from_node,
- const ports::NodeName& token,
- const ports::NodeName& child_name) override;
- void OnAddBrokerClient(const ports::NodeName& from_node,
- const ports::NodeName& client_name,
- base::ProcessHandle process_handle) override;
- void OnBrokerClientAdded(const ports::NodeName& from_node,
- const ports::NodeName& client_name,
- ScopedPlatformHandle broker_channel) override;
- void OnAcceptBrokerClient(const ports::NodeName& from_node,
- const ports::NodeName& broker_name,
- ScopedPlatformHandle broker_channel) override;
- void OnPortsMessage(const ports::NodeName& from_node,
- Channel::MessagePtr message) override;
- void OnRequestPortMerge(const ports::NodeName& from_node,
- const ports::PortName& connector_port_name,
- const std::string& token) override;
- void OnRequestIntroduction(const ports::NodeName& from_node,
- const ports::NodeName& name) override;
- void OnIntroduce(const ports::NodeName& from_node,
- const ports::NodeName& name,
- ScopedPlatformHandle channel_handle) override;
- void OnBroadcast(const ports::NodeName& from_node,
- Channel::MessagePtr message) override;
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
- void OnRelayPortsMessage(const ports::NodeName& from_node,
- base::ProcessHandle from_process,
- const ports::NodeName& destination,
- Channel::MessagePtr message) override;
- void OnPortsMessageFromRelay(const ports::NodeName& from_node,
- const ports::NodeName& source_node,
- Channel::MessagePtr message) override;
-#endif
- void OnAcceptPeer(const ports::NodeName& from_node,
- const ports::NodeName& token,
- const ports::NodeName& peer_name,
- const ports::PortName& port_name) override;
- void OnChannelError(const ports::NodeName& from_node,
- NodeChannel* channel) override;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- MachPortRelay* GetMachPortRelay() override;
-#endif
-
- // Cancels all pending port merges. These are merges which are supposed to
- // be requested from the parent ASAP, and they may be cancelled if the
- // connection to the parent is broken or never established.
- void CancelPendingPortMerges();
-
- // Marks this NodeController for destruction when the IO thread shuts down.
- // This is used in case Core is torn down before the IO thread. Must only be
- // called on the IO thread.
- void DestroyOnIOThreadShutdown();
-
- // If there is a registered shutdown callback (meaning shutdown has been
- // requested, this checks the Node's status to see if clean shutdown is
- // possible. If so, shutdown is performed and the shutdown callback is run.
- void AttemptShutdownIfRequested();
-
- // These are safe to access from any thread as long as the Node is alive.
- Core* const core_;
- const ports::NodeName name_;
- const std::unique_ptr<ports::Node> node_;
- scoped_refptr<base::TaskRunner> io_task_runner_;
-
- // Guards |peers_| and |pending_peer_messages_|.
- base::Lock peers_lock_;
-
- // Channels to known peers, including parent and children, if any.
- NodeMap peers_;
-
- // Outgoing message queues for peers we've heard of but can't yet talk to.
- std::unordered_map<ports::NodeName, OutgoingMessageQueue>
- pending_peer_messages_;
-
- // Guards |reserved_ports_| and |pending_child_tokens_|.
- base::Lock reserved_ports_lock_;
-
- // Ports reserved by token. Key is the port token.
- base::hash_map<std::string, ReservedPort> reserved_ports_;
- // TODO(amistry): This _really_ needs to be a bimap. Unfortunately, we don't
- // have one yet :(
- std::unordered_map<ports::NodeName, std::string> pending_child_tokens_;
-
- // Guards |pending_port_merges_| and |reject_pending_merges_|.
- base::Lock pending_port_merges_lock_;
-
- // A set of port merge requests awaiting parent connection.
- std::vector<std::pair<std::string, ports::PortRef>> pending_port_merges_;
-
- // Indicates that new merge requests should be rejected because the parent has
- // disconnected.
- bool reject_pending_merges_ = false;
-
- // Guards |parent_name_| and |bootstrap_parent_channel_|.
- base::Lock parent_lock_;
-
- // The name of our parent node, if any.
- ports::NodeName parent_name_;
-
- // A temporary reference to the parent channel before we know their name.
- scoped_refptr<NodeChannel> bootstrap_parent_channel_;
-
- // Guards |broker_name_|, |pending_broker_clients_|, and
- // |pending_relay_messages_|.
- base::Lock broker_lock_;
-
- // The name of our broker node, if any.
- ports::NodeName broker_name_;
-
- // A queue of pending child names waiting to be connected to a broker.
- std::queue<ports::NodeName> pending_broker_clients_;
-
- // Messages waiting to be relayed by the broker once it's known.
- std::unordered_map<ports::NodeName, OutgoingMessageQueue>
- pending_relay_messages_;
-
- // Guards |incoming_messages_| and |incoming_messages_task_posted_|.
- base::Lock messages_lock_;
- std::queue<ports::ScopedMessage> incoming_messages_;
- // Ensures that there is only one incoming messages task posted to the IO
- // thread.
- bool incoming_messages_task_posted_ = false;
- // Flag to fast-path checking |incoming_messages_|.
- AtomicFlag incoming_messages_flag_;
-
- // Guards |shutdown_callback_|.
- base::Lock shutdown_lock_;
-
- // Set by RequestShutdown(). If this is non-null, the controller will
- // begin polling the Node to see if clean shutdown is possible any time the
- // Node's state is modified by the controller.
- base::Closure shutdown_callback_;
- // Flag to fast-path checking |shutdown_callback_|.
- AtomicFlag shutdown_callback_flag_;
-
- // All other fields below must only be accessed on the I/O thread, i.e., the
- // thread on which core_->io_task_runner() runs tasks.
-
- // Channels to children during handshake.
- NodeMap pending_children_;
-
- using PeerNodeMap =
- std::unordered_map<ports::NodeName, PeerConnection>;
- PeerNodeMap peer_connections_;
-
- // Maps from peer token to node name, pending or not.
- std::unordered_map<std::string, ports::NodeName> peers_by_token_;
-
- // Indicates whether this object should delete itself on IO thread shutdown.
- // Must only be accessed from the IO thread.
- bool destroy_on_io_thread_shutdown_ = false;
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL_SFI)
- // Broker for sync shared buffer creation in children.
- std::unique_ptr<Broker> broker_;
-#endif
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- base::Lock mach_port_relay_lock_;
- // Relay for transferring mach ports to/from children.
- std::unique_ptr<MachPortRelay> mach_port_relay_;
-#endif
-
- DISALLOW_COPY_AND_ASSIGN(NodeController);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_NODE_CONTROLLER_H_
diff --git a/mojo/edk/system/options_validation.h b/mojo/edk/system/options_validation.h
deleted file mode 100644
index e1b337d..0000000
--- a/mojo/edk/system/options_validation.h
+++ /dev/null
@@ -1,97 +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.
-
-// Functions to help with verifying various |Mojo...Options| structs from the
-// (public, C) API. These are "extensible" structs, which all have |struct_size|
-// as their first member. All fields (other than |struct_size|) are optional,
-// but any |flags| specified must be known to the system (otherwise, an error of
-// |MOJO_RESULT_UNIMPLEMENTED| should be returned).
-
-#ifndef MOJO_EDK_SYSTEM_OPTIONS_VALIDATION_H_
-#define MOJO_EDK_SYSTEM_OPTIONS_VALIDATION_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/c/system/types.h"
-
-namespace mojo {
-namespace edk {
-
-template <class Options>
-class UserOptionsReader {
- public:
- // Constructor from a |const* Options| (which it checks -- this constructor
- // has side effects!).
- // Note: We initialize |options_reader_| without checking, since we do a check
- // in |GetSizeForReader()|.
- explicit UserOptionsReader(const Options* options) {
- CHECK(options && IsAligned<MOJO_ALIGNOF(Options)>(options));
- options_ = GetSizeForReader(options) == 0 ? nullptr : options;
- static_assert(offsetof(Options, struct_size) == 0,
- "struct_size not first member of Options");
- // TODO(vtl): Enable when MSVC supports this (C++11 extended sizeof):
- // static_assert(sizeof(Options::struct_size) == sizeof(uint32_t),
- // "Options::struct_size not a uint32_t");
- // (Or maybe assert that its type is uint32_t?)
- }
-
- bool is_valid() const { return !!options_; }
-
- const Options& options() const {
- DCHECK(is_valid());
- return *options_;
- }
-
- // Checks that the given (variable-size) |options| passed to the constructor
- // (plausibly) has a member at the given offset with the given size. You
- // probably want to use |OPTIONS_STRUCT_HAS_MEMBER()| instead.
- bool HasMember(size_t offset, size_t size) const {
- DCHECK(is_valid());
- // We assume that |offset| and |size| are reasonable, since they should come
- // from |offsetof(Options, some_member)| and |sizeof(Options::some_member)|,
- // respectively.
- return options().struct_size >= offset + size;
- }
-
- private:
- static inline size_t GetSizeForReader(const Options* options) {
- uint32_t struct_size = *reinterpret_cast<const uint32_t*>(options);
- if (struct_size < sizeof(uint32_t))
- return 0;
-
- return std::min(static_cast<size_t>(struct_size), sizeof(Options));
- }
-
- template <size_t alignment>
- static bool IsAligned(const void* pointer) {
- return reinterpret_cast<uintptr_t>(pointer) % alignment == 0;
- }
-
- const Options* options_;
-
- DISALLOW_COPY_AND_ASSIGN(UserOptionsReader);
-};
-
-// Macro to invoke |UserOptionsReader<Options>::HasMember()| parametrized by
-// member name instead of offset and size.
-//
-// (We can't just give |HasMember()| a member pointer template argument instead,
-// since there's no good/strictly-correct way to get an offset from that.)
-//
-// TODO(vtl): With C++11, use |sizeof(Options::member)| instead of (the
-// contortion below). We might also be able to pull out the type |Options| from
-// |reader| (using |decltype|) instead of requiring a parameter.
-#define OPTIONS_STRUCT_HAS_MEMBER(Options, member, reader) \
- reader.HasMember(offsetof(Options, member), sizeof(reader.options().member))
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_OPTIONS_VALIDATION_H_
diff --git a/mojo/edk/system/options_validation_unittest.cc b/mojo/edk/system/options_validation_unittest.cc
deleted file mode 100644
index a01a92c..0000000
--- a/mojo/edk/system/options_validation_unittest.cc
+++ /dev/null
@@ -1,134 +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/options_validation.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "mojo/public/c/system/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-// Declare a test options struct just as we do in actual public headers.
-
-using TestOptionsFlags = uint32_t;
-
-static_assert(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
-struct MOJO_ALIGNAS(8) TestOptions {
- uint32_t struct_size;
- TestOptionsFlags flags;
- uint32_t member1;
- uint32_t member2;
-};
-static_assert(sizeof(TestOptions) == 16, "TestOptions has wrong size");
-
-const uint32_t kSizeOfTestOptions = static_cast<uint32_t>(sizeof(TestOptions));
-
-TEST(OptionsValidationTest, Valid) {
- {
- const TestOptions kOptions = {kSizeOfTestOptions};
- UserOptionsReader<TestOptions> reader(&kOptions);
- EXPECT_TRUE(reader.is_valid());
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
- }
- {
- const TestOptions kOptions = {static_cast<uint32_t>(
- offsetof(TestOptions, struct_size) + sizeof(uint32_t))};
- UserOptionsReader<TestOptions> reader(&kOptions);
- EXPECT_TRUE(reader.is_valid());
- EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
- EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
- EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
- }
-
- {
- const TestOptions kOptions = {
- static_cast<uint32_t>(offsetof(TestOptions, flags) + sizeof(uint32_t))};
- UserOptionsReader<TestOptions> reader(&kOptions);
- EXPECT_TRUE(reader.is_valid());
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
- EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
- EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
- }
- {
- MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
- TestOptions* options = reinterpret_cast<TestOptions*>(buf);
- options->struct_size = kSizeOfTestOptions + 1;
- UserOptionsReader<TestOptions> reader(options);
- EXPECT_TRUE(reader.is_valid());
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
- }
- {
- MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
- TestOptions* options = reinterpret_cast<TestOptions*>(buf);
- options->struct_size = kSizeOfTestOptions + 4;
- UserOptionsReader<TestOptions> reader(options);
- EXPECT_TRUE(reader.is_valid());
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
- EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
- }
-}
-
-TEST(OptionsValidationTest, Invalid) {
- // Size too small:
- for (size_t i = 0; i < sizeof(uint32_t); i++) {
- TestOptions options = {static_cast<uint32_t>(i)};
- UserOptionsReader<TestOptions> reader(&options);
- EXPECT_FALSE(reader.is_valid()) << i;
- }
-}
-
-// These test invalid arguments that should cause death if we're being paranoid
-// about checking arguments (which we would want to do if, e.g., we were in a
-// true "kernel" situation, but we might not want to do otherwise for
-// performance reasons). Probably blatant errors like passing in null pointers
-// (for required pointer arguments) will still cause death, but perhaps not
-// predictably.
-TEST(OptionsValidationTest, InvalidDeath) {
-#if defined(OFFICIAL_BUILD)
- const char kMemoryCheckFailedRegex[] = "";
-#else
- const char kMemoryCheckFailedRegex[] = "Check failed";
-#endif
-
- // Null:
- EXPECT_DEATH_IF_SUPPORTED(
- { UserOptionsReader<TestOptions> reader((nullptr)); },
- kMemoryCheckFailedRegex);
-
- // Unaligned:
- EXPECT_DEATH_IF_SUPPORTED(
- {
- UserOptionsReader<TestOptions> reader(
- reinterpret_cast<const TestOptions*>(1));
- },
- kMemoryCheckFailedRegex);
- // Note: The current implementation checks the size only after checking the
- // alignment versus that required for the |uint32_t| size, so it won't die in
- // the expected way if you pass, e.g., 4. So we have to manufacture a valid
- // pointer at an offset of alignment 4.
- EXPECT_DEATH_IF_SUPPORTED(
- {
- uint32_t buffer[100] = {};
- TestOptions* options = (reinterpret_cast<uintptr_t>(buffer) % 8 == 0)
- ? reinterpret_cast<TestOptions*>(&buffer[1])
- : reinterpret_cast<TestOptions*>(&buffer[0]);
- options->struct_size = static_cast<uint32_t>(sizeof(TestOptions));
- UserOptionsReader<TestOptions> reader(options);
- },
- kMemoryCheckFailedRegex);
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/platform_handle_dispatcher.cc b/mojo/edk/system/platform_handle_dispatcher.cc
deleted file mode 100644
index 3e708c2..0000000
--- a/mojo/edk/system/platform_handle_dispatcher.cc
+++ /dev/null
@@ -1,104 +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/platform_handle_dispatcher.h"
-
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-
-namespace mojo {
-namespace edk {
-
-// static
-scoped_refptr<PlatformHandleDispatcher> PlatformHandleDispatcher::Create(
- ScopedPlatformHandle platform_handle) {
- return new PlatformHandleDispatcher(std::move(platform_handle));
-}
-
-ScopedPlatformHandle PlatformHandleDispatcher::PassPlatformHandle() {
- return std::move(platform_handle_);
-}
-
-Dispatcher::Type PlatformHandleDispatcher::GetType() const {
- return Type::PLATFORM_HANDLE;
-}
-
-MojoResult PlatformHandleDispatcher::Close() {
- base::AutoLock lock(lock_);
- if (is_closed_ || in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
- is_closed_ = true;
- platform_handle_.reset();
- return MOJO_RESULT_OK;
-}
-
-void PlatformHandleDispatcher::StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) {
- *num_bytes = 0;
- *num_ports = 0;
- *num_handles = 1;
-}
-
-bool PlatformHandleDispatcher::EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) {
- base::AutoLock lock(lock_);
- if (is_closed_)
- return false;
- handles[0] = platform_handle_.get();
- return true;
-}
-
-bool PlatformHandleDispatcher::BeginTransit() {
- base::AutoLock lock(lock_);
- if (in_transit_)
- return false;
- in_transit_ = !is_closed_;
- return in_transit_;
-}
-
-void PlatformHandleDispatcher::CompleteTransitAndClose() {
- base::AutoLock lock(lock_);
-
- in_transit_ = false;
- is_closed_ = true;
-
- // The system has taken ownership of our handle.
- ignore_result(platform_handle_.release());
-}
-
-void PlatformHandleDispatcher::CancelTransit() {
- base::AutoLock lock(lock_);
- in_transit_ = false;
-}
-
-// static
-scoped_refptr<PlatformHandleDispatcher> PlatformHandleDispatcher::Deserialize(
- const void* bytes,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles) {
- if (num_bytes || num_ports || num_handles != 1)
- return nullptr;
-
- PlatformHandle handle;
- std::swap(handle, handles[0]);
-
- return PlatformHandleDispatcher::Create(ScopedPlatformHandle(handle));
-}
-
-PlatformHandleDispatcher::PlatformHandleDispatcher(
- ScopedPlatformHandle platform_handle)
- : platform_handle_(std::move(platform_handle)) {}
-
-PlatformHandleDispatcher::~PlatformHandleDispatcher() {
- DCHECK(is_closed_ && !in_transit_);
- DCHECK(!platform_handle_.is_valid());
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/platform_handle_dispatcher.h b/mojo/edk/system/platform_handle_dispatcher.h
deleted file mode 100644
index a36c7a0..0000000
--- a/mojo/edk/system/platform_handle_dispatcher.h
+++ /dev/null
@@ -1,61 +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_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-namespace edk {
-
-class MOJO_SYSTEM_IMPL_EXPORT PlatformHandleDispatcher : public Dispatcher {
- public:
- static scoped_refptr<PlatformHandleDispatcher> Create(
- ScopedPlatformHandle platform_handle);
-
- ScopedPlatformHandle PassPlatformHandle();
-
- // Dispatcher:
- Type GetType() const override;
- MojoResult Close() override;
- void StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_handles) override;
- bool EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) override;
- bool BeginTransit() override;
- void CompleteTransitAndClose() override;
- void CancelTransit() override;
-
- static scoped_refptr<PlatformHandleDispatcher> Deserialize(
- const void* bytes,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* handles,
- size_t num_handles);
-
- private:
- PlatformHandleDispatcher(ScopedPlatformHandle platform_handle);
- ~PlatformHandleDispatcher() override;
-
- base::Lock lock_;
- bool in_transit_ = false;
- bool is_closed_ = false;
- ScopedPlatformHandle platform_handle_;
-
- DISALLOW_COPY_AND_ASSIGN(PlatformHandleDispatcher);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PLATFORM_HANDLE_DISPATCHER_H_
diff --git a/mojo/edk/system/platform_handle_dispatcher_unittest.cc b/mojo/edk/system/platform_handle_dispatcher_unittest.cc
deleted file mode 100644
index 7a94262..0000000
--- a/mojo/edk/system/platform_handle_dispatcher_unittest.cc
+++ /dev/null
@@ -1,123 +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/platform_handle_dispatcher.h"
-
-#include <stdio.h>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/test/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-TEST(PlatformHandleDispatcherTest, Basic) {
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- static const char kHelloWorld[] = "hello world";
-
- base::FilePath unused;
- base::ScopedFILE fp(
- CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
- ASSERT_TRUE(fp);
- EXPECT_EQ(sizeof(kHelloWorld),
- fwrite(kHelloWorld, 1, sizeof(kHelloWorld), fp.get()));
-
- ScopedPlatformHandle h(test::PlatformHandleFromFILE(std::move(fp)));
- EXPECT_FALSE(fp);
- ASSERT_TRUE(h.is_valid());
-
- scoped_refptr<PlatformHandleDispatcher> dispatcher =
- PlatformHandleDispatcher::Create(std::move(h));
- EXPECT_FALSE(h.is_valid());
- EXPECT_EQ(Dispatcher::Type::PLATFORM_HANDLE, dispatcher->GetType());
-
- h = dispatcher->PassPlatformHandle();
- EXPECT_TRUE(h.is_valid());
-
- fp = test::FILEFromPlatformHandle(std::move(h), "rb");
- EXPECT_FALSE(h.is_valid());
- EXPECT_TRUE(fp);
-
- rewind(fp.get());
- char read_buffer[1000] = {};
- EXPECT_EQ(sizeof(kHelloWorld),
- fread(read_buffer, 1, sizeof(read_buffer), fp.get()));
- EXPECT_STREQ(kHelloWorld, read_buffer);
-
- // Try getting the handle again. (It should fail cleanly.)
- h = dispatcher->PassPlatformHandle();
- EXPECT_FALSE(h.is_valid());
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
-}
-
-TEST(PlatformHandleDispatcherTest, Serialization) {
- base::ScopedTempDir temp_dir;
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-
- static const char kFooBar[] = "foo bar";
-
- base::FilePath unused;
- base::ScopedFILE fp(
- CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
- EXPECT_EQ(sizeof(kFooBar), fwrite(kFooBar, 1, sizeof(kFooBar), fp.get()));
-
- scoped_refptr<PlatformHandleDispatcher> dispatcher =
- PlatformHandleDispatcher::Create(
- test::PlatformHandleFromFILE(std::move(fp)));
-
- uint32_t num_bytes = 0;
- uint32_t num_ports = 0;
- uint32_t num_handles = 0;
- EXPECT_TRUE(dispatcher->BeginTransit());
- dispatcher->StartSerialize(&num_bytes, &num_ports, &num_handles);
-
- EXPECT_EQ(0u, num_bytes);
- EXPECT_EQ(0u, num_ports);
- EXPECT_EQ(1u, num_handles);
-
- ScopedPlatformHandleVectorPtr handles(new PlatformHandleVector(1));
- EXPECT_TRUE(dispatcher->EndSerialize(nullptr, nullptr, handles->data()));
- dispatcher->CompleteTransitAndClose();
-
- EXPECT_TRUE(handles->at(0).is_valid());
-
- ScopedPlatformHandle handle = dispatcher->PassPlatformHandle();
- EXPECT_FALSE(handle.is_valid());
-
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher->Close());
-
- dispatcher = static_cast<PlatformHandleDispatcher*>(
- Dispatcher::Deserialize(Dispatcher::Type::PLATFORM_HANDLE, nullptr,
- num_bytes, nullptr, num_ports, handles->data(),
- 1).get());
-
- EXPECT_FALSE(handles->at(0).is_valid());
- EXPECT_TRUE(dispatcher->GetType() == Dispatcher::Type::PLATFORM_HANDLE);
-
- fp = test::FILEFromPlatformHandle(dispatcher->PassPlatformHandle(), "rb");
- EXPECT_TRUE(fp);
-
- rewind(fp.get());
- char read_buffer[1000] = {};
- EXPECT_EQ(sizeof(kFooBar),
- fread(read_buffer, 1, sizeof(read_buffer), fp.get()));
- EXPECT_STREQ(kFooBar, read_buffer);
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/platform_wrapper_unittest.cc b/mojo/edk/system/platform_wrapper_unittest.cc
deleted file mode 100644
index f29d62b..0000000
--- a/mojo/edk/system/platform_wrapper_unittest.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-#include <string.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "base/files/file.h"
-#include "base/files/file_util.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process_handle.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/platform_handle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#if defined(OS_POSIX)
-#define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR
-#elif defined(OS_WIN)
-#define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE
-#endif
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#define SHARED_BUFFER_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT
-#else
-#define SHARED_BUFFER_PLATFORM_HANDLE_TYPE SIMPLE_PLATFORM_HANDLE_TYPE
-#endif
-
-uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) {
-#if defined(OS_WIN)
- return reinterpret_cast<uint64_t>(file);
-#else
- return static_cast<uint64_t>(file);
-#endif
-}
-
-base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) {
-#if defined(OS_WIN)
- return reinterpret_cast<base::PlatformFile>(value);
-#else
- return static_cast<base::PlatformFile>(value);
-#endif
-}
-
-namespace mojo {
-namespace edk {
-namespace {
-
-using PlatformWrapperTest = test::MojoTestBase;
-
-TEST_F(PlatformWrapperTest, WrapPlatformHandle) {
- // Create a temporary file and write a message to it.
- base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
- const std::string kMessage = "Hello, world!";
- EXPECT_EQ(base::WriteFile(temp_file_path, kMessage.data(),
- static_cast<int>(kMessage.size())),
- static_cast<int>(kMessage.size()));
-
- RUN_CHILD_ON_PIPE(ReadPlatformFile, h)
- // Open the temporary file for reading, wrap its handle, and send it to
- // the child along with the expected message to be read.
- base::File file(temp_file_path,
- base::File::FLAG_OPEN | base::File::FLAG_READ);
- EXPECT_TRUE(file.IsValid());
-
- MojoHandle wrapped_handle;
- MojoPlatformHandle os_file;
- os_file.struct_size = sizeof(MojoPlatformHandle);
- os_file.type = SIMPLE_PLATFORM_HANDLE_TYPE;
- os_file.value =
- PlatformHandleValueFromPlatformFile(file.TakePlatformFile());
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWrapPlatformHandle(&os_file, &wrapped_handle));
-
- WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1);
- END_CHILD()
-
- base::DeleteFile(temp_file_path, false);
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile, PlatformWrapperTest, h) {
- // Read a message and a wrapped file handle; unwrap the handle.
- MojoHandle wrapped_handle;
- std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1);
-
- MojoPlatformHandle platform_handle;
- platform_handle.struct_size = sizeof(MojoPlatformHandle);
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoUnwrapPlatformHandle(wrapped_handle, &platform_handle));
- EXPECT_EQ(SIMPLE_PLATFORM_HANDLE_TYPE, platform_handle.type);
- base::File file(PlatformFileFromPlatformHandleValue(platform_handle.value));
-
- // Expect to read the same message from the file.
- std::vector<char> data(message.size());
- EXPECT_EQ(file.ReadAtCurrentPos(data.data(), static_cast<int>(data.size())),
- static_cast<int>(data.size()));
- EXPECT_TRUE(std::equal(message.begin(), message.end(), data.begin()));
-}
-
-TEST_F(PlatformWrapperTest, WrapPlatformSharedBufferHandle) {
- // Allocate a new platform shared buffer and write a message into it.
- const std::string kMessage = "Hello, world!";
- base::SharedMemory buffer;
- buffer.CreateAndMapAnonymous(kMessage.size());
- CHECK(buffer.memory());
- memcpy(buffer.memory(), kMessage.data(), kMessage.size());
-
- RUN_CHILD_ON_PIPE(ReadPlatformSharedBuffer, h)
- // Wrap the shared memory handle and send it to the child along with the
- // expected message.
- base::SharedMemoryHandle memory_handle =
- base::SharedMemory::DuplicateHandle(buffer.handle());
- MojoPlatformHandle os_buffer;
- os_buffer.struct_size = sizeof(MojoPlatformHandle);
- os_buffer.type = SHARED_BUFFER_PLATFORM_HANDLE_TYPE;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject());
-#elif defined(OS_POSIX)
- os_buffer.value = static_cast<uint64_t>(memory_handle.fd);
-#elif defined(OS_WIN)
- os_buffer.value = reinterpret_cast<uint64_t>(memory_handle.GetHandle());
-#endif
-
- MojoHandle wrapped_handle;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoWrapPlatformSharedBufferHandle(
- &os_buffer, kMessage.size(),
- MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE,
- &wrapped_handle));
- WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1);
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer, PlatformWrapperTest,
- h) {
- // Read a message and a wrapped shared buffer handle.
- MojoHandle wrapped_handle;
- std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1);
-
- // Check the message in the buffer
- ExpectBufferContents(wrapped_handle, 0, message);
-
- // Now unwrap the buffer and verify that the base::SharedMemoryHandle also
- // works as expected.
- MojoPlatformHandle os_buffer;
- os_buffer.struct_size = sizeof(MojoPlatformHandle);
- size_t size;
- MojoPlatformSharedBufferHandleFlags flags;
- ASSERT_EQ(MOJO_RESULT_OK,
- MojoUnwrapPlatformSharedBufferHandle(wrapped_handle, &os_buffer,
- &size, &flags));
- bool read_only = flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
- EXPECT_FALSE(read_only);
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, os_buffer.type);
- base::SharedMemoryHandle memory_handle(
- static_cast<mach_port_t>(os_buffer.value), size,
- base::GetCurrentProcId());
-#elif defined(OS_POSIX)
- ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR, os_buffer.type);
- base::SharedMemoryHandle memory_handle(static_cast<int>(os_buffer.value),
- false);
-#elif defined(OS_WIN)
- ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type);
- base::SharedMemoryHandle memory_handle(
- reinterpret_cast<HANDLE>(os_buffer.value), base::GetCurrentProcId());
-#endif
-
- base::SharedMemory memory(memory_handle, read_only);
- memory.Map(message.size());
- ASSERT_TRUE(memory.memory());
-
- EXPECT_TRUE(std::equal(message.begin(), message.end(),
- static_cast<const char*>(memory.memory())));
-}
-
-TEST_F(PlatformWrapperTest, InvalidHandle) {
- // Wrap an invalid platform handle and expect to unwrap the same.
-
- MojoHandle wrapped_handle;
- MojoPlatformHandle invalid_handle;
- invalid_handle.struct_size = sizeof(MojoPlatformHandle);
- invalid_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWrapPlatformHandle(&invalid_handle, &wrapped_handle));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoUnwrapPlatformHandle(wrapped_handle, &invalid_handle));
- EXPECT_EQ(MOJO_PLATFORM_HANDLE_TYPE_INVALID, invalid_handle.type);
-}
-
-TEST_F(PlatformWrapperTest, InvalidArgument) {
- // Try to wrap an invalid MojoPlatformHandle struct and expect an error.
- MojoHandle wrapped_handle;
- MojoPlatformHandle platform_handle;
- platform_handle.struct_size = 0;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoWrapPlatformHandle(&platform_handle, &wrapped_handle));
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/BUILD.gn b/mojo/edk/system/ports/BUILD.gn
deleted file mode 100644
index 5c82761..0000000
--- a/mojo/edk/system/ports/BUILD.gn
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//testing/test.gni")
-
-source_set("ports") {
- sources = [
- "event.cc",
- "event.h",
- "message.cc",
- "message.h",
- "message_filter.h",
- "message_queue.cc",
- "message_queue.h",
- "name.cc",
- "name.h",
- "node.cc",
- "node.h",
- "node_delegate.h",
- "port.cc",
- "port.h",
- "port_ref.cc",
- "port_ref.h",
- "user_data.h",
- ]
-
- public_deps = [
- "//base",
- ]
-}
-
-source_set("tests") {
- testonly = true
-
- sources = [
- "ports_unittest.cc",
- ]
-
- deps = [
- ":ports",
- "//base",
- "//base/test:test_support",
- "//testing/gtest",
- ]
-}
diff --git a/mojo/edk/system/ports/event.cc b/mojo/edk/system/ports/event.cc
deleted file mode 100644
index 2e22086..0000000
--- a/mojo/edk/system/ports/event.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports/event.h"
-
-#include <string.h>
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-namespace {
-
-const size_t kPortsMessageAlignment = 8;
-
-static_assert(sizeof(PortDescriptor) % kPortsMessageAlignment == 0,
- "Invalid PortDescriptor size.");
-
-static_assert(sizeof(EventHeader) % kPortsMessageAlignment == 0,
- "Invalid EventHeader size.");
-
-static_assert(sizeof(UserEventData) % kPortsMessageAlignment == 0,
- "Invalid UserEventData size.");
-
-static_assert(sizeof(ObserveProxyEventData) % kPortsMessageAlignment == 0,
- "Invalid ObserveProxyEventData size.");
-
-static_assert(sizeof(ObserveProxyAckEventData) % kPortsMessageAlignment == 0,
- "Invalid ObserveProxyAckEventData size.");
-
-static_assert(sizeof(ObserveClosureEventData) % kPortsMessageAlignment == 0,
- "Invalid ObserveClosureEventData size.");
-
-static_assert(sizeof(MergePortEventData) % kPortsMessageAlignment == 0,
- "Invalid MergePortEventData size.");
-
-} // namespace
-
-PortDescriptor::PortDescriptor() {
- memset(padding, 0, sizeof(padding));
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/event.h b/mojo/edk/system/ports/event.h
deleted file mode 100644
index a66dfc1..0000000
--- a/mojo/edk/system/ports/event.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_EVENT_H_
-#define MOJO_EDK_SYSTEM_PORTS_EVENT_H_
-
-#include <stdint.h>
-
-#include "mojo/edk/system/ports/message.h"
-#include "mojo/edk/system/ports/name.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-#pragma pack(push, 1)
-
-// TODO: Add static assertions of alignment.
-
-struct PortDescriptor {
- PortDescriptor();
-
- NodeName peer_node_name;
- PortName peer_port_name;
- NodeName referring_node_name;
- PortName referring_port_name;
- uint64_t next_sequence_num_to_send;
- uint64_t next_sequence_num_to_receive;
- uint64_t last_sequence_num_to_receive;
- bool peer_closed;
- char padding[7];
-};
-
-enum struct EventType : uint32_t {
- kUser,
- kPortAccepted,
- kObserveProxy,
- kObserveProxyAck,
- kObserveClosure,
- kMergePort,
-};
-
-struct EventHeader {
- EventType type;
- uint32_t padding;
- PortName port_name;
-};
-
-struct UserEventData {
- uint64_t sequence_num;
- uint32_t num_ports;
- uint32_t padding;
-};
-
-struct ObserveProxyEventData {
- NodeName proxy_node_name;
- PortName proxy_port_name;
- NodeName proxy_to_node_name;
- PortName proxy_to_port_name;
-};
-
-struct ObserveProxyAckEventData {
- uint64_t last_sequence_num;
-};
-
-struct ObserveClosureEventData {
- uint64_t last_sequence_num;
-};
-
-struct MergePortEventData {
- PortName new_port_name;
- PortDescriptor new_port_descriptor;
-};
-
-#pragma pack(pop)
-
-inline const EventHeader* GetEventHeader(const Message& message) {
- return static_cast<const EventHeader*>(message.header_bytes());
-}
-
-inline EventHeader* GetMutableEventHeader(Message* message) {
- return static_cast<EventHeader*>(message->mutable_header_bytes());
-}
-
-template <typename EventData>
-inline const EventData* GetEventData(const Message& message) {
- return reinterpret_cast<const EventData*>(
- reinterpret_cast<const char*>(GetEventHeader(message) + 1));
-}
-
-template <typename EventData>
-inline EventData* GetMutableEventData(Message* message) {
- return reinterpret_cast<EventData*>(
- reinterpret_cast<char*>(GetMutableEventHeader(message) + 1));
-}
-
-inline const PortDescriptor* GetPortDescriptors(const UserEventData* event) {
- return reinterpret_cast<const PortDescriptor*>(
- reinterpret_cast<const char*>(event + 1));
-}
-
-inline PortDescriptor* GetMutablePortDescriptors(UserEventData* event) {
- return reinterpret_cast<PortDescriptor*>(reinterpret_cast<char*>(event + 1));
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_EVENT_H_
diff --git a/mojo/edk/system/ports/message.cc b/mojo/edk/system/ports/message.cc
deleted file mode 100644
index 5d3c000..0000000
--- a/mojo/edk/system/ports/message.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdlib.h>
-
-#include <limits>
-
-#include "base/logging.h"
-#include "mojo/edk/system/ports/event.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-// static
-bool Message::Parse(const void* bytes,
- size_t num_bytes,
- size_t* num_header_bytes,
- size_t* num_payload_bytes,
- size_t* num_ports_bytes) {
- if (num_bytes < sizeof(EventHeader))
- return false;
- const EventHeader* header = static_cast<const EventHeader*>(bytes);
- switch (header->type) {
- case EventType::kUser:
- // See below.
- break;
- case EventType::kPortAccepted:
- *num_header_bytes = sizeof(EventHeader);
- break;
- case EventType::kObserveProxy:
- *num_header_bytes = sizeof(EventHeader) + sizeof(ObserveProxyEventData);
- break;
- case EventType::kObserveProxyAck:
- *num_header_bytes =
- sizeof(EventHeader) + sizeof(ObserveProxyAckEventData);
- break;
- case EventType::kObserveClosure:
- *num_header_bytes = sizeof(EventHeader) + sizeof(ObserveClosureEventData);
- break;
- case EventType::kMergePort:
- *num_header_bytes = sizeof(EventHeader) + sizeof(MergePortEventData);
- break;
- default:
- return false;
- }
-
- if (header->type == EventType::kUser) {
- if (num_bytes < sizeof(EventHeader) + sizeof(UserEventData))
- return false;
- const UserEventData* event_data =
- reinterpret_cast<const UserEventData*>(
- reinterpret_cast<const char*>(header + 1));
- if (event_data->num_ports > std::numeric_limits<uint16_t>::max())
- return false;
- *num_header_bytes = sizeof(EventHeader) +
- sizeof(UserEventData) +
- event_data->num_ports * sizeof(PortDescriptor);
- *num_ports_bytes = event_data->num_ports * sizeof(PortName);
- if (num_bytes < *num_header_bytes + *num_ports_bytes)
- return false;
- *num_payload_bytes = num_bytes - *num_header_bytes - *num_ports_bytes;
- } else {
- if (*num_header_bytes != num_bytes)
- return false;
- *num_payload_bytes = 0;
- *num_ports_bytes = 0;
- }
-
- return true;
-}
-
-Message::Message(size_t num_payload_bytes, size_t num_ports)
- : Message(sizeof(EventHeader) + sizeof(UserEventData) +
- num_ports * sizeof(PortDescriptor),
- num_payload_bytes, num_ports * sizeof(PortName)) {
- num_ports_ = num_ports;
-}
-
-Message::Message(size_t num_header_bytes,
- size_t num_payload_bytes,
- size_t num_ports_bytes)
- : start_(nullptr),
- num_header_bytes_(num_header_bytes),
- num_ports_bytes_(num_ports_bytes),
- num_payload_bytes_(num_payload_bytes) {
-}
-
-void Message::InitializeUserMessageHeader(void* start) {
- start_ = static_cast<char*>(start);
- memset(start_, 0, num_header_bytes_);
- GetMutableEventHeader(this)->type = EventType::kUser;
- GetMutableEventData<UserEventData>(this)->num_ports =
- static_cast<uint32_t>(num_ports_);
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/message.h b/mojo/edk/system/ports/message.h
deleted file mode 100644
index 95fa046..0000000
--- a/mojo/edk/system/ports/message.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_MESSAGE_H_
-#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_H_
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "mojo/edk/system/ports/name.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-// A message consists of a header (array of bytes), payload (array of bytes)
-// and an array of ports. The header is used by the Node implementation.
-//
-// This class is designed to be subclassed, and the subclass is responsible for
-// providing the underlying storage. The header size will be aligned, and it
-// should be followed in memory by the array of ports and finally the payload.
-//
-// NOTE: This class does not manage the lifetime of the ports it references.
-class Message {
- public:
- virtual ~Message() {}
-
- // Inspect the message at |bytes| and return the size of each section. Returns
- // |false| if the message is malformed and |true| otherwise.
- static bool Parse(const void* bytes,
- size_t num_bytes,
- size_t* num_header_bytes,
- size_t* num_payload_bytes,
- size_t* num_ports_bytes);
-
- void* mutable_header_bytes() { return start_; }
- const void* header_bytes() const { return start_; }
- size_t num_header_bytes() const { return num_header_bytes_; }
-
- void* mutable_payload_bytes() {
- return start_ + num_header_bytes_ + num_ports_bytes_;
- }
- const void* payload_bytes() const {
- return const_cast<Message*>(this)->mutable_payload_bytes();
- }
- size_t num_payload_bytes() const { return num_payload_bytes_; }
-
- PortName* mutable_ports() {
- return reinterpret_cast<PortName*>(start_ + num_header_bytes_);
- }
- const PortName* ports() const {
- return const_cast<Message*>(this)->mutable_ports();
- }
- size_t num_ports_bytes() const { return num_ports_bytes_; }
- size_t num_ports() const { return num_ports_bytes_ / sizeof(PortName); }
-
- protected:
- // Constructs a new Message base for a user message.
- //
- // Note: You MUST call InitializeUserMessageHeader() before this Message is
- // ready for transmission.
- Message(size_t num_payload_bytes, size_t num_ports);
-
- // Constructs a new Message base for an internal message. Do NOT call
- // InitializeUserMessageHeader() when using this constructor.
- Message(size_t num_header_bytes,
- size_t num_payload_bytes,
- size_t num_ports_bytes);
-
- Message(const Message& other) = delete;
- void operator=(const Message& other) = delete;
-
- // Initializes the header in a newly allocated message buffer to carry a
- // user message.
- void InitializeUserMessageHeader(void* start);
-
- // Note: storage is [header][ports][payload].
- char* start_ = nullptr;
- size_t num_ports_ = 0;
- size_t num_header_bytes_ = 0;
- size_t num_ports_bytes_ = 0;
- size_t num_payload_bytes_ = 0;
-};
-
-using ScopedMessage = std::unique_ptr<Message>;
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_H_
diff --git a/mojo/edk/system/ports/message_filter.h b/mojo/edk/system/ports/message_filter.h
deleted file mode 100644
index bf8fa21..0000000
--- a/mojo/edk/system/ports/message_filter.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_MESSAGE_FILTER_H_
-#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_FILTER_H_
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-class Message;
-
-// An interface which can be implemented to filter port messages according to
-// arbitrary policy.
-class MessageFilter {
- public:
- virtual ~MessageFilter() {}
-
- // Returns true of |message| should be accepted by whomever is applying this
- // filter. See MessageQueue::GetNextMessage(), for example.
- virtual bool Match(const Message& message) = 0;
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_FILTER_H_
diff --git a/mojo/edk/system/ports/message_queue.cc b/mojo/edk/system/ports/message_queue.cc
deleted file mode 100644
index defb1b6..0000000
--- a/mojo/edk/system/ports/message_queue.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports/message_queue.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "mojo/edk/system/ports/event.h"
-#include "mojo/edk/system/ports/message_filter.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-inline uint64_t GetSequenceNum(const ScopedMessage& message) {
- return GetEventData<UserEventData>(*message)->sequence_num;
-}
-
-// Used by std::{push,pop}_heap functions
-inline bool operator<(const ScopedMessage& a, const ScopedMessage& b) {
- return GetSequenceNum(a) > GetSequenceNum(b);
-}
-
-MessageQueue::MessageQueue() : MessageQueue(kInitialSequenceNum) {}
-
-MessageQueue::MessageQueue(uint64_t next_sequence_num)
- : next_sequence_num_(next_sequence_num) {
- // The message queue is blocked waiting for a message with sequence number
- // equal to |next_sequence_num|.
-}
-
-MessageQueue::~MessageQueue() {
-#if DCHECK_IS_ON()
- size_t num_leaked_ports = 0;
- for (const auto& message : heap_)
- num_leaked_ports += message->num_ports();
- DVLOG_IF(1, num_leaked_ports > 0)
- << "Leaking " << num_leaked_ports << " ports in unreceived messages";
-#endif
-}
-
-bool MessageQueue::HasNextMessage() const {
- return !heap_.empty() && GetSequenceNum(heap_[0]) == next_sequence_num_;
-}
-
-void MessageQueue::GetNextMessage(ScopedMessage* message,
- MessageFilter* filter) {
- if (!HasNextMessage() || (filter && !filter->Match(*heap_[0].get()))) {
- message->reset();
- return;
- }
-
- std::pop_heap(heap_.begin(), heap_.end());
- *message = std::move(heap_.back());
- heap_.pop_back();
-
- next_sequence_num_++;
-}
-
-void MessageQueue::AcceptMessage(ScopedMessage message,
- bool* has_next_message) {
- DCHECK(GetEventHeader(*message)->type == EventType::kUser);
-
- // TODO: Handle sequence number roll-over.
-
- heap_.emplace_back(std::move(message));
- std::push_heap(heap_.begin(), heap_.end());
-
- if (!signalable_) {
- *has_next_message = false;
- } else {
- *has_next_message = (GetSequenceNum(heap_[0]) == next_sequence_num_);
- }
-}
-
-void MessageQueue::GetReferencedPorts(std::deque<PortName>* port_names) {
- for (const auto& message : heap_) {
- for (size_t i = 0; i < message->num_ports(); ++i)
- port_names->push_back(message->ports()[i]);
- }
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/message_queue.h b/mojo/edk/system/ports/message_queue.h
deleted file mode 100644
index d9a47ed..0000000
--- a/mojo/edk/system/ports/message_queue.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_MESSAGE_QUEUE_H_
-#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_QUEUE_H_
-
-#include <stdint.h>
-
-#include <deque>
-#include <functional>
-#include <limits>
-#include <vector>
-
-#include "base/macros.h"
-#include "mojo/edk/system/ports/message.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-const uint64_t kInitialSequenceNum = 1;
-const uint64_t kInvalidSequenceNum = std::numeric_limits<uint64_t>::max();
-
-class MessageFilter;
-
-// An incoming message queue for a port. MessageQueue keeps track of the highest
-// known sequence number and can indicate whether the next sequential message is
-// available. Thus the queue enforces message ordering for the consumer without
-// enforcing it for the producer (see AcceptMessage() below.)
-class MessageQueue {
- public:
- explicit MessageQueue();
- explicit MessageQueue(uint64_t next_sequence_num);
- ~MessageQueue();
-
- void set_signalable(bool value) { signalable_ = value; }
-
- uint64_t next_sequence_num() const { return next_sequence_num_; }
-
- bool HasNextMessage() const;
-
- // Gives ownership of the message. If |filter| is non-null, the next message
- // will only be retrieved if the filter successfully matches it.
- void GetNextMessage(ScopedMessage* message, MessageFilter* filter);
-
- // Takes ownership of the message. Note: Messages are ordered, so while we
- // have added a message to the queue, we may still be waiting on a message
- // ahead of this one before we can let any of the messages be returned by
- // GetNextMessage.
- //
- // Furthermore, once has_next_message is set to true, it will remain false
- // until GetNextMessage is called enough times to return a null message.
- // In other words, has_next_message acts like an edge trigger.
- //
- void AcceptMessage(ScopedMessage message, bool* has_next_message);
-
- // Returns all of the ports referenced by messages in this message queue.
- void GetReferencedPorts(std::deque<PortName>* ports);
-
- private:
- std::vector<ScopedMessage> heap_;
- uint64_t next_sequence_num_;
- bool signalable_ = true;
-
- DISALLOW_COPY_AND_ASSIGN(MessageQueue);
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_QUEUE_H_
diff --git a/mojo/edk/system/ports/name.cc b/mojo/edk/system/ports/name.cc
deleted file mode 100644
index ea17698..0000000
--- a/mojo/edk/system/ports/name.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports/name.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-extern const PortName kInvalidPortName = {0, 0};
-
-extern const NodeName kInvalidNodeName = {0, 0};
-
-std::ostream& operator<<(std::ostream& stream, const Name& name) {
- std::ios::fmtflags flags(stream.flags());
- stream << std::hex << std::uppercase << name.v1;
- if (name.v2 != 0)
- stream << '.' << name.v2;
- stream.flags(flags);
- return stream;
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/name.h b/mojo/edk/system/ports/name.h
deleted file mode 100644
index 72e41b9..0000000
--- a/mojo/edk/system/ports/name.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_NAME_H_
-#define MOJO_EDK_SYSTEM_PORTS_NAME_H_
-
-#include <stdint.h>
-
-#include <ostream>
-#include <tuple>
-
-#include "base/hash.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-struct Name {
- Name(uint64_t v1, uint64_t v2) : v1(v1), v2(v2) {}
- uint64_t v1, v2;
-};
-
-inline bool operator==(const Name& a, const Name& b) {
- return a.v1 == b.v1 && a.v2 == b.v2;
-}
-
-inline bool operator!=(const Name& a, const Name& b) {
- return !(a == b);
-}
-
-inline bool operator<(const Name& a, const Name& b) {
- return std::tie(a.v1, a.v2) < std::tie(b.v1, b.v2);
-}
-
-std::ostream& operator<<(std::ostream& stream, const Name& name);
-
-struct PortName : Name {
- PortName() : Name(0, 0) {}
- PortName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
-};
-
-extern const PortName kInvalidPortName;
-
-struct NodeName : Name {
- NodeName() : Name(0, 0) {}
- NodeName(uint64_t v1, uint64_t v2) : Name(v1, v2) {}
-};
-
-extern const NodeName kInvalidNodeName;
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-namespace std {
-
-template <>
-struct hash<mojo::edk::ports::PortName> {
- std::size_t operator()(const mojo::edk::ports::PortName& name) const {
- return base::HashInts64(name.v1, name.v2);
- }
-};
-
-template <>
-struct hash<mojo::edk::ports::NodeName> {
- std::size_t operator()(const mojo::edk::ports::NodeName& name) const {
- return base::HashInts64(name.v1, name.v2);
- }
-};
-
-} // namespace std
-
-#endif // MOJO_EDK_SYSTEM_PORTS_NAME_H_
diff --git a/mojo/edk/system/ports/node.cc b/mojo/edk/system/ports/node.cc
deleted file mode 100644
index f9a3feb..0000000
--- a/mojo/edk/system/ports/node.cc
+++ /dev/null
@@ -1,1385 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports/node.h"
-
-#include <string.h>
-
-#include <utility>
-
-#include "base/atomicops.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/system/ports/node_delegate.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-namespace {
-
-int DebugError(const char* message, int error_code) {
- CHECK(false) << "Oops: " << message;
- return error_code;
-}
-
-#define OOPS(x) DebugError(#x, x)
-
-bool CanAcceptMoreMessages(const Port* port) {
- // Have we already doled out the last message (i.e., do we expect to NOT
- // receive further messages)?
- uint64_t next_sequence_num = port->message_queue.next_sequence_num();
- if (port->state == Port::kClosed)
- return false;
- if (port->peer_closed || port->remove_proxy_on_last_message) {
- if (port->last_sequence_num_to_receive == next_sequence_num - 1)
- return false;
- }
- return true;
-}
-
-} // namespace
-
-class Node::LockedPort {
- public:
- explicit LockedPort(Port* port) : port_(port) {
- port_->lock.AssertAcquired();
- }
-
- Port* get() const { return port_; }
- Port* operator->() const { return port_; }
-
- private:
- Port* const port_;
-};
-
-Node::Node(const NodeName& name, NodeDelegate* delegate)
- : name_(name),
- delegate_(delegate) {
-}
-
-Node::~Node() {
- if (!ports_.empty())
- DLOG(WARNING) << "Unclean shutdown for node " << name_;
-}
-
-bool Node::CanShutdownCleanly(ShutdownPolicy policy) {
- base::AutoLock ports_lock(ports_lock_);
-
- if (policy == ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS) {
-#if DCHECK_IS_ON()
- for (auto entry : ports_) {
- DVLOG(2) << "Port " << entry.first << " referencing node "
- << entry.second->peer_node_name << " is blocking shutdown of "
- << "node " << name_ << " (state=" << entry.second->state << ")";
- }
-#endif
- return ports_.empty();
- }
-
- DCHECK_EQ(policy, ShutdownPolicy::ALLOW_LOCAL_PORTS);
-
- // NOTE: This is not efficient, though it probably doesn't need to be since
- // relatively few ports should be open during shutdown and shutdown doesn't
- // need to be blazingly fast.
- bool can_shutdown = true;
- for (auto entry : ports_) {
- base::AutoLock lock(entry.second->lock);
- if (entry.second->peer_node_name != name_ &&
- entry.second->state != Port::kReceiving) {
- can_shutdown = false;
-#if DCHECK_IS_ON()
- DVLOG(2) << "Port " << entry.first << " referencing node "
- << entry.second->peer_node_name << " is blocking shutdown of "
- << "node " << name_ << " (state=" << entry.second->state << ")";
-#else
- // Exit early when not debugging.
- break;
-#endif
- }
- }
-
- return can_shutdown;
-}
-
-int Node::GetPort(const PortName& port_name, PortRef* port_ref) {
- scoped_refptr<Port> port = GetPort(port_name);
- if (!port)
- return ERROR_PORT_UNKNOWN;
-
- *port_ref = PortRef(port_name, std::move(port));
- return OK;
-}
-
-int Node::CreateUninitializedPort(PortRef* port_ref) {
- PortName port_name;
- delegate_->GenerateRandomPortName(&port_name);
-
- scoped_refptr<Port> port(new Port(kInitialSequenceNum, kInitialSequenceNum));
- int rv = AddPortWithName(port_name, port);
- if (rv != OK)
- return rv;
-
- *port_ref = PortRef(port_name, std::move(port));
- return OK;
-}
-
-int Node::InitializePort(const PortRef& port_ref,
- const NodeName& peer_node_name,
- const PortName& peer_port_name) {
- Port* port = port_ref.port();
-
- {
- base::AutoLock lock(port->lock);
- if (port->state != Port::kUninitialized)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- port->state = Port::kReceiving;
- port->peer_node_name = peer_node_name;
- port->peer_port_name = peer_port_name;
- }
-
- delegate_->PortStatusChanged(port_ref);
-
- return OK;
-}
-
-int Node::CreatePortPair(PortRef* port0_ref, PortRef* port1_ref) {
- int rv;
-
- rv = CreateUninitializedPort(port0_ref);
- if (rv != OK)
- return rv;
-
- rv = CreateUninitializedPort(port1_ref);
- if (rv != OK)
- return rv;
-
- rv = InitializePort(*port0_ref, name_, port1_ref->name());
- if (rv != OK)
- return rv;
-
- rv = InitializePort(*port1_ref, name_, port0_ref->name());
- if (rv != OK)
- return rv;
-
- return OK;
-}
-
-int Node::SetUserData(const PortRef& port_ref,
- scoped_refptr<UserData> user_data) {
- Port* port = port_ref.port();
-
- base::AutoLock lock(port->lock);
- if (port->state == Port::kClosed)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- port->user_data = std::move(user_data);
-
- return OK;
-}
-
-int Node::GetUserData(const PortRef& port_ref,
- scoped_refptr<UserData>* user_data) {
- Port* port = port_ref.port();
-
- base::AutoLock lock(port->lock);
- if (port->state == Port::kClosed)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- *user_data = port->user_data;
-
- return OK;
-}
-
-int Node::ClosePort(const PortRef& port_ref) {
- std::deque<PortName> referenced_port_names;
-
- ObserveClosureEventData data;
-
- NodeName peer_node_name;
- PortName peer_port_name;
- Port* port = port_ref.port();
- {
- // We may need to erase the port, which requires ports_lock_ to be held,
- // but ports_lock_ must be acquired before any individual port locks.
- base::AutoLock ports_lock(ports_lock_);
-
- base::AutoLock lock(port->lock);
- if (port->state == Port::kUninitialized) {
- // If the port was not yet initialized, there's nothing interesting to do.
- ErasePort_Locked(port_ref.name());
- return OK;
- }
-
- if (port->state != Port::kReceiving)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- port->state = Port::kClosed;
-
- // We pass along the sequence number of the last message sent from this
- // port to allow the peer to have the opportunity to consume all inbound
- // messages before notifying the embedder that this port is closed.
- data.last_sequence_num = port->next_sequence_num_to_send - 1;
-
- peer_node_name = port->peer_node_name;
- peer_port_name = port->peer_port_name;
-
- // If the port being closed still has unread messages, then we need to take
- // care to close those ports so as to avoid leaking memory.
- port->message_queue.GetReferencedPorts(&referenced_port_names);
-
- ErasePort_Locked(port_ref.name());
- }
-
- DVLOG(2) << "Sending ObserveClosure from " << port_ref.name() << "@" << name_
- << " to " << peer_port_name << "@" << peer_node_name;
-
- delegate_->ForwardMessage(
- peer_node_name,
- NewInternalMessage(peer_port_name, EventType::kObserveClosure, data));
-
- for (const auto& name : referenced_port_names) {
- PortRef ref;
- if (GetPort(name, &ref) == OK)
- ClosePort(ref);
- }
- return OK;
-}
-
-int Node::GetStatus(const PortRef& port_ref, PortStatus* port_status) {
- Port* port = port_ref.port();
-
- base::AutoLock lock(port->lock);
-
- if (port->state != Port::kReceiving)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- port_status->has_messages = port->message_queue.HasNextMessage();
- port_status->receiving_messages = CanAcceptMoreMessages(port);
- port_status->peer_closed = port->peer_closed;
- return OK;
-}
-
-int Node::GetMessage(const PortRef& port_ref,
- ScopedMessage* message,
- MessageFilter* filter) {
- *message = nullptr;
-
- DVLOG(4) << "GetMessage for " << port_ref.name() << "@" << name_;
-
- Port* port = port_ref.port();
- {
- base::AutoLock lock(port->lock);
-
- // This could also be treated like the port being unknown since the
- // embedder should no longer be referring to a port that has been sent.
- if (port->state != Port::kReceiving)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- // Let the embedder get messages until there are no more before reporting
- // that the peer closed its end.
- if (!CanAcceptMoreMessages(port))
- return ERROR_PORT_PEER_CLOSED;
-
- port->message_queue.GetNextMessage(message, filter);
- }
-
- // Allow referenced ports to trigger PortStatusChanged calls.
- if (*message) {
- for (size_t i = 0; i < (*message)->num_ports(); ++i) {
- const PortName& new_port_name = (*message)->ports()[i];
- scoped_refptr<Port> new_port = GetPort(new_port_name);
-
- DCHECK(new_port) << "Port " << new_port_name << "@" << name_
- << " does not exist!";
-
- base::AutoLock lock(new_port->lock);
-
- DCHECK(new_port->state == Port::kReceiving);
- new_port->message_queue.set_signalable(true);
- }
- }
-
- return OK;
-}
-
-int Node::SendMessage(const PortRef& port_ref, ScopedMessage message) {
- int rv = SendMessageInternal(port_ref, &message);
- if (rv != OK) {
- // If send failed, close all carried ports. Note that we're careful not to
- // close the sending port itself if it happened to be one of the encoded
- // ports (an invalid but possible condition.)
- for (size_t i = 0; i < message->num_ports(); ++i) {
- if (message->ports()[i] == port_ref.name())
- continue;
-
- PortRef port;
- if (GetPort(message->ports()[i], &port) == OK)
- ClosePort(port);
- }
- }
- return rv;
-}
-
-int Node::AcceptMessage(ScopedMessage message) {
- const EventHeader* header = GetEventHeader(*message);
- switch (header->type) {
- case EventType::kUser:
- return OnUserMessage(std::move(message));
- case EventType::kPortAccepted:
- return OnPortAccepted(header->port_name);
- case EventType::kObserveProxy:
- return OnObserveProxy(
- header->port_name,
- *GetEventData<ObserveProxyEventData>(*message));
- case EventType::kObserveProxyAck:
- return OnObserveProxyAck(
- header->port_name,
- GetEventData<ObserveProxyAckEventData>(*message)->last_sequence_num);
- case EventType::kObserveClosure:
- return OnObserveClosure(
- header->port_name,
- GetEventData<ObserveClosureEventData>(*message)->last_sequence_num);
- case EventType::kMergePort:
- return OnMergePort(header->port_name,
- *GetEventData<MergePortEventData>(*message));
- }
- return OOPS(ERROR_NOT_IMPLEMENTED);
-}
-
-int Node::MergePorts(const PortRef& port_ref,
- const NodeName& destination_node_name,
- const PortName& destination_port_name) {
- Port* port = port_ref.port();
- MergePortEventData data;
- {
- base::AutoLock lock(port->lock);
-
- DVLOG(1) << "Sending MergePort from " << port_ref.name() << "@" << name_
- << " to " << destination_port_name << "@" << destination_node_name;
-
- // Send the port-to-merge over to the destination node so it can be merged
- // into the port cycle atomically there.
- data.new_port_name = port_ref.name();
- WillSendPort(LockedPort(port), destination_node_name, &data.new_port_name,
- &data.new_port_descriptor);
- }
- delegate_->ForwardMessage(
- destination_node_name,
- NewInternalMessage(destination_port_name,
- EventType::kMergePort, data));
- return OK;
-}
-
-int Node::MergeLocalPorts(const PortRef& port0_ref, const PortRef& port1_ref) {
- Port* port0 = port0_ref.port();
- Port* port1 = port1_ref.port();
- int rv;
- {
- // |ports_lock_| must be held when acquiring overlapping port locks.
- base::AutoLock ports_lock(ports_lock_);
- base::AutoLock port0_lock(port0->lock);
- base::AutoLock port1_lock(port1->lock);
-
- DVLOG(1) << "Merging local ports " << port0_ref.name() << "@" << name_
- << " and " << port1_ref.name() << "@" << name_;
-
- if (port0->state != Port::kReceiving || port1->state != Port::kReceiving)
- rv = ERROR_PORT_STATE_UNEXPECTED;
- else
- rv = MergePorts_Locked(port0_ref, port1_ref);
- }
-
- if (rv != OK) {
- ClosePort(port0_ref);
- ClosePort(port1_ref);
- }
-
- return rv;
-}
-
-int Node::LostConnectionToNode(const NodeName& node_name) {
- // We can no longer send events to the given node. We also can't expect any
- // PortAccepted events.
-
- DVLOG(1) << "Observing lost connection from node " << name_
- << " to node " << node_name;
-
- DestroyAllPortsWithPeer(node_name, kInvalidPortName);
- return OK;
-}
-
-int Node::OnUserMessage(ScopedMessage message) {
- PortName port_name = GetEventHeader(*message)->port_name;
- const auto* event = GetEventData<UserEventData>(*message);
-
-#if DCHECK_IS_ON()
- std::ostringstream ports_buf;
- for (size_t i = 0; i < message->num_ports(); ++i) {
- if (i > 0)
- ports_buf << ",";
- ports_buf << message->ports()[i];
- }
-
- DVLOG(4) << "AcceptMessage " << event->sequence_num
- << " [ports=" << ports_buf.str() << "] at "
- << port_name << "@" << name_;
-#endif
-
- scoped_refptr<Port> port = GetPort(port_name);
-
- // Even if this port does not exist, cannot receive anymore messages or is
- // buffering or proxying messages, we still need these ports to be bound to
- // this node. When the message is forwarded, these ports will get transferred
- // following the usual method. If the message cannot be accepted, then the
- // newly bound ports will simply be closed.
-
- for (size_t i = 0; i < message->num_ports(); ++i) {
- int rv = AcceptPort(message->ports()[i], GetPortDescriptors(event)[i]);
- if (rv != OK)
- return rv;
- }
-
- bool has_next_message = false;
- bool message_accepted = false;
-
- if (port) {
- // We may want to forward messages once the port lock is held, so we must
- // acquire |ports_lock_| first.
- base::AutoLock ports_lock(ports_lock_);
- base::AutoLock lock(port->lock);
-
- // Reject spurious messages if we've already received the last expected
- // message.
- if (CanAcceptMoreMessages(port.get())) {
- message_accepted = true;
- port->message_queue.AcceptMessage(std::move(message), &has_next_message);
-
- if (port->state == Port::kBuffering) {
- has_next_message = false;
- } else if (port->state == Port::kProxying) {
- has_next_message = false;
-
- // Forward messages. We forward messages in sequential order here so
- // that we maintain the message queue's notion of next sequence number.
- // That's useful for the proxy removal process as we can tell when this
- // port has seen all of the messages it is expected to see.
- int rv = ForwardMessages_Locked(LockedPort(port.get()), port_name);
- if (rv != OK)
- return rv;
-
- MaybeRemoveProxy_Locked(LockedPort(port.get()), port_name);
- }
- }
- }
-
- if (!message_accepted) {
- DVLOG(2) << "Message not accepted!\n";
- // Close all newly accepted ports as they are effectively orphaned.
- for (size_t i = 0; i < message->num_ports(); ++i) {
- PortRef port_ref;
- if (GetPort(message->ports()[i], &port_ref) == OK) {
- ClosePort(port_ref);
- } else {
- DLOG(WARNING) << "Cannot close non-existent port!\n";
- }
- }
- } else if (has_next_message) {
- PortRef port_ref(port_name, port);
- delegate_->PortStatusChanged(port_ref);
- }
-
- return OK;
-}
-
-int Node::OnPortAccepted(const PortName& port_name) {
- scoped_refptr<Port> port = GetPort(port_name);
- if (!port)
- return ERROR_PORT_UNKNOWN;
-
- DVLOG(2) << "PortAccepted at " << port_name << "@" << name_
- << " pointing to "
- << port->peer_port_name << "@" << port->peer_node_name;
-
- return BeginProxying(PortRef(port_name, std::move(port)));
-}
-
-int Node::OnObserveProxy(const PortName& port_name,
- const ObserveProxyEventData& event) {
- if (port_name == kInvalidPortName) {
- // An ObserveProxy with an invalid target port name is a broadcast used to
- // inform ports when their peer (which was itself a proxy) has become
- // defunct due to unexpected node disconnection.
- //
- // Receiving ports affected by this treat it as equivalent to peer closure.
- // Proxies affected by this can be removed and will in turn broadcast their
- // own death with a similar message.
- CHECK_EQ(event.proxy_to_node_name, kInvalidNodeName);
- CHECK_EQ(event.proxy_to_port_name, kInvalidPortName);
- DestroyAllPortsWithPeer(event.proxy_node_name, event.proxy_port_name);
- return OK;
- }
-
- // The port may have already been closed locally, in which case the
- // ObserveClosure message will contain the last_sequence_num field.
- // We can then silently ignore this message.
- scoped_refptr<Port> port = GetPort(port_name);
- if (!port) {
- DVLOG(1) << "ObserveProxy: " << port_name << "@" << name_ << " not found";
- return OK;
- }
-
- DVLOG(2) << "ObserveProxy at " << port_name << "@" << name_ << ", proxy at "
- << event.proxy_port_name << "@"
- << event.proxy_node_name << " pointing to "
- << event.proxy_to_port_name << "@"
- << event.proxy_to_node_name;
-
- {
- base::AutoLock lock(port->lock);
-
- if (port->peer_node_name == event.proxy_node_name &&
- port->peer_port_name == event.proxy_port_name) {
- if (port->state == Port::kReceiving) {
- port->peer_node_name = event.proxy_to_node_name;
- port->peer_port_name = event.proxy_to_port_name;
-
- ObserveProxyAckEventData ack;
- ack.last_sequence_num = port->next_sequence_num_to_send - 1;
-
- delegate_->ForwardMessage(
- event.proxy_node_name,
- NewInternalMessage(event.proxy_port_name,
- EventType::kObserveProxyAck,
- ack));
- } else {
- // As a proxy ourselves, we don't know how to honor the ObserveProxy
- // event or to populate the last_sequence_num field of ObserveProxyAck.
- // Afterall, another port could be sending messages to our peer now
- // that we've sent out our own ObserveProxy event. Instead, we will
- // send an ObserveProxyAck indicating that the ObserveProxy event
- // should be re-sent (last_sequence_num set to kInvalidSequenceNum).
- // However, this has to be done after we are removed as a proxy.
- // Otherwise, we might just find ourselves back here again, which
- // would be akin to a busy loop.
-
- DVLOG(2) << "Delaying ObserveProxyAck to "
- << event.proxy_port_name << "@" << event.proxy_node_name;
-
- ObserveProxyAckEventData ack;
- ack.last_sequence_num = kInvalidSequenceNum;
-
- port->send_on_proxy_removal.reset(
- new std::pair<NodeName, ScopedMessage>(
- event.proxy_node_name,
- NewInternalMessage(event.proxy_port_name,
- EventType::kObserveProxyAck,
- ack)));
- }
- } else {
- // Forward this event along to our peer. Eventually, it should find the
- // port referring to the proxy.
- delegate_->ForwardMessage(
- port->peer_node_name,
- NewInternalMessage(port->peer_port_name,
- EventType::kObserveProxy,
- event));
- }
- }
- return OK;
-}
-
-int Node::OnObserveProxyAck(const PortName& port_name,
- uint64_t last_sequence_num) {
- DVLOG(2) << "ObserveProxyAck at " << port_name << "@" << name_
- << " (last_sequence_num=" << last_sequence_num << ")";
-
- scoped_refptr<Port> port = GetPort(port_name);
- if (!port)
- return ERROR_PORT_UNKNOWN; // The port may have observed closure first, so
- // this is not an "Oops".
-
- {
- base::AutoLock lock(port->lock);
-
- if (port->state != Port::kProxying)
- return OOPS(ERROR_PORT_STATE_UNEXPECTED);
-
- if (last_sequence_num == kInvalidSequenceNum) {
- // Send again.
- InitiateProxyRemoval(LockedPort(port.get()), port_name);
- return OK;
- }
-
- // We can now remove this port once we have received and forwarded the last
- // message addressed to this port.
- port->remove_proxy_on_last_message = true;
- port->last_sequence_num_to_receive = last_sequence_num;
- }
- TryRemoveProxy(PortRef(port_name, std::move(port)));
- return OK;
-}
-
-int Node::OnObserveClosure(const PortName& port_name,
- uint64_t last_sequence_num) {
- // OK if the port doesn't exist, as it may have been closed already.
- scoped_refptr<Port> port = GetPort(port_name);
- if (!port)
- return OK;
-
- // This message tells the port that it should no longer expect more messages
- // beyond last_sequence_num. This message is forwarded along until we reach
- // the receiving end, and this message serves as an equivalent to
- // ObserveProxyAck.
-
- bool notify_delegate = false;
- ObserveClosureEventData forwarded_data;
- NodeName peer_node_name;
- PortName peer_port_name;
- bool try_remove_proxy = false;
- {
- base::AutoLock lock(port->lock);
-
- port->peer_closed = true;
- port->last_sequence_num_to_receive = last_sequence_num;
-
- DVLOG(2) << "ObserveClosure at " << port_name << "@" << name_
- << " (state=" << port->state << ") pointing to "
- << port->peer_port_name << "@" << port->peer_node_name
- << " (last_sequence_num=" << last_sequence_num << ")";
-
- // We always forward ObserveClosure, even beyond the receiving port which
- // cares about it. This ensures that any dead-end proxies beyond that port
- // are notified to remove themselves.
-
- if (port->state == Port::kReceiving) {
- notify_delegate = true;
-
- // When forwarding along the other half of the port cycle, this will only
- // reach dead-end proxies. Tell them we've sent our last message so they
- // can go away.
- //
- // TODO: Repurposing ObserveClosure for this has the desired result but
- // may be semantically confusing since the forwarding port is not actually
- // closed. Consider replacing this with a new event type.
- forwarded_data.last_sequence_num = port->next_sequence_num_to_send - 1;
- } else {
- // We haven't yet reached the receiving peer of the closed port, so
- // forward the message along as-is.
- forwarded_data.last_sequence_num = last_sequence_num;
-
- // See about removing the port if it is a proxy as our peer won't be able
- // to participate in proxy removal.
- port->remove_proxy_on_last_message = true;
- if (port->state == Port::kProxying)
- try_remove_proxy = true;
- }
-
- DVLOG(2) << "Forwarding ObserveClosure from "
- << port_name << "@" << name_ << " to peer "
- << port->peer_port_name << "@" << port->peer_node_name
- << " (last_sequence_num=" << forwarded_data.last_sequence_num
- << ")";
-
- peer_node_name = port->peer_node_name;
- peer_port_name = port->peer_port_name;
- }
- if (try_remove_proxy)
- TryRemoveProxy(PortRef(port_name, port));
-
- delegate_->ForwardMessage(
- peer_node_name,
- NewInternalMessage(peer_port_name, EventType::kObserveClosure,
- forwarded_data));
-
- if (notify_delegate) {
- PortRef port_ref(port_name, std::move(port));
- delegate_->PortStatusChanged(port_ref);
- }
- return OK;
-}
-
-int Node::OnMergePort(const PortName& port_name,
- const MergePortEventData& event) {
- scoped_refptr<Port> port = GetPort(port_name);
-
- DVLOG(1) << "MergePort at " << port_name << "@" << name_ << " (state="
- << (port ? port->state : -1) << ") merging with proxy "
- << event.new_port_name
- << "@" << name_ << " pointing to "
- << event.new_port_descriptor.peer_port_name << "@"
- << event.new_port_descriptor.peer_node_name << " referred by "
- << event.new_port_descriptor.referring_port_name << "@"
- << event.new_port_descriptor.referring_node_name;
-
- bool close_target_port = false;
- bool close_new_port = false;
-
- // Accept the new port. This is now the receiving end of the other port cycle
- // to be merged with ours.
- int rv = AcceptPort(event.new_port_name, event.new_port_descriptor);
- if (rv != OK) {
- close_target_port = true;
- } else if (port) {
- // BeginProxying_Locked may call MaybeRemoveProxy_Locked, which in turn
- // needs to hold |ports_lock_|. We also acquire multiple port locks within.
- base::AutoLock ports_lock(ports_lock_);
- base::AutoLock lock(port->lock);
-
- if (port->state != Port::kReceiving) {
- close_new_port = true;
- } else {
- scoped_refptr<Port> new_port = GetPort_Locked(event.new_port_name);
- base::AutoLock new_port_lock(new_port->lock);
- DCHECK(new_port->state == Port::kReceiving);
-
- // Both ports are locked. Now all we have to do is swap their peer
- // information and set them up as proxies.
-
- PortRef port0_ref(port_name, port);
- PortRef port1_ref(event.new_port_name, new_port);
- int rv = MergePorts_Locked(port0_ref, port1_ref);
- if (rv == OK)
- return rv;
-
- close_new_port = true;
- close_target_port = true;
- }
- } else {
- close_new_port = true;
- }
-
- if (close_target_port) {
- PortRef target_port;
- rv = GetPort(port_name, &target_port);
- DCHECK(rv == OK);
-
- ClosePort(target_port);
- }
-
- if (close_new_port) {
- PortRef new_port;
- rv = GetPort(event.new_port_name, &new_port);
- DCHECK(rv == OK);
-
- ClosePort(new_port);
- }
-
- return ERROR_PORT_STATE_UNEXPECTED;
-}
-
-int Node::AddPortWithName(const PortName& port_name, scoped_refptr<Port> port) {
- base::AutoLock lock(ports_lock_);
-
- if (!ports_.insert(std::make_pair(port_name, std::move(port))).second)
- return OOPS(ERROR_PORT_EXISTS); // Suggests a bad UUID generator.
-
- DVLOG(2) << "Created port " << port_name << "@" << name_;
- return OK;
-}
-
-void Node::ErasePort(const PortName& port_name) {
- base::AutoLock lock(ports_lock_);
- ErasePort_Locked(port_name);
-}
-
-void Node::ErasePort_Locked(const PortName& port_name) {
- ports_lock_.AssertAcquired();
- ports_.erase(port_name);
- DVLOG(2) << "Deleted port " << port_name << "@" << name_;
-}
-
-scoped_refptr<Port> Node::GetPort(const PortName& port_name) {
- base::AutoLock lock(ports_lock_);
- return GetPort_Locked(port_name);
-}
-
-scoped_refptr<Port> Node::GetPort_Locked(const PortName& port_name) {
- ports_lock_.AssertAcquired();
- auto iter = ports_.find(port_name);
- if (iter == ports_.end())
- return nullptr;
-
-#if (defined(OS_ANDROID) || defined(__ANDROID__)) && defined(ARCH_CPU_ARM64)
- // Workaround for https://crbug.com/665869.
- base::subtle::MemoryBarrier();
-#endif
-
- return iter->second;
-}
-
-int Node::SendMessageInternal(const PortRef& port_ref, ScopedMessage* message) {
- ScopedMessage& m = *message;
- for (size_t i = 0; i < m->num_ports(); ++i) {
- if (m->ports()[i] == port_ref.name())
- return ERROR_PORT_CANNOT_SEND_SELF;
- }
-
- Port* port = port_ref.port();
- NodeName peer_node_name;
- {
- // We must acquire |ports_lock_| before grabbing any port locks, because
- // WillSendMessage_Locked may need to lock multiple ports out of order.
- base::AutoLock ports_lock(ports_lock_);
- base::AutoLock lock(port->lock);
-
- if (port->state != Port::kReceiving)
- return ERROR_PORT_STATE_UNEXPECTED;
-
- if (port->peer_closed)
- return ERROR_PORT_PEER_CLOSED;
-
- int rv = WillSendMessage_Locked(LockedPort(port), port_ref.name(), m.get());
- if (rv != OK)
- return rv;
-
- // Beyond this point there's no sense in returning anything but OK. Even if
- // message forwarding or acceptance fails, there's nothing the embedder can
- // do to recover. Assume that failure beyond this point must be treated as a
- // transport failure.
-
- peer_node_name = port->peer_node_name;
- }
-
- if (peer_node_name != name_) {
- delegate_->ForwardMessage(peer_node_name, std::move(m));
- return OK;
- }
-
- int rv = AcceptMessage(std::move(m));
- if (rv != OK) {
- // See comment above for why we don't return an error in this case.
- DVLOG(2) << "AcceptMessage failed: " << rv;
- }
-
- return OK;
-}
-
-int Node::MergePorts_Locked(const PortRef& port0_ref,
- const PortRef& port1_ref) {
- Port* port0 = port0_ref.port();
- Port* port1 = port1_ref.port();
-
- ports_lock_.AssertAcquired();
- port0->lock.AssertAcquired();
- port1->lock.AssertAcquired();
-
- CHECK(port0->state == Port::kReceiving);
- CHECK(port1->state == Port::kReceiving);
-
- // Ports cannot be merged with their own receiving peer!
- if (port0->peer_node_name == name_ &&
- port0->peer_port_name == port1_ref.name())
- return ERROR_PORT_STATE_UNEXPECTED;
-
- if (port1->peer_node_name == name_ &&
- port1->peer_port_name == port0_ref.name())
- return ERROR_PORT_STATE_UNEXPECTED;
-
- // Only merge if both ports have never sent a message.
- if (port0->next_sequence_num_to_send == kInitialSequenceNum &&
- port1->next_sequence_num_to_send == kInitialSequenceNum) {
- // Swap the ports' peer information and switch them both into buffering
- // (eventually proxying) mode.
-
- std::swap(port0->peer_node_name, port1->peer_node_name);
- std::swap(port0->peer_port_name, port1->peer_port_name);
-
- port0->state = Port::kBuffering;
- if (port0->peer_closed)
- port0->remove_proxy_on_last_message = true;
-
- port1->state = Port::kBuffering;
- if (port1->peer_closed)
- port1->remove_proxy_on_last_message = true;
-
- int rv1 = BeginProxying_Locked(LockedPort(port0), port0_ref.name());
- int rv2 = BeginProxying_Locked(LockedPort(port1), port1_ref.name());
-
- if (rv1 == OK && rv2 == OK) {
- // If either merged port had a closed peer, its new peer needs to be
- // informed of this.
- if (port1->peer_closed) {
- ObserveClosureEventData data;
- data.last_sequence_num = port0->last_sequence_num_to_receive;
- delegate_->ForwardMessage(
- port0->peer_node_name,
- NewInternalMessage(port0->peer_port_name,
- EventType::kObserveClosure, data));
- }
-
- if (port0->peer_closed) {
- ObserveClosureEventData data;
- data.last_sequence_num = port1->last_sequence_num_to_receive;
- delegate_->ForwardMessage(
- port1->peer_node_name,
- NewInternalMessage(port1->peer_port_name,
- EventType::kObserveClosure, data));
- }
-
- return OK;
- }
-
- // If either proxy failed to initialize (e.g. had undeliverable messages
- // or ended up in a bad state somehow), we keep the system in a consistent
- // state by undoing the peer swap.
- std::swap(port0->peer_node_name, port1->peer_node_name);
- std::swap(port0->peer_port_name, port1->peer_port_name);
- port0->remove_proxy_on_last_message = false;
- port1->remove_proxy_on_last_message = false;
- port0->state = Port::kReceiving;
- port1->state = Port::kReceiving;
- }
-
- return ERROR_PORT_STATE_UNEXPECTED;
-}
-
-void Node::WillSendPort(const LockedPort& port,
- const NodeName& to_node_name,
- PortName* port_name,
- PortDescriptor* port_descriptor) {
- port->lock.AssertAcquired();
-
- PortName local_port_name = *port_name;
-
- PortName new_port_name;
- delegate_->GenerateRandomPortName(&new_port_name);
-
- // Make sure we don't send messages to the new peer until after we know it
- // exists. In the meantime, just buffer messages locally.
- DCHECK(port->state == Port::kReceiving);
- port->state = Port::kBuffering;
-
- // If we already know our peer is closed, we already know this proxy can
- // be removed once it receives and forwards its last expected message.
- if (port->peer_closed)
- port->remove_proxy_on_last_message = true;
-
- *port_name = new_port_name;
-
- port_descriptor->peer_node_name = port->peer_node_name;
- port_descriptor->peer_port_name = port->peer_port_name;
- port_descriptor->referring_node_name = name_;
- port_descriptor->referring_port_name = local_port_name;
- port_descriptor->next_sequence_num_to_send = port->next_sequence_num_to_send;
- port_descriptor->next_sequence_num_to_receive =
- port->message_queue.next_sequence_num();
- port_descriptor->last_sequence_num_to_receive =
- port->last_sequence_num_to_receive;
- port_descriptor->peer_closed = port->peer_closed;
- memset(port_descriptor->padding, 0, sizeof(port_descriptor->padding));
-
- // Configure the local port to point to the new port.
- port->peer_node_name = to_node_name;
- port->peer_port_name = new_port_name;
-}
-
-int Node::AcceptPort(const PortName& port_name,
- const PortDescriptor& port_descriptor) {
- scoped_refptr<Port> port = make_scoped_refptr(
- new Port(port_descriptor.next_sequence_num_to_send,
- port_descriptor.next_sequence_num_to_receive));
- port->state = Port::kReceiving;
- port->peer_node_name = port_descriptor.peer_node_name;
- port->peer_port_name = port_descriptor.peer_port_name;
- port->last_sequence_num_to_receive =
- port_descriptor.last_sequence_num_to_receive;
- port->peer_closed = port_descriptor.peer_closed;
-
- DVLOG(2) << "Accepting port " << port_name << " [peer_closed="
- << port->peer_closed << "; last_sequence_num_to_receive="
- << port->last_sequence_num_to_receive << "]";
-
- // A newly accepted port is not signalable until the message referencing the
- // new port finds its way to the consumer (see GetMessage).
- port->message_queue.set_signalable(false);
-
- int rv = AddPortWithName(port_name, std::move(port));
- if (rv != OK)
- return rv;
-
- // Allow referring port to forward messages.
- delegate_->ForwardMessage(
- port_descriptor.referring_node_name,
- NewInternalMessage(port_descriptor.referring_port_name,
- EventType::kPortAccepted));
- return OK;
-}
-
-int Node::WillSendMessage_Locked(const LockedPort& port,
- const PortName& port_name,
- Message* message) {
- ports_lock_.AssertAcquired();
- port->lock.AssertAcquired();
-
- DCHECK(message);
-
- // Messages may already have a sequence number if they're being forwarded
- // by a proxy. Otherwise, use the next outgoing sequence number.
- uint64_t* sequence_num =
- &GetMutableEventData<UserEventData>(message)->sequence_num;
- if (*sequence_num == 0)
- *sequence_num = port->next_sequence_num_to_send++;
-
-#if DCHECK_IS_ON()
- std::ostringstream ports_buf;
- for (size_t i = 0; i < message->num_ports(); ++i) {
- if (i > 0)
- ports_buf << ",";
- ports_buf << message->ports()[i];
- }
-#endif
-
- if (message->num_ports() > 0) {
- // Note: Another thread could be trying to send the same ports, so we need
- // to ensure that they are ours to send before we mutate their state.
-
- std::vector<scoped_refptr<Port>> ports;
- ports.resize(message->num_ports());
-
- {
- for (size_t i = 0; i < message->num_ports(); ++i) {
- ports[i] = GetPort_Locked(message->ports()[i]);
- DCHECK(ports[i]);
-
- ports[i]->lock.Acquire();
- int error = OK;
- if (ports[i]->state != Port::kReceiving)
- error = ERROR_PORT_STATE_UNEXPECTED;
- else if (message->ports()[i] == port->peer_port_name)
- error = ERROR_PORT_CANNOT_SEND_PEER;
-
- if (error != OK) {
- // Oops, we cannot send this port.
- for (size_t j = 0; j <= i; ++j)
- ports[i]->lock.Release();
- // Backpedal on the sequence number.
- port->next_sequence_num_to_send--;
- return error;
- }
- }
- }
-
- PortDescriptor* port_descriptors =
- GetMutablePortDescriptors(GetMutableEventData<UserEventData>(message));
-
- for (size_t i = 0; i < message->num_ports(); ++i) {
- WillSendPort(LockedPort(ports[i].get()),
- port->peer_node_name,
- message->mutable_ports() + i,
- port_descriptors + i);
- }
-
- for (size_t i = 0; i < message->num_ports(); ++i)
- ports[i]->lock.Release();
- }
-
-#if DCHECK_IS_ON()
- DVLOG(4) << "Sending message "
- << GetEventData<UserEventData>(*message)->sequence_num
- << " [ports=" << ports_buf.str() << "]"
- << " from " << port_name << "@" << name_
- << " to " << port->peer_port_name << "@" << port->peer_node_name;
-#endif
-
- GetMutableEventHeader(message)->port_name = port->peer_port_name;
- return OK;
-}
-
-int Node::BeginProxying_Locked(const LockedPort& port,
- const PortName& port_name) {
- ports_lock_.AssertAcquired();
- port->lock.AssertAcquired();
-
- if (port->state != Port::kBuffering)
- return OOPS(ERROR_PORT_STATE_UNEXPECTED);
-
- port->state = Port::kProxying;
-
- int rv = ForwardMessages_Locked(LockedPort(port), port_name);
- if (rv != OK)
- return rv;
-
- // We may have observed closure while buffering. In that case, we can advance
- // to removing the proxy without sending out an ObserveProxy message. We
- // already know the last expected message, etc.
-
- if (port->remove_proxy_on_last_message) {
- MaybeRemoveProxy_Locked(LockedPort(port), port_name);
-
- // Make sure we propagate closure to our current peer.
- ObserveClosureEventData data;
- data.last_sequence_num = port->last_sequence_num_to_receive;
- delegate_->ForwardMessage(
- port->peer_node_name,
- NewInternalMessage(port->peer_port_name,
- EventType::kObserveClosure, data));
- } else {
- InitiateProxyRemoval(LockedPort(port), port_name);
- }
-
- return OK;
-}
-
-int Node::BeginProxying(PortRef port_ref) {
- Port* port = port_ref.port();
- {
- base::AutoLock ports_lock(ports_lock_);
- base::AutoLock lock(port->lock);
-
- if (port->state != Port::kBuffering)
- return OOPS(ERROR_PORT_STATE_UNEXPECTED);
-
- port->state = Port::kProxying;
-
- int rv = ForwardMessages_Locked(LockedPort(port), port_ref.name());
- if (rv != OK)
- return rv;
- }
-
- bool should_remove;
- NodeName peer_node_name;
- ScopedMessage closure_message;
- {
- base::AutoLock lock(port->lock);
- if (port->state != Port::kProxying)
- return OOPS(ERROR_PORT_STATE_UNEXPECTED);
-
- should_remove = port->remove_proxy_on_last_message;
- if (should_remove) {
- // Make sure we propagate closure to our current peer.
- ObserveClosureEventData data;
- data.last_sequence_num = port->last_sequence_num_to_receive;
- peer_node_name = port->peer_node_name;
- closure_message = NewInternalMessage(port->peer_port_name,
- EventType::kObserveClosure, data);
- } else {
- InitiateProxyRemoval(LockedPort(port), port_ref.name());
- }
- }
-
- if (should_remove) {
- TryRemoveProxy(port_ref);
- delegate_->ForwardMessage(peer_node_name, std::move(closure_message));
- }
-
- return OK;
-}
-
-int Node::ForwardMessages_Locked(const LockedPort& port,
- const PortName &port_name) {
- ports_lock_.AssertAcquired();
- port->lock.AssertAcquired();
-
- for (;;) {
- ScopedMessage message;
- port->message_queue.GetNextMessage(&message, nullptr);
- if (!message)
- break;
-
- int rv = WillSendMessage_Locked(LockedPort(port), port_name, message.get());
- if (rv != OK)
- return rv;
-
- delegate_->ForwardMessage(port->peer_node_name, std::move(message));
- }
- return OK;
-}
-
-void Node::InitiateProxyRemoval(const LockedPort& port,
- const PortName& port_name) {
- port->lock.AssertAcquired();
-
- // To remove this node, we start by notifying the connected graph that we are
- // a proxy. This allows whatever port is referencing this node to skip it.
- // Eventually, this node will receive ObserveProxyAck (or ObserveClosure if
- // the peer was closed in the meantime).
-
- ObserveProxyEventData data;
- data.proxy_node_name = name_;
- data.proxy_port_name = port_name;
- data.proxy_to_node_name = port->peer_node_name;
- data.proxy_to_port_name = port->peer_port_name;
-
- delegate_->ForwardMessage(
- port->peer_node_name,
- NewInternalMessage(port->peer_port_name, EventType::kObserveProxy, data));
-}
-
-void Node::MaybeRemoveProxy_Locked(const LockedPort& port,
- const PortName& port_name) {
- // |ports_lock_| must be held so we can potentilaly ErasePort_Locked().
- ports_lock_.AssertAcquired();
- port->lock.AssertAcquired();
-
- DCHECK(port->state == Port::kProxying);
-
- // Make sure we have seen ObserveProxyAck before removing the port.
- if (!port->remove_proxy_on_last_message)
- return;
-
- if (!CanAcceptMoreMessages(port.get())) {
- // This proxy port is done. We can now remove it!
- ErasePort_Locked(port_name);
-
- if (port->send_on_proxy_removal) {
- NodeName to_node = port->send_on_proxy_removal->first;
- ScopedMessage& message = port->send_on_proxy_removal->second;
-
- delegate_->ForwardMessage(to_node, std::move(message));
- port->send_on_proxy_removal.reset();
- }
- } else {
- DVLOG(2) << "Cannot remove port " << port_name << "@" << name_
- << " now; waiting for more messages";
- }
-}
-
-void Node::TryRemoveProxy(PortRef port_ref) {
- Port* port = port_ref.port();
- bool should_erase = false;
- ScopedMessage msg;
- NodeName to_node;
- {
- base::AutoLock lock(port->lock);
-
- // Port already removed. Nothing to do.
- if (port->state == Port::kClosed)
- return;
-
- DCHECK(port->state == Port::kProxying);
-
- // Make sure we have seen ObserveProxyAck before removing the port.
- if (!port->remove_proxy_on_last_message)
- return;
-
- if (!CanAcceptMoreMessages(port)) {
- // This proxy port is done. We can now remove it!
- should_erase = true;
-
- if (port->send_on_proxy_removal) {
- to_node = port->send_on_proxy_removal->first;
- msg = std::move(port->send_on_proxy_removal->second);
- port->send_on_proxy_removal.reset();
- }
- } else {
- DVLOG(2) << "Cannot remove port " << port_ref.name() << "@" << name_
- << " now; waiting for more messages";
- }
- }
-
- if (should_erase)
- ErasePort(port_ref.name());
-
- if (msg)
- delegate_->ForwardMessage(to_node, std::move(msg));
-}
-
-void Node::DestroyAllPortsWithPeer(const NodeName& node_name,
- const PortName& port_name) {
- // Wipes out all ports whose peer node matches |node_name| and whose peer port
- // matches |port_name|. If |port_name| is |kInvalidPortName|, only the peer
- // node is matched.
-
- std::vector<PortRef> ports_to_notify;
- std::vector<PortName> dead_proxies_to_broadcast;
- std::deque<PortName> referenced_port_names;
-
- {
- base::AutoLock ports_lock(ports_lock_);
-
- for (auto iter = ports_.begin(); iter != ports_.end(); ++iter) {
- Port* port = iter->second.get();
- {
- base::AutoLock port_lock(port->lock);
-
- if (port->peer_node_name == node_name &&
- (port_name == kInvalidPortName ||
- port->peer_port_name == port_name)) {
- if (!port->peer_closed) {
- // Treat this as immediate peer closure. It's an exceptional
- // condition akin to a broken pipe, so we don't care about losing
- // messages.
-
- port->peer_closed = true;
- port->last_sequence_num_to_receive =
- port->message_queue.next_sequence_num() - 1;
-
- if (port->state == Port::kReceiving)
- ports_to_notify.push_back(PortRef(iter->first, port));
- }
-
- // We don't expect to forward any further messages, and we don't
- // expect to receive a Port{Accepted,Rejected} event. Because we're
- // a proxy with no active peer, we cannot use the normal proxy removal
- // procedure of forward-propagating an ObserveProxy. Instead we
- // broadcast our own death so it can be back-propagated. This is
- // inefficient but rare.
- if (port->state != Port::kReceiving) {
- dead_proxies_to_broadcast.push_back(iter->first);
- iter->second->message_queue.GetReferencedPorts(
- &referenced_port_names);
- }
- }
- }
- }
-
- for (const auto& proxy_name : dead_proxies_to_broadcast) {
- ports_.erase(proxy_name);
- DVLOG(2) << "Forcibly deleted port " << proxy_name << "@" << name_;
- }
- }
-
- // Wake up any receiving ports who have just observed simulated peer closure.
- for (const auto& port : ports_to_notify)
- delegate_->PortStatusChanged(port);
-
- for (const auto& proxy_name : dead_proxies_to_broadcast) {
- // Broadcast an event signifying that this proxy is no longer functioning.
- ObserveProxyEventData event;
- event.proxy_node_name = name_;
- event.proxy_port_name = proxy_name;
- event.proxy_to_node_name = kInvalidNodeName;
- event.proxy_to_port_name = kInvalidPortName;
- delegate_->BroadcastMessage(NewInternalMessage(
- kInvalidPortName, EventType::kObserveProxy, event));
-
- // Also process death locally since the port that points this closed one
- // could be on the current node.
- // Note: Although this is recursive, only a single port is involved which
- // limits the expected branching to 1.
- DestroyAllPortsWithPeer(name_, proxy_name);
- }
-
- // Close any ports referenced by the closed proxies.
- for (const auto& name : referenced_port_names) {
- PortRef ref;
- if (GetPort(name, &ref) == OK)
- ClosePort(ref);
- }
-}
-
-ScopedMessage Node::NewInternalMessage_Helper(const PortName& port_name,
- const EventType& type,
- const void* data,
- size_t num_data_bytes) {
- ScopedMessage message;
- delegate_->AllocMessage(sizeof(EventHeader) + num_data_bytes, &message);
-
- EventHeader* header = GetMutableEventHeader(message.get());
- header->port_name = port_name;
- header->type = type;
- header->padding = 0;
-
- if (num_data_bytes)
- memcpy(header + 1, data, num_data_bytes);
-
- return message;
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/node.h b/mojo/edk/system/ports/node.h
deleted file mode 100644
index 55b8d27..0000000
--- a/mojo/edk/system/ports/node.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_NODE_H_
-#define MOJO_EDK_SYSTEM_PORTS_NODE_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <queue>
-#include <unordered_map>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/system/ports/event.h"
-#include "mojo/edk/system/ports/message.h"
-#include "mojo/edk/system/ports/name.h"
-#include "mojo/edk/system/ports/port.h"
-#include "mojo/edk/system/ports/port_ref.h"
-#include "mojo/edk/system/ports/user_data.h"
-
-#undef SendMessage // Gah, windows
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-enum : int {
- OK = 0,
- ERROR_PORT_UNKNOWN = -10,
- ERROR_PORT_EXISTS = -11,
- ERROR_PORT_STATE_UNEXPECTED = -12,
- ERROR_PORT_CANNOT_SEND_SELF = -13,
- ERROR_PORT_PEER_CLOSED = -14,
- ERROR_PORT_CANNOT_SEND_PEER = -15,
- ERROR_NOT_IMPLEMENTED = -100,
-};
-
-struct PortStatus {
- bool has_messages;
- bool receiving_messages;
- bool peer_closed;
-};
-
-class MessageFilter;
-class NodeDelegate;
-
-class Node {
- public:
- enum class ShutdownPolicy {
- DONT_ALLOW_LOCAL_PORTS,
- ALLOW_LOCAL_PORTS,
- };
-
- // Does not take ownership of the delegate.
- Node(const NodeName& name, NodeDelegate* delegate);
- ~Node();
-
- // Returns true iff there are no open ports referring to another node or ports
- // in the process of being transferred from this node to another. If this
- // returns false, then to ensure clean shutdown, it is necessary to keep the
- // node alive and continue routing messages to it via AcceptMessage. This
- // method may be called again after AcceptMessage to check if the Node is now
- // ready to be destroyed.
- //
- // If |policy| is set to |ShutdownPolicy::ALLOW_LOCAL_PORTS|, this will return
- // |true| even if some ports remain alive, as long as none of them are proxies
- // to another node.
- bool CanShutdownCleanly(
- ShutdownPolicy policy = ShutdownPolicy::DONT_ALLOW_LOCAL_PORTS);
-
- // Lookup the named port.
- int GetPort(const PortName& port_name, PortRef* port_ref);
-
- // Creates a port on this node. Before the port can be used, it must be
- // initialized using InitializePort. This method is useful for bootstrapping
- // a connection between two nodes. Generally, ports are created using
- // CreatePortPair instead.
- int CreateUninitializedPort(PortRef* port_ref);
-
- // Initializes a newly created port.
- int InitializePort(const PortRef& port_ref,
- const NodeName& peer_node_name,
- const PortName& peer_port_name);
-
- // Generates a new connected pair of ports bound to this node. These ports
- // are initialized and ready to go.
- int CreatePortPair(PortRef* port0_ref, PortRef* port1_ref);
-
- // User data associated with the port.
- int SetUserData(const PortRef& port_ref, scoped_refptr<UserData> user_data);
- int GetUserData(const PortRef& port_ref,
- scoped_refptr<UserData>* user_data);
-
- // Prevents further messages from being sent from this port or delivered to
- // this port. The port is removed, and the port's peer is notified of the
- // closure after it has consumed all pending messages.
- int ClosePort(const PortRef& port_ref);
-
- // Returns the current status of the port.
- int GetStatus(const PortRef& port_ref, PortStatus* port_status);
-
- // Returns the next available message on the specified port or returns a null
- // message if there are none available. Returns ERROR_PORT_PEER_CLOSED to
- // indicate that this port's peer has closed. In such cases GetMessage may
- // be called until it yields a null message, indicating that no more messages
- // may be read from the port.
- //
- // If |filter| is non-null, the next available message is returned only if it
- // is matched by the filter. If the provided filter does not match the next
- // available message, GetMessage() behaves as if there is no message
- // available. Ownership of |filter| is not taken, and it must outlive the
- // extent of this call.
- int GetMessage(const PortRef& port_ref,
- ScopedMessage* message,
- MessageFilter* filter);
-
- // Sends a message from the specified port to its peer. Note that the message
- // notification may arrive synchronously (via PortStatusChanged() on the
- // delegate) if the peer is local to this Node.
- int SendMessage(const PortRef& port_ref, ScopedMessage message);
-
- // Corresponding to NodeDelegate::ForwardMessage.
- int AcceptMessage(ScopedMessage message);
-
- // Called to merge two ports with each other. If you have two independent
- // port pairs A <=> B and C <=> D, the net result of merging B and C is a
- // single connected port pair A <=> D.
- //
- // Note that the behavior of this operation is undefined if either port to be
- // merged (B or C above) has ever been read from or written to directly, and
- // this must ONLY be called on one side of the merge, though it doesn't matter
- // which side.
- //
- // It is safe for the non-merged peers (A and D above) to be transferred,
- // closed, and/or written to before, during, or after the merge.
- int MergePorts(const PortRef& port_ref,
- const NodeName& destination_node_name,
- const PortName& destination_port_name);
-
- // Like above but merges two ports local to this node. Because both ports are
- // local this can also verify that neither port has been written to before the
- // merge. If this fails for any reason, both ports are closed. Otherwise OK
- // is returned and the ports' receiving peers are connected to each other.
- int MergeLocalPorts(const PortRef& port0_ref, const PortRef& port1_ref);
-
- // Called to inform this node that communication with another node is lost
- // indefinitely. This triggers cleanup of ports bound to this node.
- int LostConnectionToNode(const NodeName& node_name);
-
- private:
- class LockedPort;
-
- // Note: Functions that end with _Locked require |ports_lock_| to be held
- // before calling.
- int OnUserMessage(ScopedMessage message);
- int OnPortAccepted(const PortName& port_name);
- int OnObserveProxy(const PortName& port_name,
- const ObserveProxyEventData& event);
- int OnObserveProxyAck(const PortName& port_name, uint64_t last_sequence_num);
- int OnObserveClosure(const PortName& port_name, uint64_t last_sequence_num);
- int OnMergePort(const PortName& port_name, const MergePortEventData& event);
-
- int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port);
- void ErasePort(const PortName& port_name);
- void ErasePort_Locked(const PortName& port_name);
- scoped_refptr<Port> GetPort(const PortName& port_name);
- scoped_refptr<Port> GetPort_Locked(const PortName& port_name);
-
- int SendMessageInternal(const PortRef& port_ref, ScopedMessage* message);
- int MergePorts_Locked(const PortRef& port0_ref, const PortRef& port1_ref);
- void WillSendPort(const LockedPort& port,
- const NodeName& to_node_name,
- PortName* port_name,
- PortDescriptor* port_descriptor);
- int AcceptPort(const PortName& port_name,
- const PortDescriptor& port_descriptor);
-
- int WillSendMessage_Locked(const LockedPort& port,
- const PortName& port_name,
- Message* message);
- int BeginProxying_Locked(const LockedPort& port, const PortName& port_name);
- int BeginProxying(PortRef port_ref);
- int ForwardMessages_Locked(const LockedPort& port, const PortName& port_name);
- void InitiateProxyRemoval(const LockedPort& port, const PortName& port_name);
- void MaybeRemoveProxy_Locked(const LockedPort& port,
- const PortName& port_name);
- void TryRemoveProxy(PortRef port_ref);
- void DestroyAllPortsWithPeer(const NodeName& node_name,
- const PortName& port_name);
-
- ScopedMessage NewInternalMessage_Helper(const PortName& port_name,
- const EventType& type,
- const void* data,
- size_t num_data_bytes);
-
- ScopedMessage NewInternalMessage(const PortName& port_name,
- const EventType& type) {
- return NewInternalMessage_Helper(port_name, type, nullptr, 0);
- }
-
- template <typename EventData>
- ScopedMessage NewInternalMessage(const PortName& port_name,
- const EventType& type,
- const EventData& data) {
- return NewInternalMessage_Helper(port_name, type, &data, sizeof(data));
- }
-
- const NodeName name_;
- NodeDelegate* const delegate_;
-
- // Guards |ports_| as well as any operation which needs to hold multiple port
- // locks simultaneously. Usage of this is subtle: it must NEVER be acquired
- // after a Port lock is acquired, and it must ALWAYS be acquired before
- // calling WillSendMessage_Locked or ForwardMessages_Locked.
- base::Lock ports_lock_;
- std::unordered_map<PortName, scoped_refptr<Port>> ports_;
-
- DISALLOW_COPY_AND_ASSIGN(Node);
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_NODE_H_
diff --git a/mojo/edk/system/ports/node_delegate.h b/mojo/edk/system/ports/node_delegate.h
deleted file mode 100644
index 8547302..0000000
--- a/mojo/edk/system/ports/node_delegate.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_NODE_DELEGATE_H_
-#define MOJO_EDK_SYSTEM_PORTS_NODE_DELEGATE_H_
-
-#include <stddef.h>
-
-#include "mojo/edk/system/ports/message.h"
-#include "mojo/edk/system/ports/name.h"
-#include "mojo/edk/system/ports/port_ref.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-class NodeDelegate {
- public:
- virtual ~NodeDelegate() {}
-
- // Port names should be difficult to guess.
- virtual void GenerateRandomPortName(PortName* port_name) = 0;
-
- // Allocate a message, including a header that can be used by the Node
- // implementation. |num_header_bytes| will be aligned. The newly allocated
- // memory need not be zero-filled.
- virtual void AllocMessage(size_t num_header_bytes,
- ScopedMessage* message) = 0;
-
- // Forward a message asynchronously to the specified node. This method MUST
- // NOT synchronously call any methods on Node.
- virtual void ForwardMessage(const NodeName& node, ScopedMessage message) = 0;
-
- // Broadcast a message to all nodes.
- virtual void BroadcastMessage(ScopedMessage message) = 0;
-
- // Indicates that the port's status has changed recently. Use Node::GetStatus
- // to query the latest status of the port. Note, this event could be spurious
- // if another thread is simultaneously modifying the status of the port.
- virtual void PortStatusChanged(const PortRef& port_ref) = 0;
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_NODE_DELEGATE_H_
diff --git a/mojo/edk/system/ports/port.cc b/mojo/edk/system/ports/port.cc
deleted file mode 100644
index e4403ae..0000000
--- a/mojo/edk/system/ports/port.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports/port.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-Port::Port(uint64_t next_sequence_num_to_send,
- uint64_t next_sequence_num_to_receive)
- : state(kUninitialized),
- next_sequence_num_to_send(next_sequence_num_to_send),
- last_sequence_num_to_receive(0),
- message_queue(next_sequence_num_to_receive),
- remove_proxy_on_last_message(false),
- peer_closed(false) {}
-
-Port::~Port() {}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/port.h b/mojo/edk/system/ports/port.h
deleted file mode 100644
index ea53d43..0000000
--- a/mojo/edk/system/ports/port.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_PORT_H_
-#define MOJO_EDK_SYSTEM_PORTS_PORT_H_
-
-#include <memory>
-#include <queue>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/system/ports/message_queue.h"
-#include "mojo/edk/system/ports/user_data.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-class Port : public base::RefCountedThreadSafe<Port> {
- public:
- enum State {
- kUninitialized,
- kReceiving,
- kBuffering,
- kProxying,
- kClosed
- };
-
- base::Lock lock;
- State state;
- NodeName peer_node_name;
- PortName peer_port_name;
- uint64_t next_sequence_num_to_send;
- uint64_t last_sequence_num_to_receive;
- MessageQueue message_queue;
- std::unique_ptr<std::pair<NodeName, ScopedMessage>> send_on_proxy_removal;
- scoped_refptr<UserData> user_data;
- bool remove_proxy_on_last_message;
- bool peer_closed;
-
- Port(uint64_t next_sequence_num_to_send,
- uint64_t next_sequence_num_to_receive);
-
- private:
- friend class base::RefCountedThreadSafe<Port>;
-
- ~Port();
-
- DISALLOW_COPY_AND_ASSIGN(Port);
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_PORT_H_
diff --git a/mojo/edk/system/ports/port_ref.cc b/mojo/edk/system/ports/port_ref.cc
deleted file mode 100644
index 675754d..0000000
--- a/mojo/edk/system/ports/port_ref.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports/port_ref.h"
-
-#include "mojo/edk/system/ports/port.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-PortRef::~PortRef() {
-}
-
-PortRef::PortRef() {
-}
-
-PortRef::PortRef(const PortName& name, scoped_refptr<Port> port)
- : name_(name), port_(std::move(port)) {}
-
-PortRef::PortRef(const PortRef& other)
- : name_(other.name_), port_(other.port_) {
-}
-
-PortRef& PortRef::operator=(const PortRef& other) {
- if (&other != this) {
- name_ = other.name_;
- port_ = other.port_;
- }
- return *this;
-}
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/port_ref.h b/mojo/edk/system/ports/port_ref.h
deleted file mode 100644
index 59036c3..0000000
--- a/mojo/edk/system/ports/port_ref.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_PORT_REF_H_
-#define MOJO_EDK_SYSTEM_PORTS_PORT_REF_H_
-
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/system/ports/name.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-class Port;
-class Node;
-
-class PortRef {
- public:
- ~PortRef();
- PortRef();
- PortRef(const PortName& name, scoped_refptr<Port> port);
-
- PortRef(const PortRef& other);
- PortRef& operator=(const PortRef& other);
-
- const PortName& name() const { return name_; }
-
- private:
- friend class Node;
- Port* port() const { return port_.get(); }
-
- PortName name_;
- scoped_refptr<Port> port_;
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_PORT_REF_H_
diff --git a/mojo/edk/system/ports/ports_unittest.cc b/mojo/edk/system/ports/ports_unittest.cc
deleted file mode 100644
index cb48b3e..0000000
--- a/mojo/edk/system/ports/ports_unittest.cc
+++ /dev/null
@@ -1,1478 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <map>
-#include <queue>
-#include <sstream>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/rand_util.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/thread.h"
-#include "mojo/edk/system/ports/event.h"
-#include "mojo/edk/system/ports/node.h"
-#include "mojo/edk/system/ports/node_delegate.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-namespace test {
-
-namespace {
-
-bool MessageEquals(const ScopedMessage& message, const base::StringPiece& s) {
- return !strcmp(static_cast<const char*>(message->payload_bytes()), s.data());
-}
-
-class TestMessage : public Message {
- public:
- static ScopedMessage NewUserMessage(size_t num_payload_bytes,
- size_t num_ports) {
- return ScopedMessage(new TestMessage(num_payload_bytes, num_ports));
- }
-
- TestMessage(size_t num_payload_bytes, size_t num_ports)
- : Message(num_payload_bytes, num_ports) {
- start_ = new char[num_header_bytes_ + num_ports_bytes_ + num_payload_bytes];
- InitializeUserMessageHeader(start_);
- }
-
- TestMessage(size_t num_header_bytes,
- size_t num_payload_bytes,
- size_t num_ports_bytes)
- : Message(num_header_bytes,
- num_payload_bytes,
- num_ports_bytes) {
- start_ = new char[num_header_bytes + num_payload_bytes + num_ports_bytes];
- }
-
- ~TestMessage() override {
- delete[] start_;
- }
-};
-
-class TestNode;
-
-class MessageRouter {
- public:
- virtual ~MessageRouter() {}
-
- virtual void GeneratePortName(PortName* name) = 0;
- virtual void ForwardMessage(TestNode* from_node,
- const NodeName& node_name,
- ScopedMessage message) = 0;
- virtual void BroadcastMessage(TestNode* from_node, ScopedMessage message) = 0;
-};
-
-class TestNode : public NodeDelegate {
- public:
- explicit TestNode(uint64_t id)
- : node_name_(id, 1),
- node_(node_name_, this),
- node_thread_(base::StringPrintf("Node %" PRIu64 " thread", id)),
- messages_available_event_(
- base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- idle_event_(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::SIGNALED) {
- }
-
- ~TestNode() override {
- StopWhenIdle();
- node_thread_.Stop();
- }
-
- const NodeName& name() const { return node_name_; }
-
- // NOTE: Node is thread-safe.
- Node& node() { return node_; }
-
- base::WaitableEvent& idle_event() { return idle_event_; }
-
- bool IsIdle() {
- base::AutoLock lock(lock_);
- return started_ && !dispatching_ &&
- (incoming_messages_.empty() || (block_on_event_ && blocked_));
- }
-
- void BlockOnEvent(EventType type) {
- base::AutoLock lock(lock_);
- blocked_event_type_ = type;
- block_on_event_ = true;
- }
-
- void Unblock() {
- base::AutoLock lock(lock_);
- block_on_event_ = false;
- messages_available_event_.Signal();
- }
-
- void Start(MessageRouter* router) {
- router_ = router;
- node_thread_.Start();
- node_thread_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&TestNode::ProcessMessages, base::Unretained(this)));
- }
-
- void StopWhenIdle() {
- base::AutoLock lock(lock_);
- should_quit_ = true;
- messages_available_event_.Signal();
- }
-
- void WakeUp() { messages_available_event_.Signal(); }
-
- int SendStringMessage(const PortRef& port, const std::string& s) {
- size_t size = s.size() + 1;
- ScopedMessage message = TestMessage::NewUserMessage(size, 0);
- memcpy(message->mutable_payload_bytes(), s.data(), size);
- return node_.SendMessage(port, std::move(message));
- }
-
- int SendStringMessageWithPort(const PortRef& port,
- const std::string& s,
- const PortName& sent_port_name) {
- size_t size = s.size() + 1;
- ScopedMessage message = TestMessage::NewUserMessage(size, 1);
- memcpy(message->mutable_payload_bytes(), s.data(), size);
- message->mutable_ports()[0] = sent_port_name;
- return node_.SendMessage(port, std::move(message));
- }
-
- int SendStringMessageWithPort(const PortRef& port,
- const std::string& s,
- const PortRef& sent_port) {
- return SendStringMessageWithPort(port, s, sent_port.name());
- }
-
- void set_drop_messages(bool value) {
- base::AutoLock lock(lock_);
- drop_messages_ = value;
- }
-
- void set_save_messages(bool value) {
- base::AutoLock lock(lock_);
- save_messages_ = value;
- }
-
- bool ReadMessage(const PortRef& port, ScopedMessage* message) {
- return node_.GetMessage(port, message, nullptr) == OK && *message;
- }
-
- bool GetSavedMessage(ScopedMessage* message) {
- base::AutoLock lock(lock_);
- if (saved_messages_.empty()) {
- message->reset();
- return false;
- }
- std::swap(*message, saved_messages_.front());
- saved_messages_.pop();
- return true;
- }
-
- void EnqueueMessage(ScopedMessage message) {
- idle_event_.Reset();
-
- // NOTE: This may be called from ForwardMessage and thus must not reenter
- // |node_|.
- base::AutoLock lock(lock_);
- incoming_messages_.emplace(std::move(message));
- messages_available_event_.Signal();
- }
-
- void GenerateRandomPortName(PortName* port_name) override {
- DCHECK(router_);
- router_->GeneratePortName(port_name);
- }
-
- void AllocMessage(size_t num_header_bytes, ScopedMessage* message) override {
- message->reset(new TestMessage(num_header_bytes, 0, 0));
- }
-
- void ForwardMessage(const NodeName& node_name,
- ScopedMessage message) override {
- {
- base::AutoLock lock(lock_);
- if (drop_messages_) {
- DVLOG(1) << "Dropping ForwardMessage from node "
- << node_name_ << " to " << node_name;
-
- base::AutoUnlock unlock(lock_);
- ClosePortsInMessage(message.get());
- return;
- }
- }
-
- DCHECK(router_);
- DVLOG(1) << "ForwardMessage from node "
- << node_name_ << " to " << node_name;
- router_->ForwardMessage(this, node_name, std::move(message));
- }
-
- void BroadcastMessage(ScopedMessage message) override {
- router_->BroadcastMessage(this, std::move(message));
- }
-
- void PortStatusChanged(const PortRef& port) override {
- // The port may be closed, in which case we ignore the notification.
- base::AutoLock lock(lock_);
- if (!save_messages_)
- return;
-
- for (;;) {
- ScopedMessage message;
- {
- base::AutoUnlock unlock(lock_);
- if (!ReadMessage(port, &message))
- break;
- }
-
- saved_messages_.emplace(std::move(message));
- }
- }
-
- void ClosePortsInMessage(Message* message) {
- for (size_t i = 0; i < message->num_ports(); ++i) {
- PortRef port;
- ASSERT_EQ(OK, node_.GetPort(message->ports()[i], &port));
- EXPECT_EQ(OK, node_.ClosePort(port));
- }
- }
-
- private:
- void ProcessMessages() {
- for (;;) {
- messages_available_event_.Wait();
-
- base::AutoLock lock(lock_);
-
- if (should_quit_)
- return;
-
- dispatching_ = true;
- while (!incoming_messages_.empty()) {
- if (block_on_event_ &&
- GetEventHeader(*incoming_messages_.front())->type ==
- blocked_event_type_) {
- blocked_ = true;
- // Go idle if we hit a blocked event type.
- break;
- } else {
- blocked_ = false;
- }
- ScopedMessage message = std::move(incoming_messages_.front());
- incoming_messages_.pop();
-
- // NOTE: AcceptMessage() can re-enter this object to call any of the
- // NodeDelegate interface methods.
- base::AutoUnlock unlock(lock_);
- node_.AcceptMessage(std::move(message));
- }
-
- dispatching_ = false;
- started_ = true;
- idle_event_.Signal();
- };
- }
-
- const NodeName node_name_;
- Node node_;
- MessageRouter* router_ = nullptr;
-
- base::Thread node_thread_;
- base::WaitableEvent messages_available_event_;
- base::WaitableEvent idle_event_;
-
- // Guards fields below.
- base::Lock lock_;
- bool started_ = false;
- bool dispatching_ = false;
- bool should_quit_ = false;
- bool drop_messages_ = false;
- bool save_messages_ = false;
- bool blocked_ = false;
- bool block_on_event_ = false;
- EventType blocked_event_type_;
- std::queue<ScopedMessage> incoming_messages_;
- std::queue<ScopedMessage> saved_messages_;
-};
-
-class PortsTest : public testing::Test, public MessageRouter {
- public:
- void AddNode(TestNode* node) {
- {
- base::AutoLock lock(lock_);
- nodes_[node->name()] = node;
- }
- node->Start(this);
- }
-
- void RemoveNode(TestNode* node) {
- {
- base::AutoLock lock(lock_);
- nodes_.erase(node->name());
- }
-
- for (const auto& entry : nodes_)
- entry.second->node().LostConnectionToNode(node->name());
- }
-
- // Waits until all known Nodes are idle. Message forwarding and processing
- // is handled in such a way that idleness is a stable state: once all nodes in
- // the system are idle, they will remain idle until the test explicitly
- // initiates some further event (e.g. sending a message, closing a port, or
- // removing a Node).
- void WaitForIdle() {
- for (;;) {
- base::AutoLock global_lock(global_lock_);
- bool all_nodes_idle = true;
- for (const auto& entry : nodes_) {
- if (!entry.second->IsIdle())
- all_nodes_idle = false;
- entry.second->WakeUp();
- }
- if (all_nodes_idle)
- return;
-
- // Wait for any Node to signal that it's idle.
- base::AutoUnlock global_unlock(global_lock_);
- std::vector<base::WaitableEvent*> events;
- for (const auto& entry : nodes_)
- events.push_back(&entry.second->idle_event());
- base::WaitableEvent::WaitMany(events.data(), events.size());
- }
- }
-
- void CreatePortPair(TestNode* node0,
- PortRef* port0,
- TestNode* node1,
- PortRef* port1) {
- if (node0 == node1) {
- EXPECT_EQ(OK, node0->node().CreatePortPair(port0, port1));
- } else {
- EXPECT_EQ(OK, node0->node().CreateUninitializedPort(port0));
- EXPECT_EQ(OK, node1->node().CreateUninitializedPort(port1));
- EXPECT_EQ(OK, node0->node().InitializePort(*port0, node1->name(),
- port1->name()));
- EXPECT_EQ(OK, node1->node().InitializePort(*port1, node0->name(),
- port0->name()));
- }
- }
-
- private:
- // MessageRouter:
- void GeneratePortName(PortName* name) override {
- base::AutoLock lock(lock_);
- name->v1 = next_port_id_++;
- name->v2 = 0;
- }
-
- void ForwardMessage(TestNode* from_node,
- const NodeName& node_name,
- ScopedMessage message) override {
- base::AutoLock global_lock(global_lock_);
- base::AutoLock lock(lock_);
- // Drop messages from nodes that have been removed.
- if (nodes_.find(from_node->name()) == nodes_.end()) {
- from_node->ClosePortsInMessage(message.get());
- return;
- }
-
- auto it = nodes_.find(node_name);
- if (it == nodes_.end()) {
- DVLOG(1) << "Node not found: " << node_name;
- return;
- }
-
- it->second->EnqueueMessage(std::move(message));
- }
-
- void BroadcastMessage(TestNode* from_node, ScopedMessage message) override {
- base::AutoLock global_lock(global_lock_);
- base::AutoLock lock(lock_);
-
- // Drop messages from nodes that have been removed.
- if (nodes_.find(from_node->name()) == nodes_.end())
- return;
-
- for (const auto& entry : nodes_) {
- TestNode* node = entry.second;
- // Broadcast doesn't deliver to the local node.
- if (node == from_node)
- continue;
-
- // NOTE: We only need to support broadcast of events. Events have no
- // payload or ports bytes.
- ScopedMessage new_message(
- new TestMessage(message->num_header_bytes(), 0, 0));
- memcpy(new_message->mutable_header_bytes(), message->header_bytes(),
- message->num_header_bytes());
- node->EnqueueMessage(std::move(new_message));
- }
- }
-
- base::MessageLoop message_loop_;
-
- // Acquired before any operation which makes a Node busy, and before testing
- // if all nodes are idle.
- base::Lock global_lock_;
-
- base::Lock lock_;
- uint64_t next_port_id_ = 1;
- std::map<NodeName, TestNode*> nodes_;
-};
-
-} // namespace
-
-TEST_F(PortsTest, Basic1) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- PortRef x0, x1;
- CreatePortPair(&node0, &x0, &node1, &x1);
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "hello", a1));
- EXPECT_EQ(OK, node0.node().ClosePort(a0));
-
- EXPECT_EQ(OK, node0.node().ClosePort(x0));
- EXPECT_EQ(OK, node1.node().ClosePort(x1));
-
- WaitForIdle();
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, Basic2) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- PortRef x0, x1;
- CreatePortPair(&node0, &x0, &node1, &x1);
-
- PortRef b0, b1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&b0, &b1));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "hello", b1));
- EXPECT_EQ(OK, node0.SendStringMessage(b0, "hello again"));
-
- EXPECT_EQ(OK, node0.node().ClosePort(b0));
-
- EXPECT_EQ(OK, node0.node().ClosePort(x0));
- EXPECT_EQ(OK, node1.node().ClosePort(x1));
-
- WaitForIdle();
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, Basic3) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- PortRef x0, x1;
- CreatePortPair(&node0, &x0, &node1, &x1);
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
-
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "hello", a1));
- EXPECT_EQ(OK, node0.SendStringMessage(a0, "hello again"));
-
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "foo", a0));
-
- PortRef b0, b1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&b0, &b1));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "bar", b1));
- EXPECT_EQ(OK, node0.SendStringMessage(b0, "baz"));
-
- EXPECT_EQ(OK, node0.node().ClosePort(b0));
-
- EXPECT_EQ(OK, node0.node().ClosePort(x0));
- EXPECT_EQ(OK, node1.node().ClosePort(x1));
-
- WaitForIdle();
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, LostConnectionToNode1) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
- node1.set_drop_messages(true);
-
- PortRef x0, x1;
- CreatePortPair(&node0, &x0, &node1, &x1);
-
- // Transfer a port to node1 and simulate a lost connection to node1.
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "foo", a1));
-
- WaitForIdle();
-
- RemoveNode(&node1);
-
- WaitForIdle();
-
- EXPECT_EQ(OK, node0.node().ClosePort(a0));
- EXPECT_EQ(OK, node0.node().ClosePort(x0));
- EXPECT_EQ(OK, node1.node().ClosePort(x1));
-
- WaitForIdle();
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, LostConnectionToNode2) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- PortRef x0, x1;
- CreatePortPair(&node0, &x0, &node1, &x1);
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "take a1", a1));
-
- WaitForIdle();
-
- node1.set_drop_messages(true);
-
- RemoveNode(&node1);
-
- WaitForIdle();
-
- // a0 should have eventually detected peer closure after node loss.
- ScopedMessage message;
- EXPECT_EQ(ERROR_PORT_PEER_CLOSED,
- node0.node().GetMessage(a0, &message, nullptr));
- EXPECT_FALSE(message);
-
- EXPECT_EQ(OK, node0.node().ClosePort(a0));
-
- EXPECT_EQ(OK, node0.node().ClosePort(x0));
-
- EXPECT_EQ(OK, node1.node().GetMessage(x1, &message, nullptr));
- EXPECT_TRUE(message);
- node1.ClosePortsInMessage(message.get());
-
- EXPECT_EQ(OK, node1.node().ClosePort(x1));
-
- WaitForIdle();
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, LostConnectionToNodeWithSecondaryProxy) {
- // Tests that a proxy gets cleaned up when its indirect peer lives on a lost
- // node.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- TestNode node2(2);
- AddNode(&node2);
-
- // Create A-B spanning nodes 0 and 1 and C-D spanning 1 and 2.
- PortRef A, B, C, D;
- CreatePortPair(&node0, &A, &node1, &B);
- CreatePortPair(&node1, &C, &node2, &D);
-
- // Create E-F and send F over A to node 1.
- PortRef E, F;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&E, &F));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, ".", F));
-
- WaitForIdle();
-
- ScopedMessage message;
- ASSERT_TRUE(node1.ReadMessage(B, &message));
- ASSERT_EQ(1u, message->num_ports());
-
- EXPECT_EQ(OK, node1.node().GetPort(message->ports()[0], &F));
-
- // Send F over C to node 2 and then simulate node 2 loss from node 1. Node 1
- // will trivially become aware of the loss, and this test verifies that the
- // port A on node 0 will eventually also become aware of it.
-
- // Make sure node2 stops processing events when it encounters an ObserveProxy.
- node2.BlockOnEvent(EventType::kObserveProxy);
-
- EXPECT_EQ(OK, node1.SendStringMessageWithPort(C, ".", F));
- WaitForIdle();
-
- // Simulate node 1 and 2 disconnecting.
- EXPECT_EQ(OK, node1.node().LostConnectionToNode(node2.name()));
-
- // Let node2 continue processing events and wait for everyone to go idle.
- node2.Unblock();
- WaitForIdle();
-
- // Port F should be gone.
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node1.node().GetPort(F.name(), &F));
-
- // Port E should have detected peer closure despite the fact that there is
- // no longer a continuous route from F to E over which the event could travel.
- PortStatus status;
- EXPECT_EQ(OK, node0.node().GetStatus(E, &status));
- EXPECT_TRUE(status.peer_closed);
-
- EXPECT_EQ(OK, node0.node().ClosePort(A));
- EXPECT_EQ(OK, node1.node().ClosePort(B));
- EXPECT_EQ(OK, node1.node().ClosePort(C));
- EXPECT_EQ(OK, node0.node().ClosePort(E));
-
- WaitForIdle();
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, LostConnectionToNodeWithLocalProxy) {
- // Tests that a proxy gets cleaned up when its direct peer lives on a lost
- // node and it's predecessor lives on the same node.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- PortRef A, B;
- CreatePortPair(&node0, &A, &node1, &B);
-
- PortRef C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&C, &D));
-
- // Send D but block node0 on an ObserveProxy event.
- node0.BlockOnEvent(EventType::kObserveProxy);
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, ".", D));
-
- // node0 won't collapse the proxy but node1 will receive the message before
- // going idle.
- WaitForIdle();
-
- ScopedMessage message;
- ASSERT_TRUE(node1.ReadMessage(B, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef E;
- EXPECT_EQ(OK, node1.node().GetPort(message->ports()[0], &E));
-
- RemoveNode(&node1);
-
- node0.Unblock();
- WaitForIdle();
-
- // Port C should have detected peer closure.
- PortStatus status;
- EXPECT_EQ(OK, node0.node().GetStatus(C, &status));
- EXPECT_TRUE(status.peer_closed);
-
- EXPECT_EQ(OK, node0.node().ClosePort(A));
- EXPECT_EQ(OK, node1.node().ClosePort(B));
- EXPECT_EQ(OK, node0.node().ClosePort(C));
- EXPECT_EQ(OK, node1.node().ClosePort(E));
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, GetMessage1) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node.node().CreatePortPair(&a0, &a1));
-
- ScopedMessage message;
- EXPECT_EQ(OK, node.node().GetMessage(a0, &message, nullptr));
- EXPECT_FALSE(message);
-
- EXPECT_EQ(OK, node.node().ClosePort(a1));
-
- WaitForIdle();
-
- EXPECT_EQ(ERROR_PORT_PEER_CLOSED,
- node.node().GetMessage(a0, &message, nullptr));
- EXPECT_FALSE(message);
-
- EXPECT_EQ(OK, node.node().ClosePort(a0));
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, GetMessage2) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node.node().CreatePortPair(&a0, &a1));
-
- EXPECT_EQ(OK, node.SendStringMessage(a1, "1"));
-
- ScopedMessage message;
- EXPECT_EQ(OK, node.node().GetMessage(a0, &message, nullptr));
-
- ASSERT_TRUE(message);
- EXPECT_TRUE(MessageEquals(message, "1"));
-
- EXPECT_EQ(OK, node.node().ClosePort(a0));
- EXPECT_EQ(OK, node.node().ClosePort(a1));
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, GetMessage3) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node.node().CreatePortPair(&a0, &a1));
-
- const char* kStrings[] = {
- "1",
- "2",
- "3"
- };
-
- for (size_t i = 0; i < sizeof(kStrings)/sizeof(kStrings[0]); ++i)
- EXPECT_EQ(OK, node.SendStringMessage(a1, kStrings[i]));
-
- ScopedMessage message;
- for (size_t i = 0; i < sizeof(kStrings)/sizeof(kStrings[0]); ++i) {
- EXPECT_EQ(OK, node.node().GetMessage(a0, &message, nullptr));
- ASSERT_TRUE(message);
- EXPECT_TRUE(MessageEquals(message, kStrings[i]));
- }
-
- EXPECT_EQ(OK, node.node().ClosePort(a0));
- EXPECT_EQ(OK, node.node().ClosePort(a1));
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, Delegation1) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- PortRef x0, x1;
- CreatePortPair(&node0, &x0, &node1, &x1);
-
- // In this test, we send a message to a port that has been moved.
-
- PortRef a0, a1;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "a1", a1));
- WaitForIdle();
-
- ScopedMessage message;
- ASSERT_TRUE(node1.ReadMessage(x1, &message));
- ASSERT_EQ(1u, message->num_ports());
- EXPECT_TRUE(MessageEquals(message, "a1"));
-
- // This is "a1" from the point of view of node1.
- PortName a2_name = message->ports()[0];
- EXPECT_EQ(OK, node1.SendStringMessageWithPort(x1, "a2", a2_name));
- EXPECT_EQ(OK, node0.SendStringMessage(a0, "hello"));
-
- WaitForIdle();
-
- ASSERT_TRUE(node0.ReadMessage(x0, &message));
- ASSERT_EQ(1u, message->num_ports());
- EXPECT_TRUE(MessageEquals(message, "a2"));
-
- // This is "a2" from the point of view of node1.
- PortName a3_name = message->ports()[0];
-
- PortRef a3;
- EXPECT_EQ(OK, node0.node().GetPort(a3_name, &a3));
-
- ASSERT_TRUE(node0.ReadMessage(a3, &message));
- EXPECT_EQ(0u, message->num_ports());
- EXPECT_TRUE(MessageEquals(message, "hello"));
-
- EXPECT_EQ(OK, node0.node().ClosePort(a0));
- EXPECT_EQ(OK, node0.node().ClosePort(a3));
-
- EXPECT_EQ(OK, node0.node().ClosePort(x0));
- EXPECT_EQ(OK, node1.node().ClosePort(x1));
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, Delegation2) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- for (int i = 0; i < 100; ++i) {
- // Setup pipe a<->b between node0 and node1.
- PortRef A, B;
- CreatePortPair(&node0, &A, &node1, &B);
-
- PortRef C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&C, &D));
-
- PortRef E, F;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&E, &F));
-
- node1.set_save_messages(true);
-
- // Pass D over A to B.
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(A, "1", D));
-
- // Pass F over C to D.
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(C, "1", F));
-
- // This message should find its way to node1.
- EXPECT_EQ(OK, node0.SendStringMessage(E, "hello"));
-
- WaitForIdle();
-
- EXPECT_EQ(OK, node0.node().ClosePort(C));
- EXPECT_EQ(OK, node0.node().ClosePort(E));
-
- EXPECT_EQ(OK, node0.node().ClosePort(A));
- EXPECT_EQ(OK, node1.node().ClosePort(B));
-
- bool got_hello = false;
- ScopedMessage message;
- while (node1.GetSavedMessage(&message)) {
- node1.ClosePortsInMessage(message.get());
- if (MessageEquals(message, "hello")) {
- got_hello = true;
- break;
- }
- }
-
- EXPECT_TRUE(got_hello);
-
- WaitForIdle(); // Because closing ports may have generated tasks.
- }
-
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, SendUninitialized) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef x0;
- EXPECT_EQ(OK, node.node().CreateUninitializedPort(&x0));
- EXPECT_EQ(ERROR_PORT_STATE_UNEXPECTED, node.SendStringMessage(x0, "oops"));
- EXPECT_EQ(OK, node.node().ClosePort(x0));
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, SendFailure) {
- TestNode node(0);
- AddNode(&node);
-
- node.set_save_messages(true);
-
- PortRef A, B;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
-
- // Try to send A over itself.
-
- EXPECT_EQ(ERROR_PORT_CANNOT_SEND_SELF,
- node.SendStringMessageWithPort(A, "oops", A));
-
- // Try to send B over A.
-
- EXPECT_EQ(ERROR_PORT_CANNOT_SEND_PEER,
- node.SendStringMessageWithPort(A, "nope", B));
-
- // B should be closed immediately.
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node.node().GetPort(B.name(), &B));
-
- WaitForIdle();
-
- // There should have been no messages accepted.
- ScopedMessage message;
- EXPECT_FALSE(node.GetSavedMessage(&message));
-
- EXPECT_EQ(OK, node.node().ClosePort(A));
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, DontLeakUnreceivedPorts) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node.node().CreatePortPair(&C, &D));
-
- EXPECT_EQ(OK, node.SendStringMessageWithPort(A, "foo", D));
-
- EXPECT_EQ(OK, node.node().ClosePort(C));
- EXPECT_EQ(OK, node.node().ClosePort(A));
- EXPECT_EQ(OK, node.node().ClosePort(B));
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, AllowShutdownWithLocalPortsOpen) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node.node().CreatePortPair(&C, &D));
-
- EXPECT_EQ(OK, node.SendStringMessageWithPort(A, "foo", D));
-
- ScopedMessage message;
- EXPECT_TRUE(node.ReadMessage(B, &message));
- ASSERT_EQ(1u, message->num_ports());
- EXPECT_TRUE(MessageEquals(message, "foo"));
- PortRef E;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &E));
-
- EXPECT_TRUE(
- node.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
-
- WaitForIdle();
-
- EXPECT_TRUE(
- node.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
- EXPECT_FALSE(node.node().CanShutdownCleanly());
-
- EXPECT_EQ(OK, node.node().ClosePort(A));
- EXPECT_EQ(OK, node.node().ClosePort(B));
- EXPECT_EQ(OK, node.node().ClosePort(C));
- EXPECT_EQ(OK, node.node().ClosePort(E));
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, ProxyCollapse1) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef A, B;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
-
- PortRef X, Y;
- EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
-
- ScopedMessage message;
-
- // Send B and receive it as C.
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef C;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &C));
-
- // Send C and receive it as D.
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", C));
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef D;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &D));
-
- // Send D and receive it as E.
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", D));
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef E;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &E));
-
- EXPECT_EQ(OK, node.node().ClosePort(X));
- EXPECT_EQ(OK, node.node().ClosePort(Y));
-
- EXPECT_EQ(OK, node.node().ClosePort(A));
- EXPECT_EQ(OK, node.node().ClosePort(E));
-
- // The node should not idle until all proxies are collapsed.
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, ProxyCollapse2) {
- TestNode node(0);
- AddNode(&node);
-
- PortRef A, B;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
-
- PortRef X, Y;
- EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
-
- ScopedMessage message;
-
- // Send B and A to create proxies in each direction.
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", A));
-
- EXPECT_EQ(OK, node.node().ClosePort(X));
- EXPECT_EQ(OK, node.node().ClosePort(Y));
-
- // At this point we have a scenario with:
- //
- // D -> [B] -> C -> [A]
- //
- // Ensure that the proxies can collapse. The sent ports will be closed
- // eventually as a result of Y's closure.
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, SendWithClosedPeer) {
- // This tests that if a port is sent when its peer is already known to be
- // closed, the newly created port will be aware of that peer closure, and the
- // proxy will eventually collapse.
-
- TestNode node(0);
- AddNode(&node);
-
- // Send a message from A to B, then close A.
- PortRef A, B;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node.SendStringMessage(A, "hey"));
- EXPECT_EQ(OK, node.node().ClosePort(A));
-
- // Now send B over X-Y as new port C.
- PortRef X, Y;
- EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
- ScopedMessage message;
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef C;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &C));
-
- EXPECT_EQ(OK, node.node().ClosePort(X));
- EXPECT_EQ(OK, node.node().ClosePort(Y));
-
- WaitForIdle();
-
- // C should have received the message originally sent to B, and it should also
- // be aware of A's closure.
-
- ASSERT_TRUE(node.ReadMessage(C, &message));
- EXPECT_TRUE(MessageEquals(message, "hey"));
-
- PortStatus status;
- EXPECT_EQ(OK, node.node().GetStatus(C, &status));
- EXPECT_FALSE(status.receiving_messages);
- EXPECT_FALSE(status.has_messages);
- EXPECT_TRUE(status.peer_closed);
-
- node.node().ClosePort(C);
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, SendWithClosedPeerSent) {
- // This tests that if a port is closed while some number of proxies are still
- // routing messages (directly or indirectly) to it, that the peer port is
- // eventually notified of the closure, and the dead-end proxies will
- // eventually be removed.
-
- TestNode node(0);
- AddNode(&node);
-
- PortRef X, Y;
- EXPECT_EQ(OK, node.node().CreatePortPair(&X, &Y));
-
- PortRef A, B;
- EXPECT_EQ(OK, node.node().CreatePortPair(&A, &B));
-
- ScopedMessage message;
-
- // Send A as new port C.
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", A));
-
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef C;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &C));
-
- // Send C as new port D.
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", C));
-
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef D;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &D));
-
- // Send a message to B through D, then close D.
- EXPECT_EQ(OK, node.SendStringMessage(D, "hey"));
- EXPECT_EQ(OK, node.node().ClosePort(D));
-
- // Now send B as new port E.
-
- EXPECT_EQ(OK, node.SendStringMessageWithPort(X, "foo", B));
- EXPECT_EQ(OK, node.node().ClosePort(X));
-
- ASSERT_TRUE(node.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef E;
- ASSERT_EQ(OK, node.node().GetPort(message->ports()[0], &E));
-
- EXPECT_EQ(OK, node.node().ClosePort(Y));
-
- WaitForIdle();
-
- // E should receive the message originally sent to B, and it should also be
- // aware of D's closure.
-
- ASSERT_TRUE(node.ReadMessage(E, &message));
- EXPECT_TRUE(MessageEquals(message, "hey"));
-
- PortStatus status;
- EXPECT_EQ(OK, node.node().GetStatus(E, &status));
- EXPECT_FALSE(status.receiving_messages);
- EXPECT_FALSE(status.has_messages);
- EXPECT_TRUE(status.peer_closed);
-
- EXPECT_EQ(OK, node.node().ClosePort(E));
-
- WaitForIdle();
-
- EXPECT_TRUE(node.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, MergePorts) {
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- // Setup two independent port pairs, A-B on node0 and C-D on node1.
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
-
- // Write a message on A.
- EXPECT_EQ(OK, node0.SendStringMessage(A, "hey"));
-
- // Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
-
- WaitForIdle();
-
- // Expect all proxies to be gone once idle.
- EXPECT_TRUE(
- node0.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
- EXPECT_TRUE(
- node1.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
-
- // Expect D to have received the message sent on A.
- ScopedMessage message;
- ASSERT_TRUE(node1.ReadMessage(D, &message));
- EXPECT_TRUE(MessageEquals(message, "hey"));
-
- EXPECT_EQ(OK, node0.node().ClosePort(A));
- EXPECT_EQ(OK, node1.node().ClosePort(D));
-
- // No more ports should be open.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, MergePortWithClosedPeer1) {
- // This tests that the right thing happens when initiating a merge on a port
- // whose peer has already been closed.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- // Setup two independent port pairs, A-B on node0 and C-D on node1.
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
-
- // Write a message on A.
- EXPECT_EQ(OK, node0.SendStringMessage(A, "hey"));
-
- // Close A.
- EXPECT_EQ(OK, node0.node().ClosePort(A));
-
- // Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
-
- WaitForIdle();
-
- // Expect all proxies to be gone once idle. node0 should have no ports since
- // A was explicitly closed.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(
- node1.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
-
- // Expect D to have received the message sent on A.
- ScopedMessage message;
- ASSERT_TRUE(node1.ReadMessage(D, &message));
- EXPECT_TRUE(MessageEquals(message, "hey"));
-
- EXPECT_EQ(OK, node1.node().ClosePort(D));
-
- // No more ports should be open.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, MergePortWithClosedPeer2) {
- // This tests that the right thing happens when merging into a port whose peer
- // has already been closed.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- // Setup two independent port pairs, A-B on node0 and C-D on node1.
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
-
- // Write a message on D and close it.
- EXPECT_EQ(OK, node0.SendStringMessage(D, "hey"));
- EXPECT_EQ(OK, node1.node().ClosePort(D));
-
- // Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
-
- WaitForIdle();
-
- // Expect all proxies to be gone once idle. node1 should have no ports since
- // D was explicitly closed.
- EXPECT_TRUE(
- node0.node().CanShutdownCleanly(Node::ShutdownPolicy::ALLOW_LOCAL_PORTS));
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-
- // Expect A to have received the message sent on D.
- ScopedMessage message;
- ASSERT_TRUE(node0.ReadMessage(A, &message));
- EXPECT_TRUE(MessageEquals(message, "hey"));
-
- EXPECT_EQ(OK, node0.node().ClosePort(A));
-
- // No more ports should be open.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, MergePortsWithClosedPeers) {
- // This tests that no residual ports are left behind if two ports are merged
- // when both of their peers have been closed.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- // Setup two independent port pairs, A-B on node0 and C-D on node1.
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
-
- // Close A and D.
- EXPECT_EQ(OK, node0.node().ClosePort(A));
- EXPECT_EQ(OK, node1.node().ClosePort(D));
-
- WaitForIdle();
-
- // Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
-
- WaitForIdle();
-
- // Expect everything to have gone away.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, MergePortsWithMovedPeers) {
- // This tests that ports can be merged successfully even if their peers are
- // moved around.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- // Setup two independent port pairs, A-B on node0 and C-D on node1.
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
-
- // Set up another pair X-Y for moving ports on node0.
- PortRef X, Y;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&X, &Y));
-
- ScopedMessage message;
-
- // Move A to new port E.
- EXPECT_EQ(OK, node0.SendStringMessageWithPort(X, "foo", A));
- ASSERT_TRUE(node0.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef E;
- ASSERT_EQ(OK, node0.node().GetPort(message->ports()[0], &E));
-
- EXPECT_EQ(OK, node0.node().ClosePort(X));
- EXPECT_EQ(OK, node0.node().ClosePort(Y));
-
- // Write messages on E and D.
- EXPECT_EQ(OK, node0.SendStringMessage(E, "hey"));
- EXPECT_EQ(OK, node1.SendStringMessage(D, "hi"));
-
- // Initiate a merge between B and C.
- EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
-
- WaitForIdle();
-
- // Expect to receive D's message on E and E's message on D.
- ASSERT_TRUE(node0.ReadMessage(E, &message));
- EXPECT_TRUE(MessageEquals(message, "hi"));
- ASSERT_TRUE(node1.ReadMessage(D, &message));
- EXPECT_TRUE(MessageEquals(message, "hey"));
-
- // Close E and D.
- EXPECT_EQ(OK, node0.node().ClosePort(E));
- EXPECT_EQ(OK, node1.node().ClosePort(D));
-
- WaitForIdle();
-
- // Expect everything to have gone away.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-TEST_F(PortsTest, MergePortsFailsGracefully) {
- // This tests that the system remains in a well-defined state if something
- // goes wrong during port merge.
-
- TestNode node0(0);
- AddNode(&node0);
-
- TestNode node1(1);
- AddNode(&node1);
-
- // Setup two independent port pairs, A-B on node0 and C-D on node1.
- PortRef A, B, C, D;
- EXPECT_EQ(OK, node0.node().CreatePortPair(&A, &B));
- EXPECT_EQ(OK, node1.node().CreatePortPair(&C, &D));
-
- ScopedMessage message;
- PortRef X, Y;
- EXPECT_EQ(OK, node1.node().CreatePortPair(&X, &Y));
-
- // Block the merge from proceeding until we can do something stupid with port
- // C. This avoids the test logic racing with async merge logic.
- node1.BlockOnEvent(EventType::kMergePort);
-
- // Initiate the merge between B and C.
- EXPECT_EQ(OK, node0.node().MergePorts(B, node1.name(), C.name()));
-
- // Move C to a new port E. This is not a sane use of Node's public API but
- // is still hypothetically possible. It allows us to force a merge failure
- // because C will be in an invalid state by the term the merge is processed.
- // As a result, B should be closed.
- EXPECT_EQ(OK, node1.SendStringMessageWithPort(X, "foo", C));
-
- node1.Unblock();
-
- ASSERT_TRUE(node1.ReadMessage(Y, &message));
- ASSERT_EQ(1u, message->num_ports());
- PortRef E;
- ASSERT_EQ(OK, node1.node().GetPort(message->ports()[0], &E));
-
- EXPECT_EQ(OK, node1.node().ClosePort(X));
- EXPECT_EQ(OK, node1.node().ClosePort(Y));
-
- WaitForIdle();
-
- // C goes away as a result of normal proxy removal. B should have been closed
- // cleanly by the failed MergePorts.
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node1.node().GetPort(C.name(), &C));
- EXPECT_EQ(ERROR_PORT_UNKNOWN, node0.node().GetPort(B.name(), &B));
-
- // Close A, D, and E.
- EXPECT_EQ(OK, node0.node().ClosePort(A));
- EXPECT_EQ(OK, node1.node().ClosePort(D));
- EXPECT_EQ(OK, node1.node().ClosePort(E));
-
- WaitForIdle();
-
- // Expect everything to have gone away.
- EXPECT_TRUE(node0.node().CanShutdownCleanly());
- EXPECT_TRUE(node1.node().CanShutdownCleanly());
-}
-
-} // namespace test
-} // namespace ports
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports/user_data.h b/mojo/edk/system/ports/user_data.h
deleted file mode 100644
index 73e7d17..0000000
--- a/mojo/edk/system/ports/user_data.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_USER_DATA_H_
-#define MOJO_EDK_SYSTEM_PORTS_USER_DATA_H_
-
-#include "base/memory/ref_counted.h"
-
-namespace mojo {
-namespace edk {
-namespace ports {
-
-class UserData : public base::RefCountedThreadSafe<UserData> {
- protected:
- friend class base::RefCountedThreadSafe<UserData>;
-
- virtual ~UserData() {}
-};
-
-} // namespace ports
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_USER_DATA_H_
diff --git a/mojo/edk/system/ports_message.cc b/mojo/edk/system/ports_message.cc
deleted file mode 100644
index 5f3e8c0..0000000
--- a/mojo/edk/system/ports_message.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/ports_message.h"
-
-#include "base/memory/ptr_util.h"
-#include "mojo/edk/system/node_channel.h"
-
-namespace mojo {
-namespace edk {
-
-// static
-std::unique_ptr<PortsMessage> PortsMessage::NewUserMessage(
- size_t num_payload_bytes,
- size_t num_ports,
- size_t num_handles) {
- return base::WrapUnique(
- new PortsMessage(num_payload_bytes, num_ports, num_handles));
-}
-
-PortsMessage::~PortsMessage() {}
-
-PortsMessage::PortsMessage(size_t num_payload_bytes,
- size_t num_ports,
- size_t num_handles)
- : ports::Message(num_payload_bytes, num_ports) {
- size_t size = num_header_bytes_ + num_ports_bytes_ + num_payload_bytes;
- void* ptr;
- channel_message_ = NodeChannel::CreatePortsMessage(size, &ptr, num_handles);
- InitializeUserMessageHeader(ptr);
-}
-
-PortsMessage::PortsMessage(size_t num_header_bytes,
- size_t num_payload_bytes,
- size_t num_ports_bytes,
- Channel::MessagePtr channel_message)
- : ports::Message(num_header_bytes,
- num_payload_bytes,
- num_ports_bytes) {
- if (channel_message) {
- channel_message_ = std::move(channel_message);
- void* data;
- size_t num_data_bytes;
- NodeChannel::GetPortsMessageData(channel_message_.get(), &data,
- &num_data_bytes);
- start_ = static_cast<char*>(data);
- } else {
- // TODO: Clean this up. In practice this branch of the constructor should
- // only be reached from Node-internal calls to AllocMessage, which never
- // carry ports or non-header bytes.
- CHECK_EQ(num_payload_bytes, 0u);
- CHECK_EQ(num_ports_bytes, 0u);
- void* ptr;
- channel_message_ =
- NodeChannel::CreatePortsMessage(num_header_bytes, &ptr, 0);
- start_ = static_cast<char*>(ptr);
- }
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/ports_message.h b/mojo/edk/system/ports_message.h
deleted file mode 100644
index 542b981..0000000
--- a/mojo/edk/system/ports_message.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_PORTS_MESSAGE_H__
-#define MOJO_EDK_SYSTEM_PORTS_MESSAGE_H__
-
-#include <memory>
-#include <utility>
-
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/system/channel.h"
-#include "mojo/edk/system/ports/message.h"
-#include "mojo/edk/system/ports/name.h"
-
-namespace mojo {
-namespace edk {
-
-class NodeController;
-
-class PortsMessage : public ports::Message {
- public:
- static std::unique_ptr<PortsMessage> NewUserMessage(size_t num_payload_bytes,
- size_t num_ports,
- size_t num_handles);
-
- ~PortsMessage() override;
-
- size_t num_handles() const { return channel_message_->num_handles(); }
- bool has_handles() const { return channel_message_->has_handles(); }
-
- void SetHandles(ScopedPlatformHandleVectorPtr handles) {
- channel_message_->SetHandles(std::move(handles));
- }
-
- ScopedPlatformHandleVectorPtr TakeHandles() {
- return channel_message_->TakeHandles();
- }
-
- Channel::MessagePtr TakeChannelMessage() {
- return std::move(channel_message_);
- }
-
- void set_source_node(const ports::NodeName& name) { source_node_ = name; }
- const ports::NodeName& source_node() const { return source_node_; }
-
- private:
- friend class NodeController;
-
- // Construct a new user PortsMessage backed by a new Channel::Message.
- PortsMessage(size_t num_payload_bytes, size_t num_ports, size_t num_handles);
-
- // Construct a new PortsMessage backed by a Channel::Message. If
- // |channel_message| is null, a new one is allocated internally.
- PortsMessage(size_t num_header_bytes,
- size_t num_payload_bytes,
- size_t num_ports_bytes,
- Channel::MessagePtr channel_message);
-
- Channel::MessagePtr channel_message_;
-
- // The node name from which this message was received, if known.
- ports::NodeName source_node_ = ports::kInvalidNodeName;
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_PORTS_MESSAGE_H__
diff --git a/mojo/edk/system/request_context.cc b/mojo/edk/system/request_context.cc
deleted file mode 100644
index 5de65d7..0000000
--- a/mojo/edk/system/request_context.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/request_context.h"
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/threading/thread_local.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-base::LazyInstance<base::ThreadLocalPointer<RequestContext>>::Leaky
- g_current_context = LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-RequestContext::RequestContext() : RequestContext(Source::LOCAL_API_CALL) {}
-
-RequestContext::RequestContext(Source source)
- : source_(source), tls_context_(g_current_context.Pointer()) {
- // We allow nested RequestContexts to exist as long as they aren't actually
- // used for anything.
- if (!tls_context_->Get())
- tls_context_->Set(this);
-}
-
-RequestContext::~RequestContext() {
- if (IsCurrent()) {
- // NOTE: Callbacks invoked by this destructor are allowed to initiate new
- // EDK requests on this thread, so we need to reset the thread-local context
- // pointer before calling them. We persist the original notification source
- // since we're starting over at the bottom of the stack.
- tls_context_->Set(nullptr);
-
- MojoWatcherNotificationFlags flags = MOJO_WATCHER_NOTIFICATION_FLAG_NONE;
- if (source_ == Source::SYSTEM)
- flags |= MOJO_WATCHER_NOTIFICATION_FLAG_FROM_SYSTEM;
-
- // We send all cancellation notifications first. This is necessary because
- // it's possible that cancelled watches have other pending notifications
- // attached to this RequestContext.
- //
- // From the application's perspective the watch is cancelled as soon as this
- // notification is received, and dispatching the cancellation notification
- // updates some internal Watch state to ensure no further notifications
- // fire. Because notifications on a single Watch are mutually exclusive,
- // this is sufficient to guarantee that MOJO_RESULT_CANCELLED is the last
- // notification received; which is the guarantee the API makes.
- for (const scoped_refptr<Watch>& watch :
- watch_cancel_finalizers_.container()) {
- static const HandleSignalsState closed_state = {0, 0};
-
- // Establish a new RequestContext to capture and run any new notifications
- // triggered by the callback invocation.
- RequestContext inner_context(source_);
- watch->InvokeCallback(MOJO_RESULT_CANCELLED, closed_state, flags);
- }
-
- for (const WatchNotifyFinalizer& watch :
- watch_notify_finalizers_.container()) {
- RequestContext inner_context(source_);
- watch.watch->InvokeCallback(watch.result, watch.state, flags);
- }
- } else {
- // It should be impossible for nested contexts to have finalizers.
- DCHECK(watch_notify_finalizers_.container().empty());
- DCHECK(watch_cancel_finalizers_.container().empty());
- }
-}
-
-// static
-RequestContext* RequestContext::current() {
- DCHECK(g_current_context.Pointer()->Get());
- return g_current_context.Pointer()->Get();
-}
-
-void RequestContext::AddWatchNotifyFinalizer(scoped_refptr<Watch> watch,
- MojoResult result,
- const HandleSignalsState& state) {
- DCHECK(IsCurrent());
- watch_notify_finalizers_->push_back(
- WatchNotifyFinalizer(std::move(watch), result, state));
-}
-
-void RequestContext::AddWatchCancelFinalizer(scoped_refptr<Watch> watch) {
- DCHECK(IsCurrent());
- watch_cancel_finalizers_->push_back(std::move(watch));
-}
-
-bool RequestContext::IsCurrent() const {
- return tls_context_->Get() == this;
-}
-
-RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
- scoped_refptr<Watch> watch,
- MojoResult result,
- const HandleSignalsState& state)
- : watch(std::move(watch)), result(result), state(state) {}
-
-RequestContext::WatchNotifyFinalizer::WatchNotifyFinalizer(
- const WatchNotifyFinalizer& other) = default;
-
-RequestContext::WatchNotifyFinalizer::~WatchNotifyFinalizer() {}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/request_context.h b/mojo/edk/system/request_context.h
deleted file mode 100644
index d1f43bd..0000000
--- a/mojo/edk/system/request_context.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_REQUEST_CONTEXT_H_
-#define MOJO_EDK_SYSTEM_REQUEST_CONTEXT_H_
-
-#include "base/containers/stack_container.h"
-#include "base/macros.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/edk/system/watch.h"
-
-namespace base {
-template<typename T> class ThreadLocalPointer;
-}
-
-namespace mojo {
-namespace edk {
-
-// A RequestContext is a thread-local object which exists for the duration of
-// a single system API call. It is constructed immediately upon EDK entry and
-// destructed immediately before returning to the caller, after any internal
-// locks have been released.
-//
-// NOTE: It is legal to construct a RequestContext while another one already
-// exists on the current thread, but it is not safe to use the nested context
-// for any reason. Therefore it is important to always use
-// |RequestContext::current()| rather than referring to any local instance
-// directly.
-class MOJO_SYSTEM_IMPL_EXPORT RequestContext {
- public:
- // Identifies the source of the current stack frame's RequestContext.
- enum class Source {
- LOCAL_API_CALL,
- SYSTEM,
- };
-
- // Constructs a RequestContext with a LOCAL_API_CALL Source.
- RequestContext();
-
- explicit RequestContext(Source source);
- ~RequestContext();
-
- // Returns the current thread-local RequestContext.
- static RequestContext* current();
-
- Source source() const { return source_; }
-
- // Adds a finalizer to this RequestContext corresponding to a watch callback
- // which should be triggered in response to some handle state change. If
- // the WatcherDispatcher hasn't been closed by the time this RequestContext is
- // destroyed, its WatchCallback will be invoked with |result| and |state|
- // arguments.
- void AddWatchNotifyFinalizer(scoped_refptr<Watch> watch,
- MojoResult result,
- const HandleSignalsState& state);
-
- // Adds a finalizer to this RequestContext corresponding to a watch callback
- // which should be triggered to notify of watch cancellation. This appends to
- // a separate finalizer list from AddWatchNotifyFinalizer, as pending
- // cancellations must always preempt other pending notifications.
- void AddWatchCancelFinalizer(scoped_refptr<Watch> watch);
-
- private:
- // Is this request context the current one?
- bool IsCurrent() const;
-
- struct WatchNotifyFinalizer {
- WatchNotifyFinalizer(scoped_refptr<Watch> watch,
- MojoResult result,
- const HandleSignalsState& state);
- WatchNotifyFinalizer(const WatchNotifyFinalizer& other);
- ~WatchNotifyFinalizer();
-
- scoped_refptr<Watch> watch;
- MojoResult result;
- HandleSignalsState state;
- };
-
- // NOTE: This upper bound was chosen somewhat arbitrarily after observing some
- // rare worst-case behavior in Chrome. A vast majority of RequestContexts only
- // ever accumulate 0 or 1 finalizers.
- static const size_t kStaticWatchFinalizersCapacity = 8;
-
- using WatchNotifyFinalizerList =
- base::StackVector<WatchNotifyFinalizer, kStaticWatchFinalizersCapacity>;
- using WatchCancelFinalizerList =
- base::StackVector<scoped_refptr<Watch>, kStaticWatchFinalizersCapacity>;
-
- const Source source_;
-
- WatchNotifyFinalizerList watch_notify_finalizers_;
- WatchCancelFinalizerList watch_cancel_finalizers_;
-
- // Pointer to the TLS context. Although this can easily be accessed via the
- // global LazyInstance, accessing a LazyInstance has a large cost relative to
- // the rest of this class and its usages.
- base::ThreadLocalPointer<RequestContext>* tls_context_;
-
- DISALLOW_COPY_AND_ASSIGN(RequestContext);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_REQUEST_CONTEXT_H_
diff --git a/mojo/edk/system/shared_buffer_dispatcher.cc b/mojo/edk/system/shared_buffer_dispatcher.cc
deleted file mode 100644
index df39105..0000000
--- a/mojo/edk/system/shared_buffer_dispatcher.cc
+++ /dev/null
@@ -1,339 +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/shared_buffer_dispatcher.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-#include <memory>
-#include <utility>
-
-#include "base/logging.h"
-#include "mojo/edk/embedder/embedder_internal.h"
-#include "mojo/edk/system/configuration.h"
-#include "mojo/edk/system/node_controller.h"
-#include "mojo/edk/system/options_validation.h"
-
-namespace mojo {
-namespace edk {
-
-namespace {
-
-#pragma pack(push, 1)
-
-struct SerializedState {
- uint64_t num_bytes;
- uint32_t flags;
- uint32_t padding;
-};
-
-const uint32_t kSerializedStateFlagsReadOnly = 1 << 0;
-
-#pragma pack(pop)
-
-static_assert(sizeof(SerializedState) % 8 == 0,
- "Invalid SerializedState size.");
-
-} // namespace
-
-// static
-const MojoCreateSharedBufferOptions
- SharedBufferDispatcher::kDefaultCreateOptions = {
- static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE};
-
-// static
-MojoResult SharedBufferDispatcher::ValidateCreateOptions(
- const MojoCreateSharedBufferOptions* in_options,
- MojoCreateSharedBufferOptions* out_options) {
- const MojoCreateSharedBufferOptionsFlags kKnownFlags =
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
-
- *out_options = kDefaultCreateOptions;
- if (!in_options)
- return MOJO_RESULT_OK;
-
- UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options);
- if (!reader.is_valid())
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader))
- return MOJO_RESULT_OK;
- if ((reader.options().flags & ~kKnownFlags))
- return MOJO_RESULT_UNIMPLEMENTED;
- out_options->flags = reader.options().flags;
-
- // Checks for fields beyond |flags|:
-
- // (Nothing here yet.)
-
- return MOJO_RESULT_OK;
-}
-
-// static
-MojoResult SharedBufferDispatcher::Create(
- const MojoCreateSharedBufferOptions& /*validated_options*/,
- NodeController* node_controller,
- uint64_t num_bytes,
- scoped_refptr<SharedBufferDispatcher>* result) {
- if (!num_bytes)
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (num_bytes > GetConfiguration().max_shared_memory_num_bytes)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- scoped_refptr<PlatformSharedBuffer> shared_buffer;
- if (node_controller) {
- shared_buffer =
- node_controller->CreateSharedBuffer(static_cast<size_t>(num_bytes));
- } else {
- shared_buffer =
- PlatformSharedBuffer::Create(static_cast<size_t>(num_bytes));
- }
- if (!shared_buffer)
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
-
- *result = CreateInternal(std::move(shared_buffer));
- return MOJO_RESULT_OK;
-}
-
-// static
-MojoResult SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
- const scoped_refptr<PlatformSharedBuffer>& shared_buffer,
- scoped_refptr<SharedBufferDispatcher>* result) {
- if (!shared_buffer)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- *result = CreateInternal(shared_buffer);
- return MOJO_RESULT_OK;
-}
-
-// static
-scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize(
- const void* bytes,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* platform_handles,
- size_t num_platform_handles) {
- if (num_bytes != sizeof(SerializedState)) {
- LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
- return nullptr;
- }
-
- const SerializedState* serialization =
- static_cast<const SerializedState*>(bytes);
- if (!serialization->num_bytes) {
- LOG(ERROR)
- << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
- return nullptr;
- }
-
- if (!platform_handles || num_platform_handles != 1 || num_ports) {
- LOG(ERROR)
- << "Invalid serialized shared buffer dispatcher (missing handles)";
- return nullptr;
- }
-
- // Starts off invalid, which is what we want.
- PlatformHandle platform_handle;
- // We take ownership of the handle, so we have to invalidate the one in
- // |platform_handles|.
- std::swap(platform_handle, *platform_handles);
-
- // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be
- // closed even if creation fails.
- bool read_only = (serialization->flags & kSerializedStateFlagsReadOnly);
- scoped_refptr<PlatformSharedBuffer> shared_buffer(
- PlatformSharedBuffer::CreateFromPlatformHandle(
- static_cast<size_t>(serialization->num_bytes), read_only,
- ScopedPlatformHandle(platform_handle)));
- if (!shared_buffer) {
- LOG(ERROR)
- << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
- return nullptr;
- }
-
- return CreateInternal(std::move(shared_buffer));
-}
-
-scoped_refptr<PlatformSharedBuffer>
-SharedBufferDispatcher::PassPlatformSharedBuffer() {
- base::AutoLock lock(lock_);
- if (!shared_buffer_ || in_transit_)
- return nullptr;
-
- scoped_refptr<PlatformSharedBuffer> retval = shared_buffer_;
- shared_buffer_ = nullptr;
- return retval;
-}
-
-Dispatcher::Type SharedBufferDispatcher::GetType() const {
- return Type::SHARED_BUFFER;
-}
-
-MojoResult SharedBufferDispatcher::Close() {
- base::AutoLock lock(lock_);
- if (in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- shared_buffer_ = nullptr;
- return MOJO_RESULT_OK;
-}
-
-MojoResult SharedBufferDispatcher::DuplicateBufferHandle(
- const MojoDuplicateBufferHandleOptions* options,
- scoped_refptr<Dispatcher>* new_dispatcher) {
- MojoDuplicateBufferHandleOptions validated_options;
- MojoResult result = ValidateDuplicateOptions(options, &validated_options);
- if (result != MOJO_RESULT_OK)
- return result;
-
- // Note: Since this is "duplicate", we keep our ref to |shared_buffer_|.
- base::AutoLock lock(lock_);
- if (in_transit_)
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if ((validated_options.flags &
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY) &&
- (!shared_buffer_->IsReadOnly())) {
- // If a read-only duplicate is requested and |shared_buffer_| is not
- // read-only, make a read-only duplicate of |shared_buffer_|.
- scoped_refptr<PlatformSharedBuffer> read_only_buffer =
- shared_buffer_->CreateReadOnlyDuplicate();
- if (!read_only_buffer)
- return MOJO_RESULT_FAILED_PRECONDITION;
- DCHECK(read_only_buffer->IsReadOnly());
- *new_dispatcher = CreateInternal(std::move(read_only_buffer));
- return MOJO_RESULT_OK;
- }
-
- *new_dispatcher = CreateInternal(shared_buffer_);
- return MOJO_RESULT_OK;
-}
-
-MojoResult SharedBufferDispatcher::MapBuffer(
- uint64_t offset,
- uint64_t num_bytes,
- MojoMapBufferFlags flags,
- std::unique_ptr<PlatformSharedBufferMapping>* mapping) {
- if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
- return MOJO_RESULT_INVALID_ARGUMENT;
- if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- base::AutoLock lock(lock_);
- DCHECK(shared_buffer_);
- if (in_transit_ ||
- !shared_buffer_->IsValidMap(static_cast<size_t>(offset),
- static_cast<size_t>(num_bytes))) {
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- DCHECK(mapping);
- *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset),
- static_cast<size_t>(num_bytes));
- if (!*mapping) {
- LOG(ERROR) << "Unable to map: read_only" << shared_buffer_->IsReadOnly();
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- }
-
- return MOJO_RESULT_OK;
-}
-
-void SharedBufferDispatcher::StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_platform_handles) {
- *num_bytes = sizeof(SerializedState);
- *num_ports = 0;
- *num_platform_handles = 1;
-}
-
-bool SharedBufferDispatcher::EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) {
- SerializedState* serialization =
- static_cast<SerializedState*>(destination);
- base::AutoLock lock(lock_);
- serialization->num_bytes =
- static_cast<uint64_t>(shared_buffer_->GetNumBytes());
- serialization->flags =
- (shared_buffer_->IsReadOnly() ? kSerializedStateFlagsReadOnly : 0);
- serialization->padding = 0;
-
- handle_for_transit_ = shared_buffer_->DuplicatePlatformHandle();
- if (!handle_for_transit_.is_valid()) {
- shared_buffer_ = nullptr;
- return false;
- }
- handles[0] = handle_for_transit_.get();
- return true;
-}
-
-bool SharedBufferDispatcher::BeginTransit() {
- base::AutoLock lock(lock_);
- if (in_transit_)
- return false;
- in_transit_ = static_cast<bool>(shared_buffer_);
- return in_transit_;
-}
-
-void SharedBufferDispatcher::CompleteTransitAndClose() {
- base::AutoLock lock(lock_);
- in_transit_ = false;
- shared_buffer_ = nullptr;
- ignore_result(handle_for_transit_.release());
-}
-
-void SharedBufferDispatcher::CancelTransit() {
- base::AutoLock lock(lock_);
- in_transit_ = false;
- handle_for_transit_.reset();
-}
-
-SharedBufferDispatcher::SharedBufferDispatcher(
- scoped_refptr<PlatformSharedBuffer> shared_buffer)
- : shared_buffer_(shared_buffer) {
- DCHECK(shared_buffer_);
-}
-
-SharedBufferDispatcher::~SharedBufferDispatcher() {
- DCHECK(!shared_buffer_ && !in_transit_);
-}
-
-// static
-MojoResult SharedBufferDispatcher::ValidateDuplicateOptions(
- const MojoDuplicateBufferHandleOptions* in_options,
- MojoDuplicateBufferHandleOptions* out_options) {
- const MojoDuplicateBufferHandleOptionsFlags kKnownFlags =
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
- static const MojoDuplicateBufferHandleOptions kDefaultOptions = {
- static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)),
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
-
- *out_options = kDefaultOptions;
- if (!in_options)
- return MOJO_RESULT_OK;
-
- UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options);
- if (!reader.is_valid())
- return MOJO_RESULT_INVALID_ARGUMENT;
-
- if (!OPTIONS_STRUCT_HAS_MEMBER(MojoDuplicateBufferHandleOptions, flags,
- reader))
- return MOJO_RESULT_OK;
- if ((reader.options().flags & ~kKnownFlags))
- return MOJO_RESULT_UNIMPLEMENTED;
- out_options->flags = reader.options().flags;
-
- // Checks for fields beyond |flags|:
-
- // (Nothing here yet.)
-
- return MOJO_RESULT_OK;
-}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/shared_buffer_dispatcher.h b/mojo/edk/system/shared_buffer_dispatcher.h
deleted file mode 100644
index 6015595..0000000
--- a/mojo/edk/system/shared_buffer_dispatcher.h
+++ /dev/null
@@ -1,127 +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_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/macros.h"
-#include "mojo/edk/embedder/platform_handle_vector.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/system_impl_export.h"
-
-namespace mojo {
-
-namespace edk {
-class NodeController;
-
-class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher {
- public:
- // The default options to use for |MojoCreateSharedBuffer()|. (Real uses
- // should obtain this via |ValidateCreateOptions()| with a null |in_options|;
- // this is exposed directly for testing convenience.)
- static const MojoCreateSharedBufferOptions kDefaultCreateOptions;
-
- // Validates and/or sets default options for |MojoCreateSharedBufferOptions|.
- // If non-null, |in_options| must point to a struct of at least
- // |in_options->struct_size| bytes. |out_options| must point to a (current)
- // |MojoCreateSharedBufferOptions| and will be entirely overwritten on success
- // (it may be partly overwritten on failure).
- static MojoResult ValidateCreateOptions(
- const MojoCreateSharedBufferOptions* in_options,
- MojoCreateSharedBufferOptions* out_options);
-
- // Static factory method: |validated_options| must be validated (obviously).
- // On failure, |*result| will be left as-is.
- // TODO(vtl): This should probably be made to return a scoped_refptr and have
- // a MojoResult out parameter instead.
- static MojoResult Create(
- const MojoCreateSharedBufferOptions& validated_options,
- NodeController* node_controller,
- uint64_t num_bytes,
- scoped_refptr<SharedBufferDispatcher>* result);
-
- // Create a |SharedBufferDispatcher| from |shared_buffer|.
- static MojoResult CreateFromPlatformSharedBuffer(
- const scoped_refptr<PlatformSharedBuffer>& shared_buffer,
- scoped_refptr<SharedBufferDispatcher>* result);
-
- // The "opposite" of SerializeAndClose(). Called by Dispatcher::Deserialize().
- static scoped_refptr<SharedBufferDispatcher> Deserialize(
- const void* bytes,
- size_t num_bytes,
- const ports::PortName* ports,
- size_t num_ports,
- PlatformHandle* platform_handles,
- size_t num_platform_handles);
-
- // Passes the underlying platform shared buffer. This dispatcher must be
- // closed after calling this function.
- scoped_refptr<PlatformSharedBuffer> PassPlatformSharedBuffer();
-
- // Dispatcher:
- Type GetType() const override;
- MojoResult Close() override;
- MojoResult DuplicateBufferHandle(
- const MojoDuplicateBufferHandleOptions* options,
- scoped_refptr<Dispatcher>* new_dispatcher) override;
- MojoResult MapBuffer(
- uint64_t offset,
- uint64_t num_bytes,
- MojoMapBufferFlags flags,
- std::unique_ptr<PlatformSharedBufferMapping>* mapping) override;
- void StartSerialize(uint32_t* num_bytes,
- uint32_t* num_ports,
- uint32_t* num_platform_handles) override;
- bool EndSerialize(void* destination,
- ports::PortName* ports,
- PlatformHandle* handles) override;
- bool BeginTransit() override;
- void CompleteTransitAndClose() override;
- void CancelTransit() override;
-
- private:
- static scoped_refptr<SharedBufferDispatcher> CreateInternal(
- scoped_refptr<PlatformSharedBuffer> shared_buffer) {
- return make_scoped_refptr(
- new SharedBufferDispatcher(std::move(shared_buffer)));
- }
-
- explicit SharedBufferDispatcher(
- scoped_refptr<PlatformSharedBuffer> shared_buffer);
- ~SharedBufferDispatcher() override;
-
- // Validates and/or sets default options for
- // |MojoDuplicateBufferHandleOptions|. If non-null, |in_options| must point to
- // a struct of at least |in_options->struct_size| bytes. |out_options| must
- // point to a (current) |MojoDuplicateBufferHandleOptions| and will be
- // entirely overwritten on success (it may be partly overwritten on failure).
- static MojoResult ValidateDuplicateOptions(
- const MojoDuplicateBufferHandleOptions* in_options,
- MojoDuplicateBufferHandleOptions* out_options);
-
- // Guards access to |shared_buffer_|.
- base::Lock lock_;
-
- bool in_transit_ = false;
-
- // We keep a copy of the buffer's platform handle during transit so we can
- // close it if something goes wrong.
- ScopedPlatformHandle handle_for_transit_;
-
- scoped_refptr<PlatformSharedBuffer> shared_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(SharedBufferDispatcher);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_SHARED_BUFFER_DISPATCHER_H_
diff --git a/mojo/edk/system/shared_buffer_dispatcher_unittest.cc b/mojo/edk/system/shared_buffer_dispatcher_unittest.cc
deleted file mode 100644
index c95bdc3..0000000
--- a/mojo/edk/system/shared_buffer_dispatcher_unittest.cc
+++ /dev/null
@@ -1,312 +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/shared_buffer_dispatcher.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <limits>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/embedder/platform_shared_buffer.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-// NOTE(vtl): There's currently not much to test for in
-// |SharedBufferDispatcher::ValidateCreateOptions()|, but the tests should be
-// expanded if/when options are added, so I've kept the general form of the
-// tests from data_pipe_unittest.cc.
-
-const uint32_t kSizeOfCreateOptions = sizeof(MojoCreateSharedBufferOptions);
-
-// Does a cursory sanity check of |validated_options|. Calls
-// |ValidateCreateOptions()| on already-validated options. The validated options
-// should be valid, and the revalidated copy should be the same.
-void RevalidateCreateOptions(
- const MojoCreateSharedBufferOptions& validated_options) {
- EXPECT_EQ(kSizeOfCreateOptions, validated_options.struct_size);
- // Nothing to check for flags.
-
- MojoCreateSharedBufferOptions revalidated_options = {};
- EXPECT_EQ(MOJO_RESULT_OK,
- SharedBufferDispatcher::ValidateCreateOptions(
- &validated_options, &revalidated_options));
- EXPECT_EQ(validated_options.struct_size, revalidated_options.struct_size);
- EXPECT_EQ(validated_options.flags, revalidated_options.flags);
-}
-
-class SharedBufferDispatcherTest : public testing::Test {
- public:
- SharedBufferDispatcherTest() {}
- ~SharedBufferDispatcherTest() override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SharedBufferDispatcherTest);
-};
-
-// Tests valid inputs to |ValidateCreateOptions()|.
-TEST_F(SharedBufferDispatcherTest, ValidateCreateOptionsValid) {
- // Default options.
- {
- MojoCreateSharedBufferOptions validated_options = {};
- EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::ValidateCreateOptions(
- nullptr, &validated_options));
- RevalidateCreateOptions(validated_options);
- }
-
- // Different flags.
- MojoCreateSharedBufferOptionsFlags flags_values[] = {
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE};
- for (size_t i = 0; i < arraysize(flags_values); i++) {
- const MojoCreateSharedBufferOptionsFlags flags = flags_values[i];
-
- // Different capacities (size 1).
- for (uint32_t capacity = 1; capacity <= 100 * 1000 * 1000; capacity *= 10) {
- MojoCreateSharedBufferOptions options = {
- kSizeOfCreateOptions, // |struct_size|.
- flags // |flags|.
- };
- MojoCreateSharedBufferOptions validated_options = {};
- EXPECT_EQ(MOJO_RESULT_OK,
- SharedBufferDispatcher::ValidateCreateOptions(
- &options, &validated_options))
- << capacity;
- RevalidateCreateOptions(validated_options);
- EXPECT_EQ(options.flags, validated_options.flags);
- }
- }
-}
-
-TEST_F(SharedBufferDispatcherTest, ValidateCreateOptionsInvalid) {
- // Invalid |struct_size|.
- {
- MojoCreateSharedBufferOptions options = {
- 1, // |struct_size|.
- MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE // |flags|.
- };
- MojoCreateSharedBufferOptions unused;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- SharedBufferDispatcher::ValidateCreateOptions(
- &options, &unused));
- }
-
- // Unknown |flags|.
- {
- MojoCreateSharedBufferOptions options = {
- kSizeOfCreateOptions, // |struct_size|.
- ~0u // |flags|.
- };
- MojoCreateSharedBufferOptions unused;
- EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- SharedBufferDispatcher::ValidateCreateOptions(
- &options, &unused));
- }
-}
-
-TEST_F(SharedBufferDispatcherTest, CreateAndMapBuffer) {
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions,
- nullptr, 100, &dispatcher));
- ASSERT_TRUE(dispatcher);
- EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher->GetType());
-
- // Make a couple of mappings.
- std::unique_ptr<PlatformSharedBufferMapping> mapping1;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(
- 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping1));
- ASSERT_TRUE(mapping1);
- ASSERT_TRUE(mapping1->GetBase());
- EXPECT_EQ(100u, mapping1->GetLength());
- // Write something.
- static_cast<char*>(mapping1->GetBase())[50] = 'x';
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping2;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(
- 50, 50, MOJO_MAP_BUFFER_FLAG_NONE, &mapping2));
- ASSERT_TRUE(mapping2);
- ASSERT_TRUE(mapping2->GetBase());
- EXPECT_EQ(50u, mapping2->GetLength());
- EXPECT_EQ('x', static_cast<char*>(mapping2->GetBase())[0]);
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
-
- // Check that we can still read/write to mappings after the dispatcher has
- // gone away.
- static_cast<char*>(mapping2->GetBase())[1] = 'y';
- EXPECT_EQ('y', static_cast<char*>(mapping1->GetBase())[51]);
-}
-
-TEST_F(SharedBufferDispatcherTest, CreateAndMapBufferFromPlatformBuffer) {
- scoped_refptr<PlatformSharedBuffer> platform_shared_buffer =
- PlatformSharedBuffer::Create(100);
- ASSERT_TRUE(platform_shared_buffer);
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- EXPECT_EQ(MOJO_RESULT_OK,
- SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
- platform_shared_buffer, &dispatcher));
- ASSERT_TRUE(dispatcher);
- EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher->GetType());
-
- // Make a couple of mappings.
- std::unique_ptr<PlatformSharedBufferMapping> mapping1;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(
- 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping1));
- ASSERT_TRUE(mapping1);
- ASSERT_TRUE(mapping1->GetBase());
- EXPECT_EQ(100u, mapping1->GetLength());
- // Write something.
- static_cast<char*>(mapping1->GetBase())[50] = 'x';
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping2;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(
- 50, 50, MOJO_MAP_BUFFER_FLAG_NONE, &mapping2));
- ASSERT_TRUE(mapping2);
- ASSERT_TRUE(mapping2->GetBase());
- EXPECT_EQ(50u, mapping2->GetLength());
- EXPECT_EQ('x', static_cast<char*>(mapping2->GetBase())[0]);
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
-
- // Check that we can still read/write to mappings after the dispatcher has
- // gone away.
- static_cast<char*>(mapping2->GetBase())[1] = 'y';
- EXPECT_EQ('y', static_cast<char*>(mapping1->GetBase())[51]);
-}
-
-TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandle) {
- scoped_refptr<SharedBufferDispatcher> dispatcher1;
- EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions,
- nullptr, 100, &dispatcher1));
-
- // Map and write something.
- std::unique_ptr<PlatformSharedBufferMapping> mapping;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->MapBuffer(
- 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping));
- static_cast<char*>(mapping->GetBase())[0] = 'x';
- mapping.reset();
-
- // Duplicate |dispatcher1| and then close it.
- scoped_refptr<Dispatcher> dispatcher2;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->DuplicateBufferHandle(
- nullptr, &dispatcher2));
- ASSERT_TRUE(dispatcher2);
- EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher2->GetType());
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close());
-
- // Map |dispatcher2| and read something.
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->MapBuffer(
- 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping));
- EXPECT_EQ('x', static_cast<char*>(mapping->GetBase())[0]);
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close());
-}
-
-TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsValid) {
- scoped_refptr<SharedBufferDispatcher> dispatcher1;
- EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions,
- nullptr, 100, &dispatcher1));
-
- MojoDuplicateBufferHandleOptions options[] = {
- {sizeof(MojoDuplicateBufferHandleOptions),
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE},
- {sizeof(MojoDuplicateBufferHandleOptions),
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY},
- {sizeof(MojoDuplicateBufferHandleOptionsFlags), ~0u}};
- for (size_t i = 0; i < arraysize(options); i++) {
- scoped_refptr<Dispatcher> dispatcher2;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->DuplicateBufferHandle(
- &options[i], &dispatcher2));
- ASSERT_TRUE(dispatcher2);
- EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher2->GetType());
- {
- std::unique_ptr<PlatformSharedBufferMapping> mapping;
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->MapBuffer(0, 100, 0, &mapping));
- }
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close());
- }
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close());
-}
-
-TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsInvalid) {
- scoped_refptr<SharedBufferDispatcher> dispatcher1;
- EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions,
- nullptr, 100, &dispatcher1));
-
- // Invalid |struct_size|.
- {
- MojoDuplicateBufferHandleOptions options = {
- 1u, MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
- scoped_refptr<Dispatcher> dispatcher2;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- dispatcher1->DuplicateBufferHandle(&options, &dispatcher2));
- EXPECT_FALSE(dispatcher2);
- }
-
- // Unknown |flags|.
- {
- MojoDuplicateBufferHandleOptions options = {
- sizeof(MojoDuplicateBufferHandleOptions), ~0u};
- scoped_refptr<Dispatcher> dispatcher2;
- EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
- dispatcher1->DuplicateBufferHandle(&options, &dispatcher2));
- EXPECT_FALSE(dispatcher2);
- }
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close());
-}
-
-TEST_F(SharedBufferDispatcherTest, CreateInvalidNumBytes) {
- // Size too big.
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
- SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions, nullptr,
- std::numeric_limits<uint64_t>::max(), &dispatcher));
- EXPECT_FALSE(dispatcher);
-
- // Zero size.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions, nullptr, 0,
- &dispatcher));
- EXPECT_FALSE(dispatcher);
-}
-
-TEST_F(SharedBufferDispatcherTest, MapBufferInvalidArguments) {
- scoped_refptr<SharedBufferDispatcher> dispatcher;
- EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create(
- SharedBufferDispatcher::kDefaultCreateOptions,
- nullptr, 100, &dispatcher));
-
- std::unique_ptr<PlatformSharedBufferMapping> mapping;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- dispatcher->MapBuffer(0, 101, MOJO_MAP_BUFFER_FLAG_NONE, &mapping));
- EXPECT_FALSE(mapping);
-
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- dispatcher->MapBuffer(1, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping));
- EXPECT_FALSE(mapping);
-
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- dispatcher->MapBuffer(0, 0, MOJO_MAP_BUFFER_FLAG_NONE, &mapping));
- EXPECT_FALSE(mapping);
-
- EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close());
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/shared_buffer_unittest.cc b/mojo/edk/system/shared_buffer_unittest.cc
deleted file mode 100644
index 3a72872..0000000
--- a/mojo/edk/system/shared_buffer_unittest.cc
+++ /dev/null
@@ -1,318 +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 <string.h>
-
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/memory/shared_memory.h"
-#include "base/strings/string_piece.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-using SharedBufferTest = test::MojoTestBase;
-
-TEST_F(SharedBufferTest, CreateSharedBuffer) {
- const std::string message = "hello";
- MojoHandle h = CreateBuffer(message.size());
- WriteToBuffer(h, 0, message);
- ExpectBufferContents(h, 0, message);
-}
-
-TEST_F(SharedBufferTest, DuplicateSharedBuffer) {
- const std::string message = "hello";
- MojoHandle h = CreateBuffer(message.size());
- WriteToBuffer(h, 0, message);
-
- MojoHandle dupe = DuplicateBuffer(h, false);
- ExpectBufferContents(dupe, 0, message);
-}
-
-TEST_F(SharedBufferTest, PassSharedBufferLocal) {
- const std::string message = "hello";
- MojoHandle h = CreateBuffer(message.size());
- WriteToBuffer(h, 0, message);
-
- MojoHandle dupe = DuplicateBuffer(h, false);
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
-
- WriteMessageWithHandles(p0, "...", &dupe, 1);
- EXPECT_EQ("...", ReadMessageWithHandles(p1, &dupe, 1));
-
- ExpectBufferContents(dupe, 0, message);
-}
-
-#if !defined(OS_IOS)
-
-// Reads a single message with a shared buffer handle, maps the buffer, copies
-// the message contents into it, then exits.
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CopyToBufferClient, SharedBufferTest, h) {
- MojoHandle b;
- std::string message = ReadMessageWithHandles(h, &b, 1);
- WriteToBuffer(b, 0, message);
-
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_F(SharedBufferTest, PassSharedBufferCrossProcess) {
- const std::string message = "hello";
- MojoHandle b = CreateBuffer(message.size());
-
- RUN_CHILD_ON_PIPE(CopyToBufferClient, h)
- MojoHandle dupe = DuplicateBuffer(b, false);
- WriteMessageWithHandles(h, message, &dupe, 1);
- WriteMessage(h, "quit");
- END_CHILD()
-
- ExpectBufferContents(b, 0, message);
-}
-
-// Creates a new buffer, maps it, writes a message contents to it, unmaps it,
-// and finally passes it back to the parent.
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateBufferClient, SharedBufferTest, h) {
- std::string message = ReadMessage(h);
- MojoHandle b = CreateBuffer(message.size());
- WriteToBuffer(b, 0, message);
- WriteMessageWithHandles(h, "have a buffer", &b, 1);
-
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_F(SharedBufferTest, PassSharedBufferFromChild) {
- const std::string message = "hello";
- MojoHandle b;
- RUN_CHILD_ON_PIPE(CreateBufferClient, h)
- WriteMessage(h, message);
- ReadMessageWithHandles(h, &b, 1);
- WriteMessage(h, "quit");
- END_CHILD()
-
- ExpectBufferContents(b, 0, message);
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBuffer, SharedBufferTest, h) {
- // Receive a pipe handle over the primordial pipe. This will be connected to
- // another child process.
- MojoHandle other_child;
- std::string message = ReadMessageWithHandles(h, &other_child, 1);
-
- // Create a new shared buffer.
- MojoHandle b = CreateBuffer(message.size());
-
- // Send a copy of the buffer to the parent and the other child.
- MojoHandle dupe = DuplicateBuffer(b, false);
- WriteMessageWithHandles(h, "", &b, 1);
- WriteMessageWithHandles(other_child, "", &dupe, 1);
-
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBuffer, SharedBufferTest, h) {
- // Receive a pipe handle over the primordial pipe. This will be connected to
- // another child process (running CreateAndPassBuffer).
- MojoHandle other_child;
- std::string message = ReadMessageWithHandles(h, &other_child, 1);
-
- // Receive a shared buffer from the other child.
- MojoHandle b;
- ReadMessageWithHandles(other_child, &b, 1);
-
- // Write the message from the parent into the buffer and exit.
- WriteToBuffer(b, 0, message);
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ("quit", ReadMessage(h));
-}
-
-TEST_F(SharedBufferTest, PassSharedBufferFromChildToChild) {
- const std::string message = "hello";
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
-
- MojoHandle b;
- RUN_CHILD_ON_PIPE(CreateAndPassBuffer, h0)
- RUN_CHILD_ON_PIPE(ReceiveAndEditBuffer, h1)
- // Send one end of the pipe to each child. The first child will create
- // and pass a buffer to the second child and back to us. The second child
- // will write our message into the buffer.
- WriteMessageWithHandles(h0, message, &p0, 1);
- WriteMessageWithHandles(h1, message, &p1, 1);
-
- // Receive the buffer back from the first child.
- ReadMessageWithHandles(h0, &b, 1);
-
- WriteMessage(h1, "quit");
- END_CHILD()
- WriteMessage(h0, "quit");
- END_CHILD()
-
- // The second child should have written this message.
- ExpectBufferContents(b, 0, message);
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBufferParent, SharedBufferTest,
- parent) {
- RUN_CHILD_ON_PIPE(CreateAndPassBuffer, child)
- // Read a pipe from the parent and forward it to our child.
- MojoHandle pipe;
- std::string message = ReadMessageWithHandles(parent, &pipe, 1);
-
- WriteMessageWithHandles(child, message, &pipe, 1);
-
- // Read a buffer handle from the child and pass it back to the parent.
- MojoHandle buffer;
- EXPECT_EQ("", ReadMessageWithHandles(child, &buffer, 1));
- WriteMessageWithHandles(parent, "", &buffer, 1);
-
- EXPECT_EQ("quit", ReadMessage(parent));
- WriteMessage(child, "quit");
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBufferParent, SharedBufferTest,
- parent) {
- RUN_CHILD_ON_PIPE(ReceiveAndEditBuffer, child)
- // Read a pipe from the parent and forward it to our child.
- MojoHandle pipe;
- std::string message = ReadMessageWithHandles(parent, &pipe, 1);
- WriteMessageWithHandles(child, message, &pipe, 1);
-
- EXPECT_EQ("quit", ReadMessage(parent));
- WriteMessage(child, "quit");
- END_CHILD()
-}
-
-#if defined(OS_ANDROID) || defined(OS_MACOSX)
-// Android multi-process tests are not executing the new process. This is flaky.
-// Passing shared memory handles between cousins is not currently supported on
-// OSX.
-#define MAYBE_PassHandleBetweenCousins DISABLED_PassHandleBetweenCousins
-#else
-#define MAYBE_PassHandleBetweenCousins PassHandleBetweenCousins
-#endif
-TEST_F(SharedBufferTest, MAYBE_PassHandleBetweenCousins) {
- const std::string message = "hello";
- MojoHandle p0, p1;
- CreateMessagePipe(&p0, &p1);
-
- // Spawn two children who will each spawn their own child. Make sure the
- // grandchildren (cousins to each other) can pass platform handles.
- MojoHandle b;
- RUN_CHILD_ON_PIPE(CreateAndPassBufferParent, child1)
- RUN_CHILD_ON_PIPE(ReceiveAndEditBufferParent, child2)
- MojoHandle pipe[2];
- CreateMessagePipe(&pipe[0], &pipe[1]);
-
- WriteMessageWithHandles(child1, message, &pipe[0], 1);
- WriteMessageWithHandles(child2, message, &pipe[1], 1);
-
- // Receive the buffer back from the first child.
- ReadMessageWithHandles(child1, &b, 1);
-
- WriteMessage(child2, "quit");
- END_CHILD()
- WriteMessage(child1, "quit");
- END_CHILD()
-
- // The second grandchild should have written this message.
- ExpectBufferContents(b, 0, message);
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndMapWriteSharedBuffer,
- SharedBufferTest, h) {
- // Receive the shared buffer.
- MojoHandle b;
- EXPECT_EQ("hello", ReadMessageWithHandles(h, &b, 1));
-
- // Read from the bufer.
- ExpectBufferContents(b, 0, "hello");
-
- // Extract the shared memory handle and try to map it writable.
- base::SharedMemoryHandle shm_handle;
- bool read_only = false;
- ASSERT_EQ(MOJO_RESULT_OK,
- PassSharedMemoryHandle(b, &shm_handle, nullptr, &read_only));
- base::SharedMemory shared_memory(shm_handle, false);
- EXPECT_TRUE(read_only);
- EXPECT_FALSE(shared_memory.Map(1234));
-
- EXPECT_EQ("quit", ReadMessage(h));
- WriteMessage(h, "ok");
-}
-
-#if defined(OS_ANDROID)
-// Android multi-process tests are not executing the new process. This is flaky.
-#define MAYBE_CreateAndPassReadOnlyBuffer DISABLED_CreateAndPassReadOnlyBuffer
-#else
-#define MAYBE_CreateAndPassReadOnlyBuffer CreateAndPassReadOnlyBuffer
-#endif
-TEST_F(SharedBufferTest, MAYBE_CreateAndPassReadOnlyBuffer) {
- RUN_CHILD_ON_PIPE(ReadAndMapWriteSharedBuffer, h)
- // Create a new shared buffer.
- MojoHandle b = CreateBuffer(1234);
- WriteToBuffer(b, 0, "hello");
-
- // Send a read-only copy of the buffer to the child.
- MojoHandle dupe = DuplicateBuffer(b, true /* read_only */);
- WriteMessageWithHandles(h, "hello", &dupe, 1);
-
- WriteMessage(h, "quit");
- EXPECT_EQ("ok", ReadMessage(h));
- END_CHILD()
-}
-
-DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassReadOnlyBuffer,
- SharedBufferTest, h) {
- // Create a new shared buffer.
- MojoHandle b = CreateBuffer(1234);
- WriteToBuffer(b, 0, "hello");
-
- // Send a read-only copy of the buffer to the parent.
- MojoHandle dupe = DuplicateBuffer(b, true /* read_only */);
- WriteMessageWithHandles(h, "", &dupe, 1);
-
- EXPECT_EQ("quit", ReadMessage(h));
- WriteMessage(h, "ok");
-}
-
-#if defined(OS_ANDROID)
-// Android multi-process tests are not executing the new process. This is flaky.
-#define MAYBE_CreateAndPassFromChildReadOnlyBuffer \
- DISABLED_CreateAndPassFromChildReadOnlyBuffer
-#else
-#define MAYBE_CreateAndPassFromChildReadOnlyBuffer \
- CreateAndPassFromChildReadOnlyBuffer
-#endif
-TEST_F(SharedBufferTest, MAYBE_CreateAndPassFromChildReadOnlyBuffer) {
- RUN_CHILD_ON_PIPE(CreateAndPassReadOnlyBuffer, h)
- MojoHandle b;
- EXPECT_EQ("", ReadMessageWithHandles(h, &b, 1));
- ExpectBufferContents(b, 0, "hello");
-
- // Extract the shared memory handle and try to map it writable.
- base::SharedMemoryHandle shm_handle;
- bool read_only = false;
- ASSERT_EQ(MOJO_RESULT_OK,
- PassSharedMemoryHandle(b, &shm_handle, nullptr, &read_only));
- base::SharedMemory shared_memory(shm_handle, false);
- EXPECT_TRUE(read_only);
- EXPECT_FALSE(shared_memory.Map(1234));
-
- WriteMessage(h, "quit");
- EXPECT_EQ("ok", ReadMessage(h));
- END_CHILD()
-}
-
-#endif // !defined(OS_IOS)
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/signals_unittest.cc b/mojo/edk/system/signals_unittest.cc
deleted file mode 100644
index e8b0cd1..0000000
--- a/mojo/edk/system/signals_unittest.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2017 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/test/mojo_test_base.h"
-#include "mojo/public/c/system/buffer.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/functions.h"
-#include "mojo/public/c/system/message_pipe.h"
-#include "mojo/public/c/system/types.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-using SignalsTest = test::MojoTestBase;
-
-TEST_F(SignalsTest, QueryInvalidArguments) {
- MojoHandleSignalsState state = {0, 0};
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoQueryHandleSignalsState(MOJO_HANDLE_INVALID, &state));
-
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoQueryHandleSignalsState(a, nullptr));
-}
-
-TEST_F(SignalsTest, QueryMessagePipeSignals) {
- MojoHandleSignalsState state = {0, 0};
-
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(a, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- state.satisfiable_signals);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- state.satisfiable_signals);
-
- WriteMessage(a, "ok");
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
- state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- state.satisfiable_signals);
-
- EXPECT_EQ("ok", ReadMessage(b));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
- MOJO_HANDLE_SIGNAL_PEER_CLOSED,
- state.satisfiable_signals);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(b, &state));
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
- EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/system_impl_export.h b/mojo/edk/system/system_impl_export.h
deleted file mode 100644
index 5bbf005..0000000
--- a/mojo/edk/system/system_impl_export.h
+++ /dev/null
@@ -1,29 +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_SYSTEM_IMPL_EXPORT_H_
-#define MOJO_EDK_SYSTEM_SYSTEM_IMPL_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(MOJO_SYSTEM_IMPL_IMPLEMENTATION)
-#define MOJO_SYSTEM_IMPL_EXPORT __declspec(dllexport)
-#else
-#define MOJO_SYSTEM_IMPL_EXPORT __declspec(dllimport)
-#endif // defined(MOJO_SYSTEM_IMPL_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(MOJO_SYSTEM_IMPL_IMPLEMENTATION)
-#define MOJO_SYSTEM_IMPL_EXPORT __attribute__((visibility("default")))
-#else
-#define MOJO_SYSTEM_IMPL_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define MOJO_SYSTEM_IMPL_EXPORT
-#endif
-
-#endif // MOJO_EDK_SYSTEM_SYSTEM_IMPL_EXPORT_H_
diff --git a/mojo/edk/system/test_utils.cc b/mojo/edk/system/test_utils.cc
deleted file mode 100644
index 4a39cf7..0000000
--- a/mojo/edk/system/test_utils.cc
+++ /dev/null
@@ -1,76 +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 <stdint.h>
-
-#include <limits>
-
-#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 edk {
-namespace test {
-
-MojoDeadline DeadlineFromMilliseconds(unsigned milliseconds) {
- return static_cast<MojoDeadline>(milliseconds) * 1000;
-}
-
-MojoDeadline EpsilonDeadline() {
-// Originally, our epsilon timeout was 10 ms, which was mostly fine but flaky on
-// some Windows bots. I don't recall ever seeing flakes on other bots. At 30 ms
-// tests seem reliable on Windows bots, but not at 25 ms. We'd like this timeout
-// to be as small as possible (see the description in the .h file).
-//
-// Currently, |tiny_timeout()| is usually 100 ms (possibly scaled under ASAN,
-// etc.). Based on this, set it to (usually be) 30 ms on Windows and 20 ms
-// elsewhere.
-#if defined(OS_WIN) || defined(OS_ANDROID)
- return (TinyDeadline() * 3) / 10;
-#else
- return (TinyDeadline() * 2) / 10;
-#endif
-}
-
-MojoDeadline TinyDeadline() {
- return static_cast<MojoDeadline>(
- TestTimeouts::tiny_timeout().InMicroseconds());
-}
-
-MojoDeadline ActionDeadline() {
- return static_cast<MojoDeadline>(
- TestTimeouts::action_timeout().InMicroseconds());
-}
-
-void Sleep(MojoDeadline deadline) {
- CHECK_LE(deadline,
- static_cast<MojoDeadline>(std::numeric_limits<int64_t>::max()));
- base::PlatformThread::Sleep(
- base::TimeDelta::FromMicroseconds(static_cast<int64_t>(deadline)));
-}
-
-Stopwatch::Stopwatch() {
-}
-
-Stopwatch::~Stopwatch() {
-}
-
-void Stopwatch::Start() {
- start_time_ = base::TimeTicks::Now();
-}
-
-MojoDeadline Stopwatch::Elapsed() {
- int64_t result = (base::TimeTicks::Now() - start_time_).InMicroseconds();
- // |DCHECK_GE|, not |CHECK_GE|, since this may be performance-important.
- DCHECK_GE(result, 0);
- return static_cast<MojoDeadline>(result);
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/test_utils.h b/mojo/edk/system/test_utils.h
deleted file mode 100644
index 1c90dc1..0000000
--- a/mojo/edk/system/test_utils.h
+++ /dev/null
@@ -1,59 +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 "base/macros.h"
-#include "base/time/time.h"
-#include "mojo/public/c/system/types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-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 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);
-
-// 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:
- base::TimeTicks start_time_;
-
- DISALLOW_COPY_AND_ASSIGN(Stopwatch);
-};
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_TEST_UTILS_H_
diff --git a/mojo/edk/system/watch.cc b/mojo/edk/system/watch.cc
deleted file mode 100644
index cf08ac3..0000000
--- a/mojo/edk/system/watch.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2017 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/watch.h"
-
-#include "mojo/edk/system/request_context.h"
-#include "mojo/edk/system/watcher_dispatcher.h"
-
-namespace mojo {
-namespace edk {
-
-Watch::Watch(const scoped_refptr<WatcherDispatcher>& watcher,
- const scoped_refptr<Dispatcher>& dispatcher,
- uintptr_t context,
- MojoHandleSignals signals)
- : watcher_(watcher),
- dispatcher_(dispatcher),
- context_(context),
- signals_(signals) {}
-
-bool Watch::NotifyState(const HandleSignalsState& state,
- bool allowed_to_call_callback) {
- AssertWatcherLockAcquired();
-
- // NOTE: This method must NEVER call into |dispatcher_| directly, because it
- // may be called while |dispatcher_| holds a lock.
-
- MojoResult rv = MOJO_RESULT_SHOULD_WAIT;
- RequestContext* const request_context = RequestContext::current();
- if (state.satisfies(signals_)) {
- rv = MOJO_RESULT_OK;
- if (allowed_to_call_callback && rv != last_known_result_) {
- request_context->AddWatchNotifyFinalizer(this, MOJO_RESULT_OK, state);
- }
- } else if (!state.can_satisfy(signals_)) {
- rv = MOJO_RESULT_FAILED_PRECONDITION;
- if (allowed_to_call_callback && rv != last_known_result_) {
- request_context->AddWatchNotifyFinalizer(
- this, MOJO_RESULT_FAILED_PRECONDITION, state);
- }
- }
-
- last_known_signals_state_ =
- *static_cast<const MojoHandleSignalsState*>(&state);
- last_known_result_ = rv;
- return ready();
-}
-
-void Watch::Cancel() {
- RequestContext::current()->AddWatchCancelFinalizer(this);
-}
-
-void Watch::InvokeCallback(MojoResult result,
- const HandleSignalsState& state,
- MojoWatcherNotificationFlags flags) {
- // We hold the lock through invocation to ensure that only one notification
- // callback runs for this context at any given time.
- base::AutoLock lock(notification_lock_);
- if (result == MOJO_RESULT_CANCELLED) {
- // Make sure cancellation is the last notification we dispatch.
- DCHECK(!is_cancelled_);
- is_cancelled_ = true;
- } else if (is_cancelled_) {
- return;
- }
-
- // NOTE: This will acquire |watcher_|'s internal lock. It's safe because a
- // thread can only enter InvokeCallback() from within a RequestContext
- // destructor where no dispatcher locks are held.
- watcher_->InvokeWatchCallback(context_, result, state, flags);
-}
-
-Watch::~Watch() {}
-
-#if DCHECK_IS_ON()
-void Watch::AssertWatcherLockAcquired() const {
- watcher_->lock_.AssertAcquired();
-}
-#endif
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/watch.h b/mojo/edk/system/watch.h
deleted file mode 100644
index f277de9..0000000
--- a/mojo/edk/system/watch.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2017 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_WATCH_H_
-#define MOJO_EDK_SYSTEM_WATCH_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/system/atomic_flag.h"
-#include "mojo/edk/system/handle_signals_state.h"
-
-namespace mojo {
-namespace edk {
-
-class Dispatcher;
-class WatcherDispatcher;
-
-// Encapsulates the state associated with a single watch context within a
-// watcher.
-//
-// Every Watch has its own cancellation state, and is captured by RequestContext
-// notification finalizers to avoid redundant context resolution during
-// finalizer execution.
-class Watch : public base::RefCountedThreadSafe<Watch> {
- public:
- // Constructs a Watch which represents a watch within |watcher| associated
- // with |context|, watching |dispatcher| for |signals|.
- Watch(const scoped_refptr<WatcherDispatcher>& watcher,
- const scoped_refptr<Dispatcher>& dispatcher,
- uintptr_t context,
- MojoHandleSignals signals);
-
- // Notifies the Watch of a potential state change.
- //
- // If |allowed_to_call_callback| is true, this may add a notification
- // finalizer to the current RequestContext to invoke the watcher's callback
- // with this watch's context. See return values below.
- //
- // This is called directly by WatcherDispatcher whenever the Watch's observed
- // dispatcher notifies the WatcherDispatcher of a state change.
- //
- // Returns |true| if the Watch entered or remains in a ready state as a result
- // of the state change. If |allowed_to_call_callback| was true in this case,
- // the Watch will have also attached a notification finalizer to the current
- // RequestContext.
- //
- // Returns |false| if the
- bool NotifyState(const HandleSignalsState& state,
- bool allowed_to_call_callback);
-
- // Notifies the watch of cancellation ASAP. This will always be the last
- // notification sent for the watch.
- void Cancel();
-
- // Finalizer method for RequestContexts. This method is invoked once for every
- // notification finalizer added to a RequestContext by this object. This calls
- // down into the WatcherDispatcher to do the actual notification call.
- void InvokeCallback(MojoResult result,
- const HandleSignalsState& state,
- MojoWatcherNotificationFlags flags);
-
- const scoped_refptr<Dispatcher>& dispatcher() const { return dispatcher_; }
- uintptr_t context() const { return context_; }
-
- MojoResult last_known_result() const {
- AssertWatcherLockAcquired();
- return last_known_result_;
- }
-
- MojoHandleSignalsState last_known_signals_state() const {
- AssertWatcherLockAcquired();
- return last_known_signals_state_;
- }
-
- bool ready() const {
- AssertWatcherLockAcquired();
- return last_known_result_ == MOJO_RESULT_OK ||
- last_known_result_ == MOJO_RESULT_FAILED_PRECONDITION;
- }
-
- private:
- friend class base::RefCountedThreadSafe<Watch>;
-
- ~Watch();
-
-#if DCHECK_IS_ON()
- void AssertWatcherLockAcquired() const;
-#else
- void AssertWatcherLockAcquired() const {}
-#endif
-
- const scoped_refptr<WatcherDispatcher> watcher_;
- const scoped_refptr<Dispatcher> dispatcher_;
- const uintptr_t context_;
- const MojoHandleSignals signals_;
-
- // The result code with which this Watch would notify if currently armed,
- // based on the last known signaling state of |dispatcher_|. Guarded by the
- // owning WatcherDispatcher's lock.
- MojoResult last_known_result_ = MOJO_RESULT_UNKNOWN;
-
- // The last known signaling state of |dispatcher_|. Guarded by the owning
- // WatcherDispatcher's lock.
- MojoHandleSignalsState last_known_signals_state_ = {0, 0};
-
- // Guards |is_cancelled_| below and mutually excludes individual watch
- // notification executions for this same watch context.
- //
- // Note that this should only be acquired from a RequestContext finalizer to
- // ensure that no other internal locks are already held.
- base::Lock notification_lock_;
-
- // Guarded by |notification_lock_|.
- bool is_cancelled_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(Watch);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_WATCH_H_
diff --git a/mojo/edk/system/watcher_dispatcher.cc b/mojo/edk/system/watcher_dispatcher.cc
deleted file mode 100644
index 409dd2a..0000000
--- a/mojo/edk/system/watcher_dispatcher.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright 2017 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/watcher_dispatcher.h"
-
-#include <algorithm>
-#include <limits>
-#include <map>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "mojo/edk/system/watch.h"
-
-namespace mojo {
-namespace edk {
-
-WatcherDispatcher::WatcherDispatcher(MojoWatcherCallback callback)
- : callback_(callback) {}
-
-void WatcherDispatcher::NotifyHandleState(Dispatcher* dispatcher,
- const HandleSignalsState& state) {
- base::AutoLock lock(lock_);
- auto it = watched_handles_.find(dispatcher);
- if (it == watched_handles_.end())
- return;
-
- // Maybe fire a notification to the watch assoicated with this dispatcher,
- // provided we're armed it cares about the new state.
- if (it->second->NotifyState(state, armed_)) {
- ready_watches_.insert(it->second.get());
-
- // If we were armed and got here, we notified the watch. Disarm.
- armed_ = false;
- } else {
- ready_watches_.erase(it->second.get());
- }
-}
-
-void WatcherDispatcher::NotifyHandleClosed(Dispatcher* dispatcher) {
- scoped_refptr<Watch> watch;
- {
- base::AutoLock lock(lock_);
- auto it = watched_handles_.find(dispatcher);
- if (it == watched_handles_.end())
- return;
-
- watch = std::move(it->second);
-
- // Wipe out all state associated with the closed dispatcher.
- watches_.erase(watch->context());
- ready_watches_.erase(watch.get());
- watched_handles_.erase(it);
- }
-
- // NOTE: It's important that this is called outside of |lock_| since it
- // acquires internal Watch locks.
- watch->Cancel();
-}
-
-void WatcherDispatcher::InvokeWatchCallback(
- uintptr_t context,
- MojoResult result,
- const HandleSignalsState& state,
- MojoWatcherNotificationFlags flags) {
- {
- // We avoid holding the lock during dispatch. It's OK for notification
- // callbacks to close this watcher, and it's OK for notifications to race
- // with closure, if for example the watcher is closed from another thread
- // between this test and the invocation of |callback_| below.
- //
- // Because cancellation synchronously blocks all future notifications, and
- // because notifications themselves are mutually exclusive for any given
- // context, we still guarantee that a single MOJO_RESULT_CANCELLED result
- // is the last notification received for any given context.
- //
- // This guarantee is sufficient to make safe, synchronized, per-context
- // state management possible in user code.
- base::AutoLock lock(lock_);
- if (closed_ && result != MOJO_RESULT_CANCELLED)
- return;
- }
-
- callback_(context, result, static_cast<MojoHandleSignalsState>(state), flags);
-}
-
-Dispatcher::Type WatcherDispatcher::GetType() const {
- return Type::WATCHER;
-}
-
-MojoResult WatcherDispatcher::Close() {
- // We swap out all the watched handle information onto the stack so we can
- // call into their dispatchers without our own lock held.
- std::map<uintptr_t, scoped_refptr<Watch>> watches;
- {
- base::AutoLock lock(lock_);
- DCHECK(!closed_);
- closed_ = true;
- std::swap(watches, watches_);
- watched_handles_.clear();
- }
-
- // Remove all refs from our watched dispatchers and fire cancellations.
- for (auto& entry : watches) {
- entry.second->dispatcher()->RemoveWatcherRef(this, entry.first);
- entry.second->Cancel();
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult WatcherDispatcher::WatchDispatcher(
- scoped_refptr<Dispatcher> dispatcher,
- MojoHandleSignals signals,
- uintptr_t context) {
- // NOTE: Because it's critical to avoid acquiring any other dispatcher locks
- // while |lock_| is held, we defer adding oursevles to the dispatcher until
- // after we've updated all our own relevant state and released |lock_|.
- {
- base::AutoLock lock(lock_);
- if (watches_.count(context) || watched_handles_.count(dispatcher.get()))
- return MOJO_RESULT_ALREADY_EXISTS;
-
- scoped_refptr<Watch> watch = new Watch(this, dispatcher, context, signals);
- watches_.insert({context, watch});
- auto result =
- watched_handles_.insert(std::make_pair(dispatcher.get(), watch));
- DCHECK(result.second);
- }
-
- MojoResult rv = dispatcher->AddWatcherRef(this, context);
- if (rv != MOJO_RESULT_OK) {
- // Oops. This was not a valid handle to watch. Undo the above work and
- // fail gracefully.
- base::AutoLock lock(lock_);
- watches_.erase(context);
- watched_handles_.erase(dispatcher.get());
- return rv;
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult WatcherDispatcher::CancelWatch(uintptr_t context) {
- // We may remove the last stored ref to the Watch below, so we retain
- // a reference on the stack.
- scoped_refptr<Watch> watch;
- {
- base::AutoLock lock(lock_);
- auto it = watches_.find(context);
- if (it == watches_.end())
- return MOJO_RESULT_NOT_FOUND;
- watch = it->second;
- watches_.erase(it);
- }
-
- // Mark the watch as cancelled so no further notifications get through.
- watch->Cancel();
-
- // We remove the watcher ref for this context before updating any more
- // internal watcher state, ensuring that we don't receiving further
- // notifications for this context.
- watch->dispatcher()->RemoveWatcherRef(this, context);
-
- {
- base::AutoLock lock(lock_);
- auto handle_it = watched_handles_.find(watch->dispatcher().get());
- DCHECK(handle_it != watched_handles_.end());
- ready_watches_.erase(handle_it->second.get());
- watched_handles_.erase(handle_it);
- }
-
- return MOJO_RESULT_OK;
-}
-
-MojoResult WatcherDispatcher::Arm(
- uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states) {
- base::AutoLock lock(lock_);
- if (num_ready_contexts &&
- (!ready_contexts || !ready_results || !ready_signals_states)) {
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
-
- if (watched_handles_.empty())
- return MOJO_RESULT_NOT_FOUND;
-
- if (ready_watches_.empty()) {
- // Fast path: No watches are ready to notify, so we're done.
- armed_ = true;
- return MOJO_RESULT_OK;
- }
-
- if (num_ready_contexts) {
- DCHECK_LE(ready_watches_.size(), std::numeric_limits<uint32_t>::max());
- *num_ready_contexts = std::min(
- *num_ready_contexts, static_cast<uint32_t>(ready_watches_.size()));
-
- WatchSet::const_iterator next_ready_iter = ready_watches_.begin();
- if (last_watch_to_block_arming_) {
- // Find the next watch to notify in simple round-robin order on the
- // |ready_watches_| map, wrapping around to the beginning if necessary.
- next_ready_iter = ready_watches_.find(last_watch_to_block_arming_);
- if (next_ready_iter != ready_watches_.end())
- ++next_ready_iter;
- if (next_ready_iter == ready_watches_.end())
- next_ready_iter = ready_watches_.begin();
- }
-
- for (size_t i = 0; i < *num_ready_contexts; ++i) {
- const Watch* const watch = *next_ready_iter;
- ready_contexts[i] = watch->context();
- ready_results[i] = watch->last_known_result();
- ready_signals_states[i] = watch->last_known_signals_state();
-
- // Iterate and wrap around.
- last_watch_to_block_arming_ = watch;
- ++next_ready_iter;
- if (next_ready_iter == ready_watches_.end())
- next_ready_iter = ready_watches_.begin();
- }
- }
-
- return MOJO_RESULT_FAILED_PRECONDITION;
-}
-
-WatcherDispatcher::~WatcherDispatcher() {}
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/watcher_dispatcher.h b/mojo/edk/system/watcher_dispatcher.h
deleted file mode 100644
index 605a315..0000000
--- a/mojo/edk/system/watcher_dispatcher.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2017 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_WATCHER_DISPATCHER_H_
-#define MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_
-
-#include <map>
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "mojo/edk/system/dispatcher.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/system_impl_export.h"
-#include "mojo/public/c/system/watcher.h"
-
-namespace mojo {
-namespace edk {
-
-class Watch;
-
-// The dispatcher type which backs watcher handles.
-class WatcherDispatcher : public Dispatcher {
- public:
- // Constructs a new WatcherDispatcher which invokes |callback| when a
- // registered watch observes some relevant state change.
- explicit WatcherDispatcher(MojoWatcherCallback callback);
-
- // Methods used by watched dispatchers to notify watchers of events.
- void NotifyHandleState(Dispatcher* dispatcher,
- const HandleSignalsState& state);
- void NotifyHandleClosed(Dispatcher* dispatcher);
-
- // Method used by RequestContext (indirectly, via Watch) to complete
- // notification operations from a safe stack frame to avoid reentrancy.
- void InvokeWatchCallback(uintptr_t context,
- MojoResult result,
- const HandleSignalsState& state,
- MojoWatcherNotificationFlags flags);
-
- // Dispatcher:
- Type GetType() const override;
- MojoResult Close() override;
- MojoResult WatchDispatcher(scoped_refptr<Dispatcher> dispatcher,
- MojoHandleSignals signals,
- uintptr_t context) override;
- MojoResult CancelWatch(uintptr_t context) override;
- MojoResult Arm(uint32_t* num_ready_contexts,
- uintptr_t* ready_contexts,
- MojoResult* ready_results,
- MojoHandleSignalsState* ready_signals_states) override;
-
- private:
- friend class Watch;
-
- using WatchSet = std::set<const Watch*>;
-
- ~WatcherDispatcher() override;
-
- const MojoWatcherCallback callback_;
-
- // Guards access to the fields below.
- //
- // NOTE: This may be acquired while holding another dispatcher's lock, as
- // watched dispatchers call into WatcherDispatcher methods which lock this
- // when issuing state change notifications. WatcherDispatcher must therefore
- // take caution to NEVER acquire other dispatcher locks while this is held.
- base::Lock lock_;
-
- bool armed_ = false;
- bool closed_ = false;
-
- // A mapping from context to Watch.
- std::map<uintptr_t, scoped_refptr<Watch>> watches_;
-
- // A mapping from watched dispatcher to Watch.
- std::map<Dispatcher*, scoped_refptr<Watch>> watched_handles_;
-
- // The set of all Watch instances which are currently ready to signal. This is
- // used for efficient arming behavior, as it allows for O(1) discovery of
- // whether or not arming can succeed and quick determination of who's
- // responsible if it can't.
- WatchSet ready_watches_;
-
- // Tracks the last Watch whose state was returned by Arm(). This is used to
- // ensure consistent round-robin behavior in the event that multiple Watches
- // remain ready over the span of several Arm() attempts.
- //
- // NOTE: This pointer is only used to index |ready_watches_| and may point to
- // an invalid object. It must therefore never be dereferenced.
- const Watch* last_watch_to_block_arming_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(WatcherDispatcher);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_WATCHER_DISPATCHER_H_
diff --git a/mojo/edk/system/watcher_set.cc b/mojo/edk/system/watcher_set.cc
deleted file mode 100644
index 0355b58..0000000
--- a/mojo/edk/system/watcher_set.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/system/watcher_set.h"
-
-#include <utility>
-
-namespace mojo {
-namespace edk {
-
-WatcherSet::WatcherSet(Dispatcher* owner) : owner_(owner) {}
-
-WatcherSet::~WatcherSet() = default;
-
-void WatcherSet::NotifyState(const HandleSignalsState& state) {
- // Avoid notifying watchers if they have already seen this state.
- if (last_known_state_.has_value() && state.equals(last_known_state_.value()))
- return;
- last_known_state_ = state;
- for (const auto& entry : watchers_)
- entry.first->NotifyHandleState(owner_, state);
-}
-
-void WatcherSet::NotifyClosed() {
- for (const auto& entry : watchers_)
- entry.first->NotifyHandleClosed(owner_);
-}
-
-MojoResult WatcherSet::Add(const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context,
- const HandleSignalsState& current_state) {
- auto it = watchers_.find(watcher.get());
- if (it == watchers_.end()) {
- auto result =
- watchers_.insert(std::make_pair(watcher.get(), Entry{watcher}));
- it = result.first;
- }
-
- if (!it->second.contexts.insert(context).second)
- return MOJO_RESULT_ALREADY_EXISTS;
-
- if (last_known_state_.has_value() &&
- !current_state.equals(last_known_state_.value())) {
- // This new state may be relevant to everyone, in which case we just
- // notify everyone.
- NotifyState(current_state);
- } else {
- // Otherwise only notify the newly added Watcher.
- watcher->NotifyHandleState(owner_, current_state);
- }
- return MOJO_RESULT_OK;
-}
-
-MojoResult WatcherSet::Remove(WatcherDispatcher* watcher, uintptr_t context) {
- auto it = watchers_.find(watcher);
- if (it == watchers_.end())
- return MOJO_RESULT_NOT_FOUND;
-
- ContextSet& contexts = it->second.contexts;
- auto context_it = contexts.find(context);
- if (context_it == contexts.end())
- return MOJO_RESULT_NOT_FOUND;
-
- contexts.erase(context_it);
- if (contexts.empty())
- watchers_.erase(it);
-
- return MOJO_RESULT_OK;
-}
-
-WatcherSet::Entry::Entry(const scoped_refptr<WatcherDispatcher>& dispatcher)
- : dispatcher(dispatcher) {}
-
-WatcherSet::Entry::Entry(Entry&& other) = default;
-
-WatcherSet::Entry::~Entry() = default;
-
-WatcherSet::Entry& WatcherSet::Entry::operator=(Entry&& other) = default;
-
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/system/watcher_set.h b/mojo/edk/system/watcher_set.h
deleted file mode 100644
index 2b7ef2c..0000000
--- a/mojo/edk/system/watcher_set.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_SYSTEM_WATCHER_SET_H_
-#define MOJO_EDK_SYSTEM_WATCHER_SET_H_
-
-#include <map>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/optional.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/edk/system/watcher_dispatcher.h"
-
-namespace mojo {
-namespace edk {
-
-// A WatcherSet maintains a set of references to WatcherDispatchers to be
-// notified when a handle changes state.
-//
-// Dispatchers which may be watched by a watcher should own a WatcherSet and
-// notify it of all relevant state changes.
-class WatcherSet {
- public:
- // |owner| is the Dispatcher who owns this WatcherSet.
- explicit WatcherSet(Dispatcher* owner);
- ~WatcherSet();
-
- // Notifies all watchers of the handle's current signals state.
- void NotifyState(const HandleSignalsState& state);
-
- // Notifies all watchers that this handle has been closed.
- void NotifyClosed();
-
- // Adds a new watcher+context.
- MojoResult Add(const scoped_refptr<WatcherDispatcher>& watcher,
- uintptr_t context,
- const HandleSignalsState& current_state);
-
- // Removes a watcher+context.
- MojoResult Remove(WatcherDispatcher* watcher, uintptr_t context);
-
- private:
- using ContextSet = std::set<uintptr_t>;
-
- struct Entry {
- Entry(const scoped_refptr<WatcherDispatcher>& dispatcher);
- Entry(Entry&& other);
- ~Entry();
-
- Entry& operator=(Entry&& other);
-
- scoped_refptr<WatcherDispatcher> dispatcher;
- ContextSet contexts;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Entry);
- };
-
- Dispatcher* const owner_;
- std::map<WatcherDispatcher*, Entry> watchers_;
- base::Optional<HandleSignalsState> last_known_state_;
-
- DISALLOW_COPY_AND_ASSIGN(WatcherSet);
-};
-
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_SYSTEM_WATCHER_SET_H_
diff --git a/mojo/edk/system/watcher_unittest.cc b/mojo/edk/system/watcher_unittest.cc
deleted file mode 100644
index dd396cd..0000000
--- a/mojo/edk/system/watcher_unittest.cc
+++ /dev/null
@@ -1,1637 +0,0 @@
-// Copyright 2017 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 <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/simple_thread.h"
-#include "base/time/time.h"
-#include "mojo/edk/test/mojo_test_base.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/types.h"
-#include "mojo/public/c/system/watcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace {
-
-using WatcherTest = test::MojoTestBase;
-
-class WatchHelper {
- public:
- using ContextCallback =
- base::Callback<void(MojoResult, MojoHandleSignalsState)>;
-
- WatchHelper() {}
- ~WatchHelper() {}
-
- MojoResult CreateWatcher(MojoHandle* handle) {
- return MojoCreateWatcher(&Notify, handle);
- }
-
- uintptr_t CreateContext(const ContextCallback& callback) {
- return CreateContextWithCancel(callback, base::Closure());
- }
-
- uintptr_t CreateContextWithCancel(const ContextCallback& callback,
- const base::Closure& cancel_callback) {
- auto context = base::MakeUnique<NotificationContext>(callback);
- NotificationContext* raw_context = context.get();
- raw_context->SetCancelCallback(base::Bind(
- [](std::unique_ptr<NotificationContext> context,
- const base::Closure& cancel_callback) {
- if (cancel_callback)
- cancel_callback.Run();
- },
- base::Passed(&context), cancel_callback));
- return reinterpret_cast<uintptr_t>(raw_context);
- }
-
- private:
- class NotificationContext {
- public:
- explicit NotificationContext(const ContextCallback& callback)
- : callback_(callback) {}
-
- ~NotificationContext() {}
-
- void SetCancelCallback(const base::Closure& cancel_callback) {
- cancel_callback_ = cancel_callback;
- }
-
- void Notify(MojoResult result, MojoHandleSignalsState state) {
- if (result == MOJO_RESULT_CANCELLED)
- cancel_callback_.Run();
- else
- callback_.Run(result, state);
- }
-
- private:
- const ContextCallback callback_;
- base::Closure cancel_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(NotificationContext);
- };
-
- static void Notify(uintptr_t context,
- MojoResult result,
- MojoHandleSignalsState state,
- MojoWatcherNotificationFlags flags) {
- reinterpret_cast<NotificationContext*>(context)->Notify(result, state);
- }
-
- DISALLOW_COPY_AND_ASSIGN(WatchHelper);
-};
-
-class ThreadedRunner : public base::SimpleThread {
- public:
- explicit ThreadedRunner(const base::Closure& callback)
- : SimpleThread("ThreadedRunner"), callback_(callback) {}
- ~ThreadedRunner() override {}
-
- void Run() override { callback_.Run(); }
-
- private:
- const base::Closure callback_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadedRunner);
-};
-
-void ExpectNoNotification(uintptr_t context,
- MojoResult result,
- MojoHandleSignalsState state,
- MojoWatcherNotificationFlags flags) {
- NOTREACHED();
-}
-
-void ExpectOnlyCancel(uintptr_t context,
- MojoResult result,
- MojoHandleSignalsState state,
- MojoWatcherNotificationFlags flags) {
- EXPECT_EQ(result, MOJO_RESULT_CANCELLED);
-}
-
-TEST_F(WatcherTest, InvalidArguments) {
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoCreateWatcher(&ExpectNoNotification, nullptr));
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w));
-
- // Try to watch unwatchable handles.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoWatch(w, w, MOJO_HANDLE_SIGNAL_READABLE, 0));
- MojoHandle buffer_handle = CreateBuffer(42);
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoWatch(w, buffer_handle, MOJO_HANDLE_SIGNAL_READABLE, 0));
-
- // Try to cancel a watch on an invalid watcher handle.
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoCancelWatch(buffer_handle, 0));
-
- // Try to arm an invalid handle.
- EXPECT_EQ(
- MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(MOJO_HANDLE_INVALID, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(buffer_handle, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(buffer_handle));
-
- // Try to arm with a non-null count but at least one null output buffer.
- uint32_t num_ready_contexts = 1;
- uintptr_t ready_context;
- MojoResult ready_result;
- MojoHandleSignalsState ready_state;
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(w, &num_ready_contexts, nullptr, &ready_result,
- &ready_state));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(w, &num_ready_contexts, &ready_context, nullptr,
- &ready_state));
- EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
- MojoArmWatcher(w, &num_ready_contexts, &ready_context,
- &ready_result, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, WatchMessagePipeReadable) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_expected_notifications = 1;
- const uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* expected_count, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_expected_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "hey hey hey hey";
- const char kMessage2[] = "i said hey";
- const char kMessage3[] = "what's goin' on?";
-
- // Writing to |b| multiple times should notify exactly once.
- WriteMessage(b, kMessage1);
- WriteMessage(b, kMessage2);
- event.Wait();
-
- // This also shouldn't fire a notification; the watcher is still disarmed.
- WriteMessage(b, kMessage3);
-
- // Arming should fail with relevant information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_a_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
-
- // Flush the three messages from above.
- EXPECT_EQ(kMessage1, ReadMessage(a));
- EXPECT_EQ(kMessage2, ReadMessage(a));
- EXPECT_EQ(kMessage3, ReadMessage(a));
-
- // Now we can rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-}
-
-TEST_F(WatcherTest, CloseWatchedMessagePipeHandle) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_a_context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
-
- // Test that closing a watched handle fires an appropriate notification, even
- // when the watcher is unarmed.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatchedMessagePipeHandlePeer) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
- event->Signal();
- },
- &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
-
- // Test that closing a watched handle's peer with an armed watcher fires an
- // appropriate notification.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- event.Wait();
-
- // And now arming should fail with correct information about |a|'s state.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_a_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals &
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-}
-
-TEST_F(WatcherTest, WatchDataPipeConsumerReadable) {
- constexpr size_t kTestPipeCapacity = 64;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_expected_notifications = 1;
- const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* expected_count, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_expected_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE,
- readable_consumer_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "hey hey hey hey";
- const char kMessage2[] = "i said hey";
- const char kMessage3[] = "what's goin' on?";
-
- // Writing to |producer| multiple times should notify exactly once.
- WriteData(producer, kMessage1);
- WriteData(producer, kMessage2);
- event.Wait();
-
- // This also shouldn't fire a notification; the watcher is still disarmed.
- WriteData(producer, kMessage3);
-
- // Arming should fail with relevant information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_consumer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
-
- // Flush the three messages from above.
- EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1));
- EXPECT_EQ(kMessage2, ReadData(consumer, sizeof(kMessage2) - 1));
- EXPECT_EQ(kMessage3, ReadData(consumer, sizeof(kMessage3) - 1));
-
- // Now we can rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-}
-
-TEST_F(WatcherTest, WatchDataPipeConsumerNewDataReadable) {
- constexpr size_t kTestPipeCapacity = 64;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_new_data_notifications = 0;
- const uintptr_t new_data_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* notification_count, MojoResult result,
- MojoHandleSignalsState state) {
- *notification_count += 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_new_data_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
- new_data_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "hey hey hey hey";
- const char kMessage2[] = "i said hey";
- const char kMessage3[] = "what's goin' on?";
-
- // Writing to |producer| multiple times should notify exactly once.
- WriteData(producer, kMessage1);
- WriteData(producer, kMessage2);
- event.Wait();
-
- // This also shouldn't fire a notification; the watcher is still disarmed.
- WriteData(producer, kMessage3);
-
- // Arming should fail with relevant information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(new_data_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
-
- // Attempt to read more data than is available. Should fail but clear the
- // NEW_DATA_READABLE signal.
- char large_buffer[512];
- uint32_t large_read_size = 512;
- EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
- MojoReadData(consumer, large_buffer, &large_read_size,
- MOJO_READ_DATA_FLAG_ALL_OR_NONE));
-
- // Attempt to arm again. Should succeed.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Write more data. Should notify.
- event.Reset();
- WriteData(producer, kMessage1);
- event.Wait();
-
- // Reading some data should clear NEW_DATA_READABLE again so we can rearm.
- EXPECT_EQ(kMessage1, ReadData(consumer, sizeof(kMessage1) - 1));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(2, num_new_data_notifications);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-}
-
-TEST_F(WatcherTest, WatchDataPipeProducerWritable) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- // Half the capacity of the data pipe.
- const char kTestData[] = "aaaa";
- static_assert((sizeof(kTestData) - 1) * 2 == kTestPipeCapacity,
- "Invalid test data for this test.");
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_expected_notifications = 1;
- const uintptr_t writable_producer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, int* expected_count, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
-
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- },
- &event, &num_expected_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
- writable_producer_context));
-
- // The producer is already writable, so arming should fail with relevant
- // information.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Write some data, but don't fill the pipe yet. Arming should fail again.
- WriteData(producer, kTestData);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Write more data, filling the pipe to capacity. Arming should succeed now.
- WriteData(producer, kTestData);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Now read from the pipe, making the producer writable again. Should notify.
- EXPECT_EQ(kTestData, ReadData(consumer, sizeof(kTestData) - 1));
- event.Wait();
-
- // Arming should fail again.
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Fill the pipe once more and arm the watcher. Should succeed.
- WriteData(producer, kTestData);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-};
-
-TEST_F(WatcherTest, CloseWatchedDataPipeConsumerHandle) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_consumer_context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE,
- readable_consumer_context));
-
- // Closing the consumer should fire a cancellation notification.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatcherDataPipeConsumerHandlePeer) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t readable_consumer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
- event->Signal();
- },
- &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, consumer, MOJO_HANDLE_SIGNAL_READABLE,
- readable_consumer_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Closing the producer should fire a notification for an unsatisfiable watch.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- event.Wait();
-
- // Now attempt to rearm and expect appropriate error feedback.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(readable_consumer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
-}
-
-TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandle) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t writable_producer_context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
- writable_producer_context));
-
- // Closing the consumer should fire a cancellation notification.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatchedDataPipeProducerHandlePeer) {
- constexpr size_t kTestPipeCapacity = 8;
- MojoHandle producer, consumer;
- CreateDataPipe(&producer, &consumer, kTestPipeCapacity);
-
- const char kTestMessageFullCapacity[] = "xxxxxxxx";
- static_assert(sizeof(kTestMessageFullCapacity) - 1 == kTestPipeCapacity,
- "Invalid test message size for this test.");
-
- // Make the pipe unwritable initially.
- WriteData(producer, kTestMessageFullCapacity);
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- const uintptr_t writable_producer_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
- event->Signal();
- },
- &event));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, producer, MOJO_HANDLE_SIGNAL_WRITABLE,
- writable_producer_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Closing the consumer should fire a notification for an unsatisfiable watch,
- // as the full data pipe can never be read from again and is therefore
- // permanently full and unwritable.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(consumer));
- event.Wait();
-
- // Now attempt to rearm and expect appropriate error feedback.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_producer_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_WRITABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(producer));
-}
-
-TEST_F(WatcherTest, ArmWithNoWatches) {
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w));
- EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, WatchDuplicateContext) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, 0));
- EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, 0));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, CancelUnknownWatch) {
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectNoNotification, &w));
- EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoCancelWatch(w, 1234));
-}
-
-TEST_F(WatcherTest, ArmWithWatchAlreadySatisfied) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_WRITABLE, 0));
-
- // |a| is always writable, so we can never arm this watcher.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(0u, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, ArmWithWatchAlreadyUnsatisfiable) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, 0));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-
- // |b| is closed and never wrote any messages, so |a| won't be readable again.
- // MojoArmWatcher() should fail, incidcating as much.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = kMaxReadyContexts;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(0u, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals &
- MOJO_HANDLE_SIGNAL_PEER_CLOSED);
- EXPECT_FALSE(ready_states[0].satisfiable_signals &
- MOJO_HANDLE_SIGNAL_READABLE);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-}
-
-TEST_F(WatcherTest, MultipleWatches) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- base::WaitableEvent a_event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent b_event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- WatchHelper helper;
- int num_a_notifications = 0;
- int num_b_notifications = 0;
- auto notify_callback =
- base::Bind([](base::WaitableEvent* event, int* notification_count,
- MojoResult result, MojoHandleSignalsState state) {
- *notification_count += 1;
- EXPECT_EQ(MOJO_RESULT_OK, result);
- event->Signal();
- });
- uintptr_t readable_a_context = helper.CreateContext(
- base::Bind(notify_callback, &a_event, &num_a_notifications));
- uintptr_t readable_b_context = helper.CreateContext(
- base::Bind(notify_callback, &b_event, &num_b_notifications));
-
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- // Add two independent watch contexts to watch for |a| or |b| readability.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, readable_b_context));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- const char kMessage1[] = "things are happening";
- const char kMessage2[] = "ok. ok. ok. ok.";
- const char kMessage3[] = "plz wake up";
-
- // Writing to |b| should signal |a|'s watch.
- WriteMessage(b, kMessage1);
- a_event.Wait();
- a_event.Reset();
-
- // Subsequent messages on |b| should not trigger another notification.
- WriteMessage(b, kMessage2);
- WriteMessage(b, kMessage3);
-
- // Messages on |a| also shouldn't trigger |b|'s notification, since the
- // watcher should be disarmed by now.
- WriteMessage(a, kMessage1);
- WriteMessage(a, kMessage2);
- WriteMessage(a, kMessage3);
-
- // Arming should fail. Since we only ask for at most one context's information
- // that's all we should get back. Which one we get is unspecified.
- constexpr size_t kMaxReadyContexts = 10;
- uint32_t num_ready_contexts = 1;
- uintptr_t ready_contexts[kMaxReadyContexts];
- MojoResult ready_results[kMaxReadyContexts];
- MojoHandleSignalsState ready_states[kMaxReadyContexts];
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_TRUE(ready_contexts[0] == readable_a_context ||
- ready_contexts[0] == readable_b_context);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Now try arming again, verifying that both contexts are returned.
- num_ready_contexts = kMaxReadyContexts;
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(2u, num_ready_contexts);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[1]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
- EXPECT_TRUE(ready_states[1].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
- EXPECT_TRUE((ready_contexts[0] == readable_a_context &&
- ready_contexts[1] == readable_b_context) ||
- (ready_contexts[0] == readable_b_context &&
- ready_contexts[1] == readable_a_context));
-
- // Flush out the test messages so we should be able to successfully rearm.
- EXPECT_EQ(kMessage1, ReadMessage(a));
- EXPECT_EQ(kMessage2, ReadMessage(a));
- EXPECT_EQ(kMessage3, ReadMessage(a));
- EXPECT_EQ(kMessage1, ReadMessage(b));
- EXPECT_EQ(kMessage2, ReadMessage(b));
- EXPECT_EQ(kMessage3, ReadMessage(b));
-
- // Add a watch which is always satisfied, so we can't arm. Arming should fail
- // with only this new watch's information.
- uintptr_t writable_c_context = helper.CreateContext(base::Bind(
- [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); }));
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, c, MOJO_HANDLE_SIGNAL_WRITABLE, writable_c_context));
- num_ready_contexts = kMaxReadyContexts;
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, ready_contexts,
- ready_results, ready_states));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(writable_c_context, ready_contexts[0]);
- EXPECT_EQ(MOJO_RESULT_OK, ready_results[0]);
- EXPECT_TRUE(ready_states[0].satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
-
- // Cancel the new watch and arming should succeed once again.
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, writable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, NotifyOtherFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hello a";
- static const char kTestMessageToB[] = "hello b";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](MojoHandle w, MojoHandle a, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ("hello a", ReadMessage(a));
-
- // Re-arm the watcher and signal |b|.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- WriteMessage(a, kTestMessageToB);
- },
- w, a));
-
- uintptr_t readable_b_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle b,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToB, ReadMessage(b));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- event->Signal();
- },
- &event, w, b));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Send a message to |a|. The relevant watch context should be notified, and
- // should in turn send a message to |b|, waking up the other context. The
- // second context signals |event|.
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-}
-
-TEST_F(WatcherTest, NotifySelfFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hello a";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- int expected_notifications = 10;
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](int* expected_count, MojoHandle w, MojoHandle a, MojoHandle b,
- base::WaitableEvent* event, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ("hello a", ReadMessage(a));
-
- EXPECT_GT(*expected_count, 0);
- *expected_count -= 1;
- if (*expected_count == 0) {
- event->Signal();
- return;
- } else {
- // Re-arm the watcher and signal |a| again.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
- WriteMessage(b, kTestMessageToA);
- }
- },
- &expected_notifications, w, a, b, &event));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Send a message to |a|. When the watch above is notified, it will rearm and
- // send another message to |a|. This will happen until
- // |expected_notifications| reaches 0.
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-}
-
-TEST_F(WatcherTest, ImplicitCancelOtherFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- static const char kTestMessageToA[] = "hi a";
- static const char kTestMessageToC[] = "hi c";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- uintptr_t readable_a_context = helper.CreateContextWithCancel(
- base::Bind([](MojoResult result, MojoHandleSignalsState state) {
- NOTREACHED();
- }),
- base::Bind([](base::WaitableEvent* event) { event->Signal(); }, &event));
-
- uintptr_t readable_c_context = helper.CreateContext(base::Bind(
- [](MojoHandle w, MojoHandle a, MojoHandle b, MojoHandle c,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToC, ReadMessage(c));
-
- // Now rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Must result in exactly ONE notification on the above context, for
- // CANCELLED only. Because we cannot dispatch notifications until the
- // stack unwinds, and because we must never dispatch non-cancellation
- // notifications for a handle once it's been closed, we must be certain
- // that cancellation due to closure preemptively invalidates any
- // pending non-cancellation notifications queued on the current
- // RequestContext, such as the one resulting from the WriteMessage here.
- WriteMessage(b, kTestMessageToA);
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- // Rearming should be fine since |a|'s watch should already be
- // implicitly cancelled (even though the notification will not have
- // been invoked yet.)
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Nothing interesting should happen as a result of this.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- },
- w, a, b, c));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, readable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(d, kTestMessageToC);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, ExplicitCancelOtherFromNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- static const char kTestMessageToA[] = "hi a";
- static const char kTestMessageToC[] = "hi c";
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- WatchHelper helper;
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](MojoResult result, MojoHandleSignalsState state) { NOTREACHED(); }));
-
- uintptr_t readable_c_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, uintptr_t readable_a_context, MojoHandle w,
- MojoHandle a, MojoHandle b, MojoHandle c, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToC, ReadMessage(c));
-
- // Now rearm the watcher.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Should result in no notifications on the above context, because the
- // watch will have been cancelled by the time the notification callback
- // can execute.
- WriteMessage(b, kTestMessageToA);
- WriteMessage(b, kTestMessageToA);
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context));
-
- // Rearming should be fine now.
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // Nothing interesting should happen as a result of these.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-
- event->Signal();
- },
- &event, readable_a_context, w, a, b, c));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, c, MOJO_HANDLE_SIGNAL_READABLE, readable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(d, kTestMessageToC);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, NestedCancellation) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle c, d;
- CreateMessagePipe(&c, &d);
-
- static const char kTestMessageToA[] = "hey a";
- static const char kTestMessageToC[] = "hey c";
- static const char kTestMessageToD[] = "hey d";
-
- // This is a tricky test. It establishes a watch on |b| using one watcher and
- // watches on |c| and |d| using another watcher.
- //
- // A message is written to |d| to wake up |c|'s watch, and the notification
- // handler for that event does the following:
- // 1. Writes to |a| to eventually wake up |b|'s watcher.
- // 2. Rearms |c|'s watcher.
- // 3. Writes to |d| to eventually wake up |c|'s watcher again.
- //
- // Meanwhile, |b|'s watch notification handler cancels |c|'s watch altogether
- // before writing to |c| to wake up |d|.
- //
- // The net result should be that |c|'s context only gets notified once (from
- // the first write to |d| above) and everyone else gets notified as expected.
-
- MojoHandle b_watcher;
- MojoHandle cd_watcher;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&cd_watcher));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- uintptr_t readable_d_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle d, MojoResult result,
- MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToD, ReadMessage(d));
- event->Signal();
- },
- &event, d));
-
- static int num_expected_c_notifications = 1;
- uintptr_t readable_c_context = helper.CreateContext(base::Bind(
- [](MojoHandle cd_watcher, MojoHandle a, MojoHandle c, MojoHandle d,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_GT(num_expected_c_notifications--, 0);
-
- // Trigger an eventual |readable_b_context| notification.
- WriteMessage(a, kTestMessageToA);
-
- EXPECT_EQ(kTestMessageToC, ReadMessage(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr,
- nullptr, nullptr));
-
- // Trigger another eventual |readable_c_context| notification.
- WriteMessage(d, kTestMessageToC);
- },
- cd_watcher, a, c, d));
-
- uintptr_t readable_b_context = helper.CreateContext(base::Bind(
- [](MojoHandle cd_watcher, uintptr_t readable_c_context, MojoHandle c,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoCancelWatch(cd_watcher, readable_c_context));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoArmWatcher(cd_watcher, nullptr, nullptr,
- nullptr, nullptr));
-
- WriteMessage(c, kTestMessageToD);
- },
- cd_watcher, readable_c_context, c));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE,
- readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(cd_watcher, c, MOJO_HANDLE_SIGNAL_READABLE,
- readable_c_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(cd_watcher, d, MOJO_HANDLE_SIGNAL_READABLE,
- readable_d_context));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(cd_watcher, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(d, kTestMessageToC);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(cd_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(c));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(d));
-}
-
-TEST_F(WatcherTest, CancelSelfInNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- static uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle a,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
-
- // There should be no problem cancelling this watch from its own
- // notification invocation.
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context));
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
-
- // Arming should fail because there are no longer any registered
- // watches on the watcher.
- EXPECT_EQ(MOJO_RESULT_NOT_FOUND,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // And closing |a| should be fine (and should not invoke this
- // notification with MOJO_RESULT_CANCELLED) for the same reason.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- event->Signal();
- },
- &event, w, a));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, CloseWatcherInNotificationCallback) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA1[] = "hey a";
- static const char kTestMessageToA2[] = "hey a again";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle a, MojoHandle b,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA1, ReadMessage(a));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // There should be no problem closing this watcher from its own
- // notification callback.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-
- // And these should not trigger more notifications, because |w| has been
- // closed already.
- WriteMessage(b, kTestMessageToA2);
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- event->Signal();
- },
- &event, w, a, b));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA1);
- event.Wait();
-}
-
-TEST_F(WatcherTest, CloseWatcherAfterImplicitCancel) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- uintptr_t readable_a_context = helper.CreateContext(base::Bind(
- [](base::WaitableEvent* event, MojoHandle w, MojoHandle a,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- // This will cue up a notification for |MOJO_RESULT_CANCELLED|...
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
-
- // ...but it should never fire because we close the watcher here.
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-
- event->Signal();
- },
- &event, w, a));
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA);
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, OtherThreadCancelDuringNotification) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent wait_for_notification(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- base::WaitableEvent wait_for_cancellation(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- static bool callback_done = false;
- uintptr_t readable_a_context = helper.CreateContextWithCancel(
- base::Bind(
- [](base::WaitableEvent* wait_for_notification, MojoHandle w,
- MojoHandle a, MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
-
- wait_for_notification->Signal();
-
- // Give the other thread sufficient time to race with the completion
- // of this callback. There should be no race, since the cancellation
- // notification must be mutually exclusive to this notification.
- base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
-
- callback_done = true;
- },
- &wait_for_notification, w, a),
- base::Bind(
- [](base::WaitableEvent* wait_for_cancellation) {
- EXPECT_TRUE(callback_done);
- wait_for_cancellation->Signal();
- },
- &wait_for_cancellation));
-
- ThreadedRunner runner(base::Bind(
- [](base::WaitableEvent* wait_for_notification,
- base::WaitableEvent* wait_for_cancellation, MojoHandle w,
- uintptr_t readable_a_context) {
- wait_for_notification->Wait();
-
- // Cancel the watch while the notification is still running.
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, readable_a_context));
-
- wait_for_cancellation->Wait();
-
- EXPECT_TRUE(callback_done);
- },
- &wait_for_notification, &wait_for_cancellation, w, readable_a_context));
- runner.Start();
-
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(w, nullptr, nullptr, nullptr, nullptr));
-
- WriteMessage(b, kTestMessageToA);
- runner.Join();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-TEST_F(WatcherTest, WatchesCancelEachOtherFromNotifications) {
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- static const char kTestMessageToA[] = "hey a";
- static const char kTestMessageToB[] = "hey b";
-
- base::WaitableEvent wait_for_a_to_notify(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent wait_for_b_to_notify(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent wait_for_a_to_cancel(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent wait_for_b_to_cancel(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- MojoHandle a_watcher;
- MojoHandle b_watcher;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&a_watcher));
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&b_watcher));
-
- // We set up two watchers, one on |a| and one on |b|. They cancel each other
- // from within their respective watch notifications. This should be safe,
- // i.e., it should not deadlock, in spite of the fact that we also guarantee
- // mutually exclusive notification execution (including cancellations) on any
- // given watch.
- bool a_cancelled = false;
- bool b_cancelled = false;
- static uintptr_t readable_b_context;
- uintptr_t readable_a_context = helper.CreateContextWithCancel(
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_notify,
- base::WaitableEvent* wait_for_b_to_notify, MojoHandle b_watcher,
- MojoHandle a, MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToA, ReadMessage(a));
- wait_for_a_to_notify->Signal();
- wait_for_b_to_notify->Wait();
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoCancelWatch(b_watcher, readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b_watcher));
- },
- &wait_for_a_to_notify, &wait_for_b_to_notify, b_watcher, a),
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_cancel,
- base::WaitableEvent* wait_for_b_to_cancel, bool* a_cancelled) {
- *a_cancelled = true;
- wait_for_a_to_cancel->Signal();
- wait_for_b_to_cancel->Wait();
- },
- &wait_for_a_to_cancel, &wait_for_b_to_cancel, &a_cancelled));
-
- readable_b_context = helper.CreateContextWithCancel(
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_notify,
- base::WaitableEvent* wait_for_b_to_notify,
- uintptr_t readable_a_context, MojoHandle a_watcher, MojoHandle b,
- MojoResult result, MojoHandleSignalsState state) {
- EXPECT_EQ(MOJO_RESULT_OK, result);
- EXPECT_EQ(kTestMessageToB, ReadMessage(b));
- wait_for_b_to_notify->Signal();
- wait_for_a_to_notify->Wait();
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoCancelWatch(a_watcher, readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a_watcher));
- },
- &wait_for_a_to_notify, &wait_for_b_to_notify, readable_a_context,
- a_watcher, b),
- base::Bind(
- [](base::WaitableEvent* wait_for_a_to_cancel,
- base::WaitableEvent* wait_for_b_to_cancel, bool* b_cancelled) {
- *b_cancelled = true;
- wait_for_b_to_cancel->Signal();
- wait_for_a_to_cancel->Wait();
- },
- &wait_for_a_to_cancel, &wait_for_b_to_cancel, &b_cancelled));
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(a_watcher, a, MOJO_HANDLE_SIGNAL_READABLE,
- readable_a_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(a_watcher, nullptr, nullptr, nullptr, nullptr));
- EXPECT_EQ(MOJO_RESULT_OK, MojoWatch(b_watcher, b, MOJO_HANDLE_SIGNAL_READABLE,
- readable_b_context));
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoArmWatcher(b_watcher, nullptr, nullptr, nullptr, nullptr));
-
- ThreadedRunner runner(
- base::Bind([](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b));
- runner.Start();
-
- WriteMessage(a, kTestMessageToB);
-
- wait_for_a_to_cancel.Wait();
- wait_for_b_to_cancel.Wait();
- runner.Join();
-
- EXPECT_TRUE(a_cancelled);
- EXPECT_TRUE(b_cancelled);
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, AlwaysCancel) {
- // Basic sanity check to ensure that all possible ways to cancel a watch
- // result in a final MOJO_RESULT_CANCELLED notification.
-
- MojoHandle a, b;
- CreateMessagePipe(&a, &b);
-
- MojoHandle w;
- WatchHelper helper;
- EXPECT_EQ(MOJO_RESULT_OK, helper.CreateWatcher(&w));
-
- base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- const base::Closure signal_event =
- base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event));
-
- // Cancel via |MojoCancelWatch()|.
- uintptr_t context = helper.CreateContextWithCancel(
- WatchHelper::ContextCallback(), signal_event);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoCancelWatch(w, context));
- event.Wait();
- event.Reset();
-
- // Cancel by closing the watched handle.
- context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(),
- signal_event);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, a, MOJO_HANDLE_SIGNAL_READABLE, context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
- event.Wait();
- event.Reset();
-
- // Cancel by closing the watcher handle.
- context = helper.CreateContextWithCancel(WatchHelper::ContextCallback(),
- signal_event);
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, b, MOJO_HANDLE_SIGNAL_READABLE, context));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
- event.Wait();
-
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
-}
-
-TEST_F(WatcherTest, ArmFailureCirculation) {
- // Sanity check to ensure that all ready handles will eventually be returned
- // over a finite number of calls to MojoArmWatcher().
-
- constexpr size_t kNumTestPipes = 100;
- constexpr size_t kNumTestHandles = kNumTestPipes * 2;
- MojoHandle handles[kNumTestHandles];
-
- // Create a bunch of pipes and make sure they're all readable.
- for (size_t i = 0; i < kNumTestPipes; ++i) {
- CreateMessagePipe(&handles[i], &handles[i + kNumTestPipes]);
- WriteMessage(handles[i], "hey");
- WriteMessage(handles[i + kNumTestPipes], "hay");
- WaitForSignals(handles[i], MOJO_HANDLE_SIGNAL_READABLE);
- WaitForSignals(handles[i + kNumTestPipes], MOJO_HANDLE_SIGNAL_READABLE);
- }
-
- // Create a watcher and watch all of them.
- MojoHandle w;
- EXPECT_EQ(MOJO_RESULT_OK, MojoCreateWatcher(&ExpectOnlyCancel, &w));
- for (size_t i = 0; i < kNumTestHandles; ++i) {
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoWatch(w, handles[i], MOJO_HANDLE_SIGNAL_READABLE, i));
- }
-
- // Keep trying to arm |w| until every watch gets an entry in |ready_contexts|.
- // If MojoArmWatcher() is well-behaved, this should terminate eventually.
- std::set<uintptr_t> ready_contexts;
- while (ready_contexts.size() < kNumTestHandles) {
- uint32_t num_ready_contexts = 1;
- uintptr_t ready_context;
- MojoResult ready_result;
- MojoHandleSignalsState ready_state;
- EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
- MojoArmWatcher(w, &num_ready_contexts, &ready_context,
- &ready_result, &ready_state));
- EXPECT_EQ(1u, num_ready_contexts);
- EXPECT_EQ(MOJO_RESULT_OK, ready_result);
- ready_contexts.insert(ready_context);
- }
-
- for (size_t i = 0; i < kNumTestHandles; ++i)
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(handles[i]));
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(w));
-}
-
-} // namespace
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn
deleted file mode 100644
index a15456a..0000000
--- a/mojo/edk/test/BUILD.gn
+++ /dev/null
@@ -1,131 +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.
-
-import("//testing/test.gni")
-
-static_library("test_support") {
- testonly = true
- sources = [
- "mojo_test_base.cc",
- "mojo_test_base.h",
- "test_utils.h",
- "test_utils_posix.cc",
- "test_utils_win.cc",
- ]
-
- if (!is_ios) {
- sources += [
- "multiprocess_test_helper.cc",
- "multiprocess_test_helper.h",
- ]
- }
-
- deps = [
- "//base",
- "//base/test:test_support",
- "//mojo/edk/system",
- "//mojo/public/cpp/system",
- "//testing/gtest",
- ]
-}
-
-source_set("run_all_unittests") {
- testonly = true
- sources = [
- "run_all_unittests.cc",
- ]
-
- deps = [
- ":test_support",
- ":test_support_impl",
- "//base",
- "//base/test:test_support",
- "//mojo/edk/system",
- "//mojo/public/c/test_support",
- "//testing/gtest",
- ]
-
- if (is_linux && !is_component_build) {
- public_configs = [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
- }
-}
-
-source_set("run_all_perftests") {
- testonly = true
- deps = [
- ":test_support_impl",
- "//base",
- "//base/test:test_support",
- "//mojo/edk/system",
- "//mojo/edk/test:test_support",
- "//mojo/public/c/test_support",
- ]
-
- sources = [
- "run_all_perftests.cc",
- ]
-
- if (is_linux && !is_component_build) {
- public_configs = [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
- }
-}
-
-static_library("test_support_impl") {
- testonly = true
- deps = [
- "//base",
- "//base/test:test_support",
- "//mojo/public/c/test_support",
- "//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_unittests",
- ":mojo_public_system_perftests",
- ":mojo_public_system_unittests",
- ]
-}
-
-test("mojo_public_bindings_perftests") {
- deps = [
- ":run_all_perftests",
- "//mojo/edk/test:test_support",
- "//mojo/public/cpp/bindings/tests:perftests",
- ]
-}
-
-test("mojo_public_bindings_unittests") {
- deps = [
- ":run_all_unittests",
- "//mojo/edk/test:test_support",
- "//mojo/public/cpp/bindings/tests",
- ]
-}
-
-test("mojo_public_system_perftests") {
- deps = [
- ":run_all_perftests",
- "//mojo/public/c/system/tests:perftests",
- ]
-}
-
-test("mojo_public_system_unittests") {
- deps = [
- ":run_all_unittests",
- "//mojo/public/cpp/system/tests",
- ]
-}
diff --git a/mojo/edk/test/mojo_test_base.cc b/mojo/edk/test/mojo_test_base.cc
deleted file mode 100644
index 71a5e3b..0000000
--- a/mojo/edk/test/mojo_test_base.cc
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/test/mojo_test_base.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/synchronization/waitable_event.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/system/handle_signals_state.h"
-#include "mojo/public/c/system/buffer.h"
-#include "mojo/public/c/system/data_pipe.h"
-#include "mojo/public/c/system/functions.h"
-#include "mojo/public/c/system/watcher.h"
-#include "mojo/public/cpp/system/wait.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "base/mac/mach_port_broker.h"
-#endif
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-namespace {
-base::MachPortBroker* g_mach_broker = nullptr;
-}
-#endif
-
-MojoTestBase::MojoTestBase() {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (!g_mach_broker) {
- g_mach_broker = new base::MachPortBroker("mojo_test");
- CHECK(g_mach_broker->Init());
- SetMachPortProvider(g_mach_broker);
- }
-#endif
-}
-
-MojoTestBase::~MojoTestBase() {}
-
-MojoTestBase::ClientController& MojoTestBase::StartClient(
- const std::string& client_name) {
- clients_.push_back(base::MakeUnique<ClientController>(
- client_name, this, process_error_callback_, launch_type_));
- return *clients_.back();
-}
-
-MojoTestBase::ClientController::ClientController(
- const std::string& client_name,
- MojoTestBase* test,
- const ProcessErrorCallback& process_error_callback,
- LaunchType launch_type) {
-#if !defined(OS_IOS)
-#if defined(OS_MACOSX)
- // This lock needs to be held while launching the child because the Mach port
- // broker only allows task ports to be received from known child processes.
- // However, it can only know the child process's pid after the child has
- // launched. To prevent a race where the child process sends its task port
- // before the pid has been registered, the lock needs to be held over both
- // launch and child pid registration.
- base::AutoLock lock(g_mach_broker->GetLock());
-#endif
- helper_.set_process_error_callback(process_error_callback);
- pipe_ = helper_.StartChild(client_name, launch_type);
-#if defined(OS_MACOSX)
- g_mach_broker->AddPlaceholderForPid(helper_.test_child().Handle());
-#endif
-#endif
-}
-
-MojoTestBase::ClientController::~ClientController() {
- CHECK(was_shutdown_)
- << "Test clients should be waited on explicitly with WaitForShutdown().";
-}
-
-void MojoTestBase::ClientController::ClosePeerConnection() {
-#if !defined(OS_IOS)
- helper_.ClosePeerConnection();
-#endif
-}
-
-int MojoTestBase::ClientController::WaitForShutdown() {
- was_shutdown_ = true;
-#if !defined(OS_IOS)
- int retval = helper_.WaitForChildShutdown();
-#if defined(OS_MACOSX)
- base::AutoLock lock(g_mach_broker->GetLock());
- g_mach_broker->InvalidatePid(helper_.test_child().Handle());
-#endif
- return retval;
-#else
- NOTREACHED();
- return 1;
-#endif
-}
-
-// static
-void MojoTestBase::CloseHandle(MojoHandle h) {
- EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h));
-}
-
-// static
-void MojoTestBase::CreateMessagePipe(MojoHandle *p0, MojoHandle* p1) {
- MojoCreateMessagePipe(nullptr, p0, p1);
- CHECK_NE(*p0, MOJO_HANDLE_INVALID);
- CHECK_NE(*p1, MOJO_HANDLE_INVALID);
-}
-
-// static
-void MojoTestBase::WriteMessageWithHandles(MojoHandle mp,
- const std::string& message,
- const MojoHandle *handles,
- uint32_t num_handles) {
- CHECK_EQ(MojoWriteMessage(mp, message.data(),
- static_cast<uint32_t>(message.size()),
- handles, num_handles, MOJO_WRITE_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
-}
-
-// static
-void MojoTestBase::WriteMessage(MojoHandle mp, const std::string& message) {
- WriteMessageWithHandles(mp, message, nullptr, 0);
-}
-
-// static
-std::string MojoTestBase::ReadMessageWithHandles(
- MojoHandle mp,
- MojoHandle* handles,
- uint32_t expected_num_handles) {
- CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE), MOJO_RESULT_OK);
-
- uint32_t message_size = 0;
- uint32_t num_handles = 0;
- CHECK_EQ(MojoReadMessage(mp, nullptr, &message_size, nullptr, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_RESOURCE_EXHAUSTED);
- CHECK_EQ(expected_num_handles, num_handles);
-
- std::string message(message_size, 'x');
- CHECK_EQ(MojoReadMessage(mp, &message[0], &message_size, handles,
- &num_handles, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(message_size, message.size());
- CHECK_EQ(num_handles, expected_num_handles);
-
- return message;
-}
-
-// static
-std::string MojoTestBase::ReadMessageWithOptionalHandle(MojoHandle mp,
- MojoHandle* handle) {
- CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE), MOJO_RESULT_OK);
-
- uint32_t message_size = 0;
- uint32_t num_handles = 0;
- CHECK_EQ(MojoReadMessage(mp, nullptr, &message_size, nullptr, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_RESOURCE_EXHAUSTED);
- CHECK(num_handles == 0 || num_handles == 1);
-
- CHECK(handle);
-
- std::string message(message_size, 'x');
- CHECK_EQ(MojoReadMessage(mp, &message[0], &message_size, handle,
- &num_handles, MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(message_size, message.size());
- CHECK(num_handles == 0 || num_handles == 1);
-
- if (num_handles)
- CHECK_NE(*handle, MOJO_HANDLE_INVALID);
- else
- *handle = MOJO_HANDLE_INVALID;
-
- return message;
-}
-
-// static
-std::string MojoTestBase::ReadMessage(MojoHandle mp) {
- return ReadMessageWithHandles(mp, nullptr, 0);
-}
-
-// static
-void MojoTestBase::ReadMessage(MojoHandle mp,
- char* data,
- size_t num_bytes) {
- CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE), MOJO_RESULT_OK);
-
- uint32_t message_size = 0;
- uint32_t num_handles = 0;
- CHECK_EQ(MojoReadMessage(mp, nullptr, &message_size, nullptr, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_RESOURCE_EXHAUSTED);
- CHECK_EQ(num_handles, 0u);
- CHECK_EQ(message_size, num_bytes);
-
- CHECK_EQ(MojoReadMessage(mp, data, &message_size, nullptr, &num_handles,
- MOJO_READ_MESSAGE_FLAG_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(num_handles, 0u);
- CHECK_EQ(message_size, num_bytes);
-}
-
-// static
-void MojoTestBase::VerifyTransmission(MojoHandle source,
- MojoHandle dest,
- const std::string& message) {
- WriteMessage(source, message);
-
- // We don't use EXPECT_EQ; failures on really long messages make life hard.
- EXPECT_TRUE(message == ReadMessage(dest));
-}
-
-// static
-void MojoTestBase::VerifyEcho(MojoHandle mp,
- const std::string& message) {
- VerifyTransmission(mp, mp, message);
-}
-
-// static
-MojoHandle MojoTestBase::CreateBuffer(uint64_t size) {
- MojoHandle h;
- EXPECT_EQ(MojoCreateSharedBuffer(nullptr, size, &h), MOJO_RESULT_OK);
- return h;
-}
-
-// static
-MojoHandle MojoTestBase::DuplicateBuffer(MojoHandle h, bool read_only) {
- MojoHandle new_handle;
- MojoDuplicateBufferHandleOptions options = {
- sizeof(MojoDuplicateBufferHandleOptions),
- MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE
- };
- if (read_only)
- options.flags |= MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoDuplicateBufferHandle(h, &options, &new_handle));
- return new_handle;
-}
-
-// static
-void MojoTestBase::WriteToBuffer(MojoHandle h,
- size_t offset,
- const base::StringPiece& s) {
- char* data;
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoMapBuffer(h, offset, s.size(), reinterpret_cast<void**>(&data),
- MOJO_MAP_BUFFER_FLAG_NONE));
- memcpy(data, s.data(), s.size());
- EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(static_cast<void*>(data)));
-}
-
-// static
-void MojoTestBase::ExpectBufferContents(MojoHandle h,
- size_t offset,
- const base::StringPiece& s) {
- char* data;
- EXPECT_EQ(MOJO_RESULT_OK,
- MojoMapBuffer(h, offset, s.size(), reinterpret_cast<void**>(&data),
- MOJO_MAP_BUFFER_FLAG_NONE));
- EXPECT_EQ(s, base::StringPiece(data, s.size()));
- EXPECT_EQ(MOJO_RESULT_OK, MojoUnmapBuffer(static_cast<void*>(data)));
-}
-
-// static
-void MojoTestBase::CreateDataPipe(MojoHandle *p0,
- MojoHandle* p1,
- size_t capacity) {
- MojoCreateDataPipeOptions options;
- options.struct_size = static_cast<uint32_t>(sizeof(options));
- options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
- options.element_num_bytes = 1;
- options.capacity_num_bytes = static_cast<uint32_t>(capacity);
-
- MojoCreateDataPipe(&options, p0, p1);
- CHECK_NE(*p0, MOJO_HANDLE_INVALID);
- CHECK_NE(*p1, MOJO_HANDLE_INVALID);
-}
-
-// static
-void MojoTestBase::WriteData(MojoHandle producer, const std::string& data) {
- CHECK_EQ(WaitForSignals(producer, MOJO_HANDLE_SIGNAL_WRITABLE),
- MOJO_RESULT_OK);
- uint32_t num_bytes = static_cast<uint32_t>(data.size());
- CHECK_EQ(MojoWriteData(producer, data.data(), &num_bytes,
- MOJO_WRITE_DATA_FLAG_ALL_OR_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(num_bytes, static_cast<uint32_t>(data.size()));
-}
-
-// static
-std::string MojoTestBase::ReadData(MojoHandle consumer, size_t size) {
- CHECK_EQ(WaitForSignals(consumer, MOJO_HANDLE_SIGNAL_READABLE),
- MOJO_RESULT_OK);
- std::vector<char> buffer(size);
- uint32_t num_bytes = static_cast<uint32_t>(size);
- CHECK_EQ(MojoReadData(consumer, buffer.data(), &num_bytes,
- MOJO_WRITE_DATA_FLAG_ALL_OR_NONE),
- MOJO_RESULT_OK);
- CHECK_EQ(num_bytes, static_cast<uint32_t>(size));
-
- return std::string(buffer.data(), buffer.size());
-}
-
-// static
-MojoHandleSignalsState MojoTestBase::GetSignalsState(MojoHandle handle) {
- MojoHandleSignalsState signals_state;
- CHECK_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(handle, &signals_state));
- return signals_state;
-}
-
-// static
-MojoResult MojoTestBase::WaitForSignals(MojoHandle handle,
- MojoHandleSignals signals,
- MojoHandleSignalsState* state) {
- return Wait(Handle(handle), signals, state);
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/mojo_test_base.h b/mojo/edk/test/mojo_test_base.h
deleted file mode 100644
index 35e2c2b..0000000
--- a/mojo/edk/test/mojo_test_base.h
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_TEST_MOJO_TEST_BASE_H_
-#define MOJO_EDK_TEST_MOJO_TEST_BASE_H_
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/test/multiprocess_test_helper.h"
-#include "mojo/public/c/system/types.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-class MojoTestBase : public testing::Test {
- public:
- MojoTestBase();
- ~MojoTestBase() override;
-
- using LaunchType = MultiprocessTestHelper::LaunchType;
- using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>;
-
- class ClientController {
- public:
- ClientController(const std::string& client_name,
- MojoTestBase* test,
- const ProcessErrorCallback& process_error_callback,
- LaunchType launch_type);
- ~ClientController();
-
- MojoHandle pipe() const { return pipe_.get().value(); }
-
- void ClosePeerConnection();
- int WaitForShutdown();
-
- private:
- friend class MojoTestBase;
-
-#if !defined(OS_IOS)
- MultiprocessTestHelper helper_;
-#endif
- ScopedMessagePipeHandle pipe_;
- bool was_shutdown_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(ClientController);
- };
-
- // Set the callback to handle bad messages received from test client
- // processes. This can be set to a different callback before starting each
- // client.
- void set_process_error_callback(const ProcessErrorCallback& callback) {
- process_error_callback_ = callback;
- }
-
- ClientController& StartClient(const std::string& client_name);
-
- template <typename HandlerFunc>
- void StartClientWithHandler(const std::string& client_name,
- HandlerFunc handler) {
- int expected_exit_code = 0;
- ClientController& c = StartClient(client_name);
- handler(c.pipe(), &expected_exit_code);
- EXPECT_EQ(expected_exit_code, c.WaitForShutdown());
- }
-
- // Closes a handle and expects success.
- static void CloseHandle(MojoHandle h);
-
- ////// Message pipe test utilities ///////
-
- // Creates a new pipe, returning endpoint handles in |p0| and |p1|.
- static void CreateMessagePipe(MojoHandle* p0, MojoHandle* p1);
-
- // Writes a string to the pipe, transferring handles in the process.
- static void WriteMessageWithHandles(MojoHandle mp,
- const std::string& message,
- const MojoHandle* handles,
- uint32_t num_handles);
-
- // Writes a string to the pipe with no handles.
- static void WriteMessage(MojoHandle mp, const std::string& message);
-
- // Reads a string from the pipe, expecting to read an exact number of handles
- // in the process. Returns the read string.
- static std::string ReadMessageWithHandles(MojoHandle mp,
- MojoHandle* handles,
- uint32_t expected_num_handles);
-
- // Reads a string from the pipe, expecting either zero or one handles.
- // If no handle is read, |handle| will be reset.
- static std::string ReadMessageWithOptionalHandle(MojoHandle mp,
- MojoHandle* handle);
-
- // Reads a string from the pipe, expecting to read no handles.
- // Returns the string.
- static std::string ReadMessage(MojoHandle mp);
-
- // Reads a string from the pipe, expecting to read no handles and exactly
- // |num_bytes| bytes, which are read into |data|.
- static void ReadMessage(MojoHandle mp, char* data, size_t num_bytes);
-
- // Writes |message| to |in| and expects to read it back from |out|.
- static void VerifyTransmission(MojoHandle in,
- MojoHandle out,
- const std::string& message);
-
- // Writes |message| to |mp| and expects to read it back from the same handle.
- static void VerifyEcho(MojoHandle mp, const std::string& message);
-
- //////// Shared buffer test utilities /////////
-
- // Creates a new shared buffer.
- static MojoHandle CreateBuffer(uint64_t size);
-
- // Duplicates a shared buffer to a new handle.
- static MojoHandle DuplicateBuffer(MojoHandle h, bool read_only);
-
- // Maps a buffer, writes some data into it, and unmaps it.
- static void WriteToBuffer(MojoHandle h,
- size_t offset,
- const base::StringPiece& s);
-
- // Maps a buffer, tests the value of some of its contents, and unmaps it.
- static void ExpectBufferContents(MojoHandle h,
- size_t offset,
- const base::StringPiece& s);
-
- //////// Data pipe test utilities /////////
-
- // Creates a new data pipe.
- static void CreateDataPipe(MojoHandle* producer,
- MojoHandle* consumer,
- size_t capacity);
-
- // Writes data to a data pipe.
- static void WriteData(MojoHandle producer, const std::string& data);
-
- // Reads data from a data pipe.
- static std::string ReadData(MojoHandle consumer, size_t size);
-
- // Queries the signals state of |handle|.
- static MojoHandleSignalsState GetSignalsState(MojoHandle handle);
-
- // Helper to block the calling thread waiting for signals to be raised.
- static MojoResult WaitForSignals(MojoHandle handle,
- MojoHandleSignals signals,
- MojoHandleSignalsState* state = nullptr);
-
- void set_launch_type(LaunchType launch_type) { launch_type_ = launch_type; }
-
- private:
- friend class ClientController;
-
- std::vector<std::unique_ptr<ClientController>> clients_;
-
- ProcessErrorCallback process_error_callback_;
-
- LaunchType launch_type_ = LaunchType::CHILD;
-
- DISALLOW_COPY_AND_ASSIGN(MojoTestBase);
-};
-
-// Launches a new child process running the test client |client_name| connected
-// to a new message pipe bound to |pipe_name|. |pipe_name| is automatically
-// closed on test teardown.
-#define RUN_CHILD_ON_PIPE(client_name, pipe_name) \
- StartClientWithHandler( \
- #client_name, \
- [&](MojoHandle pipe_name, int *expected_exit_code) { {
-
-// Waits for the client to terminate and expects a return code of zero.
-#define END_CHILD() \
- } \
- *expected_exit_code = 0; \
- });
-
-// Wait for the client to terminate with a specific return code.
-#define END_CHILD_AND_EXPECT_EXIT_CODE(code) \
- } \
- *expected_exit_code = code; \
- });
-
-// Use this to declare the child process's "main()" function for tests using
-// MojoTestBase and MultiprocessTestHelper. It returns an |int|, which will
-// will be the process's exit code (but see the comment about
-// WaitForChildShutdown()).
-//
-// The function is defined as a subclass of |test_base| to facilitate shared
-// code between test clients and to allow clients to spawn children themselves.
-//
-// |pipe_name| will be bound to the MojoHandle of a message pipe connected
-// to the parent process (see RUN_CHILD_ON_PIPE above.) This pipe handle is
-// automatically closed on test client teardown.
-#if !defined(OS_IOS)
-#define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name) \
- class client_name##_MainFixture : public test_base { \
- void TestBody() override {} \
- public: \
- int Main(MojoHandle); \
- }; \
- MULTIPROCESS_TEST_MAIN_WITH_SETUP( \
- client_name##TestChildMain, \
- ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \
- client_name##_MainFixture test; \
- return ::mojo::edk::test::MultiprocessTestHelper::RunClientMain( \
- base::Bind(&client_name##_MainFixture::Main, \
- base::Unretained(&test))); \
- } \
- int client_name##_MainFixture::Main(MojoHandle pipe_name)
-
-// This is a version of DEFINE_TEST_CLIENT_WITH_PIPE which can be used with
-// gtest ASSERT/EXPECT macros.
-#define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name) \
- class client_name##_MainFixture : public test_base { \
- void TestBody() override {} \
- public: \
- void Main(MojoHandle); \
- }; \
- MULTIPROCESS_TEST_MAIN_WITH_SETUP( \
- client_name##TestChildMain, \
- ::mojo::edk::test::MultiprocessTestHelper::ChildSetup) { \
- client_name##_MainFixture test; \
- return ::mojo::edk::test::MultiprocessTestHelper::RunClientTestMain( \
- base::Bind(&client_name##_MainFixture::Main, \
- base::Unretained(&test))); \
- } \
- void client_name##_MainFixture::Main(MojoHandle pipe_name)
-#else // !defined(OS_IOS)
-#define DEFINE_TEST_CLIENT_WITH_PIPE(client_name, test_base, pipe_name)
-#define DEFINE_TEST_CLIENT_TEST_WITH_PIPE(client_name, test_base, pipe_name)
-#endif // !defined(OS_IOS)
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_TEST_MOJO_TEST_BASE_H_
diff --git a/mojo/edk/test/multiprocess_test_helper.cc b/mojo/edk/test/multiprocess_test_helper.cc
deleted file mode 100644
index cf37782..0000000
--- a/mojo/edk/test/multiprocess_test_helper.cc
+++ /dev/null
@@ -1,263 +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/test/multiprocess_test_helper.h"
-
-#include <functional>
-#include <set>
-#include <utility>
-
-#include "base/base_paths.h"
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/path_service.h"
-#include "base/process/kill.h"
-#include "base/process/process_handle.h"
-#include "base/run_loop.h"
-#include "base/strings/stringprintf.h"
-#include "base/task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/named_platform_handle.h"
-#include "mojo/edk/embedder/named_platform_handle_utils.h"
-#include "mojo/edk/embedder/pending_process_connection.h"
-#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
-#include "base/mac/mach_port_broker.h"
-#endif
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-namespace {
-
-const char kMojoPrimordialPipeToken[] = "mojo-primordial-pipe-token";
-const char kMojoNamedPipeName[] = "mojo-named-pipe-name";
-
-template <typename Func>
-int RunClientFunction(Func handler, bool pass_pipe_ownership_to_main) {
- CHECK(MultiprocessTestHelper::primordial_pipe.is_valid());
- ScopedMessagePipeHandle pipe =
- std::move(MultiprocessTestHelper::primordial_pipe);
- MessagePipeHandle pipe_handle =
- pass_pipe_ownership_to_main ? pipe.release() : pipe.get();
- return handler(pipe_handle.value());
-}
-
-} // namespace
-
-MultiprocessTestHelper::MultiprocessTestHelper() {}
-
-MultiprocessTestHelper::~MultiprocessTestHelper() {
- CHECK(!test_child_.process.IsValid());
-}
-
-ScopedMessagePipeHandle MultiprocessTestHelper::StartChild(
- const std::string& test_child_name,
- LaunchType launch_type) {
- return StartChildWithExtraSwitch(test_child_name, std::string(),
- std::string(), launch_type);
-}
-
-ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch(
- const std::string& test_child_name,
- const std::string& switch_string,
- const std::string& switch_value,
- LaunchType launch_type) {
- CHECK(!test_child_name.empty());
- CHECK(!test_child_.process.IsValid());
-
- std::string test_child_main = test_child_name + "TestChildMain";
-
- // Manually construct the new child's commandline to avoid copying unwanted
- // values.
- base::CommandLine command_line(
- base::GetMultiProcessTestChildBaseCommandLine().GetProgram());
-
- std::set<std::string> uninherited_args;
- uninherited_args.insert("mojo-platform-channel-handle");
- uninherited_args.insert(switches::kTestChildProcess);
-
- // Copy commandline switches from the parent process, except for the
- // multiprocess client name and mojo message pipe handle; this allows test
- // clients to spawn other test clients.
- for (const auto& entry :
- base::CommandLine::ForCurrentProcess()->GetSwitches()) {
- if (uninherited_args.find(entry.first) == uninherited_args.end())
- command_line.AppendSwitchNative(entry.first, entry.second);
- }
-
- PlatformChannelPair channel;
- NamedPlatformHandle named_pipe;
- HandlePassingInformation handle_passing_info;
- if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER) {
- channel.PrepareToPassClientHandleToChildProcess(&command_line,
- &handle_passing_info);
- } else if (launch_type == LaunchType::NAMED_CHILD ||
- launch_type == LaunchType::NAMED_PEER) {
-#if defined(OS_POSIX)
- base::FilePath temp_dir;
- CHECK(base::PathService::Get(base::DIR_TEMP, &temp_dir));
- named_pipe = NamedPlatformHandle(
- temp_dir.AppendASCII(GenerateRandomToken()).value());
-#else
- named_pipe = NamedPlatformHandle(GenerateRandomToken());
-#endif
- command_line.AppendSwitchNative(kMojoNamedPipeName, named_pipe.name);
- }
-
- if (!switch_string.empty()) {
- CHECK(!command_line.HasSwitch(switch_string));
- if (!switch_value.empty())
- command_line.AppendSwitchASCII(switch_string, switch_value);
- else
- command_line.AppendSwitch(switch_string);
- }
-
- base::LaunchOptions options;
-#if defined(OS_POSIX)
- options.fds_to_remap = &handle_passing_info;
-#elif defined(OS_WIN)
- options.start_hidden = true;
- if (base::win::GetVersion() >= base::win::VERSION_VISTA)
- options.handles_to_inherit = &handle_passing_info;
- else
- options.inherit_handles = true;
-#else
-#error "Not supported yet."
-#endif
-
- // NOTE: In the case of named pipes, it's important that the server handle be
- // created before the child process is launched; otherwise the server binding
- // the pipe path can race with child's connection to the pipe.
- ScopedPlatformHandle server_handle;
- if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER) {
- server_handle = channel.PassServerHandle();
- } else if (launch_type == LaunchType::NAMED_CHILD ||
- launch_type == LaunchType::NAMED_PEER) {
- server_handle = CreateServerHandle(named_pipe);
- }
-
- PendingProcessConnection process;
- ScopedMessagePipeHandle pipe;
- if (launch_type == LaunchType::CHILD ||
- launch_type == LaunchType::NAMED_CHILD) {
- std::string pipe_token;
- pipe = process.CreateMessagePipe(&pipe_token);
- command_line.AppendSwitchASCII(kMojoPrimordialPipeToken, pipe_token);
- } else if (launch_type == LaunchType::PEER ||
- launch_type == LaunchType::NAMED_PEER) {
- peer_token_ = mojo::edk::GenerateRandomToken();
- pipe = ConnectToPeerProcess(std::move(server_handle), peer_token_);
- }
-
- test_child_ =
- base::SpawnMultiProcessTestChild(test_child_main, command_line, options);
- if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER)
- channel.ChildProcessLaunched();
-
- if (launch_type == LaunchType::CHILD ||
- launch_type == LaunchType::NAMED_CHILD) {
- DCHECK(server_handle.is_valid());
- process.Connect(test_child_.process.Handle(),
- ConnectionParams(std::move(server_handle)),
- process_error_callback_);
- }
-
- CHECK(test_child_.process.IsValid());
- return pipe;
-}
-
-int MultiprocessTestHelper::WaitForChildShutdown() {
- CHECK(test_child_.process.IsValid());
-
- int rv = -1;
- WaitForMultiprocessTestChildExit(test_child_.process,
- TestTimeouts::action_timeout(), &rv);
- test_child_.process.Close();
- return rv;
-}
-
-void MultiprocessTestHelper::ClosePeerConnection() {
- DCHECK(!peer_token_.empty());
- ::mojo::edk::ClosePeerConnection(peer_token_);
- peer_token_.clear();
-}
-
-bool MultiprocessTestHelper::WaitForChildTestShutdown() {
- return WaitForChildShutdown() == 0;
-}
-
-// static
-void MultiprocessTestHelper::ChildSetup() {
- CHECK(base::CommandLine::InitializedForCurrentProcess());
-
- std::string primordial_pipe_token =
- base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- kMojoPrimordialPipeToken);
- NamedPlatformHandle named_pipe(
- base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
- kMojoNamedPipeName));
- if (!primordial_pipe_token.empty()) {
- primordial_pipe = CreateChildMessagePipe(primordial_pipe_token);
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- CHECK(base::MachPortBroker::ChildSendTaskPortToParent("mojo_test"));
-#endif
- if (named_pipe.is_valid()) {
- SetParentPipeHandle(CreateClientHandle(named_pipe));
- } else {
- SetParentPipeHandle(
- PlatformChannelPair::PassClientHandleFromParentProcess(
- *base::CommandLine::ForCurrentProcess()));
- }
- } else {
- if (named_pipe.is_valid()) {
- primordial_pipe = ConnectToPeerProcess(CreateClientHandle(named_pipe));
- } else {
- primordial_pipe = ConnectToPeerProcess(
- PlatformChannelPair::PassClientHandleFromParentProcess(
- *base::CommandLine::ForCurrentProcess()));
- }
- }
-}
-
-// static
-int MultiprocessTestHelper::RunClientMain(
- const base::Callback<int(MojoHandle)>& main,
- bool pass_pipe_ownership_to_main) {
- return RunClientFunction(
- [main](MojoHandle handle) { return main.Run(handle); },
- pass_pipe_ownership_to_main);
-}
-
-// static
-int MultiprocessTestHelper::RunClientTestMain(
- const base::Callback<void(MojoHandle)>& main) {
- return RunClientFunction(
- [main](MojoHandle handle) {
- main.Run(handle);
- return (::testing::Test::HasFatalFailure() ||
- ::testing::Test::HasNonfatalFailure())
- ? 1
- : 0;
- },
- true /* close_pipe_on_exit */);
-}
-
-// static
-mojo::ScopedMessagePipeHandle MultiprocessTestHelper::primordial_pipe;
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/multiprocess_test_helper.h b/mojo/edk/test/multiprocess_test_helper.h
deleted file mode 100644
index dc1c9bc..0000000
--- a/mojo/edk/test/multiprocess_test_helper.h
+++ /dev/null
@@ -1,110 +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_TEST_MULTIPROCESS_TEST_HELPER_H_
-#define MOJO_EDK_TEST_MULTIPROCESS_TEST_HELPER_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/process/process.h"
-#include "base/test/multiprocess_test.h"
-#include "base/test/test_timeouts.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "testing/multiprocess_func_list.h"
-
-namespace mojo {
-
-namespace edk {
-
-namespace test {
-
-class MultiprocessTestHelper {
- public:
- using HandlerCallback = base::Callback<void(ScopedMessagePipeHandle)>;
-
- enum class LaunchType {
- // Launch the child process as a child in the mojo system.
- CHILD,
-
- // Launch the child process as an unrelated peer process in the mojo system.
- PEER,
-
- // Launch the child process as a child in the mojo system, using a named
- // pipe.
- NAMED_CHILD,
-
- // Launch the child process as an unrelated peer process in the mojo
- // system, using a named pipe.
- NAMED_PEER,
- };
-
- MultiprocessTestHelper();
- ~MultiprocessTestHelper();
-
- // Start a child process and run the "main" function "named" |test_child_name|
- // declared using |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| or
- // |MOJO_MULTIPROCESS_TEST_CHILD_TEST()| (below).
- ScopedMessagePipeHandle StartChild(
- const std::string& test_child_name,
- LaunchType launch_type = LaunchType::CHILD);
-
- // Like |StartChild()|, but appends an extra switch (with ASCII value) to the
- // command line. (The switch must not already be present in the default
- // command line.)
- ScopedMessagePipeHandle StartChildWithExtraSwitch(
- const std::string& test_child_name,
- const std::string& switch_string,
- const std::string& switch_value,
- LaunchType launch_type);
-
- void set_process_error_callback(const ProcessErrorCallback& callback) {
- process_error_callback_ = callback;
- }
-
- void ClosePeerConnection();
-
- // Wait for the child process to terminate.
- // Returns the exit code of the child process. Note that, though it's declared
- // to be an |int|, the exit code is subject to mangling by the OS. E.g., we
- // usually return -1 on error in the child (e.g., if |test_child_name| was not
- // found), but this is mangled to 255 on Linux. You should only rely on codes
- // 0-127 being preserved, and -1 being outside the range 0-127.
- int WaitForChildShutdown();
-
- // Like |WaitForChildShutdown()|, but returns true on success (exit code of 0)
- // and false otherwise. You probably want to do something like
- // |EXPECT_TRUE(WaitForChildTestShutdown());|.
- bool WaitForChildTestShutdown();
-
- const base::Process& test_child() const { return test_child_.process; }
-
- // Used by macros in mojo/edk/test/mojo_test_base.h to support multiprocess
- // test client initialization.
- static void ChildSetup();
- static int RunClientMain(const base::Callback<int(MojoHandle)>& main,
- bool pass_pipe_ownership_to_main = false);
- static int RunClientTestMain(const base::Callback<void(MojoHandle)>& main);
-
- // For use (and only valid) in the child process:
- static mojo::ScopedMessagePipeHandle primordial_pipe;
-
- private:
- // Valid after |StartChild()| and before |WaitForChildShutdown()|.
- base::SpawnChildResult test_child_;
-
- ProcessErrorCallback process_error_callback_;
-
- std::string peer_token_;
-
- DISALLOW_COPY_AND_ASSIGN(MultiprocessTestHelper);
-};
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_TEST_MULTIPROCESS_TEST_HELPER_H_
diff --git a/mojo/edk/test/multiprocess_test_helper_unittest.cc b/mojo/edk/test/multiprocess_test_helper_unittest.cc
deleted file mode 100644
index f7e9e83..0000000
--- a/mojo/edk/test/multiprocess_test_helper_unittest.cc
+++ /dev/null
@@ -1,165 +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/test/multiprocess_test_helper.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/logging.h"
-#include "build/build_config.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "mojo/edk/system/test_utils.h"
-#include "mojo/edk/test/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_POSIX)
-#include <fcntl.h>
-#endif
-
-namespace mojo {
-namespace edk {
-namespace test {
-namespace {
-
-bool IsNonBlocking(const PlatformHandle& handle) {
-#if defined(OS_WIN)
- // Haven't figured out a way to query whether a HANDLE was created with
- // FILE_FLAG_OVERLAPPED.
- return true;
-#else
- return fcntl(handle.handle, F_GETFL) & O_NONBLOCK;
-#endif
-}
-
-bool WriteByte(const PlatformHandle& handle, char c) {
- size_t bytes_written = 0;
- BlockingWrite(handle, &c, 1, &bytes_written);
- return bytes_written == 1;
-}
-
-bool ReadByte(const PlatformHandle& handle, char* c) {
- size_t bytes_read = 0;
- BlockingRead(handle, c, 1, &bytes_read);
- return bytes_read == 1;
-}
-
-using MultiprocessTestHelperTest = testing::Test;
-
-TEST_F(MultiprocessTestHelperTest, RunChild) {
- MultiprocessTestHelper helper;
- EXPECT_TRUE(helper.server_platform_handle.is_valid());
-
- helper.StartChild("RunChild");
- EXPECT_EQ(123, helper.WaitForChildShutdown());
-}
-
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) {
- CHECK(MultiprocessTestHelper::client_platform_handle.is_valid());
- return 123;
-}
-
-TEST_F(MultiprocessTestHelperTest, TestChildMainNotFound) {
- MultiprocessTestHelper helper;
- helper.StartChild("NoSuchTestChildMain");
- int result = helper.WaitForChildShutdown();
- EXPECT_FALSE(result >= 0 && result <= 127);
-}
-
-TEST_F(MultiprocessTestHelperTest, PassedChannel) {
- MultiprocessTestHelper helper;
- EXPECT_TRUE(helper.server_platform_handle.is_valid());
- helper.StartChild("PassedChannel");
-
- // Take ownership of the handle.
- ScopedPlatformHandle handle = std::move(helper.server_platform_handle);
-
- // The handle should be non-blocking.
- EXPECT_TRUE(IsNonBlocking(handle.get()));
-
- // Write a byte.
- const char c = 'X';
- EXPECT_TRUE(WriteByte(handle.get(), c));
-
- // It'll echo it back to us, incremented.
- char d = 0;
- EXPECT_TRUE(ReadByte(handle.get(), &d));
- EXPECT_EQ(c + 1, d);
-
- // And return it, incremented again.
- EXPECT_EQ(c + 2, helper.WaitForChildShutdown());
-}
-
-MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel) {
- CHECK(MultiprocessTestHelper::client_platform_handle.is_valid());
-
- // Take ownership of the handle.
- ScopedPlatformHandle handle =
- std::move(MultiprocessTestHelper::client_platform_handle);
-
- // The handle should be non-blocking.
- EXPECT_TRUE(IsNonBlocking(handle.get()));
-
- // Read a byte.
- char c = 0;
- EXPECT_TRUE(ReadByte(handle.get(), &c));
-
- // Write it back, incremented.
- c++;
- EXPECT_TRUE(WriteByte(handle.get(), c));
-
- // And return it, incremented again.
- c++;
- return static_cast<int>(c);
-}
-
-TEST_F(MultiprocessTestHelperTest, ChildTestPasses) {
- MultiprocessTestHelper helper;
- EXPECT_TRUE(helper.server_platform_handle.is_valid());
- helper.StartChild("ChildTestPasses");
- EXPECT_TRUE(helper.WaitForChildTestShutdown());
-}
-
-MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestPasses) {
- ASSERT_TRUE(MultiprocessTestHelper::client_platform_handle.is_valid());
- EXPECT_TRUE(
- IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()));
-}
-
-TEST_F(MultiprocessTestHelperTest, ChildTestFailsAssert) {
- MultiprocessTestHelper helper;
- EXPECT_TRUE(helper.server_platform_handle.is_valid());
- helper.StartChild("ChildTestFailsAssert");
- EXPECT_FALSE(helper.WaitForChildTestShutdown());
-}
-
-MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsAssert) {
- ASSERT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid())
- << "DISREGARD: Expected failure in child process";
- ASSERT_FALSE(
- IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()))
- << "Not reached";
- CHECK(false) << "Not reached";
-}
-
-TEST_F(MultiprocessTestHelperTest, ChildTestFailsExpect) {
- MultiprocessTestHelper helper;
- EXPECT_TRUE(helper.server_platform_handle.is_valid());
- helper.StartChild("ChildTestFailsExpect");
- EXPECT_FALSE(helper.WaitForChildTestShutdown());
-}
-
-MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsExpect) {
- EXPECT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid())
- << "DISREGARD: Expected failure #1 in child process";
- EXPECT_FALSE(
- IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get()))
- << "DISREGARD: Expected failure #2 in child process";
-}
-
-} // namespace
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/run_all_perftests.cc b/mojo/edk/test/run_all_perftests.cc
deleted file mode 100644
index 3ce3b47..0000000
--- a/mojo/edk/test/run_all_perftests.cc
+++ /dev/null
@@ -1,26 +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 "base/command_line.h"
-#include "base/test/multiprocess_test.h"
-#include "base/test/perf_test_suite.h"
-#include "base/test/test_io_thread.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-#include "mojo/edk/test/multiprocess_test_helper.h"
-#include "mojo/edk/test/test_support_impl.h"
-#include "mojo/public/tests/test_support_private.h"
-
-int main(int argc, char** argv) {
- base::PerfTestSuite test(argc, argv);
-
- mojo::edk::Init();
- base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
- mojo::edk::ScopedIPCSupport ipc_support(
- test_io_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
- mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
-
- return test.Run();
-}
diff --git a/mojo/edk/test/run_all_unittests.cc b/mojo/edk/test/run_all_unittests.cc
deleted file mode 100644
index a057825..0000000
--- a/mojo/edk/test/run_all_unittests.cc
+++ /dev/null
@@ -1,49 +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 <signal.h>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/test/launcher/unit_test_launcher.h"
-#include "base/test/multiprocess_test.h"
-#include "base/test/test_io_thread.h"
-#include "base/test/test_suite.h"
-#include "mojo/edk/embedder/embedder.h"
-#include "mojo/edk/embedder/scoped_ipc_support.h"
-#include "mojo/edk/test/multiprocess_test_helper.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) {
-#if !defined(OS_ANDROID)
- // 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
- // relies on execve which is not available.
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
-#endif
-#if defined(OS_ANDROID)
- // On android, the test framework has a signal handler that will print a
- // [ CRASH ] line when the application crashes. This breaks death test has the
- // test runner will consider the death of the child process a test failure.
- // Removing the signal handler solves this issue.
- signal(SIGABRT, SIG_DFL);
-#endif
-
- base::TestSuite test_suite(argc, argv);
-
- mojo::edk::Init();
-
- mojo::test::TestSupport::Init(new mojo::edk::test::TestSupportImpl());
- base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
-
- mojo::edk::ScopedIPCSupport ipc_support(
- test_io_thread.task_runner(),
- mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
- return base::LaunchUnitTests(
- argc, argv,
- base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
-}
diff --git a/mojo/edk/test/test_support_impl.cc b/mojo/edk/test/test_support_impl.cc
deleted file mode 100644
index 25684e4..0000000
--- a/mojo/edk/test/test_support_impl.cc
+++ /dev/null
@@ -1,84 +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/test/test_support_impl.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-
-#include "base/files/file_enumerator.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/test/perf_log.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-namespace {
-
-base::FilePath ResolveSourceRootRelativePath(const char* relative_path) {
- base::FilePath path;
- if (!PathService::Get(base::DIR_SOURCE_ROOT, &path))
- return base::FilePath();
-
- for (const base::StringPiece& component : base::SplitStringPiece(
- relative_path, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
- if (!component.empty())
- path = path.AppendASCII(component);
- }
-
- return path;
-}
-
-} // namespace
-
-TestSupportImpl::TestSupportImpl() {
-}
-
-TestSupportImpl::~TestSupportImpl() {
-}
-
-void TestSupportImpl::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 = base::StringPrintf("%s/%s", test_name, sub_test_name);
- base::LogPerfResult(name.c_str(), value, units);
- } else {
- base::LogPerfResult(test_name, value, units);
- }
-}
-
-FILE* TestSupportImpl::OpenSourceRootRelativeFile(const char* relative_path) {
- return base::OpenFile(ResolveSourceRootRelativePath(relative_path), "rb");
-}
-
-char** TestSupportImpl::EnumerateSourceRootRelativeDirectory(
- const char* relative_path) {
- std::vector<std::string> 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<char**>(calloc(names.size() + 1, sizeof(char*)));
- for (size_t i = 0; i < names.size(); ++i)
- rv[i] = base::strdup(names[i].c_str());
- return rv;
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/test_support_impl.h b/mojo/edk/test/test_support_impl.h
deleted file mode 100644
index ebb5ce6..0000000
--- a/mojo/edk/test/test_support_impl.h
+++ /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.
-
-#ifndef MOJO_EDK_TEST_TEST_SUPPORT_IMPL_H_
-#define MOJO_EDK_TEST_TEST_SUPPORT_IMPL_H_
-
-#include <stdio.h>
-
-#include "base/macros.h"
-#include "mojo/public/tests/test_support_private.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-class TestSupportImpl : public mojo::test::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:
- DISALLOW_COPY_AND_ASSIGN(TestSupportImpl);
-};
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_TEST_TEST_SUPPORT_IMPL_H_
diff --git a/mojo/edk/test/test_utils.h b/mojo/edk/test/test_utils.h
deleted file mode 100644
index 939171b..0000000
--- a/mojo/edk/test/test_utils.h
+++ /dev/null
@@ -1,55 +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_UTILS_H_
-#define MOJO_EDK_TEST_TEST_UTILS_H_
-
-#include <stddef.h>
-#include <stdio.h>
-
-#include <string>
-
-#include "base/files/scoped_file.h"
-#include "mojo/edk/embedder/platform_handle.h"
-#include "mojo/edk/embedder/scoped_platform_handle.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-// On success, |bytes_written| is updated to the number of bytes written;
-// otherwise it is untouched.
-bool BlockingWrite(const PlatformHandle& handle,
- const void* buffer,
- size_t bytes_to_write,
- size_t* bytes_written);
-
-// On success, |bytes_read| is updated to the number of bytes read; otherwise it
-// is untouched.
-bool BlockingRead(const PlatformHandle& handle,
- void* buffer,
- size_t buffer_size,
- size_t* bytes_read);
-
-// If the read is done successfully or would block, the function returns true
-// and updates |bytes_read| to the number of bytes read (0 if the read would
-// block); otherwise it returns false and leaves |bytes_read| untouched.
-// |handle| must already be in non-blocking mode.
-bool NonBlockingRead(const PlatformHandle& handle,
- void* buffer,
- size_t buffer_size,
- size_t* bytes_read);
-
-// Gets a (scoped) |PlatformHandle| from the given (scoped) |FILE|.
-ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp);
-
-// Gets a (scoped) |FILE| from a (scoped) |PlatformHandle|.
-base::ScopedFILE FILEFromPlatformHandle(ScopedPlatformHandle h,
- const char* mode);
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
-
-#endif // MOJO_EDK_TEST_TEST_UTILS_H_
diff --git a/mojo/edk/test/test_utils_posix.cc b/mojo/edk/test/test_utils_posix.cc
deleted file mode 100644
index 60d5db5..0000000
--- a/mojo/edk/test/test_utils_posix.cc
+++ /dev/null
@@ -1,94 +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/test/test_utils.h"
-
-#include <fcntl.h>
-#include <stddef.h>
-#include <unistd.h>
-
-#include "base/posix/eintr_wrapper.h"
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-bool BlockingWrite(const PlatformHandle& handle,
- const void* buffer,
- size_t bytes_to_write,
- size_t* bytes_written) {
- int original_flags = fcntl(handle.handle, F_GETFL);
- if (original_flags == -1 ||
- fcntl(handle.handle, F_SETFL, original_flags & (~O_NONBLOCK)) != 0) {
- return false;
- }
-
- ssize_t result = HANDLE_EINTR(write(handle.handle, buffer, bytes_to_write));
-
- fcntl(handle.handle, F_SETFL, original_flags);
-
- if (result < 0)
- return false;
-
- *bytes_written = result;
- return true;
-}
-
-bool BlockingRead(const PlatformHandle& handle,
- void* buffer,
- size_t buffer_size,
- size_t* bytes_read) {
- int original_flags = fcntl(handle.handle, F_GETFL);
- if (original_flags == -1 ||
- fcntl(handle.handle, F_SETFL, original_flags & (~O_NONBLOCK)) != 0) {
- return false;
- }
-
- ssize_t result = HANDLE_EINTR(read(handle.handle, buffer, buffer_size));
-
- fcntl(handle.handle, F_SETFL, original_flags);
-
- if (result < 0)
- return false;
-
- *bytes_read = result;
- return true;
-}
-
-bool NonBlockingRead(const PlatformHandle& handle,
- void* buffer,
- size_t buffer_size,
- size_t* bytes_read) {
- ssize_t result = HANDLE_EINTR(read(handle.handle, buffer, buffer_size));
-
- if (result < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK)
- return false;
-
- *bytes_read = 0;
- } else {
- *bytes_read = result;
- }
-
- return true;
-}
-
-ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp) {
- CHECK(fp);
- int rv = dup(fileno(fp.get()));
- PCHECK(rv != -1) << "dup";
- return ScopedPlatformHandle(PlatformHandle(rv));
-}
-
-base::ScopedFILE FILEFromPlatformHandle(ScopedPlatformHandle h,
- const char* mode) {
- CHECK(h.is_valid());
- base::ScopedFILE rv(fdopen(h.release().handle, mode));
- PCHECK(rv) << "fdopen";
- return rv;
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo
diff --git a/mojo/edk/test/test_utils_win.cc b/mojo/edk/test/test_utils_win.cc
deleted file mode 100644
index 17bf5bb..0000000
--- a/mojo/edk/test/test_utils_win.cc
+++ /dev/null
@@ -1,115 +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/test/test_utils.h"
-
-#include <windows.h>
-#include <fcntl.h>
-#include <io.h>
-#include <stddef.h>
-#include <string.h>
-
-namespace mojo {
-namespace edk {
-namespace test {
-
-bool BlockingWrite(const PlatformHandle& handle,
- const void* buffer,
- size_t bytes_to_write,
- size_t* bytes_written) {
- OVERLAPPED overlapped = {0};
- DWORD bytes_written_dword = 0;
-
- if (!WriteFile(handle.handle, buffer, static_cast<DWORD>(bytes_to_write),
- &bytes_written_dword, &overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING ||
- !GetOverlappedResult(handle.handle, &overlapped, &bytes_written_dword,
- TRUE)) {
- return false;
- }
- }
-
- *bytes_written = bytes_written_dword;
- return true;
-}
-
-bool BlockingRead(const PlatformHandle& handle,
- void* buffer,
- size_t buffer_size,
- size_t* bytes_read) {
- OVERLAPPED overlapped = {0};
- DWORD bytes_read_dword = 0;
-
- if (!ReadFile(handle.handle, buffer, static_cast<DWORD>(buffer_size),
- &bytes_read_dword, &overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING ||
- !GetOverlappedResult(handle.handle, &overlapped, &bytes_read_dword,
- TRUE)) {
- return false;
- }
- }
-
- *bytes_read = bytes_read_dword;
- return true;
-}
-
-bool NonBlockingRead(const PlatformHandle& handle,
- void* buffer,
- size_t buffer_size,
- size_t* bytes_read) {
- OVERLAPPED overlapped = {0};
- DWORD bytes_read_dword = 0;
-
- if (!ReadFile(handle.handle, buffer, static_cast<DWORD>(buffer_size),
- &bytes_read_dword, &overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING)
- return false;
-
- CancelIo(handle.handle);
-
- if (!GetOverlappedResult(handle.handle, &overlapped, &bytes_read_dword,
- TRUE)) {
- *bytes_read = 0;
- return true;
- }
- }
-
- *bytes_read = bytes_read_dword;
- return true;
-}
-
-ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp) {
- CHECK(fp);
-
- HANDLE rv = INVALID_HANDLE_VALUE;
- PCHECK(DuplicateHandle(
- GetCurrentProcess(),
- reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp.get()))),
- GetCurrentProcess(), &rv, 0, TRUE, DUPLICATE_SAME_ACCESS))
- << "DuplicateHandle";
- return ScopedPlatformHandle(PlatformHandle(rv));
-}
-
-base::ScopedFILE FILEFromPlatformHandle(ScopedPlatformHandle h,
- const char* mode) {
- CHECK(h.is_valid());
- // Microsoft's documentation for |_open_osfhandle()| only discusses these
- // flags (and |_O_WTEXT|). Hmmm.
- int flags = 0;
- if (strchr(mode, 'a'))
- flags |= _O_APPEND;
- if (strchr(mode, 'r'))
- flags |= _O_RDONLY;
- if (strchr(mode, 't'))
- flags |= _O_TEXT;
- base::ScopedFILE rv(_fdopen(
- _open_osfhandle(reinterpret_cast<intptr_t>(h.release().handle), flags),
- mode));
- PCHECK(rv) << "_fdopen";
- return rv;
-}
-
-} // namespace test
-} // namespace edk
-} // namespace mojo