0

Update mojo sdk to rev e01f9a49449381a5eb430c1fd88bf2cae73ec35a

Includes updates to ipc/mojo/ipc_channel_mojo.cc for mojo::embedder API
changes and updates to use mojo::Binding<> in ui/keyboard and
device/battery.

Review URL: https://codereview.chromium.org/728133002

Cr-Commit-Position: refs/heads/master@{#304731}
This commit is contained in:
jamesr
2014-11-18 17:35:28 -08:00
committed by Commit bot
parent 558999147d
commit a9125266d3
211 changed files with 7299 additions and 3643 deletions
build
content
device/battery
ipc/mojo
media/mojo/services
mojo
BUILD.gn
edk
embedder
js
mojo_edk.gypmojo_edk_tests.gyp
system
test
mojo.gypmojo_base.gyp
public
services
ui/keyboard/webui

@ -42,13 +42,13 @@
# NOTE: This list of targets is present because
# mojo_base.gyp:mojo_base cannot be built on iOS, as
# javascript-related targets cause v8 to be built.
'../mojo/edk/mojo_edk.gyp:mojo_public_bindings_unittests',
'../mojo/edk/mojo_edk.gyp:mojo_public_environment_unittests',
'../mojo/edk/mojo_edk.gyp:mojo_public_system_perftests',
'../mojo/edk/mojo_edk.gyp:mojo_public_system_unittests',
'../mojo/edk/mojo_edk.gyp:mojo_public_utility_unittests',
'../mojo/edk/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
'../mojo/edk/mojo_edk_tests.gyp:mojo_public_environment_unittests',
'../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_perftests',
'../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_unittests',
'../mojo/edk/mojo_edk_tests.gyp:mojo_public_utility_unittests',
'../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../mojo/edk/mojo_edk.gyp:mojo_system_unittests',
'../mojo/edk/mojo_edk_tests.gyp:mojo_system_unittests',
'../mojo/mojo_base.gyp:mojo_common_lib',
'../mojo/mojo_base.gyp:mojo_common_unittests',
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',

@ -82,9 +82,6 @@ class PingBrowserTargetImpl : public BrowserTargetImpl {
~PingBrowserTargetImpl() override {}
// mojo::InterfaceImpl<BrowserTarget> overrides:
void OnConnectionEstablished() override { client()->Ping(); }
// Quit the RunLoop when called.
void PingResponse() override {
got_message = true;
@ -134,6 +131,7 @@ class PingTestWebUIController : public TestWebUIController {
void CreateHandler(mojo::InterfaceRequest<BrowserTarget> request) {
browser_target_.reset(mojo::WeakBindToRequest(
new PingBrowserTargetImpl(run_loop_), &request));
browser_target_->client()->Ping();
}
private:

@ -24,9 +24,9 @@
'conditions': [
['OS != "ios"', {
'includes': [
'../build/win_precompile.gypi',
'content_common_mojo_bindings.gypi',
'content_resources.gypi',
'../build/win_precompile.gypi',
],
}],
['OS == "win"', {
@ -75,6 +75,7 @@
['OS != "ios"', {
'dependencies': [
'content_child',
'content_common_mojo_bindings',
'content_gpu',
'content_plugin',
'content_ppapi_plugin',
@ -174,6 +175,7 @@
}],
['OS != "ios"', {
'dependencies': [
'content_common_mojo_bindings',
'content_resources',
],
}],
@ -190,6 +192,7 @@
'conditions': [
['OS != "ios"', {
'dependencies': [
'content_common_mojo_bindings',
'content_resources',
],
}],
@ -306,6 +309,11 @@
'../v8/src/third_party/vtune/v8vtune.gyp:v8_vtune',
],
}],
['OS != "ios"', {
'dependencies': [
'content_common_mojo_bindings',
]
}]
],
'includes': [
'content_app.gypi',
@ -427,6 +435,7 @@
'../device/battery/battery.gyp:device_battery_java',
'../media/media.gyp:media_java',
'../mojo/mojo_base.gyp:mojo_system_java',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../mojo/public/mojo_public.gyp:mojo_bindings_java',
'../net/net.gyp:net',
'../ui/android/ui_android.gyp:ui_java',

@ -66,7 +66,6 @@
'dependencies': [
'../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
],
}],
],

@ -1666,10 +1666,8 @@
'app/strings/content_strings.gyp:content_strings',
'browser/devtools/devtools_resources.gyp:devtools_resources',
'browser/devtools/devtools.gyp:devtools_protocol_handler',
'content_common_mojo_bindings',
'../cc/cc.gyp:cc',
'../cc/cc.gyp:cc_surfaces',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
'../mojo/public/mojo_public.gyp:mojo_js_bindings',
'../net/net.gyp:http_server',

@ -8,7 +8,6 @@
'../components/tracing.gyp:tracing',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/mojo_base.gyp:mojo_common_lib',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../ui/base/ui_base.gyp:ui_base',
'../ui/gfx/gfx.gyp:gfx',

@ -572,7 +572,6 @@
'../media/media.gyp:shared_memory_support',
'../mojo/edk/mojo_edk.gyp:mojo_system_impl',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
'../storage/storage_browser.gyp:storage',
'../storage/storage_common.gyp:storage_common',

@ -4,30 +4,33 @@
{
'targets': [
{
'target_name': 'content_common_mojo_bindings_mojom',
'type': 'none',
'variables': {
'mojom_files': [
# NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings.
'common/geolocation_service.mojom',
'common/permission_service.mojom',
'common/render_frame_setup.mojom',
# NOTE: Sources duplicated in
# //content/public/common/BUILD.gn:mojo_bindings.
'public/common/mojo_geoposition.mojom',
],
},
'includes': [ '../mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi' ],
},
{
'target_name': 'content_common_mojo_bindings',
'type': 'static_library',
'variables': { 'enable_wexit_time_destructors': 1, },
'dependencies': [
'content_common_mojo_bindings_mojom',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
],
'sources': [
# NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings.
'common/geolocation_service.mojom',
'common/permission_service.mojom',
'common/render_frame_setup.mojom',
# NOTE: Sources duplicated in
# //content/public/common/BUILD.gn:mojo_bindings.
'public/common/mojo_geoposition.mojom',
],
'includes': [ '../mojo/public/tools/bindings/mojom_bindings_generator.gypi' ],
'export_dependent_settings': [
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
],
]
},
],
]
}

@ -5,7 +5,6 @@
{
'dependencies': [
'../base/base.gyp:base',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../ui/gl/gl.gyp:gl',
],

@ -6,7 +6,6 @@
'conditions': [
['enable_plugins==1 and OS!="linux"', {
'dependencies': [
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../skia/skia.gyp:skia',
'../third_party/WebKit/public/blink.gyp:blink',
'../third_party/npapi/npapi.gyp:npapi',

@ -7,7 +7,6 @@
['enable_plugins==1', {
'dependencies': [
'../base/base.gyp:base',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
'../ui/base/ui_base.gyp:ui_base',
'../ui/gfx/gfx.gyp:gfx',

@ -4,7 +4,6 @@
{
'dependencies': [
'content_common_mojo_bindings',
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
'../cc/cc.gyp:cc',
@ -18,7 +17,6 @@
'../media/media.gyp:media',
'../mojo/edk/mojo_edk.gyp:mojo_js_lib',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
'../net/net.gyp:net',
'../skia/skia.gyp:skia',
'../storage/storage_common.gyp:storage_common',

@ -6,7 +6,6 @@
'dependencies': [
'../base/base.gyp:base',
'../courgette/courgette.gyp:courgette_lib',
'../mojo/public/mojo_public.gyp:mojo_application_bindings',
],
'sources': [
'public/utility/content_utility_client.cc',

@ -11,24 +11,26 @@ namespace device {
// static
void BatteryMonitorImpl::Create(
mojo::InterfaceRequest<BatteryMonitor> request) {
BindToRequest(new BatteryMonitorImpl(), &request);
new BatteryMonitorImpl(request.Pass());
}
BatteryMonitorImpl::BatteryMonitorImpl() {
BatteryMonitorImpl::BatteryMonitorImpl(
mojo::InterfaceRequest<BatteryMonitor> request)
: binding_(this, request.Pass()),
subscription_(BatteryStatusService::GetInstance()->AddCallback(
base::Bind(&BatteryMonitorImpl::DidChange, base::Unretained(this)))) {
}
BatteryMonitorImpl::~BatteryMonitorImpl() {
}
void BatteryMonitorImpl::OnConnectionEstablished() {
subscription_ = BatteryStatusService::GetInstance()->AddCallback(
base::Bind(&BatteryMonitorImpl::DidChange, base::Unretained(this)));
void BatteryMonitorImpl::RegisterSubscription() {
}
void BatteryMonitorImpl::DidChange(const BatteryStatus& battery_status) {
BatteryStatusPtr status(BatteryStatus::New());
*status = battery_status;
client()->DidChange(status.Pass());
binding_.client()->DidChange(status.Pass());
}
} // namespace device

@ -2,31 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_BATTERY_BATTERY_MONITOR_IMPL_H_
#define DEVICE_BATTERY_BATTERY_MONITOR_IMPL_H_
#include "base/memory/scoped_ptr.h"
#include "device/battery/battery_export.h"
#include "device/battery/battery_monitor.mojom.h"
#include "device/battery/battery_status_service.h"
#ifndef DEVICE_BATTERY_BATTERY_MONITOR_IMPL_H_
#define DEVICE_BATTERY_BATTERY_MONITOR_IMPL_H_
#include "mojo/public/cpp/bindings/strong_binding.h"
namespace device {
class BatteryMonitorImpl : public mojo::InterfaceImpl<BatteryMonitor> {
class BatteryMonitorImpl : public BatteryMonitor {
public:
DEVICE_BATTERY_EXPORT static void Create(
mojo::InterfaceRequest<BatteryMonitor> request);
private:
BatteryMonitorImpl();
explicit BatteryMonitorImpl(mojo::InterfaceRequest<BatteryMonitor> request);
~BatteryMonitorImpl() override;
// mojo::InterfaceImpl<..> methods:
void OnConnectionEstablished() override;
void RegisterSubscription();
void DidChange(const BatteryStatus& battery_status);
mojo::StrongBinding<BatteryMonitor> binding_;
scoped_ptr<BatteryStatusService::BatteryUpdateSubscription> subscription_;
DISALLOW_COPY_AND_ASSIGN(BatteryMonitorImpl);
};
} // namespace device

@ -168,7 +168,7 @@ void ServerChannelMojo::Close() {
void ChannelMojo::ChannelInfoDeleter::operator()(
mojo::embedder::ChannelInfo* ptr) const {
mojo::embedder::DestroyChannelOnIOThread(ptr);
mojo::embedder::DestroyChannel(ptr);
}
//------------------------------------------------------------------------------

@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//mojo/public/mojo_application.gni")
# Things needed by multiple targets, like renderer_impl and renderer_app.
# GYP version: media/media.gyp:media_mojo_lib
source_set("lib") {
@ -49,7 +51,7 @@ source_set("renderer_impl_lib") {
# mojo media::Renderer application.
# GYP version: media/media.gyp:mojo_media_renderer_app
shared_library("renderer_app") {
mojo_native_application("renderer_app") {
output_name = "mojo_media_renderer_app"
deps = [
@ -99,7 +101,7 @@ test("mojo_media_lib_unittests") {
# libraries.
# TODO(msw): Fix GYP build for ApplicationTestBase so that we can add a GYP
# version of this test.
shared_library("media_renderer_apptest") {
mojo_native_application("media_renderer_apptest") {
testonly = true
output_name = "mojo_media_renderer_apptest"

@ -51,7 +51,7 @@ void MojoDemuxerStreamImpl::OnBufferReady(
mojo::MediaDecoderBuffer::From(buffer));
}
void MojoDemuxerStreamImpl::OnConnectionEstablished() {
void MojoDemuxerStreamImpl::DidConnect() {
// This is called when our DemuxerStreamClient has connected itself and is
// ready to receive messages. Send an initial config and notify it that
// we are now ready for business.

@ -28,8 +28,7 @@ class MojoDemuxerStreamImpl : public mojo::InterfaceImpl<mojo::DemuxerStream> {
mojo::MediaDecoderBufferPtr)>& callback)
override;
// mojo::InterfaceImpl overrides.
void OnConnectionEstablished() override;
void DidConnect();
private:
// |callback| is the callback that was passed to the initiating Read()

@ -63,12 +63,16 @@ void MojoRendererImpl::Initialize(
demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO);
mojo::DemuxerStreamPtr audio_stream;
if (audio)
mojo::BindToProxy(new MojoDemuxerStreamImpl(audio), &audio_stream);
if (audio) {
mojo::BindToProxy(new MojoDemuxerStreamImpl(audio), &audio_stream)
->DidConnect();
}
mojo::DemuxerStreamPtr video_stream;
if (video)
mojo::BindToProxy(new MojoDemuxerStreamImpl(video), &video_stream);
if (video) {
mojo::BindToProxy(new MojoDemuxerStreamImpl(video), &video_stream)
->DidConnect();
}
remote_audio_renderer_->Initialize(
audio_stream.Pass(),

@ -26,7 +26,7 @@ group("tests") {
deps = [
"//mojo/common:mojo_common_unittests",
"//mojo/converters/surfaces/tests:mojo_surfaces_lib_unittests",
"//mojo/edk/js/tests:js_unittests",
"//mojo/edk/js/test:js_unittests",
"//mojo/edk/system:mojo_message_pipe_perftests",
"//mojo/edk/system:mojo_system_unittests",
"//mojo/public/c/system/tests:perftests",

@ -3,11 +3,26 @@
# found in the LICENSE file.
source_set("embedder") {
# This isn't really a standalone target, it must be linked into the
# This isn't really a standalone target; it must be linked into the
# mojo_system_impl component.
visibility = [ "//mojo/edk/system" ]
deps = [ "//base", ]
sources = [
"channel_info_forward.h",
"channel_init.cc",
"channel_init.h",
"configuration.h",
"embedder.cc",
"embedder.h",
"embedder_internal.h",
"entrypoints.cc",
# 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",
@ -16,12 +31,23 @@ source_set("embedder") {
configs += [ "//mojo/edk/system:system_config" ]
public_deps = [
":platform",
"//mojo/public/cpp/system",
]
deps = [ "//base" ]
}
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 = [
"channel_info_forward.h",
"channel_init.cc",
"channel_init.h",
"embedder.cc",
"embedder.h",
"platform_channel_pair.cc",
"platform_channel_pair.h",
"platform_channel_pair_posix.cc",
@ -43,30 +69,30 @@ source_set("embedder") {
"simple_platform_shared_buffer_win.cc",
"simple_platform_support.cc",
"simple_platform_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" ]
configs += [ "//mojo/edk/system:system_config" ]
deps = [ "//base" ]
}
source_set("embedder_unittests") {
testonly = true
visibility = [ "//mojo/edk/system:mojo_system_unittests" ]
testonly = true
deps = [
"//base",
"//mojo/edk/test:test_support",
"//mojo/edk/system",
"//testing/gtest",
]
sources = [
"embedder_unittest.cc",
"platform_channel_pair_posix_unittest.cc",
"simple_platform_shared_buffer_unittest.cc",
]
deps = [
"//base",
"//base/test:test_support",
"//mojo/edk/test:test_support",
"//mojo/edk/system",
"//testing/gtest",
]
}

@ -9,23 +9,14 @@
#define MOJO_EDK_EMBEDDER_CHANNEL_INFO_FORWARD_H_
namespace mojo {
// Forward declare |system::ChannelInfo|, so that we can typedef it to
// |embedder::ChannelInfo|. Users of the embedder API shouldn't use this
// directly; instead they should use |embedder::ChannelInfo|.
namespace system {
struct ChannelInfo;
}
namespace embedder {
// This is an opaque type. The embedder API uses (returns and takes as
// arguments) pointers to this type. (We don't simply use |void*|, so that
// custom deleters and such can be used without additional wrappers.
typedef system::ChannelInfo ChannelInfo;
struct ChannelInfo;
} // namespace embedder
} // namespace mojo
#endif // MOJO_EDK_EMBEDDER_CHANNEL_INFO_FORWARD_H_

@ -25,12 +25,11 @@ ScopedMessagePipeHandle ChannelInit::Init(
DCHECK(!io_thread_task_runner_.get()); // Should only init once.
io_thread_task_runner_ = io_thread_task_runner;
ScopedMessagePipeHandle message_pipe =
CreateChannel(ScopedPlatformHandle(PlatformHandle(file)),
io_thread_task_runner,
base::Bind(&ChannelInit::OnCreatedChannel,
weak_factory_.GetWeakPtr(),
io_thread_task_runner),
base::MessageLoop::current()->message_loop_proxy()).Pass();
CreateChannel(
ScopedPlatformHandle(PlatformHandle(file)), io_thread_task_runner,
base::Bind(&ChannelInit::OnCreatedChannel, weak_factory_.GetWeakPtr(),
io_thread_task_runner),
base::MessageLoop::current()->message_loop_proxy()).Pass();
return message_pipe.Pass();
}

@ -10,7 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "mojo/edk/embedder/channel_info_forward.h"
#include "mojo/edk/system/system_impl_export.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace base {
class MessageLoopProxy;

@ -0,0 +1,68 @@
// 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>
namespace mojo {
namespace embedder {
// 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;
// Upper limit of |MojoWaitMany()|'s |num_handles|. The default is 1,000,000.
// Must be same as or smaller than |max_handle_table_size|.
size_t max_wait_many_num_handles;
// 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 embedder
} // namespace mojo
#endif // MOJO_EDK_EMBEDDER_CONFIGURATION_H_

@ -9,12 +9,13 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h"
#include "mojo/edk/embedder/embedder_internal.h"
#include "mojo/edk/embedder/platform_support.h"
#include "mojo/edk/system/channel.h"
#include "mojo/edk/system/channel_endpoint.h"
#include "mojo/edk/system/channel_info.h"
#include "mojo/edk/system/channel_manager.h"
#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/core.h"
#include "mojo/edk/system/entrypoints.h"
#include "mojo/edk/system/message_pipe_dispatcher.h"
#include "mojo/edk/system/platform_handle_dispatcher.h"
#include "mojo/edk/system/raw_channel.h"
@ -24,39 +25,41 @@ namespace embedder {
namespace {
// Helper for |CreateChannel...()|. (Note: May return null for some failures.)
scoped_refptr<system::Channel> MakeChannel(
system::Core* core,
// Helper for |CreateChannel...()|. Returns 0 on failure. Called on the channel
// creation thread.
system::ChannelId MakeChannel(
ScopedPlatformHandle platform_handle,
scoped_refptr<system::ChannelEndpoint> channel_endpoint) {
DCHECK(platform_handle.is_valid());
// Create and initialize a |system::Channel|.
DCHECK(internal::g_core);
scoped_refptr<system::Channel> channel =
new system::Channel(core->platform_support());
new system::Channel(internal::g_core->platform_support());
if (!channel->Init(system::RawChannel::Create(platform_handle.Pass()))) {
// This is very unusual (e.g., maybe |platform_handle| was invalid or we
// reached some system resource limit).
LOG(ERROR) << "Channel::Init() failed";
// Return null, since |Shutdown()| shouldn't be called in this case.
return scoped_refptr<system::Channel>();
return 0;
}
// Once |Init()| has succeeded, we have to return |channel| (since
// |Shutdown()| will have to be called on it).
channel->AttachAndRunEndpoint(channel_endpoint, true);
return channel;
DCHECK(internal::g_channel_manager);
return internal::g_channel_manager->AddChannel(
channel, base::MessageLoopProxy::current());
}
// Helper for |CreateChannel()|. Called on the channel creation thread.
void CreateChannelHelper(
system::Core* core,
ScopedPlatformHandle platform_handle,
scoped_ptr<ChannelInfo> channel_info,
scoped_refptr<system::ChannelEndpoint> channel_endpoint,
DidCreateChannelCallback callback,
scoped_refptr<base::TaskRunner> callback_thread_task_runner) {
channel_info->channel =
MakeChannel(core, platform_handle.Pass(), channel_endpoint);
channel_info->channel_id =
MakeChannel(platform_handle.Pass(), channel_endpoint);
// Hand the channel back to the embedder.
if (callback_thread_task_runner.get()) {
@ -69,8 +72,23 @@ void CreateChannelHelper(
} // namespace
namespace internal {
// Declared in embedder_internal.h.
system::Core* g_core = nullptr;
system::ChannelManager* g_channel_manager = nullptr;
} // namespace internal
void Init(scoped_ptr<PlatformSupport> platform_support) {
system::entrypoints::SetCore(new system::Core(platform_support.Pass()));
DCHECK(!internal::g_core);
internal::g_core = new system::Core(platform_support.Pass());
DCHECK(!internal::g_channel_manager);
internal::g_channel_manager = new system::ChannelManager();
}
Configuration* GetConfiguration() {
return system::GetMutableConfiguration();
}
// TODO(vtl): Write tests for this.
@ -84,14 +102,12 @@ ScopedMessagePipeHandle CreateChannelOnIOThread(
scoped_refptr<system::MessagePipeDispatcher> dispatcher =
system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint);
system::Core* core = system::entrypoints::GetCore();
DCHECK(core);
DCHECK(internal::g_core);
ScopedMessagePipeHandle rv(
MessagePipeHandle(core->AddDispatcher(dispatcher)));
MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher)));
*channel_info = new ChannelInfo(
MakeChannel(core, platform_handle.Pass(), channel_endpoint),
base::MessageLoopProxy::current());
*channel_info =
new ChannelInfo(MakeChannel(platform_handle.Pass(), channel_endpoint));
return rv.Pass();
}
@ -109,24 +125,19 @@ ScopedMessagePipeHandle CreateChannel(
scoped_refptr<system::MessagePipeDispatcher> dispatcher =
system::MessagePipeDispatcher::CreateRemoteMessagePipe(&channel_endpoint);
system::Core* core = system::entrypoints::GetCore();
DCHECK(core);
DCHECK(internal::g_core);
ScopedMessagePipeHandle rv(
MessagePipeHandle(core->AddDispatcher(dispatcher)));
MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher)));
// We'll have to set |channel_info->channel_id| on the I/O thread.
scoped_ptr<ChannelInfo> channel_info(new ChannelInfo());
// We'll have to set |channel_info->channel| on the I/O thread.
channel_info->channel_thread_task_runner = io_thread_task_runner;
if (rv.is_valid()) {
io_thread_task_runner->PostTask(FROM_HERE,
base::Bind(&CreateChannelHelper,
base::Unretained(core),
base::Passed(&platform_handle),
base::Passed(&channel_info),
channel_endpoint,
callback,
callback_thread_task_runner));
io_thread_task_runner->PostTask(
FROM_HERE,
base::Bind(&CreateChannelHelper, base::Passed(&platform_handle),
base::Passed(&channel_info), channel_endpoint, callback,
callback_thread_task_runner));
} else {
(callback_thread_task_runner.get() ? callback_thread_task_runner
: io_thread_task_runner)
@ -136,35 +147,25 @@ ScopedMessagePipeHandle CreateChannel(
return rv.Pass();
}
void DestroyChannelOnIOThread(ChannelInfo* channel_info) {
DCHECK(channel_info);
if (!channel_info->channel.get()) {
// Presumably, |Init()| on the channel failed.
return;
}
channel_info->channel->Shutdown();
delete channel_info;
}
// TODO(vtl): Write tests for this.
void DestroyChannel(ChannelInfo* channel_info) {
DCHECK(channel_info);
DCHECK(channel_info->channel_thread_task_runner.get());
if (!channel_info->channel.get()) {
if (!channel_info->channel_id) {
// Presumably, |Init()| on the channel failed.
return;
}
channel_info->channel->WillShutdownSoon();
channel_info->channel_thread_task_runner->PostTask(
FROM_HERE, base::Bind(&DestroyChannelOnIOThread, channel_info));
DCHECK(internal::g_channel_manager);
// This will destroy the channel synchronously if called from the channel
// thread.
internal::g_channel_manager->ShutdownChannel(channel_info->channel_id);
delete channel_info;
}
void WillDestroyChannelSoon(ChannelInfo* channel_info) {
DCHECK(channel_info);
channel_info->channel->WillShutdownSoon();
DCHECK(internal::g_channel_manager);
internal::g_channel_manager->WillShutdownChannel(channel_info->channel_id);
}
MojoResult CreatePlatformHandleWrapper(
@ -175,9 +176,8 @@ MojoResult CreatePlatformHandleWrapper(
scoped_refptr<system::Dispatcher> dispatcher(
new system::PlatformHandleDispatcher(platform_handle.Pass()));
system::Core* core = system::entrypoints::GetCore();
DCHECK(core);
MojoHandle h = core->AddDispatcher(dispatcher);
DCHECK(internal::g_core);
MojoHandle h = internal::g_core->AddDispatcher(dispatcher);
if (h == MOJO_HANDLE_INVALID) {
LOG(ERROR) << "Handle table full";
dispatcher->Close();
@ -192,10 +192,9 @@ MojoResult PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
ScopedPlatformHandle* platform_handle) {
DCHECK(platform_handle);
system::Core* core = system::entrypoints::GetCore();
DCHECK(core);
DCHECK(internal::g_core);
scoped_refptr<system::Dispatcher> dispatcher(
core->GetDispatcher(platform_handle_wrapper_handle));
internal::g_core->GetDispatcher(platform_handle_wrapper_handle));
if (!dispatcher.get())
return MOJO_RESULT_INVALID_ARGUMENT;

@ -12,23 +12,32 @@
#include "mojo/edk/embedder/channel_info_forward.h"
#include "mojo/edk/embedder/scoped_platform_handle.h"
#include "mojo/edk/system/system_impl_export.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
namespace embedder {
struct Configuration;
class PlatformSupport;
// Must be called first to initialize the (global, singleton) system.
// Must be called first, or just after setting configuration parameters,
// to initialize the (global, singleton) system.
MOJO_SYSTEM_IMPL_EXPORT void Init(scoped_ptr<PlatformSupport> platform_support);
// Returns the global configuration. In general there should be no need to
// change the configuration, but if you do so this must be done before calling
// |Init()|.
MOJO_SYSTEM_IMPL_EXPORT Configuration* GetConfiguration();
// A "channel" is a connection on top of an OS "pipe", on top of which Mojo
// message pipes (etc.) can be multiplexed. It must "live" on some I/O thread.
//
// There are two "channel" creation/destruction APIs: the synchronous
// |CreateChannelOnIOThread()|/|DestroyChannelOnIOThread()|, which must be
// called from the I/O thread, and the asynchronous
// |CreateChannel()|/|DestroyChannel()|, which may be called from any thread.
// There are two channel creation APIs: |CreateChannelOnIOThread()| creates a
// channel synchronously and must be called from the I/O thread, while
// |CreateChannel()| is asynchronous and may be called from any thread.
// |DestroyChannel()| is used to destroy the channel in either case and may be
// called from any thread, but completes synchronously when called from the I/O
// thread.
//
// Both creation functions have a |platform_handle| argument, which should be an
// OS-dependent handle to one side of a suitable bidirectional OS "pipe" (e.g.,
@ -60,44 +69,37 @@ MOJO_SYSTEM_IMPL_EXPORT void Init(scoped_ptr<PlatformSupport> platform_support);
// Creates a channel; must only be called from the I/O thread. |platform_handle|
// should be a handle to a connected OS "pipe". Eventually (even on failure),
// the "out" value |*channel_info| should be passed to
// |DestroyChannelOnIOThread()| (or |DestoryChannel()|) to tear down the
// channel. Returns a handle to the bootstrap message pipe.
// the "out" value |*channel_info| should be passed to |DestoryChannel()| to
// tear down the channel. Returns a handle to the bootstrap message pipe.
MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
CreateChannelOnIOThread(ScopedPlatformHandle platform_handle,
ChannelInfo** channel_info);
CreateChannelOnIOThread(ScopedPlatformHandle platform_handle,
ChannelInfo** channel_info);
typedef base::Callback<void(ChannelInfo*)> DidCreateChannelCallback;
// Creates a channel asynchronously; may be called from any thread.
// |platform_handle| should be a handle to a connected OS "pipe".
// |io_thread_task_runner| should be the |TaskRunner| for the I/O thread.
// |callback| should be the callback to call with the |ChannelInfo*|, which
// should eventually be passed to |DestroyChannel()| (or
// |DestroyChannelOnIOThread()|) to tear down the channel; the callback will be
// called using |callback_thread_task_runner| if that is non-null, or otherwise
// it will be called using |io_thread_task_runner|. Returns a handle to the
// bootstrap message pipe.
// should eventually be passed to |DestroyChannel()| to tear down the channel;
// the callback will be called using |callback_thread_task_runner| if that is
// non-null, or otherwise it will be called using |io_thread_task_runner|.
// Returns a handle to the bootstrap message pipe.
MOJO_SYSTEM_IMPL_EXPORT ScopedMessagePipeHandle
CreateChannel(ScopedPlatformHandle platform_handle,
scoped_refptr<base::TaskRunner> io_thread_task_runner,
DidCreateChannelCallback callback,
scoped_refptr<base::TaskRunner> callback_thread_task_runner);
CreateChannel(ScopedPlatformHandle platform_handle,
scoped_refptr<base::TaskRunner> io_thread_task_runner,
DidCreateChannelCallback callback,
scoped_refptr<base::TaskRunner> callback_thread_task_runner);
// Destroys a channel that was created using either |CreateChannelOnIOThread()|
// or |CreateChannel()|; must only be called from the I/O thread. |channel_info|
// should be the "out" value from |CreateChannelOnIOThread()| or the value
// provided to the callback to |CreateChannel()|.
MOJO_SYSTEM_IMPL_EXPORT void DestroyChannelOnIOThread(
ChannelInfo* channel_info);
// Destroys a channel (asynchronously) that was created using |CreateChannel()|;
// may be called from any thread. |channel_info| should be the value provided to
// the callback to |CreateChannel()|.
// Destroys a channel that was created using |CreateChannel()| (or
// |CreateChannelOnIOThread()|); may be called from any thread. |channel_info|
// should be the value provided to the callback to |CreateChannel()| (or
// returned by |CreateChannelOnIOThread()|). If called from the I/O thread, this
// will complete synchronously (in particular, it will post no tasks).
MOJO_SYSTEM_IMPL_EXPORT void DestroyChannel(ChannelInfo* channel_info);
// Inform the channel that it will soon be destroyed (doing so is optional).
// This may be called from any thread, but the caller must ensure that this is
// called before |DestroyChannel()| or |DestroyChannelOnIOThread()|.
// called before |DestroyChannel()|.
MOJO_SYSTEM_IMPL_EXPORT void WillDestroyChannelSoon(ChannelInfo* channel_info);
// Creates a |MojoHandle| that wraps the given |PlatformHandle| (taking
@ -106,14 +108,14 @@ MOJO_SYSTEM_IMPL_EXPORT void WillDestroyChannelSoon(ChannelInfo* channel_info);
// 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);
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| must still
// be closed separately.
MOJO_SYSTEM_IMPL_EXPORT MojoResult
PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
ScopedPlatformHandle* platform_handle);
PassWrappedPlatformHandle(MojoHandle platform_handle_wrapper_handle,
ScopedPlatformHandle* platform_handle);
} // namespace embedder
} // namespace mojo

@ -0,0 +1,53 @@
// 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>
namespace mojo {
namespace system {
class ChannelManager;
class Core;
// Repeat a typedef in mojo/edk/system/channel_manager.h, to avoid including it.
typedef uintptr_t ChannelId;
} // namespace system
namespace embedder {
// This is a type that's opaque to users of the embedder API (which only
// gives/takes |ChannelInfo*|s). We make it a struct to make it
// template-friendly.
struct ChannelInfo {
explicit ChannelInfo(system::ChannelId channel_id = 0)
: channel_id(channel_id) {}
system::ChannelId channel_id;
};
namespace internal {
// Instance of |Core| used by the system functions (|Mojo...()|).
extern system::Core* g_core;
// Instance of |ChannelManager| used by the channel management functions
// (|mojo::embedder::CreateChannel()|, etc.).
extern system::ChannelManager* g_channel_manager;
} // namespace internal
} // namepace embedder
} // namespace mojo
#endif // MOJO_EDK_EMBEDDER_EMBEDDER_INTERNAL_H_

@ -39,8 +39,7 @@ class ScopedTestChannel {
did_create_channel_event_(true, false),
channel_info_(nullptr) {
bootstrap_message_pipe_ =
CreateChannel(platform_handle.Pass(),
io_thread_task_runner_,
CreateChannel(platform_handle.Pass(), io_thread_task_runner_,
base::Bind(&ScopedTestChannel::DidCreateChannel,
base::Unretained(this)),
nullptr)
@ -51,12 +50,7 @@ class ScopedTestChannel {
// Destructor: Shuts down the channel. (As noted above, for this to happen,
// the I/O thread must be alive and pumping messages.)
~ScopedTestChannel() {
system::test::PostTaskAndWait(
io_thread_task_runner_,
FROM_HERE,
base::Bind(&ScopedTestChannel::DestroyChannel, base::Unretained(this)));
}
~ScopedTestChannel() { DestroyChannel(channel_info_); }
// Waits for channel creation to be completed.
void WaitForChannelCreationCompletion() { did_create_channel_event_.Wait(); }
@ -75,12 +69,6 @@ class ScopedTestChannel {
did_create_channel_event_.Signal();
}
void DestroyChannel() {
CHECK(channel_info_);
DestroyChannelOnIOThread(channel_info_);
channel_info_ = nullptr;
}
scoped_refptr<base::TaskRunner> io_thread_task_runner_;
// Valid from creation until whenever it gets closed (by the "owner" of this
@ -130,27 +118,18 @@ TEST_F(EmbedderTest, ChannelsBasic) {
// We can write to a message pipe handle immediately.
const char kHello[] = "hello";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(server_mp,
kHello,
static_cast<uint32_t>(sizeof(kHello)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(server_mp, kHello,
static_cast<uint32_t>(sizeof(kHello)), nullptr,
0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// Now wait for the other side to become readable.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(
client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
char buffer[1000] = {};
uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(client_mp,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(sizeof(kHello), num_bytes);
EXPECT_STREQ(kHello, buffer);
@ -189,40 +168,28 @@ TEST_F(EmbedderTest, ChannelsHandlePassing) {
// Write a message to |h0| (attaching nothing).
const char kHello[] = "hello";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(h0,
kHello,
static_cast<uint32_t>(sizeof(kHello)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWriteMessage(h0, kHello, static_cast<uint32_t>(sizeof(kHello)),
nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// Write one message to |server_mp|, attaching |h1|.
const char kWorld[] = "world!!!";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(server_mp,
kWorld,
static_cast<uint32_t>(sizeof(kWorld)),
&h1,
1,
MojoWriteMessage(server_mp, kWorld,
static_cast<uint32_t>(sizeof(kWorld)), &h1, 1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
h1 = MOJO_HANDLE_INVALID;
// Write another message to |h0|.
const char kFoo[] = "foo";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(h0,
kFoo,
static_cast<uint32_t>(sizeof(kFoo)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(h0, kFoo, static_cast<uint32_t>(sizeof(kFoo)),
nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// Wait for |client_mp| to become readable.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(
client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
// Read a message from |client_mp|.
char buffer[1000] = {};
@ -230,12 +197,8 @@ TEST_F(EmbedderTest, ChannelsHandlePassing) {
MojoHandle handles[10] = {};
uint32_t num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(client_mp,
buffer,
&num_bytes,
handles,
&num_handles,
MOJO_READ_MESSAGE_FLAG_NONE));
MojoReadMessage(client_mp, buffer, &num_bytes, handles,
&num_handles, MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(sizeof(kWorld), num_bytes);
EXPECT_STREQ(kWorld, buffer);
EXPECT_EQ(1u, num_handles);
@ -243,9 +206,8 @@ TEST_F(EmbedderTest, ChannelsHandlePassing) {
h1 = handles[0];
// Wait for |h1| to become readable.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
// Read a message from |h1|.
memset(buffer, 0, sizeof(buffer));
@ -253,58 +215,41 @@ TEST_F(EmbedderTest, ChannelsHandlePassing) {
memset(handles, 0, sizeof(handles));
num_handles = arraysize(handles);
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(h1,
buffer,
&num_bytes,
handles,
&num_handles,
MojoReadMessage(h1, buffer, &num_bytes, handles, &num_handles,
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(sizeof(kHello), num_bytes);
EXPECT_STREQ(kHello, buffer);
EXPECT_EQ(0u, num_handles);
// Wait for |h1| to become readable (again).
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h1, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
// Read the second message from |h1|.
memset(buffer, 0, sizeof(buffer));
num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(h1,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(h1, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(sizeof(kFoo), num_bytes);
EXPECT_STREQ(kFoo, buffer);
// Write a message to |h1|.
const char kBarBaz[] = "barbaz";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(h1,
kBarBaz,
static_cast<uint32_t>(sizeof(kBarBaz)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
// Wait for |h0| to become readable.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
MojoWriteMessage(h1, kBarBaz, static_cast<uint32_t>(sizeof(kBarBaz)),
nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// Wait for |h0| to become readable.
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
// Read a message from |h0|.
memset(buffer, 0, sizeof(buffer));
num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(h0,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(h0, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
EXPECT_EQ(sizeof(kBarBaz), num_bytes);
EXPECT_STREQ(kBarBaz, buffer);
@ -354,29 +299,20 @@ TEST_F(EmbedderTest, MultiprocessChannels) {
// 1. Write a message to |server_mp| (attaching nothing).
const char kHello[] = "hello";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(server_mp,
kHello,
static_cast<uint32_t>(sizeof(kHello)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(server_mp, kHello,
static_cast<uint32_t>(sizeof(kHello)), nullptr,
0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// TODO(vtl): If the scope were ended immediately here (maybe after closing
// |server_mp|), we die with a fatal error in |Channel::HandleLocalError()|.
// 2. Read a message from |server_mp|.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(
server_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(server_mp, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
char buffer[1000] = {};
uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(server_mp,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(server_mp, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
const char kWorld[] = "world!";
EXPECT_EQ(sizeof(kWorld), num_bytes);
@ -389,41 +325,29 @@ TEST_F(EmbedderTest, MultiprocessChannels) {
// 3. Write something to |mp0|.
const char kFoo[] = "FOO";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(mp0,
kFoo,
static_cast<uint32_t>(sizeof(kFoo)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(mp0, kFoo, static_cast<uint32_t>(sizeof(kFoo)),
nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// 4. Write a message to |server_mp|, attaching |mp1|.
const char kBar[] = "Bar";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(server_mp,
kBar,
static_cast<uint32_t>(sizeof(kBar)),
&mp1,
1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWriteMessage(server_mp, kBar, static_cast<uint32_t>(sizeof(kBar)),
&mp1, 1, MOJO_WRITE_MESSAGE_FLAG_NONE));
mp1 = MOJO_HANDLE_INVALID;
// 5. Close |server_mp|.
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
// 9. Read a message from |mp0|, which should have |mp2| attached.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(mp0, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(mp0, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
memset(buffer, 0, sizeof(buffer));
num_bytes = static_cast<uint32_t>(sizeof(buffer));
MojoHandle mp2 = MOJO_HANDLE_INVALID;
uint32_t num_handles = 1;
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(mp0,
buffer,
&num_bytes,
&mp2,
&num_handles,
MojoReadMessage(mp0, buffer, &num_bytes, &mp2, &num_handles,
MOJO_READ_MESSAGE_FLAG_NONE));
const char kQuux[] = "quux";
EXPECT_EQ(sizeof(kQuux), num_bytes);
@ -432,17 +356,12 @@ TEST_F(EmbedderTest, MultiprocessChannels) {
EXPECT_NE(mp2, MOJO_HANDLE_INVALID);
// 7. Read a message from |mp2|.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
memset(buffer, 0, sizeof(buffer));
num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(mp2,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(mp2, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
const char kBaz[] = "baz";
EXPECT_EQ(sizeof(kBaz), num_bytes);
@ -482,18 +401,12 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
CHECK(client_channel.channel_info() != nullptr);
// 1. Read the first message from |client_mp|.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(
client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
char buffer[1000] = {};
uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(client_mp,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(client_mp, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
const char kHello[] = "hello";
EXPECT_EQ(sizeof(kHello), num_bytes);
@ -502,18 +415,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
// 2. Write a message to |client_mp| (attaching nothing).
const char kWorld[] = "world!";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(client_mp,
kWorld,
static_cast<uint32_t>(sizeof(kWorld)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(client_mp, kWorld,
static_cast<uint32_t>(sizeof(kWorld)), nullptr,
0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// 4. Read a message from |client_mp|, which should have |mp1| attached.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(
client_mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(client_mp, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
// TODO(vtl): If the scope were to end here (and |client_mp| closed), we'd
// die (again due to |Channel::HandleLocalError()|).
memset(buffer, 0, sizeof(buffer));
@ -521,11 +429,7 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
MojoHandle mp1 = MOJO_HANDLE_INVALID;
uint32_t num_handles = 1;
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(client_mp,
buffer,
&num_bytes,
&mp1,
&num_handles,
MojoReadMessage(client_mp, buffer, &num_bytes, &mp1, &num_handles,
MOJO_READ_MESSAGE_FLAG_NONE));
const char kBar[] = "Bar";
EXPECT_EQ(sizeof(kBar), num_bytes);
@ -546,12 +450,8 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
// 7. Write a message to |mp3|.
const char kBaz[] = "baz";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(mp3,
kBaz,
static_cast<uint32_t>(sizeof(kBaz)),
nullptr,
0,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(mp3, kBaz, static_cast<uint32_t>(sizeof(kBaz)),
nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
// 8. Close |mp3|.
EXPECT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
@ -559,26 +459,17 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
// 9. Write a message to |mp1|, attaching |mp2|.
const char kQuux[] = "quux";
EXPECT_EQ(MOJO_RESULT_OK,
MojoWriteMessage(mp1,
kQuux,
static_cast<uint32_t>(sizeof(kQuux)),
&mp2,
1,
MOJO_WRITE_MESSAGE_FLAG_NONE));
MojoWriteMessage(mp1, kQuux, static_cast<uint32_t>(sizeof(kQuux)),
&mp2, 1, MOJO_WRITE_MESSAGE_FLAG_NONE));
mp2 = MOJO_HANDLE_INVALID;
// 3. Read a message from |mp1|.
EXPECT_EQ(
MOJO_RESULT_OK,
MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE));
EXPECT_EQ(MOJO_RESULT_OK, MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE,
MOJO_DEADLINE_INDEFINITE));
memset(buffer, 0, sizeof(buffer));
num_bytes = static_cast<uint32_t>(sizeof(buffer));
EXPECT_EQ(MOJO_RESULT_OK,
MojoReadMessage(mp1,
buffer,
&num_bytes,
nullptr,
nullptr,
MojoReadMessage(mp1, buffer, &num_bytes, nullptr, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE));
const char kFoo[] = "FOO";
EXPECT_EQ(sizeof(kFoo), num_bytes);

@ -2,35 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/edk/system/entrypoints.h"
#include "base/logging.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"
static mojo::system::Core* g_core = nullptr;
using mojo::embedder::internal::g_core;
using mojo::system::MakeUserPointer;
namespace mojo {
namespace system {
namespace entrypoints {
void SetCore(Core* core) {
g_core = core;
}
Core* GetCore() {
return g_core;
}
} // namespace entrypoints
} // namepace system
} // namespace mojo
// Definitions of the system functions.
extern "C" {
MojoTimeTicks MojoGetTimeTicksNow() {
@ -44,8 +25,8 @@ MojoResult MojoClose(MojoHandle handle) {
MojoResult MojoWait(MojoHandle handle,
MojoHandleSignals signals,
MojoDeadline deadline) {
return g_core->Wait(
handle, signals, deadline, mojo::system::NullUserPointer());
return g_core->Wait(handle, signals, deadline,
mojo::system::NullUserPointer());
}
MojoResult MojoWaitMany(const MojoHandle* handles,
@ -53,12 +34,9 @@ MojoResult MojoWaitMany(const MojoHandle* handles,
uint32_t num_handles,
MojoDeadline deadline) {
uint32_t result_index = static_cast<uint32_t>(-1);
MojoResult result = g_core->WaitMany(MakeUserPointer(handles),
MakeUserPointer(signals),
num_handles,
deadline,
MakeUserPointer(&result_index),
mojo::system::NullUserPointer());
MojoResult result = g_core->WaitMany(
MakeUserPointer(handles), MakeUserPointer(signals), num_handles, deadline,
MakeUserPointer(&result_index), mojo::system::NullUserPointer());
return (result == MOJO_RESULT_OK) ? static_cast<MojoResult>(result_index)
: result;
}
@ -77,11 +55,8 @@ MojoResult MojoWriteMessage(MojoHandle message_pipe_handle,
const MojoHandle* handles,
uint32_t num_handles,
MojoWriteMessageFlags flags) {
return g_core->WriteMessage(message_pipe_handle,
MakeUserPointer(bytes),
num_bytes,
MakeUserPointer(handles),
num_handles,
return g_core->WriteMessage(message_pipe_handle, MakeUserPointer(bytes),
num_bytes, MakeUserPointer(handles), num_handles,
flags);
}
@ -91,12 +66,9 @@ MojoResult MojoReadMessage(MojoHandle message_pipe_handle,
MojoHandle* handles,
uint32_t* num_handles,
MojoReadMessageFlags flags) {
return g_core->ReadMessage(message_pipe_handle,
MakeUserPointer(bytes),
MakeUserPointer(num_bytes),
MakeUserPointer(handles),
MakeUserPointer(num_handles),
flags);
return g_core->ReadMessage(
message_pipe_handle, MakeUserPointer(bytes), MakeUserPointer(num_bytes),
MakeUserPointer(handles), MakeUserPointer(num_handles), flags);
}
MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options,
@ -111,10 +83,8 @@ MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle,
const void* elements,
uint32_t* num_elements,
MojoWriteDataFlags flags) {
return g_core->WriteData(data_pipe_producer_handle,
MakeUserPointer(elements),
MakeUserPointer(num_elements),
flags);
return g_core->WriteData(data_pipe_producer_handle, MakeUserPointer(elements),
MakeUserPointer(num_elements), flags);
}
MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
@ -123,8 +93,7 @@ MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle,
MojoWriteDataFlags flags) {
return g_core->BeginWriteData(data_pipe_producer_handle,
MakeUserPointer(buffer),
MakeUserPointer(buffer_num_elements),
flags);
MakeUserPointer(buffer_num_elements), flags);
}
MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle,
@ -136,10 +105,8 @@ MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle,
void* elements,
uint32_t* num_elements,
MojoReadDataFlags flags) {
return g_core->ReadData(data_pipe_consumer_handle,
MakeUserPointer(elements),
MakeUserPointer(num_elements),
flags);
return g_core->ReadData(data_pipe_consumer_handle, MakeUserPointer(elements),
MakeUserPointer(num_elements), flags);
}
MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
@ -148,8 +115,7 @@ MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle,
MojoReadDataFlags flags) {
return g_core->BeginReadData(data_pipe_consumer_handle,
MakeUserPointer(buffer),
MakeUserPointer(buffer_num_elements),
flags);
MakeUserPointer(buffer_num_elements), flags);
}
MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle,
@ -161,8 +127,7 @@ MojoResult MojoCreateSharedBuffer(
const struct MojoCreateSharedBufferOptions* options,
uint64_t num_bytes,
MojoHandle* shared_buffer_handle) {
return g_core->CreateSharedBuffer(MakeUserPointer(options),
num_bytes,
return g_core->CreateSharedBuffer(MakeUserPointer(options), num_bytes,
MakeUserPointer(shared_buffer_handle));
}
@ -170,8 +135,7 @@ MojoResult MojoDuplicateBufferHandle(
MojoHandle buffer_handle,
const struct MojoDuplicateBufferHandleOptions* options,
MojoHandle* new_buffer_handle) {
return g_core->DuplicateBufferHandle(buffer_handle,
MakeUserPointer(options),
return g_core->DuplicateBufferHandle(buffer_handle, MakeUserPointer(options),
MakeUserPointer(new_buffer_handle));
}
@ -180,8 +144,8 @@ MojoResult MojoMapBuffer(MojoHandle buffer_handle,
uint64_t num_bytes,
void** buffer,
MojoMapBufferFlags flags) {
return g_core->MapBuffer(
buffer_handle, offset, num_bytes, MakeUserPointer(buffer), flags);
return g_core->MapBuffer(buffer_handle, offset, num_bytes,
MakeUserPointer(buffer), flags);
}
MojoResult MojoUnmapBuffer(void* buffer) {

@ -46,14 +46,10 @@ PlatformChannelPair::PlatformChannelPair() {
// 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);
PCHECK(setsockopt(fds[0], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
sizeof(no_sigpipe)) == 0);
PCHECK(setsockopt(fds[1], SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe,
sizeof(no_sigpipe)) == 0);
#endif // defined(OS_MACOSX)
server_handle_.reset(PlatformHandle(fds[0]));

@ -112,15 +112,15 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveData) {
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()));
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);
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());
@ -155,9 +155,7 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
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,
PlatformChannelSendmsgWithHandles(server_handle.get(), &iov, 1,
&platform_handles[0],
platform_handles.size()));
@ -167,8 +165,8 @@ TEST_F(PlatformChannelPairPosixTest, SendReceiveFDs) {
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));
PlatformChannelRecvmsg(client_handle.get(), buf, sizeof(buf),
&received_handles));
EXPECT_STREQ(kHello, buf);
EXPECT_EQ(i, received_handles.size());
@ -214,9 +212,7 @@ TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
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,
PlatformChannelSendmsgWithHandles(server_handle.get(), &iov, 1,
&platform_handles[0],
platform_handles.size()));
}
@ -230,8 +226,8 @@ TEST_F(PlatformChannelPairPosixTest, AppendReceivedFDs) {
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));
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());

@ -23,8 +23,7 @@ namespace {
std::wstring GeneratePipeName() {
return base::StringPrintf(L"\\\\.\\pipe\\mojo.%u.%u.%I64u",
GetCurrentProcessId(),
GetCurrentThreadId(),
GetCurrentProcessId(), GetCurrentThreadId(),
base::RandUint64());
}
@ -37,9 +36,7 @@ PlatformChannelPair::PlatformChannelPair() {
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,
CreateNamedPipeW(pipe_name.c_str(), kOpenMode, kPipeMode,
1, // Max instances.
4096, // Out buffer size.
4096, // In buffer size.
@ -56,12 +53,9 @@ PlatformChannelPair::PlatformChannelPair() {
SECURITY_ATTRIBUTES security_attributes = {
sizeof(SECURITY_ATTRIBUTES), nullptr, TRUE};
client_handle_.reset(
PlatformHandle(CreateFileW(pipe_name.c_str(),
kDesiredAccess,
PlatformHandle(CreateFileW(pipe_name.c_str(), kDesiredAccess,
0, // No sharing.
&security_attributes,
OPEN_EXISTING,
kFlags,
&security_attributes, OPEN_EXISTING, kFlags,
nullptr))); // No template file.
PCHECK(client_handle_.is_valid());

@ -30,9 +30,9 @@ const size_t kPlatformChannelMaxNumHandles = 7;
// 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);
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);
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
@ -43,11 +43,11 @@ MOJO_SYSTEM_IMPL_EXPORT ssize_t
// 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);
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()|.
@ -65,10 +65,10 @@ MOJO_SYSTEM_IMPL_EXPORT bool PlatformChannelSendHandles(PlatformHandle h,
// (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);
PlatformChannelRecvmsg(PlatformHandle h,
void* buf,
size_t num_bytes,
std::deque<PlatformHandle>* platform_handles);
} // namespace embedder
} // namespace mojo

@ -18,15 +18,14 @@ MOJO_SYSTEM_IMPL_EXPORT inline void CloseAllPlatformHandles(
PlatformHandleContainer* platform_handles) {
for (typename PlatformHandleContainer::iterator it =
platform_handles->begin();
it != platform_handles->end();
++it)
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);
DuplicatePlatformHandle(PlatformHandle platform_handle);
} // namespace embedder
} // namespace mojo

@ -15,12 +15,8 @@ ScopedPlatformHandle DuplicatePlatformHandle(PlatformHandle platform_handle) {
DCHECK(platform_handle.is_valid());
HANDLE new_handle;
if (!DuplicateHandle(GetCurrentProcess(),
platform_handle.handle,
GetCurrentProcess(),
&new_handle,
0,
TRUE,
if (!DuplicateHandle(GetCurrentProcess(), platform_handle.handle,
GetCurrentProcess(), &new_handle, 0, TRUE,
DUPLICATE_SAME_ACCESS))
return ScopedPlatformHandle();
DCHECK_NE(new_handle, INVALID_HANDLE_VALUE);

@ -127,12 +127,9 @@ scoped_ptr<PlatformSharedBufferMapping> SimplePlatformSharedBuffer::MapImpl(
DCHECK_LE(static_cast<uint64_t>(real_offset),
static_cast<uint64_t>(std::numeric_limits<off_t>::max()));
void* real_base = mmap(nullptr,
real_length,
PROT_READ | PROT_WRITE,
MAP_SHARED,
handle_.get().fd,
static_cast<off_t>(real_offset));
void* real_base =
mmap(nullptr, real_length, PROT_READ | PROT_WRITE, MAP_SHARED,
handle_.get().fd, static_cast<off_t>(real_offset));
// |mmap()| should return |MAP_FAILED| (a.k.a. -1) on error. But it shouldn't
// return null either.
if (real_base == MAP_FAILED || !real_base) {

@ -33,12 +33,9 @@ bool SimplePlatformSharedBuffer::Init() {
// TODO(vtl): Unlike |base::SharedMemory|, we don't round up the size (to a
// multiple of 64 KB). This may cause problems with NaCl. Cross this bridge
// when we get there. crbug.com/210609
handle_.reset(PlatformHandle(CreateFileMapping(INVALID_HANDLE_VALUE,
nullptr,
PAGE_READWRITE,
0,
static_cast<DWORD>(num_bytes_),
nullptr)));
handle_.reset(PlatformHandle(
CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
static_cast<DWORD>(num_bytes_), nullptr)));
if (!handle_.is_valid()) {
PLOG(ERROR) << "CreateFileMapping";
return false;
@ -68,11 +65,9 @@ scoped_ptr<PlatformSharedBufferMapping> SimplePlatformSharedBuffer::MapImpl(
DCHECK_LE(static_cast<uint64_t>(real_offset),
static_cast<uint64_t>(std::numeric_limits<DWORD>::max()));
void* real_base = MapViewOfFile(handle_.get().handle,
FILE_MAP_READ | FILE_MAP_WRITE,
0,
static_cast<DWORD>(real_offset),
real_length);
void* real_base =
MapViewOfFile(handle_.get().handle, FILE_MAP_READ | FILE_MAP_WRITE, 0,
static_cast<DWORD>(real_offset), real_length);
if (!real_base) {
PLOG(ERROR) << "MapViewOfFile";
return nullptr;

@ -8,9 +8,10 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "mojo/edk/embedder/embedder.h"
#include "mojo/edk/embedder/embedder_internal.h"
#include "mojo/edk/embedder/simple_platform_support.h"
#include "mojo/edk/system/channel_manager.h"
#include "mojo/edk/system/core.h"
#include "mojo/edk/system/entrypoints.h"
#include "mojo/edk/system/handle_table.h"
namespace mojo {
@ -18,18 +19,17 @@ namespace mojo {
namespace system {
namespace internal {
bool ShutdownCheckNoLeaks(Core* core_impl) {
bool ShutdownCheckNoLeaks(Core* core) {
// No point in taking the lock.
const HandleTable::HandleToEntryMap& handle_to_entry_map =
core_impl->handle_table_.handle_to_entry_map_;
core->handle_table_.handle_to_entry_map_;
if (handle_to_entry_map.empty())
return true;
for (HandleTable::HandleToEntryMap::const_iterator it =
handle_to_entry_map.begin();
it != handle_to_entry_map.end();
++it) {
it != handle_to_entry_map.end(); ++it) {
LOG(ERROR) << "Mojo embedder shutdown: Leaking handle " << (*it).first;
}
return false;
@ -46,12 +46,14 @@ void InitWithSimplePlatformSupport() {
}
bool Shutdown() {
system::Core* core = system::entrypoints::GetCore();
CHECK(core);
system::entrypoints::SetCore(nullptr);
CHECK(internal::g_channel_manager);
delete internal::g_channel_manager;
internal::g_channel_manager = nullptr;
bool rv = system::internal::ShutdownCheckNoLeaks(core);
delete core;
CHECK(internal::g_core);
bool rv = system::internal::ShutdownCheckNoLeaks(internal::g_core);
delete internal::g_core;
internal::g_core = nullptr;
return rv;
}

@ -20,6 +20,9 @@ MOJO_SYSTEM_IMPL_EXPORT void InitWithSimplePlatformSupport();
// 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

@ -11,8 +11,12 @@ source_set("js") {
"handle.cc",
"handle.h",
"handle_close_observer.h",
"mojo_runner_delegate.cc",
"mojo_runner_delegate.h",
"support.cc",
"support.h",
"threading.cc",
"threading.h",
"waiting_callback.cc",
"waiting_callback.h",
]
@ -22,15 +26,24 @@ source_set("js") {
"//gin",
"//v8",
]
deps = [
"//mojo/public/cpp/environment",
"//mojo/public/cpp/system",
]
}
source_set("js_unittests") {
testonly = true
deps = [
"//mojo/edk/test:test_support",
]
sources = [
"handle_unittest.cc",
]
deps = [
"//mojo/edk/js",
"//mojo/edk/test:test_support",
"//mojo/public/cpp/system",
"//testing/gtest",
]
}

@ -1,4 +1,5 @@
include_rules = [
"+base",
"+gin",
"+v8",
]

@ -247,69 +247,73 @@ v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) {
&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("wait", WaitHandle)
.SetMethod("waitMany", WaitMany)
.SetMethod("createMessagePipe", CreateMessagePipe)
.SetMethod("writeMessage", WriteMessage)
.SetMethod("readMessage", ReadMessage)
.SetMethod("createDataPipe", CreateDataPipe)
.SetMethod("writeData", WriteData)
.SetMethod("readData", ReadData)
.SetMethod("drainData", DoDrainData)
templ =
gin::ObjectTemplateBuilder(isolate)
// TODO(mpcomplete): Should these just be methods on the JS Handle
// object?
.SetMethod("close", CloseHandle)
.SetMethod("wait", WaitHandle)
.SetMethod("waitMany", WaitMany)
.SetMethod("createMessagePipe", CreateMessagePipe)
.SetMethod("writeMessage", WriteMessage)
.SetMethod("readMessage", ReadMessage)
.SetMethod("createDataPipe", CreateDataPipe)
.SetMethod("writeData", WriteData)
.SetMethod("readData", ReadData)
.SetMethod("drainData", DoDrainData)
.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("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("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE)
.SetValue("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE)
.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_NONE", MOJO_HANDLE_SIGNAL_NONE)
.SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
.SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE)
.SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE",
MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE)
.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("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("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("CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD",
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)
.SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE",
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE)
.SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD",
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)
.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("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)
.Build();
.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)
.Build();
data->SetObjectTemplate(&g_wrapper_info, templ);
}

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_BINDINGS_JS_CORE_H_
#define MOJO_BINDINGS_JS_CORE_H_
#ifndef MOJO_EDK_JS_CORE_H_
#define MOJO_EDK_JS_CORE_H_
#include "v8/include/v8.h"
@ -19,4 +19,4 @@ class Core {
} // namespace js
} // namespace mojo
#endif // MOJO_BINDINGS_JS_CORE_H_
#endif // MOJO_EDK_JS_CORE_H_

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_BINDINGS_JS_DRAIN_DATA_H_
#define MOJO_BINDINGS_JS_DRAIN_DATA_H_
#ifndef MOJO_EDK_JS_DRAIN_DATA_H_
#define MOJO_EDK_JS_DRAIN_DATA_H_
#include "base/memory/scoped_vector.h"
#include "gin/runner.h"
@ -61,4 +61,4 @@ class DrainData {
} // namespace js
} // namespace mojo
#endif // MOJO_BINDINGS_JS_DRAIN_DATA_H_
#endif // MOJO_EDK_JS_DRAIN_DATA_H_

@ -4,7 +4,6 @@
#include "mojo/edk/js/handle.h"
#include <sstream>
#include "mojo/edk/js/handle_close_observer.h"
namespace mojo {
@ -20,23 +19,6 @@ HandleWrapper::~HandleWrapper() {
NotifyCloseObservers();
}
std::string HandleWrapper::ToString() {
std::ostringstream oss;
oss << "[mojo::Handle ";
if (handle_.is_valid())
oss << handle_.get().value();
else
oss << "null";
oss << "]";
return oss.str();
}
gin::ObjectTemplateBuilder HandleWrapper::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return Wrappable<HandleWrapper>::GetObjectTemplateBuilder(isolate)
.SetMethod("toString", &HandleWrapper::ToString);
}
void HandleWrapper::Close() {
NotifyCloseObservers();
handle_.reset();

@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_BINDINGS_JS_HANDLE_H_
#define MOJO_BINDINGS_JS_HANDLE_H_
#ifndef MOJO_EDK_JS_HANDLE_H_
#define MOJO_EDK_JS_HANDLE_H_
#include "base/observer_list.h"
#include "gin/converter.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "gin/wrappable.h"
#include "mojo/public/cpp/system/core.h"
@ -27,11 +26,6 @@ class HandleWrapper : public gin::Wrappable<HandleWrapper> {
return gin::CreateHandle(isolate, new HandleWrapper(handle));
}
std::string ToString();
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate)
override;
mojo::Handle get() const { return handle_.get(); }
mojo::Handle release() { return handle_.release(); }
void Close();
@ -101,4 +95,4 @@ struct Converter<gin::Handle<mojo::js::HandleWrapper> > {
} // namespace gin
#endif // MOJO_BINDINGS_JS_HANDLE_H_
#endif // MOJO_EDK_JS_HANDLE_H_

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_BINDINGS_JS_HANDLE_CLOSE_OBSERVER_H_
#define MOJO_BINDINGS_JS_HANDLE_CLOSE_OBSERVER_H_
#ifndef MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
#define MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
namespace mojo {
namespace js {
@ -19,4 +19,4 @@ class HandleCloseObserver {
} // namespace js
} // namespace mojo
#endif // MOJO_BINDINGS_JS_HANDLE_CLOSE_OBSERVER_H_
#endif // MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_

@ -0,0 +1,78 @@
// 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 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(js::Core::kModuleName, js::Core::GetModule);
AddBuiltinModule(js::Support::kModuleName, js::Support::GetModule);
AddBuiltinModule(js::Threading::kModuleName, js::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 mojo

@ -0,0 +1,33 @@
// 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/public/c/system/core.h"
namespace mojo {
namespace js {
class 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 mojo
#endif // MOJO_EDK_JS_MOJO_RUNNER_DELEGATE_H_

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_BINDINGS_JS_SUPPORT_H_
#define MOJO_BINDINGS_JS_SUPPORT_H_
#ifndef MOJO_EDK_JS_SUPPORT_H_
#define MOJO_EDK_JS_SUPPORT_H_
#include "v8/include/v8.h"
@ -19,4 +19,4 @@ class Support {
} // namespace js
} // namespace mojo
#endif // MOJO_BINDINGS_JS_SUPPORT_H_
#endif // MOJO_EDK_JS_SUPPORT_H_

39
mojo/edk/js/test/BUILD.gn Normal file

@ -0,0 +1,39 @@
# 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.
test("js_unittests") {
deps = [
"//base",
"//gin:gin_test",
"//mojo/edk/js",
"//mojo/edk/js:js_unittests",
"//mojo/edk/test:run_all_unittests",
"//mojo/edk/test:test_support",
"//mojo/public/cpp/environment",
"//mojo/public/cpp/system",
"//mojo/public/cpp/utility",
"//mojo/environment:chromium",
"//mojo/public/interfaces/bindings/tests:test_interfaces",
]
sources = [ "run_js_tests.cc" ]
}
test("js_integration_tests") {
deps = [
"//base",
"//gin:gin_test",
"//mojo/edk/js",
"//mojo/edk/js/tests:js_to_cpp_tests",
"//mojo/edk/test:run_all_unittests",
"//mojo/edk/test:test_support",
"//mojo/public/cpp/bindings",
"//mojo/environment:chromium",
"//mojo/public/interfaces/bindings/tests:test_interfaces",
]
sources = [
"run_js_integration_tests.cc"
]
}

@ -0,0 +1,34 @@
// 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.
define(function() {
function hexify(value, length) {
var hex = value.toString(16);
while (hex.length < length)
hex = "0" + hex;
return hex;
}
function dumpArray(bytes) {
var dumped = "";
for (var i = 0; i < bytes.length; ++i) {
dumped += hexify(bytes[i], 2);
if (i % 16 == 15) {
dumped += "\n";
continue;
}
if (i % 2 == 1)
dumped += " ";
if (i % 8 == 7)
dumped += " ";
}
return dumped;
}
var exports = {};
exports.dumpArray = dumpArray;
return exports;
});

@ -0,0 +1,57 @@
// 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/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 js {
namespace {
class TestRunnerDelegate : public gin::FileRunnerDelegate {
public:
TestRunnerDelegate() {
AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
AddBuiltinModule(Core::kModuleName, Core::GetModule);
AddBuiltinModule(gin::TimerModule::kName, gin::TimerModule::GetModule);
AddBuiltinModule(Threading::kModuleName, Threading::GetModule);
}
private:
DISALLOW_COPY_AND_ASSIGN(TestRunnerDelegate);
};
void RunTest(std::string test, bool addSupportModule) {
base::FilePath path;
PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.AppendASCII("mojo")
.AppendASCII("edk")
.AppendASCII("js")
.AppendASCII("tests")
.AppendASCII(test);
TestRunnerDelegate delegate;
if (addSupportModule)
delegate.AddBuiltinModule(Support::kModuleName, Support::GetModule);
gin::RunTestFromFile(path, &delegate, true);
}
TEST(JSTest, connection) {
RunTest("connection_tests.js", false);
}
TEST(JSTest, sample_service) {
RunTest("sample_service_tests.js", true);
}
} // namespace
} // namespace js
} // namespace mojo

@ -6,7 +6,6 @@
#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"
@ -31,7 +30,6 @@ class TestRunnerDelegate : public gin::FileRunnerDelegate {
};
void RunTest(std::string test, bool run_until_idle) {
Environment env;
base::FilePath path;
PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.AppendASCII("mojo")

@ -2,17 +2,26 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
test("js_unittests") {
import("//mojo/public/tools/bindings/mojom.gni")
source_set("js_to_cpp_tests") {
testonly = true
deps = [
":js_to_cpp_bindings",
"//gin:gin_test",
"//mojo/edk/js",
"//mojo/edk/js:js_unittests",
"//mojo/edk/test:run_all_unittests",
"//mojo/edk/test:test_support",
"//mojo/public/cpp/environment:standalone",
"//mojo/public/cpp/utility",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//mojo/public/interfaces/bindings/tests:test_interfaces",
]
sources = [ "run_js_tests.cc" ]
sources = [
"js_to_cpp_tests.cc",
]
}
mojom("js_to_cpp_bindings") {
sources = [ "js_to_cpp.mojom" ]
}

@ -1,7 +0,0 @@
include_rules = [
"+base",
"+gin",
"+v8",
"+mojo/edk/js/core.h",
"+mojo/edk/js/support.h",
]

@ -0,0 +1,261 @@
// 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.
// Mock out the support module to avoid depending on the message loop.
define("mojo/public/js/support", ["timer"], function(timer) {
var waitingCallbacks = [];
function WaitCookie(id) {
this.id = id;
}
function asyncWait(handle, flags, callback) {
var id = waitingCallbacks.length;
waitingCallbacks.push(callback);
return new WaitCookie(id);
}
function cancelWait(cookie) {
waitingCallbacks[cookie.id] = null;
}
function numberOfWaitingCallbacks() {
var count = 0;
for (var i = 0; i < waitingCallbacks.length; ++i) {
if (waitingCallbacks[i])
++count;
}
return count;
}
function pumpOnce(result) {
var callbacks = waitingCallbacks;
waitingCallbacks = [];
for (var i = 0; i < callbacks.length; ++i) {
if (callbacks[i])
callbacks[i](result);
}
}
// Queue up a pumpOnce call to execute after the stack unwinds. Use
// this to trigger a pump after all Promises are executed.
function queuePump(result) {
timer.createOneShot(0, pumpOnce.bind(undefined, result));
}
var exports = {};
exports.asyncWait = asyncWait;
exports.cancelWait = cancelWait;
exports.numberOfWaitingCallbacks = numberOfWaitingCallbacks;
exports.pumpOnce = pumpOnce;
exports.queuePump = queuePump;
return exports;
});
define([
"gin/test/expect",
"mojo/public/js/support",
"mojo/public/js/core",
"mojo/public/js/connection",
"mojo/public/interfaces/bindings/tests/sample_interfaces.mojom",
"mojo/public/interfaces/bindings/tests/sample_service.mojom",
"mojo/public/js/threading",
"gc",
], function(expect,
mockSupport,
core,
connection,
sample_interfaces,
sample_service,
threading,
gc) {
testClientServer();
testWriteToClosedPipe();
testRequestResponse().then(function() {
this.result = "PASS";
gc.collectGarbage(); // should not crash
threading.quit();
}.bind(this)).catch(function(e) {
this.result = "FAIL: " + (e.stack || e);
threading.quit();
}.bind(this));
function testClientServer() {
var receivedFrobinate = false;
var receivedDidFrobinate = false;
// ServiceImpl ------------------------------------------------------------
function ServiceImpl(peer) {
this.peer = peer;
}
ServiceImpl.prototype = Object.create(
sample_service.Service.stubClass.prototype);
ServiceImpl.prototype.frobinate = function(foo, baz, port) {
receivedFrobinate = true;
expect(foo.name).toBe("Example name");
expect(baz).toBeTruthy();
expect(core.close(port)).toBe(core.RESULT_OK);
this.peer.didFrobinate(42);
};
// ServiceClientImpl ------------------------------------------------------
function ServiceClientImpl(peer) {
this.peer = peer;
}
ServiceClientImpl.prototype =
Object.create(sample_service.ServiceClient.stubClass.prototype);
ServiceClientImpl.prototype.didFrobinate = function(result) {
receivedDidFrobinate = true;
expect(result).toBe(42);
};
var pipe = core.createMessagePipe();
var anotherPipe = core.createMessagePipe();
var sourcePipe = core.createMessagePipe();
var connection0 = new connection.Connection(
pipe.handle0, ServiceImpl, sample_service.ServiceClient.proxyClass);
var connection1 = new connection.Connection(
pipe.handle1, ServiceClientImpl, sample_service.Service.proxyClass);
var foo = new sample_service.Foo();
foo.bar = new sample_service.Bar();
foo.name = "Example name";
foo.source = sourcePipe.handle0;
connection1.remote.frobinate(foo, true, anotherPipe.handle0);
mockSupport.pumpOnce(core.RESULT_OK);
expect(receivedFrobinate).toBeTruthy();
expect(receivedDidFrobinate).toBeTruthy();
connection0.close();
connection1.close();
expect(mockSupport.numberOfWaitingCallbacks()).toBe(0);
// sourcePipe.handle0 was closed automatically when sent over IPC.
expect(core.close(sourcePipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
// sourcePipe.handle1 hasn't been closed yet.
expect(core.close(sourcePipe.handle1)).toBe(core.RESULT_OK);
// anotherPipe.handle0 was closed automatically when sent over IPC.
expect(core.close(anotherPipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
// anotherPipe.handle1 hasn't been closed yet.
expect(core.close(anotherPipe.handle1)).toBe(core.RESULT_OK);
// The Connection object is responsible for closing these handles.
expect(core.close(pipe.handle0)).toBe(core.RESULT_INVALID_ARGUMENT);
expect(core.close(pipe.handle1)).toBe(core.RESULT_INVALID_ARGUMENT);
}
function testWriteToClosedPipe() {
var pipe = core.createMessagePipe();
var connection1 = new connection.Connection(
pipe.handle1, function() {}, sample_service.Service.proxyClass);
// Close the other end of the pipe.
core.close(pipe.handle0);
// Not observed yet because we haven't pumped events yet.
expect(connection1.encounteredError()).toBeFalsy();
var foo = new sample_service.Foo();
foo.bar = new sample_service.Bar();
// TODO(darin): crbug.com/357043: pass null in place of |foo| here.
connection1.remote.frobinate(foo, true, null);
// Write failures are not reported.
expect(connection1.encounteredError()).toBeFalsy();
// Pump events, and then we should start observing the closed pipe.
mockSupport.pumpOnce(core.RESULT_OK);
expect(connection1.encounteredError()).toBeTruthy();
connection1.close();
}
function testRequestResponse() {
// ProviderImpl ------------------------------------------------------------
function ProviderImpl(peer) {
this.peer = peer;
}
ProviderImpl.prototype =
Object.create(sample_interfaces.Provider.stubClass.prototype);
ProviderImpl.prototype.echoString = function(a) {
mockSupport.queuePump(core.RESULT_OK);
return Promise.resolve({a: a});
};
ProviderImpl.prototype.echoStrings = function(a, b) {
mockSupport.queuePump(core.RESULT_OK);
return Promise.resolve({a: a, b: b});
};
// ProviderClientImpl ------------------------------------------------------
function ProviderClientImpl(peer) {
this.peer = peer;
}
ProviderClientImpl.prototype =
Object.create(sample_interfaces.ProviderClient.stubClass.prototype);
var pipe = core.createMessagePipe();
var connection0 = new connection.Connection(
pipe.handle0,
ProviderImpl,
sample_interfaces.ProviderClient.proxyClass);
var connection1 = new connection.Connection(
pipe.handle1,
ProviderClientImpl,
sample_interfaces.Provider.proxyClass);
var origReadMessage = core.readMessage;
// echoString
mockSupport.queuePump(core.RESULT_OK);
return connection1.remote.echoString("hello").then(function(response) {
expect(response.a).toBe("hello");
}).then(function() {
// echoStrings
mockSupport.queuePump(core.RESULT_OK);
return connection1.remote.echoStrings("hello", "world");
}).then(function(response) {
expect(response.a).toBe("hello");
expect(response.b).toBe("world");
}).then(function() {
// Mock a read failure, expect it to fail.
core.readMessage = function() {
return { result: core.RESULT_UNKNOWN };
};
mockSupport.queuePump(core.RESULT_OK);
return connection1.remote.echoString("goodbye");
}).then(function() {
throw Error("Expected echoString to fail.");
}, function(error) {
expect(error.message).toBe("Connection error: " + core.RESULT_UNKNOWN);
// Clean up.
core.readMessage = origReadMessage;
});
}
});

@ -0,0 +1,53 @@
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);
};
[Client=CppSide]
interface JsSide {
Ping();
Echo(int32 numIterations, EchoArgs arg);
BitFlip(EchoArgs arg);
BackPointer(EchoArgs arg);
};

@ -0,0 +1,418 @@
// 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/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 "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "mojo/edk/js/mojo_runner_delegate.h"
#include "mojo/edk/js/tests/js_to_cpp.mojom.h"
#include "mojo/edk/test/test_utils.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace js {
// Global value updated by some checks to prevent compilers from optimizing
// reads out of existence.
uint32 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 kExpectedInt8Value = -65;
const int16 kExpectedInt16Value = -16961;
const int32 kExpectedInt32Value = -1145258561;
const int64 kExpectedInt64Value = -77263311946305LL;
// Positive numbers with different values in each byte, the last of
// which can survive promotion to double and back.
const uint8 kExpectedUInt8Value = 65;
const uint16 kExpectedUInt16Value = 16961;
const uint32 kExpectedUInt32Value = 1145258561;
const uint64 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(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);
EXPECT_EQ(MOJO_RESULT_OK, result);
EXPECT_EQ(64u, buffer_size);
for (int i = 0; i < 64; ++i) {
EXPECT_EQ(i, buffer[i]);
}
}
void CheckMessagePipe(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);
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 = "coming";
Array<String> string_array(3);
string_array[0] = "one";
string_array[1] = "two";
string_array[2] = "three";
args->string_array = string_array.Pass();
return args.Pass();
}
void CheckSampleEchoArgs(const js_to_cpp::EchoArgs& 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.get());
EXPECT_EQ(std::string("one"), arg.string_array[0].get());
EXPECT_EQ(std::string("two"), arg.string_array[1].get());
EXPECT_EQ(std::string("three"), arg.string_array[2].get());
CheckDataPipe(arg.data_handle.get().value());
CheckMessagePipe(arg.message_handle.get().value());
}
void CheckSampleEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) {
if (list.is_null())
return;
CheckSampleEchoArgs(*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 String& arg) {
if (arg.is_null())
return;
for (size_t i = 0; i < arg.size(); ++i)
g_waste_accumulator += arg[i];
}
void CheckCorruptedStringArray(const Array<String>& string_array) {
if (string_array.is_null())
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_(NULL),
js_side_(NULL),
mishandled_messages_(0) {
}
~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_; }
// 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_;
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.To<std::string>());
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_);
MessagePipe pipe;
js_to_cpp::JsSidePtr js_side =
MakeProxy<js_to_cpp::JsSide>(pipe.handle0.Pass());
js_side.set_client(cpp_side);
js_side.internal_state()->router_for_testing()->EnableTestingMode();
cpp_side->set_js_side(js_side.get());
gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
gin::ArrayBufferAllocator::SharedInstance());
gin::IsolateHolder instance;
MojoRunnerDelegate delegate;
gin::ShellRunner runner(&delegate, instance.isolate());
delegate.Start(&runner, pipe.handle1.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) {
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) {
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 mojo

@ -0,0 +1,221 @@
// 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/connection',
'mojo/public/js/connector',
'mojo/public/js/core',
], function (console, jsToCpp, connection, connector, core) {
var retainedConnection;
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(cppSide) {
this.cppSide_ = cppSide;
cppSide.startTest();
}
JsSideConnection.prototype =
Object.create(jsToCpp.JsSide.stubClass.prototype);
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(handle) {
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;
}
retainedConnection = new connection.Connection(handle, JsSideConnection,
jsToCpp.CppSide.proxyClass);
};
});

@ -0,0 +1,168 @@
// 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.
define([
"console",
"mojo/edk/js/test/hexdump",
"gin/test/expect",
"mojo/public/interfaces/bindings/tests/sample_service.mojom",
"mojo/public/interfaces/bindings/tests/sample_import.mojom",
"mojo/public/interfaces/bindings/tests/sample_import2.mojom",
], function(console, hexdump, expect, sample, imported, imported2) {
var global = this;
// Set this variable to true to print the binary message in hex.
var dumpMessageAsHex = false;
function makeFoo() {
var bar = new sample.Bar();
bar.alpha = 20;
bar.beta = 40;
bar.gamma = 60;
bar.type = sample.Bar.Type.VERTICAL;
var extra_bars = new Array(3);
for (var i = 0; i < extra_bars.length; ++i) {
var base = i * 100;
var type = i % 2 ?
sample.Bar.Type.VERTICAL : sample.Bar.Type.HORIZONTAL;
extra_bars[i] = new sample.Bar();
extra_bars[i].alpha = base;
extra_bars[i].beta = base + 20;
extra_bars[i].gamma = base + 40;
extra_bars[i].type = type;
}
var data = new Array(10);
for (var i = 0; i < data.length; ++i) {
data[i] = data.length - i;
}
var source = 0xFFFF; // Invent a dummy handle.
var foo = new sample.Foo();
foo.name = "foopy";
foo.x = 1;
foo.y = 2;
foo.a = false;
foo.b = true;
foo.c = false;
foo.bar = bar;
foo.extra_bars = extra_bars;
foo.data = data;
foo.source = source;
return foo;
}
// Check that the given |Foo| is identical to the one made by |MakeFoo()|.
function checkFoo(foo) {
expect(foo.name).toBe("foopy");
expect(foo.x).toBe(1);
expect(foo.y).toBe(2);
expect(foo.a).toBeFalsy();
expect(foo.b).toBeTruthy();
expect(foo.c).toBeFalsy();
expect(foo.bar.alpha).toBe(20);
expect(foo.bar.beta).toBe(40);
expect(foo.bar.gamma).toBe(60);
expect(foo.bar.type).toBe(sample.Bar.Type.VERTICAL);
expect(foo.extra_bars.length).toBe(3);
for (var i = 0; i < foo.extra_bars.length; ++i) {
var base = i * 100;
var type = i % 2 ?
sample.Bar.Type.VERTICAL : sample.Bar.Type.HORIZONTAL;
expect(foo.extra_bars[i].alpha).toBe(base);
expect(foo.extra_bars[i].beta).toBe(base + 20);
expect(foo.extra_bars[i].gamma).toBe(base + 40);
expect(foo.extra_bars[i].type).toBe(type);
}
expect(foo.data.length).toBe(10);
for (var i = 0; i < foo.data.length; ++i)
expect(foo.data[i]).toBe(foo.data.length - i);
expect(foo.source).toBe(0xFFFF);
}
// Check that values are set to the defaults if we don't override them.
function checkDefaultValues() {
var bar = new sample.Bar();
expect(bar.alpha).toBe(255);
expect(bar.type).toBe(sample.Bar.Type.VERTICAL);
var foo = new sample.Foo();
expect(foo.name).toBe("Fooby");
expect(foo.a).toBeTruthy();
expect(foo.data).toBeNull();
var defaults = new sample.DefaultsTest();
expect(defaults.a0).toBe(-12);
expect(defaults.a1).toBe(sample.kTwelve);
expect(defaults.a2).toBe(1234);
expect(defaults.a3).toBe(34567);
expect(defaults.a4).toBe(123456);
expect(defaults.a5).toBe(3456789012);
expect(defaults.a6).toBe(-111111111111);
// JS doesn't have a 64 bit integer type so this is just checking that the
// expected and actual values have the same closest double value.
expect(defaults.a7).toBe(9999999999999999999);
expect(defaults.a8).toBe(0x12345);
expect(defaults.a9).toBe(-0x12345);
expect(defaults.a10).toBe(1234);
expect(defaults.a11).toBe(true);
expect(defaults.a12).toBe(false);
expect(defaults.a13).toBe(123.25);
expect(defaults.a14).toBe(1234567890.123);
expect(defaults.a15).toBe(1E10);
expect(defaults.a16).toBe(-1.2E+20);
expect(defaults.a17).toBe(1.23E-20);
expect(defaults.a20).toBe(sample.Bar.Type.BOTH);
expect(defaults.a21).toBeNull();
expect(defaults.a22).toBeTruthy();
expect(defaults.a22.shape).toBe(imported.Shape.RECTANGLE);
expect(defaults.a22.color).toBe(imported2.Color.BLACK);
expect(defaults.a21).toBeNull();
expect(defaults.a23).toBe(0xFFFFFFFFFFFFFFFF);
expect(defaults.a24).toBe(0x123456789);
expect(defaults.a25).toBe(-0x123456789);
}
function ServiceImpl() {
}
ServiceImpl.prototype = Object.create(sample.Service.stubClass.prototype);
ServiceImpl.prototype.frobinate = function(foo, baz, port) {
checkFoo(foo);
expect(baz).toBe(sample.Service.BazOptions.EXTRA);
expect(port).toBe(10);
global.result = "PASS";
};
function SimpleMessageReceiver() {
}
SimpleMessageReceiver.prototype.accept = function(message) {
if (dumpMessageAsHex) {
var uint8Array = new Uint8Array(message.buffer.arrayBuffer);
console.log(hexdump.dumpArray(uint8Array));
}
// Imagine some IPC happened here.
var serviceImpl = new ServiceImpl();
serviceImpl.accept(message);
};
var receiver = new SimpleMessageReceiver();
var serviceProxy = new sample.Service.proxyClass(receiver);
checkDefaultValues();
var foo = makeFoo();
checkFoo(foo);
var port = 10;
serviceProxy.frobinate(foo, sample.Service.BazOptions.EXTRA, port);
});

47
mojo/edk/js/threading.cc Normal file

@ -0,0 +1,47 @@
// 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 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 mojo

25
mojo/edk/js/threading.h Normal file

@ -0,0 +1,25 @@
// 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 "v8/include/v8.h"
namespace mojo {
namespace js {
class Threading {
public:
static const char kModuleName[];
static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
private:
Threading();
};
} // namespace js
} // namespace mojo
#endif // MOJO_EDK_JS_THREADING_H_

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MOJO_BINDINGS_JS_WAITING_CALLBACK_H_
#define MOJO_BINDINGS_JS_WAITING_CALLBACK_H_
#ifndef MOJO_EDK_JS_WAITING_CALLBACK_H_
#define MOJO_EDK_JS_WAITING_CALLBACK_H_
#include "gin/handle.h"
#include "gin/runner.h"
@ -60,4 +60,4 @@ class WaitingCallback : public gin::Wrappable<WaitingCallback>,
} // namespace js
} // namespace mojo
#endif // MOJO_BINDINGS_JS_WAITING_CALLBACK_H_
#endif // MOJO_EDK_JS_WAITING_CALLBACK_H_

@ -2,195 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Essential components (and their tests) that are needed to build
# Chrome should be here. Other components that are useful only in
# Mojo land like mojo_shell should be in mojo.gyp.
{
'includes': [
'../mojo_variables.gypi',
],
'targets': [
{
'target_name': 'mojo_edk',
'type': 'none',
'dependencies': [
# NOTE: If adding a new dependency here, please consider whether it
# should also be added to the list of Mojo-related dependencies of
# build/all.gyp:All on iOS, as All cannot depend on the mojo_base
# target on iOS due to the presence of the js targets, which cause v8
# to be built.
'mojo_message_pipe_perftests',
'mojo_public_application_unittests',
'mojo_public_bindings_unittests',
'mojo_public_environment_unittests',
'mojo_public_system_perftests',
'mojo_public_system_unittests',
'mojo_public_utility_unittests',
'mojo_system_impl',
'mojo_system_unittests',
'mojo_js_unittests',
],
},
{
'target_name': 'mojo_none',
'type': 'none',
},
{
# GN version: //mojo/edk/test:run_all_unittests
'target_name': 'mojo_run_all_unittests',
'type': 'static_library',
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../testing/gtest.gyp:gtest',
'mojo_system_impl',
'mojo_test_support_impl',
'../public/mojo_public.gyp:mojo_test_support',
],
'sources': [
'test/run_all_unittests.cc',
],
},
{
# GN version: //mojo/edk/test:run_all_perftests
'target_name': 'mojo_run_all_perftests',
'type': 'static_library',
'dependencies': [
'../../base/base.gyp:test_support_base',
'mojo_system_impl',
'mojo_test_support_impl',
'../public/mojo_public.gyp:mojo_test_support',
],
'sources': [
'test/run_all_perftests.cc',
],
},
# TODO(vtl): Reorganize the mojo_public_*_unittests.
{
# GN version: //mojo/public/cpp/bindings/tests:mojo_public_bindings_unittests
'target_name': 'mojo_public_bindings_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_cpp_bindings',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_bindings_test_utils',
'../public/mojo_public.gyp:mojo_public_test_interfaces',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'sources': [
'../public/cpp/bindings/tests/array_unittest.cc',
'../public/cpp/bindings/tests/bounds_checker_unittest.cc',
'../public/cpp/bindings/tests/buffer_unittest.cc',
'../public/cpp/bindings/tests/connector_unittest.cc',
'../public/cpp/bindings/tests/container_test_util.cc',
'../public/cpp/bindings/tests/equals_unittest.cc',
'../public/cpp/bindings/tests/handle_passing_unittest.cc',
'../public/cpp/bindings/tests/interface_ptr_unittest.cc',
'../public/cpp/bindings/tests/map_unittest.cc',
'../public/cpp/bindings/tests/request_response_unittest.cc',
'../public/cpp/bindings/tests/router_unittest.cc',
'../public/cpp/bindings/tests/sample_service_unittest.cc',
'../public/cpp/bindings/tests/serialization_warning_unittest.cc',
'../public/cpp/bindings/tests/string_unittest.cc',
'../public/cpp/bindings/tests/struct_unittest.cc',
'../public/cpp/bindings/tests/type_conversion_unittest.cc',
'../public/cpp/bindings/tests/validation_unittest.cc',
],
},
{
# GN version: //mojo/public/cpp/environment/tests:mojo_public_environment_unittests
'target_name': 'mojo_public_environment_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'include_dirs': [ '../..' ],
'sources': [
'../public/cpp/environment/tests/async_wait_unittest.cc',
'../public/cpp/environment/tests/async_waiter_unittest.cc',
'../public/cpp/environment/tests/logger_unittest.cc',
'../public/cpp/environment/tests/logging_unittest.cc',
],
},
{
# GN version: //mojo/public/cpp/application/tests:mojo_public_application_unittests
'target_name': 'mojo_public_application_unittests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../testing/gtest.gyp:gtest',
'mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_application_standalone',
'../public/mojo_public.gyp:mojo_utility',
'../public/mojo_public.gyp:mojo_environment_standalone',
],
'sources': [
'../public/cpp/application/tests/service_registry_unittest.cc',
],
},
{
# GN version: //mojo/public/cpp/application/tests:mojo_public_system_unittests
'target_name': 'mojo_public_system_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_public_test_utils',
],
'include_dirs': [ '../..' ],
'sources': [
'<@(mojo_public_system_unittest_sources)',
],
},
{
# GN version: //mojo/public/cpp/application/tests:mojo_public_utility_unittests
'target_name': 'mojo_public_utility_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'include_dirs': [ '../..' ],
'sources': [
'../public/cpp/utility/tests/mutex_unittest.cc',
'../public/cpp/utility/tests/run_loop_unittest.cc',
'../public/cpp/utility/tests/thread_unittest.cc',
],
'conditions': [
# See crbug.com/342893:
['OS=="win"', {
'sources!': [
'../public/cpp/utility/tests/mutex_unittest.cc',
'../public/cpp/utility/tests/thread_unittest.cc',
],
}],
],
},
{
# GN version: //mojo/public/c/system/tests:perftests
'target_name': 'mojo_public_system_perftests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../testing/gtest.gyp:gtest',
'mojo_run_all_perftests',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'sources': [
'../public/c/system/tests/core_perftest.cc',
],
},
{
# GN version: //mojo/edk/system
'target_name': 'mojo_system_impl',
@ -205,11 +21,14 @@
'MOJO_USE_SYSTEM_IMPL',
],
'sources': [
'embedder/configuration.h',
'embedder/channel_info_forward.h',
'embedder/channel_init.cc',
'embedder/channel_init.h',
'embedder/embedder.cc',
'embedder/embedder.h',
'embedder/embedder_internal.h',
'embedder/entrypoints.cc',
'embedder/platform_channel_pair.cc',
'embedder/platform_channel_pair.h',
'embedder/platform_channel_pair_posix.cc',
@ -239,7 +58,10 @@
'system/channel_endpoint_id.h',
'system/channel_info.cc',
'system/channel_info.h',
'system/constants.h',
'system/channel_manager.cc',
'system/channel_manager.h',
'system/configuration.cc',
'system/configuration.h',
'system/core.cc',
'system/core.h',
'system/data_pipe.cc',
@ -250,7 +72,6 @@
'system/data_pipe_producer_dispatcher.h',
'system/dispatcher.cc',
'system/dispatcher.h',
'system/entrypoints.cc',
'system/handle_signals_state.h',
'system/handle_table.cc',
'system/handle_table.h',
@ -303,77 +124,6 @@
'defines': ['MOJO_USE_SYSTEM_IMPL'],
}
},
{
# GN version: //mojo/edk/system:mojo_system_unittests
'target_name': 'mojo_system_unittests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../testing/gtest.gyp:gtest',
'mojo_common_test_support',
'mojo_system_impl',
],
'sources': [
'embedder/embedder_unittest.cc',
'embedder/platform_channel_pair_posix_unittest.cc',
'embedder/simple_platform_shared_buffer_unittest.cc',
'system/channel_endpoint_id_unittest.cc',
'system/channel_unittest.cc',
'system/core_unittest.cc',
'system/core_test_base.cc',
'system/core_test_base.h',
'system/data_pipe_unittest.cc',
'system/dispatcher_unittest.cc',
'system/local_data_pipe_unittest.cc',
'system/memory_unittest.cc',
'system/message_pipe_dispatcher_unittest.cc',
'system/message_pipe_test_utils.h',
'system/message_pipe_test_utils.cc',
'system/message_pipe_unittest.cc',
'system/multiprocess_message_pipe_unittest.cc',
'system/options_validation_unittest.cc',
'system/platform_handle_dispatcher_unittest.cc',
'system/raw_channel_unittest.cc',
'system/remote_message_pipe_unittest.cc',
'system/run_all_unittests.cc',
'system/shared_buffer_dispatcher_unittest.cc',
'system/simple_dispatcher_unittest.cc',
'system/test_utils.cc',
'system/test_utils.h',
'system/waiter_list_unittest.cc',
'system/waiter_test_utils.cc',
'system/waiter_test_utils.h',
'system/waiter_unittest.cc',
],
'conditions': [
['OS=="ios"', {
'sources!': [
'embedder/embedder_unittest.cc',
'system/multiprocess_message_pipe_unittest.cc',
],
}],
],
},
{
# GN version: //mojo/edk/system:mojo_message_pipe_perftests
'target_name': 'mojo_message_pipe_perftests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../base/base.gyp:test_support_perf',
'../../testing/gtest.gyp:gtest',
'mojo_common_test_support',
'mojo_system_impl',
],
'sources': [
'system/message_pipe_perftest.cc',
'system/message_pipe_test_utils.h',
'system/message_pipe_test_utils.cc',
'system/test_utils.cc',
'system/test_utils.h',
],
},
{
# GN version: //mojo/edk/js
'target_name': 'mojo_js_lib',
@ -396,32 +146,18 @@
'js/handle.cc',
'js/handle.h',
'js/handle_close_observer.h',
'js/mojo_runner_delegate.cc',
'js/mojo_runner_delegate.h',
'js/support.cc',
'js/support.h',
'js/threading.cc',
'js/threading.h',
'js/waiting_callback.cc',
'js/waiting_callback.h',
],
},
{
# GN version: //mojo/edk/js:js_unittests
'target_name': 'mojo_js_unittests',
'type': 'executable',
'dependencies': [
'../../gin/gin.gyp:gin_test',
'mojo_common_test_support',
'mojo_run_all_unittests',
'mojo_js_lib',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_test_interfaces',
'../public/mojo_public.gyp:mojo_utility',
],
'sources': [
'js/handle_unittest.cc',
'js/tests/run_js_tests.cc',
],
},
{
# GN version: //mojo/common/test:test_support_impl
# GN version: //mojo/edk/test:test_support_impl
'target_name': 'mojo_test_support_impl',
'type': 'static_library',
'dependencies': [
@ -457,5 +193,35 @@
}],
],
},
{
# GN version: //mojo/edk/test:run_all_unittests
'target_name': 'mojo_run_all_unittests',
'type': 'static_library',
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../testing/gtest.gyp:gtest',
'mojo_system_impl',
'mojo_test_support_impl',
'../public/mojo_public.gyp:mojo_test_support',
],
'sources': [
'test/run_all_unittests.cc',
],
},
{
# GN version: //mojo/edk/test:run_all_perftests
'target_name': 'mojo_run_all_perftests',
'type': 'static_library',
'dependencies': [
'../../base/base.gyp:test_support_base',
'mojo_edk.gyp:mojo_system_impl',
'mojo_test_support_impl',
'../public/mojo_public.gyp:mojo_test_support',
],
'sources': [
'test/run_all_perftests.cc',
],
},
],
}

278
mojo/edk/mojo_edk_tests.gyp Normal file

@ -0,0 +1,278 @@
# 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.
{
'includes': [
'../mojo_variables.gypi',
],
'targets': [
{
'target_name': 'mojo_edk_tests',
'type': 'none',
'dependencies': [
# NOTE: If adding a new dependency here, please consider whether it
# should also be added to the list of Mojo-related dependencies of
# build/all.gyp:All on iOS, as All cannot depend on the mojo_base
# target on iOS due to the presence of the js targets, which cause v8
# to be built.
'mojo_message_pipe_perftests',
'mojo_public_application_unittests',
'mojo_public_bindings_unittests',
'mojo_public_environment_unittests',
'mojo_public_system_perftests',
'mojo_public_system_unittests',
'mojo_public_utility_unittests',
'mojo_system_unittests',
'mojo_js_unittests',
'mojo_js_integration_tests',
],
},
# TODO(vtl): Reorganize the mojo_public_*_unittests.
{
# GN version: //mojo/public/cpp/bindings/tests:mojo_public_bindings_unittests
'target_name': 'mojo_public_bindings_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_cpp_bindings',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_bindings_test_utils',
'../public/mojo_public.gyp:mojo_public_test_interfaces',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'sources': [
'../public/cpp/bindings/tests/array_unittest.cc',
'../public/cpp/bindings/tests/bounds_checker_unittest.cc',
'../public/cpp/bindings/tests/buffer_unittest.cc',
'../public/cpp/bindings/tests/connector_unittest.cc',
'../public/cpp/bindings/tests/container_test_util.cc',
'../public/cpp/bindings/tests/equals_unittest.cc',
'../public/cpp/bindings/tests/handle_passing_unittest.cc',
'../public/cpp/bindings/tests/interface_ptr_unittest.cc',
'../public/cpp/bindings/tests/map_unittest.cc',
'../public/cpp/bindings/tests/request_response_unittest.cc',
'../public/cpp/bindings/tests/router_unittest.cc',
'../public/cpp/bindings/tests/sample_service_unittest.cc',
'../public/cpp/bindings/tests/serialization_warning_unittest.cc',
'../public/cpp/bindings/tests/string_unittest.cc',
'../public/cpp/bindings/tests/struct_unittest.cc',
'../public/cpp/bindings/tests/type_conversion_unittest.cc',
'../public/cpp/bindings/tests/validation_unittest.cc',
],
},
{
# GN version: //mojo/public/cpp/environment/tests:mojo_public_environment_unittests
'target_name': 'mojo_public_environment_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'include_dirs': [ '../..' ],
'sources': [
'../public/cpp/environment/tests/async_wait_unittest.cc',
'../public/cpp/environment/tests/async_waiter_unittest.cc',
'../public/cpp/environment/tests/logger_unittest.cc',
'../public/cpp/environment/tests/logging_unittest.cc',
],
},
{
# GN version: //mojo/public/cpp/application/tests:mojo_public_application_unittests
'target_name': 'mojo_public_application_unittests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_application_standalone',
'../public/mojo_public.gyp:mojo_utility',
'../public/mojo_public.gyp:mojo_environment_standalone',
],
'sources': [
'../public/cpp/application/tests/service_registry_unittest.cc',
],
},
{
# GN version: //mojo/public/cpp/system/tests:mojo_public_system_unittests
# and //mojo/public/c/system/tests
'target_name': 'mojo_public_system_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_public_test_utils',
],
'include_dirs': [ '../..' ],
'sources': [
'<@(mojo_public_system_unittest_sources)',
],
},
{
# GN version: //mojo/public/cpp/application/tests:mojo_public_utility_unittests
'target_name': 'mojo_public_utility_unittests',
'type': 'executable',
'dependencies': [
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_run_all_unittests',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'include_dirs': [ '../..' ],
'sources': [
'../public/cpp/utility/tests/mutex_unittest.cc',
'../public/cpp/utility/tests/run_loop_unittest.cc',
'../public/cpp/utility/tests/thread_unittest.cc',
],
'conditions': [
# See crbug.com/342893:
['OS=="win"', {
'sources!': [
'../public/cpp/utility/tests/mutex_unittest.cc',
'../public/cpp/utility/tests/thread_unittest.cc',
],
}],
],
},
{
# GN version: //mojo/public/c/system/tests:perftests
'target_name': 'mojo_public_system_perftests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_run_all_perftests',
'../public/mojo_public.gyp:mojo_public_test_utils',
'../public/mojo_public.gyp:mojo_utility',
],
'sources': [
'../public/c/system/tests/core_perftest.cc',
],
},
{
# GN version: //mojo/edk/system:mojo_system_unittests
'target_name': 'mojo_system_unittests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_common_test_support',
'mojo_edk.gyp:mojo_system_impl',
],
'sources': [
'embedder/embedder_unittest.cc',
'embedder/platform_channel_pair_posix_unittest.cc',
'embedder/simple_platform_shared_buffer_unittest.cc',
'system/channel_endpoint_id_unittest.cc',
'system/channel_unittest.cc',
'system/core_unittest.cc',
'system/core_test_base.cc',
'system/core_test_base.h',
'system/data_pipe_unittest.cc',
'system/dispatcher_unittest.cc',
'system/local_data_pipe_unittest.cc',
'system/memory_unittest.cc',
'system/message_pipe_dispatcher_unittest.cc',
'system/message_pipe_test_utils.h',
'system/message_pipe_test_utils.cc',
'system/message_pipe_unittest.cc',
'system/multiprocess_message_pipe_unittest.cc',
'system/options_validation_unittest.cc',
'system/platform_handle_dispatcher_unittest.cc',
'system/raw_channel_unittest.cc',
'system/remote_message_pipe_unittest.cc',
'system/run_all_unittests.cc',
'system/shared_buffer_dispatcher_unittest.cc',
'system/simple_dispatcher_unittest.cc',
'system/test_utils.cc',
'system/test_utils.h',
'system/waiter_list_unittest.cc',
'system/waiter_test_utils.cc',
'system/waiter_test_utils.h',
'system/waiter_unittest.cc',
'test/multiprocess_test_helper_unittest.cc',
],
'conditions': [
['OS=="ios"', {
'sources!': [
'embedder/embedder_unittest.cc',
'system/multiprocess_message_pipe_unittest.cc',
'test/multiprocess_test_helper_unittest.cc',
],
}],
],
},
{
# GN version: //mojo/edk/system:mojo_message_pipe_perftests
'target_name': 'mojo_message_pipe_perftests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../base/base.gyp:test_support_perf',
'../../testing/gtest.gyp:gtest',
'mojo_edk.gyp:mojo_common_test_support',
'mojo_edk.gyp:mojo_system_impl',
],
'sources': [
'system/message_pipe_perftest.cc',
'system/message_pipe_test_utils.h',
'system/message_pipe_test_utils.cc',
'system/test_utils.cc',
'system/test_utils.h',
],
},
{
# GN version: //mojo/edk/js/test:js_unittests
'target_name': 'mojo_js_unittests',
'type': 'executable',
'dependencies': [
'../../gin/gin.gyp:gin_test',
'mojo_edk.gyp:mojo_common_test_support',
'mojo_edk.gyp:mojo_run_all_unittests',
'mojo_edk.gyp:mojo_js_lib',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_test_interfaces',
'../public/mojo_public.gyp:mojo_utility',
],
'sources': [
'js/handle_unittest.cc',
'js/test/run_js_tests.cc',
],
},
{
# GN version: //mojo/edk/js/test:js_integration_tests
'target_name': 'mojo_js_integration_tests',
'type': 'executable',
'dependencies': [
'../../base/base.gyp:base',
'../../gin/gin.gyp:gin_test',
'../public/mojo_public.gyp:mojo_environment_standalone',
'../public/mojo_public.gyp:mojo_public_test_interfaces',
'../public/mojo_public.gyp:mojo_utility',
'mojo_edk.gyp:mojo_js_lib',
'mojo_edk.gyp:mojo_run_all_unittests',
'mojo_js_to_cpp_bindings',
],
'sources': [
'js/test/run_js_integration_tests.cc',
'js/tests/js_to_cpp_tests',
],
},
{
'target_name': 'mojo_js_to_cpp_bindings',
'type': 'none',
'variables': {
'mojom_files': [
'js/tests/js_to_cpp.mojom',
],
},
'includes': [ '../public/tools/bindings/mojom_bindings_generator_explicit.gypi' ],
},
],
}

@ -12,19 +12,6 @@ config("system_config") {
component("system") {
output_name = "mojo_system_impl"
deps = [
"//base",
"//base/third_party/dynamic_annotations",
"//mojo/edk/embedder",
]
defines = [
"MOJO_SYSTEM_IMPL_IMPLEMENTATION",
"MOJO_SYSTEM_IMPLEMENTATION",
]
all_dependent_configs = [ ":system_config" ]
sources = [
"channel.cc",
"channel.h",
@ -34,7 +21,10 @@ component("system") {
"channel_endpoint_id.h",
"channel_info.cc",
"channel_info.h",
"constants.h",
"channel_manager.cc",
"channel_manager.h",
"configuration.cc",
"configuration.h",
"core.cc",
"core.h",
"data_pipe.cc",
@ -45,7 +35,6 @@ component("system") {
"data_pipe_producer_dispatcher.h",
"dispatcher.cc",
"dispatcher.h",
"entrypoints.cc",
"handle_signals_state.h",
"handle_table.cc",
"handle_table.h",
@ -87,18 +76,30 @@ component("system") {
"waiter_list.cc",
"waiter_list.h",
]
defines = [
"MOJO_SYSTEM_IMPL_IMPLEMENTATION",
"MOJO_SYSTEM_IMPLEMENTATION",
]
all_dependent_configs = [ ":system_config" ]
public_deps = [
"//mojo/edk/embedder",
"//mojo/edk/embedder:platform",
"//mojo/public/c/system",
]
deps = [
"//base",
"//base/third_party/dynamic_annotations",
]
allow_circular_includes_from = [ "//mojo/edk/embedder" ]
}
# GYP version: mojo/edk/mojo_edk.gyp:mojo_system_unittests
test("mojo_system_unittests") {
deps = [
":system",
"//base",
"//mojo/edk/embedder:embedder_unittests",
"//mojo/edk/test:test_support",
"//testing/gtest",
]
sources = [
"../test/multiprocess_test_helper_unittest.cc",
"channel_endpoint_id_unittest.cc",
@ -122,6 +123,7 @@ test("mojo_system_unittests") {
"run_all_unittests.cc",
"shared_buffer_dispatcher_unittest.cc",
"simple_dispatcher_unittest.cc",
# TODO(vtl): Factor test_utils.* into their own source set.
"test_utils.cc",
"test_utils.h",
"waiter_list_unittest.cc",
@ -129,10 +131,29 @@ test("mojo_system_unittests") {
"waiter_test_utils.h",
"waiter_unittest.cc",
]
deps = [
":system",
"//base",
"//base/test:test_support",
"//mojo/edk/embedder:embedder_unittests",
"//mojo/edk/test:test_support",
"//testing/gtest",
]
allow_circular_includes_from = [ "//mojo/edk/embedder:embedder_unittests" ]
}
# GYP version: mojo/edk/mojo_edk.gyp:mojo_message_pipe_perftests
test("mojo_message_pipe_perftests") {
sources = [
"message_pipe_perftest.cc",
"message_pipe_test_utils.h",
"message_pipe_test_utils.cc",
"test_utils.cc",
"test_utils.h",
]
deps = [
":system",
"//base",
@ -141,12 +162,4 @@ test("mojo_message_pipe_perftests") {
"//mojo/edk/test:test_support",
"//testing/gtest",
]
sources = [
"message_pipe_perftest.cc",
"message_pipe_test_utils.h",
"message_pipe_test_utils.cc",
"test_utils.cc",
"test_utils.h",
]
}

@ -20,7 +20,8 @@ namespace system {
Channel::Channel(embedder::PlatformSupport* platform_support)
: platform_support_(platform_support),
is_running_(false),
is_shutting_down_(false) {
is_shutting_down_(false),
channel_manager_(nullptr) {
}
bool Channel::Init(scoped_ptr<RawChannel> raw_channel) {
@ -41,6 +42,15 @@ bool Channel::Init(scoped_ptr<RawChannel> raw_channel) {
return true;
}
void Channel::SetChannelManager(ChannelManager* channel_manager) {
DCHECK(channel_manager);
base::AutoLock locker(lock_);
DCHECK(!is_shutting_down_);
DCHECK(!channel_manager_);
channel_manager_ = channel_manager;
}
void Channel::Shutdown() {
DCHECK(creation_thread_checker_.CalledOnValidThread());
@ -62,8 +72,7 @@ void Channel::Shutdown() {
size_t num_live = 0;
size_t num_zombies = 0;
for (IdToEndpointMap::iterator it = to_destroy.begin();
it != to_destroy.end();
++it) {
it != to_destroy.end(); ++it) {
if (it->second.get()) {
num_live++;
it->second->OnDisconnect();
@ -80,6 +89,7 @@ void Channel::Shutdown() {
void Channel::WillShutdownSoon() {
base::AutoLock locker(lock_);
is_shutting_down_ = true;
channel_manager_ = nullptr;
}
// Note: |endpoint| being a |scoped_refptr| makes this function safe, since it
@ -120,8 +130,7 @@ ChannelEndpointId Channel::AttachAndRunEndpoint(
if (!is_bootstrap) {
if (!SendControlMessage(
MessageInTransit::kSubtypeChannelAttachAndRunEndpoint,
local_id,
MessageInTransit::kSubtypeChannelAttachAndRunEndpoint, local_id,
remote_id)) {
HandleLocalError(base::StringPrintf(
"Failed to send message to run remote message pipe endpoint (local "
@ -185,8 +194,7 @@ void Channel::DetachEndpoint(ChannelEndpoint* endpoint,
}
if (!SendControlMessage(
MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint,
local_id,
MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpoint, local_id,
remote_id)) {
HandleLocalError(base::StringPrintf(
"Failed to send message to remove remote message pipe endpoint (local "
@ -207,7 +215,7 @@ scoped_refptr<MessagePipe> Channel::PassIncomingMessagePipe(
auto it = incoming_message_pipes_.find(local_id);
if (it == incoming_message_pipes_.end())
return scoped_refptr<MessagePipe>();
return nullptr;
scoped_refptr<MessagePipe> rv;
rv.swap(it->second);
@ -459,8 +467,7 @@ bool Channel::OnRemoveMessagePipeEndpoint(ChannelEndpointId local_id,
if (!SendControlMessage(
MessageInTransit::kSubtypeChannelRemoveMessagePipeEndpointAck,
local_id,
remote_id)) {
local_id, remote_id)) {
HandleLocalError(base::StringPrintf(
"Failed to send message to remove remote message pipe endpoint ack "
"(local ID %u, remote ID %u)",

@ -32,6 +32,7 @@ class PlatformSupport;
namespace system {
class ChannelEndpoint;
class ChannelManager;
// This class is mostly thread-safe. It must be created on an I/O thread.
// |Init()| must be called on that same thread before it becomes thread-safe (in
@ -61,6 +62,11 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
// failure, no other methods should be called (including |Shutdown()|).
bool Init(scoped_ptr<RawChannel> raw_channel);
// Sets the channel manager associated with this channel. This should be set
// at most once and only called before |WillShutdownSoon()| (and
// |Shutdown()|).
void SetChannelManager(ChannelManager* channel_manager);
// This must be called on the creation thread before destruction (which can
// happen on any thread).
void Shutdown();
@ -69,6 +75,8 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
// thread, unlike |Shutdown()|). Warnings will be issued if, e.g., messages
// are written after this is called; other warnings may be suppressed. (This
// may be called multiple times, or not at all.)
//
// If set, the channel manager associated with this channel will be reset.
void WillShutdownSoon();
// Attaches the given endpoint to this channel and runs it. |is_bootstrap|
@ -175,6 +183,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
// Set when |WillShutdownSoon()| is called.
bool is_shutting_down_;
// Has a reference to us.
ChannelManager* channel_manager_;
typedef base::hash_map<ChannelEndpointId, scoped_refptr<ChannelEndpoint>>
IdToEndpointMap;
// Map from local IDs to endpoints. If the endpoint is null, this means that

@ -109,8 +109,7 @@ bool ChannelEndpoint::OnReadMessage(
DCHECK(message_view.transport_data_buffer());
message->SetDispatchers(TransportData::DeserializeDispatchers(
message_view.transport_data_buffer(),
message_view.transport_data_buffer_size(),
platform_handles.Pass(),
message_view.transport_data_buffer_size(), platform_handles.Pass(),
channel_));
}

@ -26,13 +26,13 @@ class MessagePipe;
// refcounted, and not copyable. Make |Channel| a friend. Make things work.
// - (Done.) Give |ChannelEndpoint| a lock. The lock order (in order of
// allowable acquisition) is: |MessagePipe|, |ChannelEndpoint|, |Channel|.
// - Stop having |Channel| as a friend.
// - Move logic from |ProxyMessagePipeEndpoint| into |ChannelEndpoint|. Right
// now, we have to go through lots of contortions to manipulate state owned
// by |ProxyMessagePipeEndpoint| (in particular, |Channel::Endpoint| doesn't
// know about the remote ID; the local ID is duplicated in two places).
// Hollow out |ProxyMessagePipeEndpoint|, and have it just own a reference
// to |ChannelEndpoint| (hence the refcounting).
// - (Done) Stop having |Channel| as a friend.
// - (Done) Move logic from |ProxyMessagePipeEndpoint| into |ChannelEndpoint|.
// Right now, we have to go through lots of contortions to manipulate state
// owned by |ProxyMessagePipeEndpoint| (in particular, |Channel::Endpoint|
// doesn't know about the remote ID; the local ID is duplicated in two
// places). Hollow out |ProxyMessagePipeEndpoint|, and have it just own a
// reference to |ChannelEndpoint| (hence the refcounting).
// - In essence, |ChannelEndpoint| becomes the thing that knows about
// channel-specific aspects of an endpoint (notably local and remote IDs,
// and knowledge about handshaking), and mediates between the |Channel| and

@ -4,6 +4,8 @@
#include "mojo/edk/system/channel_info.h"
#include <algorithm>
namespace mojo {
namespace system {
@ -19,5 +21,11 @@ ChannelInfo::ChannelInfo(
ChannelInfo::~ChannelInfo() {
}
void ChannelInfo::Swap(ChannelInfo* other) {
// Note: Swapping avoids refcount churn.
std::swap(channel, other->channel);
std::swap(channel_thread_task_runner, other->channel_thread_task_runner);
}
} // namespace system
} // namespace mojo

@ -19,6 +19,8 @@ struct MOJO_SYSTEM_IMPL_EXPORT ChannelInfo {
scoped_refptr<base::TaskRunner> channel_thread_task_runner);
~ChannelInfo();
void Swap(ChannelInfo* other);
scoped_refptr<Channel> channel;
// The task runner for |channel|'s creation thread (a.k.a. its I/O thread), on
// which it must, e.g., be shut down.

@ -0,0 +1,78 @@
// 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/channel_manager.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
namespace mojo {
namespace system {
namespace {
void ShutdownChannelHelper(const ChannelInfo& channel_info) {
if (base::MessageLoopProxy::current() ==
channel_info.channel_thread_task_runner) {
channel_info.channel->Shutdown();
} else {
channel_info.channel->WillShutdownSoon();
channel_info.channel_thread_task_runner->PostTask(
FROM_HERE, base::Bind(&Channel::Shutdown, channel_info.channel));
}
}
} // namespace
ChannelManager::ChannelManager() {
}
ChannelManager::~ChannelManager() {
// No need to take the lock.
for (const auto& map_elem : channel_infos_)
ShutdownChannelHelper(map_elem.second);
}
ChannelId ChannelManager::AddChannel(
scoped_refptr<Channel> channel,
scoped_refptr<base::TaskRunner> channel_thread_task_runner) {
ChannelId channel_id = GetChannelId(channel.get());
{
base::AutoLock locker(lock_);
DCHECK(channel_infos_.find(channel_id) == channel_infos_.end());
channel_infos_[channel_id] =
ChannelInfo(channel, channel_thread_task_runner);
}
channel->SetChannelManager(this);
return channel_id;
}
void ChannelManager::WillShutdownChannel(ChannelId channel_id) {
GetChannelInfo(channel_id).channel->WillShutdownSoon();
}
void ChannelManager::ShutdownChannel(ChannelId channel_id) {
ChannelInfo channel_info;
{
base::AutoLock locker(lock_);
auto it = channel_infos_.find(channel_id);
DCHECK(it != channel_infos_.end());
channel_info.Swap(&it->second);
channel_infos_.erase(it);
}
ShutdownChannelHelper(channel_info);
}
ChannelInfo ChannelManager::GetChannelInfo(ChannelId channel_id) {
base::AutoLock locker(lock_);
auto it = channel_infos_.find(channel_id);
DCHECK(it != channel_infos_.end());
return it->second;
}
} // namespace system
} // namespace mojo

@ -0,0 +1,83 @@
// 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_CHANNEL_MANAGER_H_
#define MOJO_EDK_SYSTEM_CHANNEL_MANAGER_H_
#include <stdint.h>
#include "base/containers/hash_tables.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
#include "mojo/edk/system/channel.h"
#include "mojo/edk/system/channel_info.h"
namespace mojo {
namespace system {
// IDs for |Channel|s managed by a |ChannelManager|. (IDs should be thought of
// as specific to a given |ChannelManager|.) 0 is never a valid ID.
//
// Note: We currently just use the pointer of the |Channel| casted to a
// |uintptr_t|, but we reserve the right to change this.
typedef uintptr_t ChannelId;
// This class manages and "owns" |Channel|s (which typically connect to other
// processes) for a given process. This class is thread-safe.
class MOJO_SYSTEM_IMPL_EXPORT ChannelManager {
public:
ChannelManager();
~ChannelManager();
// Gets the ID for a given channel.
//
// Note: This is currently a static method and thus may be called under
// |lock_|. If this is ever made non-static (i.e., made specific to a given
// |ChannelManager|), those call sites may have to changed.
static ChannelId GetChannelId(const Channel* channel) {
return reinterpret_cast<ChannelId>(channel);
}
// Adds |channel| to the set of |Channel|s managed by this |ChannelManager|;
// |channel_thread_task_runner| should be the task runner for |channel|'s
// creation (a.k.a. I/O) thread. |channel| should either already be
// initialized. It should not be managed by any |ChannelManager| yet. Returns
// the ID for the added channel.
ChannelId AddChannel(
scoped_refptr<Channel> channel,
scoped_refptr<base::TaskRunner> channel_thread_task_runner);
// Informs the channel manager (and thus channel) that it will be shutdown
// soon (by calling |ShutdownChannel()|). Calling this is optional (and may in
// fact be called multiple times) but it will suppress certain warnings (e.g.,
// for the channel being broken) and enable others (if messages are written to
// the channel).
void WillShutdownChannel(ChannelId channel_id);
// Shuts down the channel specified by the given ID. It is up to the caller to
// guarantee that this is only called once per channel (that was added using
// |AddChannel()|). If called from the chanel's creation thread (i.e.,
// |base::MessageLoopProxy::current()| is the channel thread's |TaskRunner|),
// this will complete synchronously.
void ShutdownChannel(ChannelId channel_id);
private:
// Gets the |ChannelInfo| for the channel specified by the given ID. (This
// should *not* be called under lock.)
ChannelInfo GetChannelInfo(ChannelId channel_id);
// Note: |Channel| methods should not be called under |lock_|.
base::Lock lock_; // Protects the members below.
base::hash_map<ChannelId, ChannelInfo> channel_infos_;
DISALLOW_COPY_AND_ASSIGN(ChannelManager);
};
} // namespace system
} // namespace mojo
#endif // MOJO_EDK_SYSTEM_CHANNEL_MANAGER_H_

@ -104,9 +104,8 @@ TEST_F(ChannelTest, InitShutdown) {
EXPECT_EQ(TRISTATE_TRUE, init_result());
io_thread()->PostTaskAndWait(
FROM_HERE,
base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
base::Unretained(this)));
FROM_HERE, base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
base::Unretained(this)));
// Okay to destroy |Channel| on not-the-I/O-thread.
EXPECT_TRUE(channel()->HasOneRef());
@ -203,9 +202,8 @@ TEST_F(ChannelTest, CloseBeforeRun) {
channel()->AttachAndRunEndpoint(channel_endpoint, true);
io_thread()->PostTaskAndWait(
FROM_HERE,
base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
base::Unretained(this)));
FROM_HERE, base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
base::Unretained(this)));
EXPECT_TRUE(channel()->HasOneRef());
}
@ -273,9 +271,8 @@ TEST_F(ChannelTest, WaitAfterAttachRunAndShutdown) {
channel()->AttachAndRunEndpoint(channel_endpoint, true);
io_thread()->PostTaskAndWait(
FROM_HERE,
base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
base::Unretained(this)));
FROM_HERE, base::Bind(&ChannelTest::ShutdownChannelOnIOThread,
base::Unretained(this)));
Waiter waiter;
waiter.Init();

@ -0,0 +1,26 @@
// 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 system {
namespace internal {
// These default values should be synced with the documentation in
// mojo/edk/embedder/configuration.h.
embedder::Configuration g_configuration = {
1000000, // max_handle_table_size
1000000, // max_mapping_table_sze
1000000, // max_wait_many_num_handles
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 system
} // namespace mojo

@ -0,0 +1,31 @@
// 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 system {
namespace internal {
MOJO_SYSTEM_IMPL_EXPORT extern embedder::Configuration g_configuration;
} // namespace internal
MOJO_SYSTEM_IMPL_EXPORT inline const embedder::Configuration&
GetConfiguration() {
return internal::g_configuration;
}
MOJO_SYSTEM_IMPL_EXPORT inline embedder::Configuration*
GetMutableConfiguration() {
return &internal::g_configuration;
}
} // namespace system
} // namespace mojo
#endif // MOJO_EDK_SYSTEM_CONFIGURATION_H_

@ -1,48 +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_CONSTANTS_H_
#define MOJO_EDK_SYSTEM_CONSTANTS_H_
#include <stddef.h>
namespace mojo {
namespace system {
// Maximum number of open (Mojo) handles.
// TODO(vtl): This doesn't count "live" handles, some of which may live in
// messages.
const size_t kMaxHandleTableSize = 1000000;
// Maximum number of active memory mappings.
const size_t kMaxMappingTableSize = 1000000;
const size_t kMaxWaitManyNumHandles = kMaxHandleTableSize;
const size_t kMaxMessageNumBytes = 4 * 1024 * 1024;
const size_t kMaxMessageNumHandles = 10000;
// Maximum capacity of a data pipe, in bytes. 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).
const size_t kMaxDataPipeCapacityBytes = 256 * 1024 * 1024; // 256 MB.
const size_t kDefaultDataPipeCapacityBytes = 1024 * 1024; // 1 MB.
// Alignment for the "start" of the data buffer used by data pipes. (The
// alignment of elements will depend on this and the element size.)
const size_t kDataPipeBufferAlignmentBytes = 16;
// 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.)
const size_t kMaxSharedMemoryNumBytes = 1024 * 1024 * 1024; // 1 GB.
} // namespace system
} // namespace mojo
#endif // MOJO_EDK_SYSTEM_CONSTANTS_H_

@ -10,7 +10,7 @@
#include "base/time/time.h"
#include "mojo/edk/embedder/platform_shared_buffer.h"
#include "mojo/edk/embedder/platform_support.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/data_pipe.h"
#include "mojo/edk/system/data_pipe_consumer_dispatcher.h"
#include "mojo/edk/system/data_pipe_producer_dispatcher.h"
@ -126,11 +126,7 @@ MojoResult Core::Wait(MojoHandle handle,
UserPointer<MojoHandleSignalsState> signals_state) {
uint32_t unused = static_cast<uint32_t>(-1);
HandleSignalsState hss;
MojoResult rv = WaitManyInternal(&handle,
&signals,
1,
deadline,
&unused,
MojoResult rv = WaitManyInternal(&handle, &signals, 1, deadline, &unused,
signals_state.IsNull() ? nullptr : &hss);
if (rv != MOJO_RESULT_INVALID_ARGUMENT && !signals_state.IsNull())
signals_state.Put(hss);
@ -145,7 +141,7 @@ MojoResult Core::WaitMany(UserPointer<const MojoHandle> handles,
UserPointer<MojoHandleSignalsState> signals_states) {
if (num_handles < 1)
return MOJO_RESULT_INVALID_ARGUMENT;
if (num_handles > kMaxWaitManyNumHandles)
if (num_handles > GetConfiguration().max_wait_many_num_handles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
@ -155,23 +151,17 @@ MojoResult Core::WaitMany(UserPointer<const MojoHandle> handles,
MojoResult rv;
if (signals_states.IsNull()) {
rv = WaitManyInternal(handles_reader.GetPointer(),
signals_reader.GetPointer(),
num_handles,
deadline,
&index,
nullptr);
signals_reader.GetPointer(), num_handles, deadline,
&index, nullptr);
} else {
UserPointer<MojoHandleSignalsState>::Writer signals_states_writer(
signals_states, num_handles);
// Note: The |reinterpret_cast| is safe, since |HandleSignalsState| is a
// subclass of |MojoHandleSignalsState| that doesn't add any data members.
rv = WaitManyInternal(handles_reader.GetPointer(),
signals_reader.GetPointer(),
num_handles,
deadline,
&index,
reinterpret_cast<HandleSignalsState*>(
signals_states_writer.GetPointer()));
signals_reader.GetPointer(), num_handles, deadline,
&index, reinterpret_cast<HandleSignalsState*>(
signals_states_writer.GetPointer()));
if (rv != MOJO_RESULT_INVALID_ARGUMENT)
signals_states_writer.Commit();
}
@ -246,7 +236,7 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
// validity, even for dispatchers that don't support |WriteMessage()| and will
// simply return failure unconditionally. It also breaks the usual
// left-to-right verification order of arguments.)
if (num_handles > kMaxMessageNumHandles)
if (num_handles > GetConfiguration().max_message_num_handles)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
UserPointer<const MojoHandle>::Reader handles_reader(handles, num_handles);
@ -263,11 +253,9 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle,
// handles from the handle table.
{
base::AutoLock locker(handle_table_lock_);
MojoResult result =
handle_table_.MarkBusyAndStartTransport(message_pipe_handle,
handles_reader.GetPointer(),
num_handles,
&transports);
MojoResult result = handle_table_.MarkBusyAndStartTransport(
message_pipe_handle, handles_reader.GetPointer(), num_handles,
&transports);
if (result != MOJO_RESULT_OK)
return result;
}
@ -308,12 +296,12 @@ MojoResult Core::ReadMessage(MojoHandle message_pipe_handle,
MojoResult rv;
if (num_handles_value == 0) {
// Easy case: won't receive any handles.
rv = dispatcher->ReadMessage(
bytes, num_bytes, nullptr, &num_handles_value, flags);
rv = dispatcher->ReadMessage(bytes, num_bytes, nullptr, &num_handles_value,
flags);
} else {
DispatcherVector dispatchers;
rv = dispatcher->ReadMessage(
bytes, num_bytes, &dispatchers, &num_handles_value, flags);
rv = dispatcher->ReadMessage(bytes, num_bytes, &dispatchers,
&num_handles_value, flags);
if (!dispatchers.empty()) {
DCHECK_EQ(rv, MOJO_RESULT_OK);
DCHECK(!num_handles.IsNull());
@ -466,8 +454,8 @@ MojoResult Core::CreateSharedBuffer(
return result;
scoped_refptr<SharedBufferDispatcher> dispatcher;
result = SharedBufferDispatcher::Create(
platform_support(), validated_options, num_bytes, &dispatcher);
result = SharedBufferDispatcher::Create(platform_support(), validated_options,
num_bytes, &dispatcher);
if (result != MOJO_RESULT_OK) {
DCHECK(!dispatcher.get());
return result;

@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "mojo/edk/embedder/simple_platform_support.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/core.h"
#include "mojo/edk/system/dispatcher.h"
#include "mojo/edk/system/memory.h"
@ -50,7 +50,7 @@ class MockDispatcher : public Dispatcher {
info_->IncrementWriteMessageCallCount();
lock().AssertAcquired();
if (num_bytes > kMaxMessageNumBytes)
if (num_bytes > GetConfiguration().max_message_num_bytes)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
if (transports)

File diff suppressed because it is too large Load Diff

@ -10,7 +10,7 @@
#include <limits>
#include "base/logging.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/memory.h"
#include "mojo/edk/system/options_validation.h"
#include "mojo/edk/system/waiter_list.h"
@ -19,11 +19,15 @@ namespace mojo {
namespace system {
// static
const MojoCreateDataPipeOptions DataPipe::kDefaultCreateOptions = {
static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)),
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
1u,
static_cast<uint32_t>(kDefaultDataPipeCapacityBytes)};
MojoCreateDataPipeOptions DataPipe::GetDefaultCreateOptions() {
MojoCreateDataPipeOptions result = {
static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)),
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
1u,
static_cast<uint32_t>(
GetConfiguration().default_data_pipe_capacity_bytes)};
return result;
}
// static
MojoResult DataPipe::ValidateCreateOptions(
@ -32,7 +36,7 @@ MojoResult DataPipe::ValidateCreateOptions(
const MojoCreateDataPipeOptionsFlags kKnownFlags =
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD;
*out_options = kDefaultCreateOptions;
*out_options = GetDefaultCreateOptions();
if (in_options.IsNull())
return MOJO_RESULT_OK;
@ -48,28 +52,31 @@ MojoResult DataPipe::ValidateCreateOptions(
// Checks for fields beyond |flags|:
if (!OPTIONS_STRUCT_HAS_MEMBER(
MojoCreateDataPipeOptions, element_num_bytes, reader))
if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, element_num_bytes,
reader))
return MOJO_RESULT_OK;
if (reader.options().element_num_bytes == 0)
return MOJO_RESULT_INVALID_ARGUMENT;
out_options->element_num_bytes = reader.options().element_num_bytes;
if (!OPTIONS_STRUCT_HAS_MEMBER(
MojoCreateDataPipeOptions, capacity_num_bytes, reader) ||
if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, capacity_num_bytes,
reader) ||
reader.options().capacity_num_bytes == 0) {
// Round the default capacity down to a multiple of the element size (but at
// least one element).
size_t default_data_pipe_capacity_bytes =
GetConfiguration().default_data_pipe_capacity_bytes;
out_options->capacity_num_bytes =
std::max(static_cast<uint32_t>(kDefaultDataPipeCapacityBytes -
(kDefaultDataPipeCapacityBytes %
std::max(static_cast<uint32_t>(default_data_pipe_capacity_bytes -
(default_data_pipe_capacity_bytes %
out_options->element_num_bytes)),
out_options->element_num_bytes);
return MOJO_RESULT_OK;
}
if (reader.options().capacity_num_bytes % out_options->element_num_bytes != 0)
return MOJO_RESULT_INVALID_ARGUMENT;
if (reader.options().capacity_num_bytes > kMaxDataPipeCapacityBytes)
if (reader.options().capacity_num_bytes >
GetConfiguration().max_data_pipe_capacity_bytes)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
out_options->capacity_num_bytes = reader.options().capacity_num_bytes;
@ -148,8 +155,8 @@ MojoResult DataPipe::ProducerBeginWriteData(
return MOJO_RESULT_INVALID_ARGUMENT;
}
MojoResult rv = ProducerBeginWriteDataImplNoLock(
buffer, buffer_num_bytes, min_num_bytes_to_write);
MojoResult rv = ProducerBeginWriteDataImplNoLock(buffer, buffer_num_bytes,
min_num_bytes_to_write);
if (rv != MOJO_RESULT_OK)
return rv;
// Note: No need to awake producer waiters, even though we're going from
@ -345,8 +352,8 @@ MojoResult DataPipe::ConsumerBeginReadData(
return MOJO_RESULT_INVALID_ARGUMENT;
}
MojoResult rv = ConsumerBeginReadDataImplNoLock(
buffer, buffer_num_bytes, min_num_bytes_to_read);
MojoResult rv = ConsumerBeginReadDataImplNoLock(buffer, buffer_num_bytes,
min_num_bytes_to_read);
if (rv != MOJO_RESULT_OK)
return rv;
DCHECK(consumer_in_two_phase_read_no_lock());

@ -35,7 +35,7 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipe
// The default options for |MojoCreateDataPipe()|. (Real uses should obtain
// this via |ValidateCreateOptions()| with a null |in_options|; this is
// exposed directly for testing convenience.)
static const MojoCreateDataPipeOptions kDefaultCreateOptions;
static MojoCreateDataPipeOptions GetDefaultCreateOptions();
// Validates and/or sets default options for |MojoCreateDataPipeOptions|. If
// non-null, |in_options| must point to a struct of at least
@ -117,12 +117,11 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipe
virtual void ConsumerCloseImplNoLock() = 0;
// |*num_bytes| will be a nonzero multiple of |element_num_bytes_|.
virtual MojoResult ConsumerReadDataImplNoLock(
UserPointer<void> elements,
UserPointer<uint32_t> num_bytes,
uint32_t max_num_bytes_to_read,
uint32_t min_num_bytes_to_read,
bool peek) = 0;
virtual MojoResult ConsumerReadDataImplNoLock(UserPointer<void> elements,
UserPointer<uint32_t> num_bytes,
uint32_t max_num_bytes_to_read,
uint32_t min_num_bytes_to_read,
bool peek) = 0;
virtual MojoResult ConsumerDiscardDataImplNoLock(
UserPointer<uint32_t> num_bytes,
uint32_t max_num_bytes_to_discard,

@ -77,9 +77,7 @@ MojoResult DataPipeConsumerDispatcher::ReadDataImplNoLock(
}
return data_pipe_->ConsumerReadData(
elements,
num_bytes,
!!(flags & MOJO_READ_DATA_FLAG_ALL_OR_NONE),
elements, num_bytes, !!(flags & MOJO_READ_DATA_FLAG_ALL_OR_NONE),
!!(flags & MOJO_READ_DATA_FLAG_PEEK));
}
@ -91,8 +89,7 @@ MojoResult DataPipeConsumerDispatcher::BeginReadDataImplNoLock(
// 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))
(flags & MOJO_READ_DATA_FLAG_QUERY) || (flags & MOJO_READ_DATA_FLAG_PEEK))
return MOJO_RESULT_INVALID_ARGUMENT;
return data_pipe_->ConsumerBeginReadData(

@ -9,7 +9,7 @@
#include <limits>
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
@ -28,9 +28,8 @@ void RevalidateCreateOptions(
// Nothing to check for flags.
EXPECT_GT(validated_options.element_num_bytes, 0u);
EXPECT_GT(validated_options.capacity_num_bytes, 0u);
EXPECT_EQ(0u,
validated_options.capacity_num_bytes %
validated_options.element_num_bytes);
EXPECT_EQ(0u, validated_options.capacity_num_bytes %
validated_options.element_num_bytes);
MojoCreateDataPipeOptions revalidated_options = {};
EXPECT_EQ(MOJO_RESULT_OK,
@ -48,10 +47,10 @@ void RevalidateCreateOptions(
// checks done by |RevalidateCreateOptions()|.)
void CheckDefaultCapacity(const MojoCreateDataPipeOptions& validated_options) {
EXPECT_LE(validated_options.capacity_num_bytes,
kDefaultDataPipeCapacityBytes);
GetConfiguration().default_data_pipe_capacity_bytes);
EXPECT_GT(validated_options.capacity_num_bytes +
validated_options.element_num_bytes,
kDefaultDataPipeCapacityBytes);
GetConfiguration().default_data_pipe_capacity_bytes);
}
// Tests valid inputs to |ValidateCreateOptions()|.
@ -59,9 +58,8 @@ TEST(DataPipeTest, ValidateCreateOptionsValid) {
// Default options.
{
MojoCreateDataPipeOptions validated_options = {};
EXPECT_EQ(
MOJO_RESULT_OK,
DataPipe::ValidateCreateOptions(NullUserPointer(), &validated_options));
EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions(
NullUserPointer(), &validated_options));
RevalidateCreateOptions(validated_options);
CheckDefaultCapacity(validated_options);
}

@ -5,7 +5,7 @@
#include "mojo/edk/system/dispatcher.h"
#include "base/logging.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.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"
@ -58,8 +58,8 @@ bool Dispatcher::TransportDataAccess::EndSerializeAndClose(
size_t* actual_size,
embedder::PlatformHandleVector* platform_handles) {
DCHECK(dispatcher);
return dispatcher->EndSerializeAndClose(
channel, destination, actual_size, platform_handles);
return dispatcher->EndSerializeAndClose(channel, destination, actual_size,
platform_handles);
}
// static
@ -72,7 +72,7 @@ scoped_refptr<Dispatcher> Dispatcher::TransportDataAccess::Deserialize(
switch (static_cast<int32_t>(type)) {
case kTypeUnknown:
DVLOG(2) << "Deserializing invalid handle";
return scoped_refptr<Dispatcher>();
return nullptr;
case kTypeMessagePipe:
return scoped_refptr<Dispatcher>(
MessagePipeDispatcher::Deserialize(channel, source, size));
@ -81,7 +81,7 @@ scoped_refptr<Dispatcher> Dispatcher::TransportDataAccess::Deserialize(
// TODO(vtl): Implement.
LOG(WARNING) << "Deserialization of dispatcher type " << type
<< " not supported";
return scoped_refptr<Dispatcher>();
return nullptr;
case kTypeSharedBuffer:
return scoped_refptr<Dispatcher>(SharedBufferDispatcher::Deserialize(
channel, source, size, platform_handles));
@ -90,7 +90,7 @@ scoped_refptr<Dispatcher> Dispatcher::TransportDataAccess::Deserialize(
channel, source, size, platform_handles));
}
LOG(WARNING) << "Unknown dispatcher type " << type;
return scoped_refptr<Dispatcher>();
return nullptr;
}
MojoResult Dispatcher::Close() {
@ -107,8 +107,9 @@ MojoResult Dispatcher::WriteMessage(
uint32_t num_bytes,
std::vector<DispatcherTransport>* transports,
MojoWriteMessageFlags flags) {
DCHECK(!transports || (transports->size() > 0 &&
transports->size() < kMaxMessageNumHandles));
DCHECK(!transports ||
(transports->size() > 0 &&
transports->size() < GetConfiguration().max_message_num_handles));
base::AutoLock locker(lock_);
if (is_closed_)
@ -129,8 +130,8 @@ MojoResult Dispatcher::ReadMessage(UserPointer<void> bytes,
if (is_closed_)
return MOJO_RESULT_INVALID_ARGUMENT;
return ReadMessageImplNoLock(
bytes, num_bytes, dispatchers, num_dispatchers, flags);
return ReadMessageImplNoLock(bytes, num_bytes, dispatchers, num_dispatchers,
flags);
}
MojoResult Dispatcher::WriteData(UserPointer<const void> elements,
@ -473,8 +474,8 @@ bool Dispatcher::EndSerializeAndClose(
base::AutoLock locker(lock_);
#endif
return EndSerializeAndCloseImplNoLock(
channel, destination, actual_size, platform_handles);
return EndSerializeAndCloseImplNoLock(channel, destination, actual_size,
platform_handles);
}
// DispatcherTransport ---------------------------------------------------------

@ -14,7 +14,6 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "mojo/edk/embedder/platform_handle.h"
#include "mojo/edk/embedder/platform_handle_vector.h"
#include "mojo/edk/system/handle_signals_state.h"
#include "mojo/edk/system/memory.h"
@ -48,7 +47,7 @@ namespace test {
// Test helper. We need to declare it here so we can friend it.
MOJO_SYSTEM_IMPL_EXPORT DispatcherTransport
DispatcherTryStartTransport(Dispatcher* dispatcher);
DispatcherTryStartTransport(Dispatcher* dispatcher);
} // namespace test

@ -44,31 +44,24 @@ TEST(DispatcherTest, Basic) {
EXPECT_EQ(Dispatcher::kTypeUnknown, d->GetType());
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->WriteMessage(
NullUserPointer(), 0, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE));
d->WriteMessage(NullUserPointer(), 0, nullptr,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->ReadMessage(NullUserPointer(),
NullUserPointer(),
nullptr,
nullptr,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->WriteData(
NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->BeginWriteData(
NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE));
d->ReadMessage(NullUserPointer(), NullUserPointer(), nullptr,
nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->WriteData(NullUserPointer(), NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->BeginWriteData(NullUserPointer(), NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndWriteData(0));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->ReadData(
NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->BeginReadData(
NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->ReadData(NullUserPointer(), NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->BeginReadData(NullUserPointer(), NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndReadData(0));
Waiter w;
w.Init();
@ -90,31 +83,24 @@ TEST(DispatcherTest, Basic) {
EXPECT_EQ(MOJO_RESULT_OK, d->Close());
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->WriteMessage(
NullUserPointer(), 0, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE));
d->WriteMessage(NullUserPointer(), 0, nullptr,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->ReadMessage(NullUserPointer(),
NullUserPointer(),
nullptr,
nullptr,
MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->WriteData(
NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->BeginWriteData(
NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE));
d->ReadMessage(NullUserPointer(), NullUserPointer(), nullptr,
nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->WriteData(NullUserPointer(), NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->BeginWriteData(NullUserPointer(), NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndWriteData(0));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->ReadData(
NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
d->BeginReadData(
NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->ReadData(NullUserPointer(), NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
d->BeginReadData(NullUserPointer(), NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, d->EndReadData(0));
hss = HandleSignalsState();
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
@ -172,45 +158,40 @@ class ThreadSafetyStressThread : public base::SimpleThread {
break;
}
case WRITE_MESSAGE:
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->WriteMessage(
NullUserPointer(), 0, nullptr, MOJO_WRITE_MESSAGE_FLAG_NONE));
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->WriteMessage(NullUserPointer(), 0, nullptr,
MOJO_WRITE_MESSAGE_FLAG_NONE));
break;
case READ_MESSAGE:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->ReadMessage(NullUserPointer(),
NullUserPointer(),
nullptr,
nullptr,
dispatcher_->ReadMessage(NullUserPointer(), NullUserPointer(),
nullptr, nullptr,
MOJO_WRITE_MESSAGE_FLAG_NONE));
break;
case WRITE_DATA:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->WriteData(NullUserPointer(),
NullUserPointer(),
dispatcher_->WriteData(NullUserPointer(), NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
break;
case BEGIN_WRITE_DATA:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->BeginWriteData(NullUserPointer(),
NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->BeginWriteData(NullUserPointer(), NullUserPointer(),
MOJO_WRITE_DATA_FLAG_NONE));
break;
case END_WRITE_DATA:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher_->EndWriteData(0));
break;
case READ_DATA:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->ReadData(NullUserPointer(),
NullUserPointer(),
dispatcher_->ReadData(NullUserPointer(), NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
break;
case BEGIN_READ_DATA:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->BeginReadData(NullUserPointer(),
NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
EXPECT_EQ(
MOJO_RESULT_INVALID_ARGUMENT,
dispatcher_->BeginReadData(NullUserPointer(), NullUserPointer(),
MOJO_READ_DATA_FLAG_NONE));
break;
case END_READ_DATA:
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher_->EndReadData(0));

@ -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_SYSTEM_ENTRYPOINTS_H_
#define MOJO_EDK_SYSTEM_ENTRYPOINTS_H_
namespace mojo {
namespace system {
class Core;
namespace entrypoints {
// Sets the instance of Core to be used by system functions.
void SetCore(Core* core);
// Gets the instance of Core to be used by system functions.
Core* GetCore();
} // namespace entrypoints
} // namepace system
} // namespace mojo
#endif // MOJO_EDK_SYSTEM_ENTRYPOINTS_H_

@ -4,9 +4,10 @@
#include "mojo/edk/system/handle_table.h"
#include <limits>
#include "base/logging.h"
#include "base/macros.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/dispatcher.h"
namespace mojo {
@ -59,7 +60,7 @@ MojoResult HandleTable::GetAndRemoveDispatcher(
MojoHandle HandleTable::AddDispatcher(
const scoped_refptr<Dispatcher>& dispatcher) {
if (handle_to_entry_map_.size() >= kMaxHandleTableSize)
if (handle_to_entry_map_.size() >= GetConfiguration().max_handle_table_size)
return MOJO_HANDLE_INVALID;
return AddDispatcherNoSizeCheck(dispatcher);
}
@ -67,7 +68,8 @@ MojoHandle HandleTable::AddDispatcher(
std::pair<MojoHandle, MojoHandle> HandleTable::AddDispatcherPair(
const scoped_refptr<Dispatcher>& dispatcher0,
const scoped_refptr<Dispatcher>& dispatcher1) {
if (handle_to_entry_map_.size() + 1 >= kMaxHandleTableSize)
if (handle_to_entry_map_.size() + 1 >=
GetConfiguration().max_handle_table_size)
return std::make_pair(MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID);
return std::make_pair(AddDispatcherNoSizeCheck(dispatcher0),
AddDispatcherNoSizeCheck(dispatcher1));
@ -75,17 +77,17 @@ std::pair<MojoHandle, MojoHandle> HandleTable::AddDispatcherPair(
bool HandleTable::AddDispatcherVector(const DispatcherVector& dispatchers,
MojoHandle* handles) {
DCHECK_LE(dispatchers.size(), kMaxMessageNumHandles);
DCHECK(handles);
// TODO(vtl): |std::numeric_limits<size_t>::max()| isn't a compile-time
// expression in C++03.
static_assert(
static_cast<uint64_t>(kMaxHandleTableSize) + kMaxMessageNumHandles <
(sizeof(size_t) == 8 ? kuint64max
: static_cast<uint64_t>(kuint32max)),
"Addition may overflow");
size_t max_message_num_handles = GetConfiguration().max_message_num_handles;
size_t max_handle_table_size = GetConfiguration().max_handle_table_size;
if (handle_to_entry_map_.size() + dispatchers.size() > kMaxHandleTableSize)
DCHECK_LE(dispatchers.size(), max_message_num_handles);
DCHECK(handles);
DCHECK_LT(
static_cast<uint64_t>(max_handle_table_size) + max_message_num_handles,
std::numeric_limits<size_t>::max())
<< "Addition may overflow";
if (handle_to_entry_map_.size() + dispatchers.size() > max_handle_table_size)
return false;
for (size_t i = 0; i < dispatchers.size(); i++) {
@ -106,7 +108,7 @@ MojoResult HandleTable::MarkBusyAndStartTransport(
std::vector<DispatcherTransport>* transports) {
DCHECK_NE(disallowed_handle, MOJO_HANDLE_INVALID);
DCHECK(handles);
DCHECK_LE(num_handles, kMaxMessageNumHandles);
DCHECK_LE(num_handles, GetConfiguration().max_message_num_handles);
DCHECK(transports);
DCHECK_EQ(transports->size(), num_handles);
@ -187,7 +189,8 @@ MojoResult HandleTable::MarkBusyAndStartTransport(
MojoHandle HandleTable::AddDispatcherNoSizeCheck(
const scoped_refptr<Dispatcher>& dispatcher) {
DCHECK(dispatcher.get());
DCHECK_LT(handle_to_entry_map_.size(), kMaxHandleTableSize);
DCHECK_LT(handle_to_entry_map_.size(),
GetConfiguration().max_handle_table_size);
DCHECK_NE(next_handle_, MOJO_HANDLE_INVALID);
// TODO(vtl): Maybe we want to do something different/smarter. (Or maybe try
@ -212,7 +215,7 @@ MojoHandle HandleTable::AddDispatcherNoSizeCheck(
void HandleTable::RemoveBusyHandles(const MojoHandle* handles,
uint32_t num_handles) {
DCHECK(handles);
DCHECK_LE(num_handles, kMaxMessageNumHandles);
DCHECK_LE(num_handles, GetConfiguration().max_message_num_handles);
for (uint32_t i = 0; i < num_handles; i++) {
HandleToEntryMap::iterator it = handle_to_entry_map_.find(handles[i]);
@ -226,7 +229,7 @@ void HandleTable::RemoveBusyHandles(const MojoHandle* handles,
void HandleTable::RestoreBusyHandles(const MojoHandle* handles,
uint32_t num_handles) {
DCHECK(handles);
DCHECK_LE(num_handles, kMaxMessageNumHandles);
DCHECK_LE(num_handles, GetConfiguration().max_message_num_handles);
for (uint32_t i = 0; i < num_handles; i++) {
HandleToEntryMap::iterator it = handle_to_entry_map_.find(handles[i]);

@ -15,7 +15,7 @@
#include <algorithm>
#include "base/logging.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
namespace mojo {
namespace system {
@ -301,7 +301,8 @@ void LocalDataPipe::EnsureBufferNoLock() {
if (buffer_)
return;
buffer_.reset(static_cast<char*>(
base::AlignedAlloc(capacity_num_bytes(), kDataPipeBufferAlignmentBytes)));
base::AlignedAlloc(capacity_num_bytes(),
GetConfiguration().data_pipe_buffer_alignment_bytes)));
}
void LocalDataPipe::DestroyBufferNoLock() {

@ -44,12 +44,11 @@ class MOJO_SYSTEM_IMPL_EXPORT LocalDataPipe : public DataPipe {
uint32_t num_bytes_written) override;
HandleSignalsState ProducerGetHandleSignalsStateImplNoLock() const override;
void ConsumerCloseImplNoLock() override;
MojoResult ConsumerReadDataImplNoLock(
UserPointer<void> elements,
UserPointer<uint32_t> num_bytes,
uint32_t max_num_bytes_to_read,
uint32_t min_num_bytes_to_read,
bool peek) override;
MojoResult ConsumerReadDataImplNoLock(UserPointer<void> elements,
UserPointer<uint32_t> num_bytes,
uint32_t max_num_bytes_to_read,
uint32_t min_num_bytes_to_read,
bool peek) override;
MojoResult ConsumerDiscardDataImplNoLock(
UserPointer<uint32_t> num_bytes,
uint32_t max_num_bytes_to_discard,

File diff suppressed because it is too large Load Diff

@ -6,7 +6,7 @@
#include "base/logging.h"
#include "mojo/edk/embedder/platform_shared_buffer.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
namespace mojo {
namespace system {
@ -23,7 +23,8 @@ MojoResult MappingTable::AddMapping(
scoped_ptr<embedder::PlatformSharedBufferMapping> mapping) {
DCHECK(mapping);
if (address_to_mapping_map_.size() >= kMaxMappingTableSize)
if (address_to_mapping_map_.size() >=
GetConfiguration().max_mapping_table_sze)
return MOJO_RESULT_RESOURCE_EXHAUSTED;
uintptr_t address = reinterpret_cast<uintptr_t>(mapping->GetBase());

@ -40,20 +40,20 @@ template void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointer<8, 8>(const void*);
template <size_t size, size_t alignment>
void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithCount(const void* pointer, size_t count) {
CheckUserPointerWithCount(const void* pointer, size_t count) {
CHECK_LE(count, std::numeric_limits<size_t>::max() / size);
CHECK(count == 0 || (pointer && IsAligned<alignment>(pointer)));
}
// Explicitly instantiate the sizes we need. Add instantiations as needed.
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithCount<1, 1>(const void*, size_t);
CheckUserPointerWithCount<1, 1>(const void*, size_t);
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithCount<4, 4>(const void*, size_t);
CheckUserPointerWithCount<4, 4>(const void*, size_t);
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithCount<8, 4>(const void*, size_t);
CheckUserPointerWithCount<8, 4>(const void*, size_t);
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithCount<8, 8>(const void*, size_t);
CheckUserPointerWithCount<8, 8>(const void*, size_t);
template <size_t alignment>
void CheckUserPointerWithSize(const void* pointer, size_t size) {
@ -65,9 +65,9 @@ void CheckUserPointerWithSize(const void* pointer, size_t size) {
// Explicitly instantiate the sizes we need. Add instantiations as needed.
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithSize<1>(const void*, size_t);
CheckUserPointerWithSize<1>(const void*, size_t);
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithSize<4>(const void*, size_t);
CheckUserPointerWithSize<4>(const void*, size_t);
// Whereas the other |Check...()| functions are usually used with integral typs
// or arrays of integral types, this one is used with Options structs for which
// alignment has been explicitly been specified (using |MOJO_ALIGNAS()|), which
@ -75,13 +75,13 @@ template void MOJO_SYSTEM_IMPL_EXPORT
#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
template <>
void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithSize<8>(const void* pointer, size_t size) {
CheckUserPointerWithSize<8>(const void* pointer, size_t size) {
CHECK(size == 0 ||
(!!pointer && reinterpret_cast<uintptr_t>(pointer) % 8 == 0));
}
#else
template void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithSize<8>(const void*, size_t);
CheckUserPointerWithSize<8>(const void*, size_t);
#endif
} // namespace internal

@ -53,13 +53,13 @@ void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointer(const void* pointer);
// a buffer of |count| elements of the given size and alignment (both in bytes).
template <size_t size, size_t alignment>
void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithCount(const void* pointer, size_t count);
CheckUserPointerWithCount(const void* pointer, size_t count);
// Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to
// a buffer of the given size and alignment (both in bytes).
template <size_t alignment>
void MOJO_SYSTEM_IMPL_EXPORT
CheckUserPointerWithSize(const void* pointer, size_t size);
CheckUserPointerWithSize(const void* pointer, size_t size);
} // namespace internal

@ -8,7 +8,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "mojo/edk/system/constants.h"
#include "mojo/edk/system/configuration.h"
#include "mojo/edk/system/transport_data.h"
namespace mojo {
@ -38,23 +38,13 @@ struct MessageInTransit::PrivateStructForCompileAsserts {
// The size of |Header| must be a multiple of the alignment.
static_assert(sizeof(Header) % kMessageAlignment == 0,
"sizeof(MessageInTransit::Header) invalid");
// Avoid dangerous situations, but making sure that the size of the "header" +
// the size of the data fits into a 31-bit number.
static_assert(static_cast<uint64_t>(sizeof(Header)) + kMaxMessageNumBytes <=
0x7fffffffULL,
"kMaxMessageNumBytes too big");
// We assume (to avoid extra rounding code) that the maximum message (data)
// size is a multiple of the alignment.
static_assert(kMaxMessageNumBytes % kMessageAlignment == 0,
"kMessageAlignment not a multiple of alignment");
};
MessageInTransit::View::View(size_t message_size, const void* buffer)
: buffer_(buffer) {
size_t next_message_size = 0;
DCHECK(MessageInTransit::GetNextMessageSize(
buffer_, message_size, &next_message_size));
DCHECK(MessageInTransit::GetNextMessageSize(buffer_, message_size,
&next_message_size));
DCHECK_EQ(message_size, next_message_size);
// This should be equivalent.
DCHECK_EQ(message_size, total_size());
@ -62,18 +52,29 @@ MessageInTransit::View::View(size_t message_size, const void* buffer)
bool MessageInTransit::View::IsValid(size_t serialized_platform_handle_size,
const char** error_message) const {
size_t max_message_num_bytes = GetConfiguration().max_message_num_bytes;
// Avoid dangerous situations, but making sure that the size of the "header" +
// the size of the data fits into a 31-bit number.
DCHECK_LE(static_cast<uint64_t>(sizeof(Header)) + max_message_num_bytes,
0x7fffffffULL)
<< "GetConfiguration().max_message_num_bytes too big";
// We assume (to avoid extra rounding code) that the maximum message (data)
// size is a multiple of the alignment.
DCHECK_EQ(max_message_num_bytes % kMessageAlignment, 0U)
<< "GetConfiguration().max_message_num_bytes not a multiple of alignment";
// Note: This also implies a check on the |main_buffer_size()|, which is just
// |RoundUpMessageAlignment(sizeof(Header) + num_bytes())|.
if (num_bytes() > kMaxMessageNumBytes) {
if (num_bytes() > max_message_num_bytes) {
*error_message = "Message data payload too large";
return false;
}
if (transport_data_buffer_size() > 0) {
const char* e =
TransportData::ValidateBuffer(serialized_platform_handle_size,
transport_data_buffer(),
transport_data_buffer_size());
const char* e = TransportData::ValidateBuffer(
serialized_platform_handle_size, transport_data_buffer(),
transport_data_buffer_size());
if (e) {
*error_message = e;
return false;
@ -93,8 +94,7 @@ MessageInTransit::MessageInTransit(Type type,
ConstructorHelper(type, subtype, num_bytes);
if (bytes) {
memcpy(MessageInTransit::bytes(), bytes, num_bytes);
memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes,
0,
memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0,
main_buffer_size_ - sizeof(Header) - num_bytes);
} else {
memset(MessageInTransit::bytes(), 0, main_buffer_size_ - sizeof(Header));
@ -195,7 +195,7 @@ void MessageInTransit::SerializeAndCloseDispatchers(Channel* channel) {
void MessageInTransit::ConstructorHelper(Type type,
Subtype subtype,
uint32_t num_bytes) {
DCHECK_LE(num_bytes, kMaxMessageNumBytes);
DCHECK_LE(num_bytes, GetConfiguration().max_message_num_bytes);
// |total_size| is updated below, from the other values.
header()->type = type;

Some files were not shown because too many files have changed in this diff Show More