diff options
60 files changed, 1121 insertions, 529 deletions
diff --git a/media/mojo/services/media_renderer_apptest.cc b/media/mojo/services/media_renderer_apptest.cc index bdf5048..8813b38 100644 --- a/media/mojo/services/media_renderer_apptest.cc +++ b/media/mojo/services/media_renderer_apptest.cc @@ -99,8 +99,7 @@ namespace media { class MojoRendererTest : public mojo::test::ApplicationTestBase { public: MojoRendererTest() - : ApplicationTestBase(mojo::Array<mojo::String>()), - service_provider_(NULL) {} + : service_provider_(NULL) {} ~MojoRendererTest() override {} protected: diff --git a/mojo/cc/output_surface_mojo.cc b/mojo/cc/output_surface_mojo.cc index 193c7ac..e7a8def 100644 --- a/mojo/cc/output_surface_mojo.cc +++ b/mojo/cc/output_surface_mojo.cc @@ -49,7 +49,8 @@ void OutputSurfaceMojo::SwapBuffers(cc::CompositorFrame* frame) { surface_size_ = frame_size; } - surface_->SubmitFrame(SurfaceId::From(surface_id_), Frame::From(*frame)); + surface_->SubmitFrame(SurfaceId::From(surface_id_), Frame::From(*frame), + mojo::Closure()); client_->DidSwapBuffers(); client_->DidSwapBuffersComplete(); diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc index 16a5ce2..b138a2d 100644 --- a/mojo/edk/embedder/embedder_unittest.cc +++ b/mojo/edk/embedder/embedder_unittest.cc @@ -282,7 +282,13 @@ TEST_F(EmbedderTest, ChannelsHandlePassing) { // 10. (close) // 11. (wait/cl.) // 12. (wait/cl.) -TEST_F(EmbedderTest, MultiprocessChannels) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_MultiprocessChannels DISABLED_MultiprocessChannels +#else +#define MAYBE_MultiprocessChannels MultiprocessChannels +#endif // defined(OS_ANDROID) +TEST_F(EmbedderTest, MAYBE_MultiprocessChannels) { mojo::embedder::test::InitWithSimplePlatformSupport(); mojo::test::MultiprocessTestHelper multiprocess_test_helper; multiprocess_test_helper.StartChild("MultiprocessChannelsClient"); diff --git a/mojo/edk/js/core.cc b/mojo/edk/js/core.cc index 232f0e3..e70931d 100644 --- a/mojo/edk/js/core.cc +++ b/mojo/edk/js/core.cc @@ -288,6 +288,8 @@ v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) { .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE) .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE) .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE) + .SetValue("HANDLE_SIGNAL_PEER_CLOSED", + MOJO_HANDLE_SIGNAL_PEER_CLOSED) .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE", MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE) diff --git a/mojo/edk/mojo_edk.gyp b/mojo/edk/mojo_edk.gyp index 0959aac..b85cae7 100644 --- a/mojo/edk/mojo_edk.gyp +++ b/mojo/edk/mojo_edk.gyp @@ -15,115 +15,9 @@ '../../base/base.gyp:base', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', ], - 'defines': [ - 'MOJO_SYSTEM_IMPL_IMPLEMENTATION', - 'MOJO_SYSTEM_IMPLEMENTATION', - 'MOJO_USE_SYSTEM_IMPL', + 'includes': [ + 'mojo_edk_system_impl.gypi', ], - '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', - 'embedder/platform_channel_pair_win.cc', - 'embedder/platform_channel_utils_posix.cc', - 'embedder/platform_channel_utils_posix.h', - 'embedder/platform_handle.cc', - 'embedder/platform_handle.h', - 'embedder/platform_handle_utils.h', - 'embedder/platform_handle_utils_posix.cc', - 'embedder/platform_handle_utils_win.cc', - 'embedder/platform_handle_vector.h', - 'embedder/platform_shared_buffer.h', - 'embedder/platform_support.h', - 'embedder/scoped_platform_handle.h', - 'embedder/simple_platform_shared_buffer.cc', - 'embedder/simple_platform_shared_buffer.h', - 'embedder/simple_platform_shared_buffer_posix.cc', - 'embedder/simple_platform_shared_buffer_win.cc', - 'embedder/simple_platform_support.cc', - 'embedder/simple_platform_support.h', - 'system/channel.cc', - 'system/channel.h', - 'system/channel_endpoint.cc', - 'system/channel_endpoint.h', - 'system/channel_endpoint_client.h', - 'system/channel_endpoint_id.cc', - 'system/channel_endpoint_id.h', - 'system/channel_info.cc', - 'system/channel_info.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', - 'system/data_pipe.h', - 'system/data_pipe_consumer_dispatcher.cc', - 'system/data_pipe_consumer_dispatcher.h', - 'system/data_pipe_producer_dispatcher.cc', - 'system/data_pipe_producer_dispatcher.h', - 'system/dispatcher.cc', - 'system/dispatcher.h', - 'system/handle_signals_state.h', - 'system/handle_table.cc', - 'system/handle_table.h', - 'system/local_data_pipe.cc', - 'system/local_data_pipe.h', - 'system/local_message_pipe_endpoint.cc', - 'system/local_message_pipe_endpoint.h', - 'system/mapping_table.cc', - 'system/mapping_table.h', - 'system/memory.cc', - 'system/memory.h', - 'system/message_in_transit.cc', - 'system/message_in_transit.h', - 'system/message_in_transit_queue.cc', - 'system/message_in_transit_queue.h', - 'system/message_pipe.cc', - 'system/message_pipe.h', - 'system/message_pipe_dispatcher.cc', - 'system/message_pipe_dispatcher.h', - 'system/message_pipe_endpoint.cc', - 'system/message_pipe_endpoint.h', - 'system/options_validation.h', - 'system/platform_handle_dispatcher.cc', - 'system/platform_handle_dispatcher.h', - 'system/proxy_message_pipe_endpoint.cc', - 'system/proxy_message_pipe_endpoint.h', - 'system/raw_channel.cc', - 'system/raw_channel.h', - 'system/raw_channel_posix.cc', - 'system/raw_channel_win.cc', - 'system/shared_buffer_dispatcher.cc', - 'system/shared_buffer_dispatcher.h', - 'system/simple_dispatcher.cc', - 'system/simple_dispatcher.h', - 'system/transport_data.cc', - 'system/transport_data.h', - 'system/waiter.cc', - 'system/waiter.h', - 'system/waiter_list.cc', - 'system/waiter_list.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. - 'embedder/test_embedder.cc', - 'embedder/test_embedder.h', - ], - 'all_dependent_settings': { - # Ensures that dependent projects import the core functions on Windows. - 'defines': ['MOJO_USE_SYSTEM_IMPL'], - } }, { # GN version: //mojo/edk/js @@ -225,4 +119,26 @@ ], }, ], + 'conditions': [ + ['OS=="win" and target_arch=="ia32"', { + 'targets': [ + { + 'target_name': 'mojo_system_impl_win64', + 'type': '<(component)', + 'dependencies': [ + '../../base/base.gyp:base_win64', + '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', + ], + 'includes': [ + 'mojo_edk_system_impl.gypi', + ], + 'configurations': { + 'Common_Base': { + 'msvs_target_platform': 'x64', + }, + }, + }, + ], + }], + ], } diff --git a/mojo/edk/mojo_edk_system_impl.gypi b/mojo/edk/mojo_edk_system_impl.gypi new file mode 100644 index 0000000..a0af387 --- /dev/null +++ b/mojo/edk/mojo_edk_system_impl.gypi @@ -0,0 +1,118 @@ +# Copyright (c) 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. + +# The dictionary here is defined for use by the "mojo_system_impl" and +# "mojo_system_impl_win64" targets in mojo/edk/mojo_edk.gyp. It's defined in +# this .gypi file so the sections aren't duplicated. +{ + 'defines': [ + 'MOJO_SYSTEM_IMPL_IMPLEMENTATION', + 'MOJO_SYSTEM_IMPLEMENTATION', + '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', + 'embedder/platform_channel_pair_win.cc', + 'embedder/platform_channel_utils_posix.cc', + 'embedder/platform_channel_utils_posix.h', + 'embedder/platform_handle.cc', + 'embedder/platform_handle.h', + 'embedder/platform_handle_utils.h', + 'embedder/platform_handle_utils_posix.cc', + 'embedder/platform_handle_utils_win.cc', + 'embedder/platform_handle_vector.h', + 'embedder/platform_shared_buffer.h', + 'embedder/platform_support.h', + 'embedder/scoped_platform_handle.h', + 'embedder/simple_platform_shared_buffer.cc', + 'embedder/simple_platform_shared_buffer.h', + 'embedder/simple_platform_shared_buffer_posix.cc', + 'embedder/simple_platform_shared_buffer_win.cc', + 'embedder/simple_platform_support.cc', + 'embedder/simple_platform_support.h', + 'system/channel.cc', + 'system/channel.h', + 'system/channel_endpoint.cc', + 'system/channel_endpoint.h', + 'system/channel_endpoint_client.h', + 'system/channel_endpoint_id.cc', + 'system/channel_endpoint_id.h', + 'system/channel_info.cc', + 'system/channel_info.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', + 'system/data_pipe.h', + 'system/data_pipe_consumer_dispatcher.cc', + 'system/data_pipe_consumer_dispatcher.h', + 'system/data_pipe_producer_dispatcher.cc', + 'system/data_pipe_producer_dispatcher.h', + 'system/dispatcher.cc', + 'system/dispatcher.h', + 'system/handle_signals_state.h', + 'system/handle_table.cc', + 'system/handle_table.h', + 'system/local_data_pipe.cc', + 'system/local_data_pipe.h', + 'system/local_message_pipe_endpoint.cc', + 'system/local_message_pipe_endpoint.h', + 'system/mapping_table.cc', + 'system/mapping_table.h', + 'system/memory.cc', + 'system/memory.h', + 'system/message_in_transit.cc', + 'system/message_in_transit.h', + 'system/message_in_transit_queue.cc', + 'system/message_in_transit_queue.h', + 'system/message_pipe.cc', + 'system/message_pipe.h', + 'system/message_pipe_dispatcher.cc', + 'system/message_pipe_dispatcher.h', + 'system/message_pipe_endpoint.cc', + 'system/message_pipe_endpoint.h', + 'system/options_validation.h', + 'system/platform_handle_dispatcher.cc', + 'system/platform_handle_dispatcher.h', + 'system/proxy_message_pipe_endpoint.cc', + 'system/proxy_message_pipe_endpoint.h', + 'system/raw_channel.cc', + 'system/raw_channel.h', + 'system/raw_channel_posix.cc', + 'system/raw_channel_win.cc', + 'system/shared_buffer_dispatcher.cc', + 'system/shared_buffer_dispatcher.h', + 'system/simple_dispatcher.cc', + 'system/simple_dispatcher.h', + 'system/transport_data.cc', + 'system/transport_data.h', + 'system/waiter.cc', + 'system/waiter.h', + 'system/waiter_list.cc', + 'system/waiter_list.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. + 'embedder/test_embedder.cc', + 'embedder/test_embedder.h', + ], + 'all_dependent_settings': { + # Ensures that dependent projects import the core functions on Windows. + 'defines': ['MOJO_USE_SYSTEM_IMPL'], + }, +} diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn index b87c76a..0701484 100644 --- a/mojo/edk/system/BUILD.gn +++ b/mojo/edk/system/BUILD.gn @@ -2,6 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + config("system_config") { defines = [ # Ensures that dependent projects import the core functions on Windows. @@ -143,6 +148,12 @@ test("mojo_system_unittests") { "//testing/gtest", ] + if (is_android) { + deps += [ + "//testing/android:native_test_native_code", + ] + } + allow_circular_includes_from = [ "//mojo/edk/embedder:embedder_unittests" ] } @@ -165,3 +176,12 @@ test("mojo_message_pipe_perftests") { "//testing/gtest", ] } + +if (is_android) { + unittest_apk("mojo_system_unittests_apk") { + deps = [ + ":mojo_system_unittests", + ] + unittests_dep = ":mojo_system_unittests" + } +} diff --git a/mojo/edk/system/channel.cc b/mojo/edk/system/channel.cc index 50d4b65..3d6c54f 100644 --- a/mojo/edk/system/channel.cc +++ b/mojo/edk/system/channel.cc @@ -7,7 +7,6 @@ #include <algorithm> #include "base/bind.h" -#include "base/compiler_specific.h" #include "base/logging.h" #include "base/macros.h" #include "base/strings/stringprintf.h" @@ -237,9 +236,8 @@ void Channel::OnReadMessage( DCHECK(creation_thread_checker_.CalledOnValidThread()); switch (message_view.type()) { - case MessageInTransit::kTypeMessagePipeEndpoint: - case MessageInTransit::kTypeMessagePipe: - OnReadMessageForDownstream(message_view, platform_handles.Pass()); + case MessageInTransit::kTypeEndpoint: + OnReadMessageForEndpoint(message_view, platform_handles.Pass()); break; case MessageInTransit::kTypeChannel: OnReadMessageForChannel(message_view, platform_handles.Pass()); @@ -283,12 +281,11 @@ void Channel::OnError(Error error) { Shutdown(); } -void Channel::OnReadMessageForDownstream( +void Channel::OnReadMessageForEndpoint( const MessageInTransit::View& message_view, embedder::ScopedPlatformHandleVectorPtr platform_handles) { DCHECK(creation_thread_checker_.CalledOnValidThread()); - DCHECK(message_view.type() == MessageInTransit::kTypeMessagePipeEndpoint || - message_view.type() == MessageInTransit::kTypeMessagePipe); + DCHECK(message_view.type() == MessageInTransit::kTypeEndpoint); ChannelEndpointId local_id = message_view.destination_id(); if (!local_id.is_valid()) { @@ -331,12 +328,16 @@ void Channel::OnReadMessageForDownstream( return; } - if (!endpoint->OnReadMessage(message_view, platform_handles.Pass())) { - HandleLocalError( - base::StringPrintf("Failed to enqueue message to local ID %u", - static_cast<unsigned>(local_id.value()))); - return; + scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); + if (message_view.transport_data_buffer_size() > 0) { + DCHECK(message_view.transport_data_buffer()); + message->SetDispatchers(TransportData::DeserializeDispatchers( + message_view.transport_data_buffer(), + message_view.transport_data_buffer_size(), platform_handles.Pass(), + this)); } + + endpoint->OnReadMessage(message.Pass()); } void Channel::OnReadMessageForChannel( diff --git a/mojo/edk/system/channel.h b/mojo/edk/system/channel.h index e0ecc3b..227d202 100644 --- a/mojo/edk/system/channel.h +++ b/mojo/edk/system/channel.h @@ -139,7 +139,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel void OnError(Error error) override; // Helpers for |OnReadMessage| (only called on the creation thread): - void OnReadMessageForDownstream( + void OnReadMessageForEndpoint( const MessageInTransit::View& message_view, embedder::ScopedPlatformHandleVectorPtr platform_handles); void OnReadMessageForChannel( diff --git a/mojo/edk/system/channel_endpoint.cc b/mojo/edk/system/channel_endpoint.cc index ca86b5f..a8bbbb2 100644 --- a/mojo/edk/system/channel_endpoint.cc +++ b/mojo/edk/system/channel_endpoint.cc @@ -7,7 +7,6 @@ #include "base/logging.h" #include "mojo/edk/system/channel.h" #include "mojo/edk/system/channel_endpoint_client.h" -#include "mojo/edk/system/transport_data.h" namespace mojo { namespace system { @@ -19,7 +18,7 @@ ChannelEndpoint::ChannelEndpoint(ChannelEndpointClient* client, DCHECK(client_.get() || message_queue); if (message_queue) - paused_message_queue_.Swap(message_queue); + channel_message_queue_.Swap(message_queue); } bool ChannelEndpoint::EnqueueMessage(scoped_ptr<MessageInTransit> message) { @@ -33,7 +32,7 @@ bool ChannelEndpoint::EnqueueMessage(scoped_ptr<MessageInTransit> message) { // some reason (with live message pipes on it). Ideally, we'd return false // (and not enqueue the message), but we currently don't have a way to check // this. - paused_message_queue_.AddMessage(message.Pass()); + channel_message_queue_.AddMessage(message.Pass()); return true; } @@ -72,8 +71,8 @@ void ChannelEndpoint::AttachAndRun(Channel* channel, local_id_ = local_id; remote_id_ = remote_id; - while (!paused_message_queue_.IsEmpty()) { - LOG_IF(WARNING, !WriteMessageNoLock(paused_message_queue_.GetMessage())) + while (!channel_message_queue_.IsEmpty()) { + LOG_IF(WARNING, !WriteMessageNoLock(channel_message_queue_.GetMessage())) << "Failed to write enqueue message to channel"; } @@ -85,10 +84,7 @@ void ChannelEndpoint::AttachAndRun(Channel* channel, } } -bool ChannelEndpoint::OnReadMessage( - const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles) { - scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); +void ChannelEndpoint::OnReadMessage(scoped_ptr<MessageInTransit> message) { scoped_refptr<ChannelEndpointClient> client; unsigned client_port; { @@ -97,15 +93,7 @@ bool ChannelEndpoint::OnReadMessage( if (!client_.get()) { // This isn't a failure per se. (It just means that, e.g., the other end // of the message point closed first.) - return true; - } - - if (message_view.transport_data_buffer_size() > 0) { - DCHECK(message_view.transport_data_buffer()); - message->SetDispatchers(TransportData::DeserializeDispatchers( - message_view.transport_data_buffer(), - message_view.transport_data_buffer_size(), platform_handles.Pass(), - channel_)); + return; } // Take a ref, and call |OnReadMessage()| outside the lock. @@ -113,7 +101,7 @@ bool ChannelEndpoint::OnReadMessage( client_port = client_port_; } - return client->OnReadMessage(client_port, message.Pass()); + client->OnReadMessage(client_port, message.Pass()); } void ChannelEndpoint::DetachFromChannel() { diff --git a/mojo/edk/system/channel_endpoint.h b/mojo/edk/system/channel_endpoint.h index 8de169b..71b6f9b 100644 --- a/mojo/edk/system/channel_endpoint.h +++ b/mojo/edk/system/channel_endpoint.h @@ -9,9 +9,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" -#include "mojo/edk/embedder/platform_handle_vector.h" #include "mojo/edk/system/channel_endpoint_id.h" -#include "mojo/edk/system/message_in_transit.h" #include "mojo/edk/system/message_in_transit_queue.h" #include "mojo/edk/system/system_impl_export.h" @@ -139,15 +137,14 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelEndpoint // Methods called by |Channel|: // Called when the |Channel| takes a reference to this object. This will send - // all queue messages (in |paused_message_queue_|). + // all queue messages (in |channel_message_queue_|). // TODO(vtl): Maybe rename this "OnAttach"? void AttachAndRun(Channel* channel, ChannelEndpointId local_id, ChannelEndpointId remote_id); // Called when the |Channel| receives a message for the |ChannelEndpoint|. - bool OnReadMessage(const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles); + void OnReadMessage(scoped_ptr<MessageInTransit> message); // Called before the |Channel| gives up its reference to this object. void DetachFromChannel(); @@ -182,8 +179,8 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelEndpoint ChannelEndpointId remote_id_; // This queue is used before we're running on a channel and ready to send - // messages. - MessageInTransitQueue paused_message_queue_; + // messages to the channel. + MessageInTransitQueue channel_message_queue_; DISALLOW_COPY_AND_ASSIGN(ChannelEndpoint); }; diff --git a/mojo/edk/system/channel_endpoint_client.h b/mojo/edk/system/channel_endpoint_client.h index e14326f..7a7d5b8 100644 --- a/mojo/edk/system/channel_endpoint_client.h +++ b/mojo/edk/system/channel_endpoint_client.h @@ -38,7 +38,7 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelEndpointClient // called by |Channel| when it receives a message for the |ChannelEndpoint|. // (|port| is the value passed to |ChannelEndpoint|'s constructor as // |client_port|.) - virtual bool OnReadMessage(unsigned port, + virtual void OnReadMessage(unsigned port, scoped_ptr<MessageInTransit> message) = 0; // Called by |ChannelEndpoint| when the |Channel| is relinquishing its pointer diff --git a/mojo/edk/system/channel_unittest.cc b/mojo/edk/system/channel_unittest.cc index 68b1315..e84ab5b 100644 --- a/mojo/edk/system/channel_unittest.cc +++ b/mojo/edk/system/channel_unittest.cc @@ -243,8 +243,8 @@ TEST_F(ChannelTest, ShutdownAfterAttach) { waiter.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); HandleSignalsState hss; mp->RemoveWaiter(0, &waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); @@ -279,8 +279,8 @@ TEST_F(ChannelTest, WaitAfterAttachRunAndShutdown) { HandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc index 96780f7..51a4022 100644 --- a/mojo/edk/system/core_unittest.cc +++ b/mojo/edk/system/core_unittest.cc @@ -18,6 +18,9 @@ namespace { const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u}; const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u}; +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; typedef test::CoreTestBase CoreTest; @@ -545,11 +548,9 @@ TEST_F(CoreTest, MessagePipe) { MakeUserPointer(&result_index), MakeUserPointer(hss))); EXPECT_EQ(static_cast<uint32_t>(-1), result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[1].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals); // Try to read anyway. char buffer[1] = {'a'}; @@ -568,14 +569,12 @@ TEST_F(CoreTest, MessagePipe) { EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[0], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); // Also check that |h[1]| is writable using |WaitMany()|. signals[0] = MOJO_HANDLE_SIGNAL_READABLE; @@ -590,11 +589,9 @@ TEST_F(CoreTest, MessagePipe) { MakeUserPointer(hss))); EXPECT_EQ(1u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[1].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals); // Write to |h[1]|. buffer[0] = 'b'; @@ -617,11 +614,9 @@ TEST_F(CoreTest, MessagePipe) { EXPECT_EQ(0u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[1].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals); // Read from |h[0]|. // First, get only the size. @@ -649,8 +644,7 @@ TEST_F(CoreTest, MessagePipe) { core()->Wait(h[0], MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); // Write to |h[0]|. buffer[0] = 'd'; @@ -667,15 +661,19 @@ TEST_F(CoreTest, MessagePipe) { EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfiable_signals); // Check that |h[1]| is still readable (for the moment). hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss[0]))); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfiable_signals); // Discard a message from |h[1]|. EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, @@ -688,8 +686,8 @@ TEST_F(CoreTest, MessagePipe) { EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss[0]))); - EXPECT_EQ(0u, hss[0].satisfied_signals); - EXPECT_EQ(0u, hss[0].satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[0].satisfiable_signals); // Try writing to |h[1]|. buffer[0] = 'e'; @@ -732,8 +730,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -773,8 +770,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -797,8 +793,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -833,8 +828,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -870,12 +864,14 @@ TEST_F(CoreTest, DataPipe) { MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ph, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ph, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Consumer should be never-writable, and not yet readable. hss = kFullMojoHandleSignalsState; @@ -883,16 +879,18 @@ TEST_F(CoreTest, DataPipe) { MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ch, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Write. - char elements[2] = {'A', 'B'}; + signed char elements[2] = {'A', 'B'}; uint32_t num_bytes = 2u; EXPECT_EQ(MOJO_RESULT_OK, core()->WriteData(ph, UserPointer<const void>(elements), @@ -905,7 +903,8 @@ TEST_F(CoreTest, DataPipe) { EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Peek one character. elements[0] = -1; @@ -1022,7 +1021,8 @@ TEST_F(CoreTest, DataPipe) { MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // TODO(vtl): More. @@ -1034,8 +1034,8 @@ TEST_F(CoreTest, DataPipe) { EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch)); } @@ -1075,8 +1075,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -1111,7 +1110,8 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch_received, UserPointer<void>(buffer), @@ -1131,8 +1131,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -1167,7 +1166,8 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch_received, UserPointer<void>(buffer), @@ -1225,7 +1225,8 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Make sure that |ch| can't be sent if it's in a two-phase read. const void* read_ptr = nullptr; @@ -1251,8 +1252,7 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) { MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, diff --git a/mojo/edk/system/local_data_pipe.cc b/mojo/edk/system/local_data_pipe.cc index 177b238..8b9f673 100644 --- a/mojo/edk/system/local_data_pipe.cc +++ b/mojo/edk/system/local_data_pipe.cc @@ -160,7 +160,10 @@ HandleSignalsState LocalDataPipe::ProducerGetHandleSignalsStateImplNoLock() !producer_in_two_phase_write_no_lock()) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; + } else { + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; } + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; } @@ -293,6 +296,9 @@ HandleSignalsState LocalDataPipe::ConsumerGetHandleSignalsStateImplNoLock() } else if (producer_open_no_lock()) { rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; } + if (!producer_open_no_lock()) + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; } diff --git a/mojo/edk/system/local_data_pipe_unittest.cc b/mojo/edk/system/local_data_pipe_unittest.cc index 9ba6b21..cea50a0 100644 --- a/mojo/edk/system/local_data_pipe_unittest.cc +++ b/mojo/edk/system/local_data_pipe_unittest.cc @@ -239,7 +239,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { MOJO_RESULT_FAILED_PRECONDITION, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Already writable. waiter.Init(); @@ -266,7 +267,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Peek one element. elements[0] = -1; @@ -289,7 +291,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Do it again. waiter.Init(); @@ -314,7 +317,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Try writing, using a two-phase write. void* buffer = nullptr; @@ -357,7 +361,8 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Write one element. elements[0] = 123; @@ -381,12 +386,75 @@ TEST(LocalDataPipeTest, BasicProducerWaiting) { EXPECT_EQ(12u, context); hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); dp->ProducerClose(); } +TEST(LocalDataPipeTest, PeerClosedWaiting) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 2 * sizeof(int32_t) // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( + MakeUserPointer(&options), &validated_options)); + + Waiter waiter; + HandleSignalsState hss; + + // Check MOJO_HANDLE_SIGNAL_PEER_CLOSED on producer. + { + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); + // Add a waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, + nullptr)); + + // Close the consumer. + dp->ConsumerClose(); + + // It should be signaled. + uint32_t context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + dp->ProducerRemoveWaiter(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + dp->ProducerClose(); + } + + // Check MOJO_HANDLE_SIGNAL_PEER_CLOSED on consumer. + { + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); + // Add a waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, + nullptr)); + + // Close the producer. + dp->ProducerClose(); + + // It should be signaled. + uint32_t context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + dp->ConsumerRemoveWaiter(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + dp->ConsumerClose(); + } +} + TEST(LocalDataPipeTest, BasicConsumerWaiting) { const MojoCreateDataPipeOptions options = { kSizeOfOptions, // |struct_size|. @@ -411,7 +479,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { MOJO_RESULT_FAILED_PRECONDITION, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, &hss)); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Not yet readable. waiter.Init(); @@ -422,7 +491,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Write two elements. int32_t elements[2] = {123, 456}; @@ -438,7 +508,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Discard one element. num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); @@ -453,7 +524,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Peek one element. elements[0] = -1; @@ -473,7 +545,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. elements[0] = -1; @@ -506,7 +579,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Close the producer. dp->ProducerClose(); @@ -517,8 +591,10 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { EXPECT_EQ( MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. elements[0] = -1; @@ -537,8 +613,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); dp->ConsumerClose(); } @@ -574,7 +650,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. // Request two in all-or-none mode, but only read one. @@ -597,7 +674,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. // Request three, but not in all-or-none mode. @@ -627,8 +705,8 @@ TEST(LocalDataPipeTest, BasicConsumerWaiting) { EXPECT_EQ(56u, context); hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); dp->ConsumerClose(); } @@ -657,7 +735,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); uint32_t num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t)); void* write_ptr = nullptr; @@ -676,7 +755,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // It shouldn't be readable yet either. waiter.Init(); @@ -687,7 +767,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); static_cast<int32_t*>(write_ptr)[0] = 123; EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData( @@ -700,7 +781,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // And readable. waiter.Init(); @@ -709,7 +791,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 4, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Start another two-phase write and check that it's readable even in the // middle of it. @@ -728,7 +811,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // End the two-phase write without writing anything. EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(0u)); @@ -749,7 +833,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // But not readable. waiter.Init(); @@ -760,7 +845,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // End the two-phase read without reading anything. EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(0u)); @@ -772,7 +858,8 @@ TEST(LocalDataPipeTest, BasicTwoPhaseWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); dp->ProducerClose(); dp->ConsumerClose(); @@ -801,7 +888,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Not readable. waiter.Init(); @@ -812,7 +900,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); uint32_t num_bytes = static_cast<uint32_t>(sizeof(int32_t)); int32_t element = 123; @@ -828,7 +917,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 2, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Now readable. waiter.Init(); @@ -837,7 +927,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Overwrite that element. num_bytes = static_cast<uint32_t>(sizeof(int32_t)); @@ -854,7 +945,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // And still readable. waiter.Init(); @@ -863,7 +955,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read that element. num_bytes = static_cast<uint32_t>(sizeof(int32_t)); @@ -881,7 +974,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // No longer readable. waiter.Init(); @@ -892,7 +986,8 @@ TEST(LocalDataPipeTest, BasicMayDiscardWaiting) { hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); dp->ProducerClose(); dp->ConsumerClose(); diff --git a/mojo/edk/system/local_message_pipe_endpoint.cc b/mojo/edk/system/local_message_pipe_endpoint.cc index 124241e..86d241c 100644 --- a/mojo/edk/system/local_message_pipe_endpoint.cc +++ b/mojo/edk/system/local_message_pipe_endpoint.cc @@ -137,7 +137,10 @@ HandleSignalsState LocalMessagePipeEndpoint::GetHandleSignalsState() const { rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; + } else { + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; } + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; } diff --git a/mojo/edk/system/message_in_transit.cc b/mojo/edk/system/message_in_transit.cc index 0f2ff5e..624a546 100644 --- a/mojo/edk/system/message_in_transit.cc +++ b/mojo/edk/system/message_in_transit.cc @@ -15,15 +15,13 @@ namespace mojo { namespace system { STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type - MessageInTransit::kTypeMessagePipeEndpoint; -STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type - MessageInTransit::kTypeMessagePipe; + MessageInTransit::kTypeEndpoint; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type MessageInTransit::kTypeChannel; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type MessageInTransit::kTypeRawChannel; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype - MessageInTransit::kSubtypeMessagePipeEndpointData; + MessageInTransit::kSubtypeEndpointData; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype MessageInTransit::kSubtypeChannelAttachAndRunEndpoint; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype @@ -110,6 +108,8 @@ MessageInTransit::MessageInTransit(Type type, base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) { ConstructorHelper(type, subtype, num_bytes); bytes.GetArray(MessageInTransit::bytes(), num_bytes); + memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0, + main_buffer_size_ - sizeof(Header) - num_bytes); } MessageInTransit::MessageInTransit(const View& message_view) diff --git a/mojo/edk/system/message_in_transit.h b/mojo/edk/system/message_in_transit.h index 2b9da6d..0f92b05 100644 --- a/mojo/edk/system/message_in_transit.h +++ b/mojo/edk/system/message_in_transit.h @@ -44,20 +44,16 @@ class TransportData; class MOJO_SYSTEM_IMPL_EXPORT MessageInTransit { public: typedef uint16_t Type; - // Messages that are forwarded to |MessagePipeEndpoint|s. - static const Type kTypeMessagePipeEndpoint = 0; - // Messages that are forwarded to |MessagePipe|s. - static const Type kTypeMessagePipe = 1; + // Messages that are forwarded to endpoints. + static const Type kTypeEndpoint = 0; // Messages that are consumed by the |Channel|. - static const Type kTypeChannel = 2; + static const Type kTypeChannel = 1; // Messages that are consumed by the |RawChannel| (implementation). - static const Type kTypeRawChannel = 3; + static const Type kTypeRawChannel = 2; typedef uint16_t Subtype; - // Subtypes for type |kTypeMessagePipeEndpoint|: - static const Subtype kSubtypeMessagePipeEndpointData = 0; - // Subtypes for type |kTypeMessagePipe|: - // Nothing currently. + // Subtypes for type |kTypeEndpoint|: + static const Subtype kSubtypeEndpointData = 0; // Subtypes for type |kTypeChannel|: static const Subtype kSubtypeChannelAttachAndRunEndpoint = 0; static const Subtype kSubtypeChannelRemoveMessagePipeEndpoint = 1; diff --git a/mojo/edk/system/message_pipe.cc b/mojo/edk/system/message_pipe.cc index 8e1be57..ee5036f 100644 --- a/mojo/edk/system/message_pipe.cc +++ b/mojo/edk/system/message_pipe.cc @@ -142,8 +142,8 @@ MojoResult MessagePipe::WriteMessage( return EnqueueMessage( GetPeerPort(port), make_scoped_ptr(new MessageInTransit( - MessageInTransit::kTypeMessagePipeEndpoint, - MessageInTransit::kSubtypeMessagePipeEndpointData, num_bytes, bytes)), + MessageInTransit::kTypeEndpoint, + MessageInTransit::kSubtypeEndpointData, num_bytes, bytes)), transports); } @@ -287,14 +287,16 @@ bool MessagePipe::EndSerialize( return true; } -bool MessagePipe::OnReadMessage(unsigned port, +void MessagePipe::OnReadMessage(unsigned port, scoped_ptr<MessageInTransit> message) { // This is called when the |ChannelEndpoint| for the // |ProxyMessagePipeEndpoint| |port| receives a message (from the |Channel|). // We need to pass this message on to its peer port (typically a // |LocalMessagePipeEndpoint|). - return EnqueueMessage(GetPeerPort(port), message.Pass(), nullptr) == - MOJO_RESULT_OK; + MojoResult result = + EnqueueMessage(GetPeerPort(port), message.Pass(), nullptr); + DLOG_IF(WARNING, result != MOJO_RESULT_OK) + << "EnqueueMessage() failed (result = " << result << ")"; } void MessagePipe::OnDetachFromChannel(unsigned port) { @@ -319,12 +321,7 @@ MojoResult MessagePipe::EnqueueMessage( DCHECK(port == 0 || port == 1); DCHECK(message); - if (message->type() == MessageInTransit::kTypeMessagePipe) { - DCHECK(!transports); - return HandleControlMessage(port, message.Pass()); - } - - DCHECK_EQ(message->type(), MessageInTransit::kTypeMessagePipeEndpoint); + DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpoint); base::AutoLock locker(lock_); DCHECK(endpoints_[GetPeerPort(port)]); @@ -388,13 +385,5 @@ MojoResult MessagePipe::AttachTransportsNoLock( return MOJO_RESULT_OK; } -MojoResult MessagePipe::HandleControlMessage( - unsigned /*port*/, - scoped_ptr<MessageInTransit> message) { - LOG(WARNING) << "Unrecognized MessagePipe control message subtype " - << message->subtype(); - return MOJO_RESULT_UNKNOWN; -} - } // namespace system } // namespace mojo diff --git a/mojo/edk/system/message_pipe.h b/mojo/edk/system/message_pipe.h index 1c1af1e..e8f97d0 100644 --- a/mojo/edk/system/message_pipe.h +++ b/mojo/edk/system/message_pipe.h @@ -107,7 +107,7 @@ class MOJO_SYSTEM_IMPL_EXPORT MessagePipe : public ChannelEndpointClient { embedder::PlatformHandleVector* platform_handles); // |ChannelEndpointClient| methods: - bool OnReadMessage(unsigned port, + void OnReadMessage(unsigned port, scoped_ptr<MessageInTransit> message) override; void OnDetachFromChannel(unsigned port) override; @@ -128,11 +128,6 @@ class MOJO_SYSTEM_IMPL_EXPORT MessagePipe : public ChannelEndpointClient { MessageInTransit* message, std::vector<DispatcherTransport>* transports); - // Used by |EnqueueMessage()| to handle control messages that are actually - // meant for us. - MojoResult HandleControlMessage(unsigned port, - scoped_ptr<MessageInTransit> message); - base::Lock lock_; // Protects the following members. scoped_ptr<MessagePipeEndpoint> endpoints_[2]; diff --git a/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/mojo/edk/system/message_pipe_dispatcher_unittest.cc index 8076a99..303ae6a 100644 --- a/mojo/edk/system/message_pipe_dispatcher_unittest.cc +++ b/mojo/edk/system/message_pipe_dispatcher_unittest.cc @@ -29,6 +29,10 @@ namespace mojo { namespace system { namespace { +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + TEST(MessagePipeDispatcherTest, Basic) { test::Stopwatch stopwatch; int32_t buffer[1]; @@ -57,8 +61,7 @@ TEST(MessagePipeDispatcherTest, Basic) { EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Shouldn't need to remove the waiter (it was not added). // Add a readable waiter to |d0|, then make it readable (by writing to @@ -78,8 +81,7 @@ TEST(MessagePipeDispatcherTest, Basic) { d0->RemoveWaiter(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Try adding a readable waiter when already readable (from above). w.Init(); @@ -88,8 +90,7 @@ TEST(MessagePipeDispatcherTest, Basic) { d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Shouldn't need to remove the waiter (it was not added). // Make |d0| no longer readable (by reading from it). @@ -112,8 +113,7 @@ TEST(MessagePipeDispatcherTest, Basic) { hss = HandleSignalsState(); d0->RemoveWaiter(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Wait for non-zero, finite time for readability on |d0| (will time out). w.Init(); @@ -128,11 +128,25 @@ TEST(MessagePipeDispatcherTest, Basic) { hss = HandleSignalsState(); d0->RemoveWaiter(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); - EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); + // Check the peer closed signal. + w.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, nullptr)); + + // Close the peer. EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); + + // It should be signaled. + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(1000, &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + d0->RemoveWaiter(&w, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); } } @@ -238,8 +252,7 @@ TEST(MessagePipeDispatcherTest, BasicClosed) { d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Try reading from |d1|; should fail (nothing to read). buffer[0] = 0; @@ -257,8 +270,10 @@ TEST(MessagePipeDispatcherTest, BasicClosed) { hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 1, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read from |d0|. buffer[0] = 0; @@ -275,8 +290,10 @@ TEST(MessagePipeDispatcherTest, BasicClosed) { hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read again from |d0|. buffer[0] = 0; @@ -293,16 +310,16 @@ TEST(MessagePipeDispatcherTest, BasicClosed) { hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Try waiting for writable on |d0|; should fail (unsatisfiable). w.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Try reading from |d0|; should fail (nothing to read and other end // closed). @@ -374,8 +391,7 @@ TEST(MessagePipeDispatcherTest, MAYBE_BasicThreaded) { EXPECT_EQ(1u, context); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Now |d1| is already readable. Try waiting for it again. { @@ -390,8 +406,7 @@ TEST(MessagePipeDispatcherTest, MAYBE_BasicThreaded) { EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Consume what we wrote to |d0|. buffer[0] = 0; @@ -420,8 +435,8 @@ TEST(MessagePipeDispatcherTest, MAYBE_BasicThreaded) { EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); EXPECT_EQ(3u, context); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); } diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc index 9f1ac5d..2387782 100644 --- a/mojo/edk/system/message_pipe_perftest.cc +++ b/mojo/edk/system/message_pipe_perftest.cc @@ -140,7 +140,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PingPongClient) { // Repeatedly sends messages as previous one got replied by the child. // Waits for the child to close its end before quitting once specified // number of messages has been sent. -TEST_F(MultiprocessMessagePipePerfTest, PingPong) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_PingPong DISABLED_PingPong +#else +#define MAYBE_PingPong PingPong +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessMessagePipePerfTest, MAYBE_PingPong) { helper()->StartChild("PingPongClient"); scoped_refptr<ChannelEndpoint> ep; diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc index 030084b..c700891 100644 --- a/mojo/edk/system/message_pipe_unittest.cc +++ b/mojo/edk/system/message_pipe_unittest.cc @@ -15,6 +15,10 @@ namespace mojo { namespace system { namespace { +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + // Tests: // - only default flags // - reading messages from a port @@ -335,8 +339,7 @@ TEST(MessagePipeTest, BasicWaiting) { EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, @@ -344,8 +347,7 @@ TEST(MessagePipeTest, BasicWaiting) { MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Not yet readable. waiter.Init(); @@ -355,8 +357,18 @@ TEST(MessagePipeTest, BasicWaiting) { hss = HandleSignalsState(); mp->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); + + // The peer is not closed. + waiter.Init(); + ASSERT_EQ( + MOJO_RESULT_OK, + mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 2, nullptr)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); + hss = HandleSignalsState(); + mp->RemoveWaiter(0, &waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Write from port 0 (to port 1), to make port 1 readable. buffer[0] = 123456789; @@ -368,11 +380,10 @@ TEST(MessagePipeTest, BasicWaiting) { waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, @@ -381,36 +392,48 @@ TEST(MessagePipeTest, BasicWaiting) { 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // ... and still writable. waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss)); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Close port 0. mp->Close(0); - // Now port 1 should not be writable. + // Port 1 should be signaled with peer closed. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 5, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Port 1 should not be writable. waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // But it should still be readable. waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 7, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read from port 1. buffer[0] = 0; @@ -425,7 +448,7 @@ TEST(MessagePipeTest, BasicWaiting) { waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 6, nullptr)); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, nullptr)); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); @@ -460,8 +483,7 @@ TEST(MessagePipeTest, ThreadedWaiting) { mp->RemoveWaiter(1, thread.waiter(), &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); mp->Close(0); mp->Close(1); @@ -493,6 +515,29 @@ TEST(MessagePipeTest, ThreadedWaiting) { EXPECT_EQ(MOJO_RESULT_CANCELLED, result); EXPECT_EQ(2u, context); + // Close to cancel waiter using peer closed signal. + { + scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); + test::SimpleWaiterThread thread(&result, &context); + + thread.waiter()->Init(); + ASSERT_EQ(MOJO_RESULT_OK, + mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + 3, nullptr)); + thread.Start(); + + // Close port 1 first -- this should result in the waiter being cancelled. + mp->CancelAllWaiters(1); + mp->Close(1); + + // Port 1 is closed, so |Dispatcher::RemoveWaiter()| wouldn't call into the + // |MessagePipe| to remove any waiter. + + mp->Close(0); + } // Joins |thread|. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(3u, context); + // Close to make waiter un-wake-up-able. { scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); @@ -500,7 +545,7 @@ TEST(MessagePipeTest, ThreadedWaiting) { thread.waiter()->Init(); ASSERT_EQ(MOJO_RESULT_OK, - mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3, + mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 4, nullptr)); thread.Start(); @@ -511,14 +556,14 @@ TEST(MessagePipeTest, ThreadedWaiting) { HandleSignalsState hss; mp->RemoveWaiter(1, thread.waiter(), &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->CancelAllWaiters(1); mp->Close(1); } // Joins |thread|. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); - EXPECT_EQ(3u, context); + EXPECT_EQ(4u, context); } } // namespace diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc index ab2e75c..f486152 100644 --- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc @@ -62,8 +62,8 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { if (result != MOJO_RESULT_OK) { // It was closed, probably. CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION); - CHECK_EQ(hss.satisfied_signals, 0u); - CHECK_EQ(hss.satisfiable_signals, 0u); + CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED); break; } else { CHECK((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); @@ -96,7 +96,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) { } // Sends "hello" to child, and expects "hellohello" back. -TEST_F(MultiprocessMessagePipeTest, Basic) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_Basic DISABLED_Basic +#else +#define MAYBE_Basic Basic +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessMessagePipeTest, MAYBE_Basic) { helper()->StartChild("EchoEcho"); scoped_refptr<ChannelEndpoint> ep; @@ -136,7 +142,13 @@ TEST_F(MultiprocessMessagePipeTest, Basic) { // Sends a bunch of messages to the child. Expects them "repeated" back. Waits // for the child to close its end before quitting. -TEST_F(MultiprocessMessagePipeTest, QueueMessages) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_QueueMessages DISABLED_QueueMessages +#else +#define MAYBE_QueueMessages QueueMessages +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessMessagePipeTest, DISABLED_QueueMessages) { helper()->StartChild("EchoEcho"); scoped_refptr<ChannelEndpoint> ep; @@ -184,8 +196,8 @@ TEST_F(MultiprocessMessagePipeTest, QueueMessages) { HandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); @@ -211,8 +223,9 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { // pipe before we do. CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); - CHECK_EQ(hss.satisfiable_signals, - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED); // It should have a shared buffer. std::string read_buffer(100, '\0'); @@ -260,8 +273,9 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { MOJO_RESULT_OK); CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); - CHECK_EQ(hss.satisfiable_signals, - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED); read_buffer = std::string(100, '\0'); num_bytes = static_cast<uint32_t>(read_buffer.size()); @@ -282,10 +296,11 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckSharedBuffer) { return 0; } -#if defined(OS_POSIX) +#if defined(OS_POSIX) && !defined(OS_ANDROID) #define MAYBE_SharedBufferPassing SharedBufferPassing #else // Not yet implemented (on Windows). +// Android multi-process tests are not executing the new process. This is flaky. #define MAYBE_SharedBufferPassing DISABLED_SharedBufferPassing #endif TEST_F(MultiprocessMessagePipeTest, MAYBE_SharedBufferPassing) { @@ -364,8 +379,8 @@ TEST_F(MultiprocessMessagePipeTest, MAYBE_SharedBufferPassing) { hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); @@ -387,8 +402,9 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { MOJO_RESULT_OK); CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); - CHECK_EQ(hss.satisfiable_signals, - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED); std::string read_buffer(100, '\0'); uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size()); @@ -422,10 +438,11 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) { return 0; } -#if defined(OS_POSIX) +#if defined(OS_POSIX) && !defined(OS_ANDROID) #define MAYBE_PlatformHandlePassing PlatformHandlePassing #else // Not yet implemented (on Windows). +// Android multi-process tests are not executing the new process. This is flaky. #define MAYBE_PlatformHandlePassing DISABLED_PlatformHandlePassing #endif TEST_F(MultiprocessMessagePipeTest, MAYBE_PlatformHandlePassing) { @@ -471,8 +488,8 @@ TEST_F(MultiprocessMessagePipeTest, MAYBE_PlatformHandlePassing) { HandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); diff --git a/mojo/edk/system/raw_channel_unittest.cc b/mojo/edk/system/raw_channel_unittest.cc index 7717f49..1c39010 100644 --- a/mojo/edk/system/raw_channel_unittest.cc +++ b/mojo/edk/system/raw_channel_unittest.cc @@ -38,10 +38,9 @@ scoped_ptr<MessageInTransit> MakeTestMessage(uint32_t num_bytes) { std::vector<unsigned char> bytes(num_bytes, 0); for (size_t i = 0; i < num_bytes; i++) bytes[i] = static_cast<unsigned char>(i + num_bytes); - return make_scoped_ptr( - new MessageInTransit(MessageInTransit::kTypeMessagePipeEndpoint, - MessageInTransit::kSubtypeMessagePipeEndpointData, - num_bytes, bytes.empty() ? nullptr : &bytes[0])); + return make_scoped_ptr(new MessageInTransit( + MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, + num_bytes, bytes.empty() ? nullptr : &bytes[0])); } bool CheckMessageData(const void* bytes, uint32_t num_bytes) { diff --git a/mojo/edk/system/remote_message_pipe_unittest.cc b/mojo/edk/system/remote_message_pipe_unittest.cc index e3a320e..926ca0b 100644 --- a/mojo/edk/system/remote_message_pipe_unittest.cc +++ b/mojo/edk/system/remote_message_pipe_unittest.cc @@ -41,6 +41,10 @@ namespace mojo { namespace system { namespace { +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + class RemoteMessagePipeTest : public testing::Test { public: RemoteMessagePipeTest() : io_thread_(base::TestIOThread::kAutoStart) {} @@ -204,8 +208,7 @@ TEST_F(RemoteMessagePipeTest, Basic) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. EXPECT_EQ(MOJO_RESULT_OK, @@ -233,8 +236,7 @@ TEST_F(RemoteMessagePipeTest, Basic) { mp0->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_OK, @@ -261,8 +263,44 @@ TEST_F(RemoteMessagePipeTest, Basic) { hss = HandleSignalsState(); mp1->RemoveWaiter(1, &waiter, &hss); } - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + // And MP 1, port 1. + mp1->Close(1); +} + +TEST_F(RemoteMessagePipeTest, PeerClosed) { + Waiter waiter; + HandleSignalsState hss; + uint32_t context = 0; + + // Connect message pipes. MP 0, port 1 will be attached to channel 0 and + // connected to MP 1, port 0, which will be attached to channel 1. This leaves + // MP 0, port 0 and MP 1, port 1 as the "user-facing" endpoints. + + scoped_refptr<ChannelEndpoint> ep0; + scoped_refptr<MessagePipe> mp0(MessagePipe::CreateLocalProxy(&ep0)); + scoped_refptr<ChannelEndpoint> ep1; + scoped_refptr<MessagePipe> mp1(MessagePipe::CreateProxyLocal(&ep1)); + BootstrapChannelEndpoints(ep0, ep1); + + // Close MP 0, port 0. + mp0->Close(0); + + // Try to wait for MP 1, port 1 to be signaled with peer closed. + waiter.Init(); + hss = HandleSignalsState(); + MojoResult result = + mp1->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 101, &hss); + if (result == MOJO_RESULT_OK) { + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(101u, context); + hss = HandleSignalsState(); + mp1->RemoveWaiter(1, &waiter, &hss); + } + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // And MP 1, port 1. mp1->Close(1); @@ -314,8 +352,7 @@ TEST_F(RemoteMessagePipeTest, Multiplex) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); ChannelEndpointId received_id; buffer_size = static_cast<uint32_t>(sizeof(received_id)); @@ -349,8 +386,7 @@ TEST_F(RemoteMessagePipeTest, Multiplex) { mp3->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Make sure there's nothing on MP 0, port 0 or MP 1, port 1 or MP 2, port 0. buffer_size = static_cast<uint32_t>(sizeof(buffer)); @@ -396,7 +432,7 @@ TEST_F(RemoteMessagePipeTest, Multiplex) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + EXPECT_EQ(kAllSignals | MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Make sure there's nothing on the other ports. @@ -606,8 +642,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -651,8 +686,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { dispatcher->RemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from the dispatcher. memset(read_buffer, 0, sizeof(read_buffer)); @@ -682,8 +716,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassing) { local_mp->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from "local_mp", port 1. memset(read_buffer, 0, sizeof(read_buffer)); @@ -721,8 +754,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { hss = local_mp->GetHandleSignalsState(0); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Write to the other end (|local_mp|, port 1), and then close it. EXPECT_EQ( MOJO_RESULT_OK, @@ -731,8 +763,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { hss = local_mp->GetHandleSignalsState(0); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Then the second message.... EXPECT_EQ( MOJO_RESULT_OK, @@ -741,8 +772,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { hss = local_mp->GetHandleSignalsState(0); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Then close it. local_mp->Close(1); @@ -786,8 +816,7 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -811,8 +840,10 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { // |dispatcher| should already be readable and not writable. hss = dispatcher->GetHandleSignalsState(); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // So read from it. memset(read_buffer, 0, sizeof(read_buffer)); read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); @@ -824,8 +855,10 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { EXPECT_STREQ(kHello, read_buffer); // It should still be readable. hss = dispatcher->GetHandleSignalsState(); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // So read from it. memset(read_buffer, 0, sizeof(read_buffer)); read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); @@ -837,8 +870,8 @@ TEST_F(RemoteMessagePipeTest, HandlePassingHalfClosed) { EXPECT_STREQ(kWorld, read_buffer); // Now it should no longer be readable. hss = dispatcher->GetHandleSignalsState(); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Close everything that belongs to us. mp0->Close(0); @@ -917,8 +950,7 @@ TEST_F(RemoteMessagePipeTest, MAYBE_SharedBufferPassing) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -1037,8 +1069,7 @@ TEST_F(RemoteMessagePipeTest, MAYBE_PlatformHandlePassing) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -1175,8 +1206,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -1235,8 +1265,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { mp0->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 0, port 0. read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); @@ -1276,8 +1305,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { dispatcher->RemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from the dispatcher. memset(read_buffer, 0, sizeof(read_buffer)); @@ -1307,8 +1335,7 @@ TEST_F(RemoteMessagePipeTest, PassMessagePipeHandleAcrossAndBack) { local_mp->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from "local_mp", port 1. memset(read_buffer, 0, sizeof(read_buffer)); diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/run_all_unittests.cc index 3ea1682..cd61337 100644 --- a/mojo/edk/system/run_all_unittests.cc +++ b/mojo/edk/system/run_all_unittests.cc @@ -8,9 +8,13 @@ #include "testing/gtest/include/gtest/gtest.h" int main(int argc, char** argv) { - // Silence death test thread warnings on Linux. We can afford to run our death - // tests a little more slowly (< 10 ms per death test on a Z620). +// Silence death test thread warnings on Linux. We can afford to run our death +// tests a little more slowly (< 10 ms per death test on a Z620). +// On android, we need to run in the default mode, as the threadsafe mode +// relies on execve which is not available. +#if !defined(OS_ANDROID) testing::GTEST_FLAG(death_test_style) = "threadsafe"; +#endif base::TestSuite test_suite(argc, argv); diff --git a/mojo/edk/test/multiprocess_test_helper_unittest.cc b/mojo/edk/test/multiprocess_test_helper_unittest.cc index 2961a74..93496fb 100644 --- a/mojo/edk/test/multiprocess_test_helper_unittest.cc +++ b/mojo/edk/test/multiprocess_test_helper_unittest.cc @@ -42,7 +42,13 @@ bool ReadByte(const embedder::PlatformHandle& handle, char* c) { typedef testing::Test MultiprocessTestHelperTest; -TEST_F(MultiprocessTestHelperTest, RunChild) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_RunChild DISABLED_RunChild +#else +#define MAYBE_RunChild RunChild +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_RunChild) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); @@ -55,14 +61,26 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) { return 123; } -TEST_F(MultiprocessTestHelperTest, TestChildMainNotFound) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_TestChildMainNotFound DISABLED_TestChildMainNotFound +#else +#define MAYBE_TestChildMainNotFound TestChildMainNotFound +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_TestChildMainNotFound) { MultiprocessTestHelper helper; helper.StartChild("NoSuchTestChildMain"); int result = helper.WaitForChildShutdown(); EXPECT_FALSE(result >= 0 && result <= 127); } -TEST_F(MultiprocessTestHelperTest, PassedChannel) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_PassedChannel DISABLED_PassedChannel +#else +#define MAYBE_PassedChannel PassedChannel +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_PassedChannel) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("PassedChannel"); @@ -109,7 +127,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel) { return static_cast<int>(c); } -TEST_F(MultiprocessTestHelperTest, ChildTestPasses) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_ChildTestPasses DISABLED_ChildTestPasses +#else +#define MAYBE_ChildTestPasses ChildTestPasses +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_ChildTestPasses) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("ChildTestPasses"); @@ -122,7 +146,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestPasses) { IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get())); } -TEST_F(MultiprocessTestHelperTest, ChildTestFailsAssert) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_ChildTestFailsAssert DISABLED_ChildTestFailsAssert +#else +#define MAYBE_ChildTestFailsAssert ChildTestFailsAssert +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_ChildTestFailsAssert) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("ChildTestFailsAssert"); @@ -138,7 +168,13 @@ MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsAssert) { CHECK(false) << "Not reached"; } -TEST_F(MultiprocessTestHelperTest, ChildTestFailsExpect) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_ChildTestFailsExpect DISABLED_ChildTestFailsExpect +#else +#define MAYBE_ChildTestFailsExpect ChildTestFailsExpect +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_ChildTestFailsExpect) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("ChildTestFailsExpect"); diff --git a/mojo/public/VERSION b/mojo/public/VERSION index 282b862..eca68d9 100644 --- a/mojo/public/VERSION +++ b/mojo/public/VERSION @@ -1 +1 @@ -5aa6dbdccf1950daf0cd3014bf763f35899bccf9
\ No newline at end of file +98d8236f7eea383e5214254c8d045df6c7a6297a
\ No newline at end of file diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h index 96441dc..9b1eedc 100644 --- a/mojo/public/c/system/types.h +++ b/mojo/public/c/system/types.h @@ -149,6 +149,7 @@ const MojoDeadline MOJO_DEADLINE_INDEFINITE = static_cast<MojoDeadline>(-1); // |MOJO_RESULT_FAILED_PRECONDITION| if you attempt to wait on this. // |MOJO_HANDLE_SIGNAL_READABLE| - Can read (e.g., a message) from the handle. // |MOJO_HANDLE_SIGNAL_WRITABLE| - Can write (e.g., a message) to the handle. +// |MOJO_HANDLE_SIGNAL_PEER_CLOSED| - The peer handle is closed. typedef uint32_t MojoHandleSignals; @@ -156,10 +157,12 @@ typedef uint32_t MojoHandleSignals; const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE = 0; const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE = 1 << 0; const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1; +const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2; #else #define MOJO_HANDLE_SIGNAL_NONE ((MojoHandleSignals)0) #define MOJO_HANDLE_SIGNAL_READABLE ((MojoHandleSignals)1 << 0) #define MOJO_HANDLE_SIGNAL_WRITABLE ((MojoHandleSignals)1 << 1) +#define MOJO_HANDLE_SIGNAL_PEER_CLOSED ((MojoHandleSignals)1 << 2) #endif // TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany. diff --git a/mojo/public/cpp/application/application_test_base.h b/mojo/public/cpp/application/application_test_base.h index 2f400a4..04580c7 100644 --- a/mojo/public/cpp/application/application_test_base.h +++ b/mojo/public/cpp/application/application_test_base.h @@ -5,6 +5,7 @@ #ifndef MOJO_PUBLIC_CPP_APPLICATION_APPLICATION_TEST_BASE_H_ #define MOJO_PUBLIC_CPP_APPLICATION_APPLICATION_TEST_BASE_H_ +#include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/system/macros.h" @@ -12,7 +13,6 @@ namespace mojo { -class ApplicationDelegate; class ApplicationImpl; namespace test { @@ -21,28 +21,35 @@ namespace test { ScopedMessagePipeHandle PassShellHandle(); void SetShellHandle(ScopedMessagePipeHandle handle); +// Access the command line arguments passed to the application test. +const Array<String>& Args(); +void InitializeArgs(int argc, std::vector<const char*> argv); + // A GTEST base class for application testing executed in mojo_shell. class ApplicationTestBase : public testing::Test { public: - explicit ApplicationTestBase(Array<String> args); + ApplicationTestBase(); ~ApplicationTestBase() override; protected: ApplicationImpl* application_impl() { return application_impl_; } // Get the ApplicationDelegate for the application to be tested. - virtual ApplicationDelegate* GetApplicationDelegate() = 0; + virtual ApplicationDelegate* GetApplicationDelegate(); + + // A testing::Test::SetUp helper to override the application command + // line arguments. + void SetUpWithArgs(const Array<String>& args); // testing::Test: void SetUp() override; void TearDown() override; private: - // The command line arguments supplied to each test application instance. - Array<String> args_; - // The application implementation instance, reconstructed for each test. ApplicationImpl* application_impl_; + // The application delegate used if GetApplicationDelegate is not overridden. + ApplicationDelegate default_application_delegate_; MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationTestBase); }; diff --git a/mojo/public/cpp/application/lib/application_test_base.cc b/mojo/public/cpp/application/lib/application_test_base.cc index 42dbda5..93eb3d0 100644 --- a/mojo/public/cpp/application/lib/application_test_base.cc +++ b/mojo/public/cpp/application/lib/application_test_base.cc @@ -7,7 +7,6 @@ #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" #include "mojo/public/cpp/environment/environment.h" -#include "mojo/public/cpp/environment/logging.h" #include "mojo/public/cpp/system/message_pipe.h" namespace mojo { @@ -17,6 +16,8 @@ namespace { // This shell handle is shared by multiple test application instances. MessagePipeHandle g_shell_handle; +// Share the application command-line arguments with multiple application tests. +Array<String> g_args; } // namespace @@ -33,14 +34,29 @@ void SetShellHandle(ScopedMessagePipeHandle handle) { g_shell_handle = handle.release(); } -ApplicationTestBase::ApplicationTestBase(Array<String> args) - : args_(args.Pass()), application_impl_(nullptr) { +const Array<String>& Args() { + return g_args; +} + +void InitializeArgs(int argc, std::vector<const char*> argv) { + MOJO_CHECK(g_args.is_null()); + for (const char* arg : argv) { + if (arg) + g_args.push_back(arg); + } +} + +ApplicationTestBase::ApplicationTestBase() : application_impl_(nullptr) { } ApplicationTestBase::~ApplicationTestBase() { } -void ApplicationTestBase::SetUp() { +ApplicationDelegate* ApplicationTestBase::GetApplicationDelegate() { + return &default_application_delegate_; +} + +void ApplicationTestBase::SetUpWithArgs(const Array<String>& args) { // A run loop is needed for ApplicationImpl initialization and communication. Environment::InstantiateDefaultRunLoop(); @@ -49,7 +65,11 @@ void ApplicationTestBase::SetUp() { PassShellHandle()); // Fake application initialization with the given command line arguments. - application_impl_->Initialize(args_.Clone()); + application_impl_->Initialize(args.Clone()); +} + +void ApplicationTestBase::SetUp() { + SetUpWithArgs(Args()); } void ApplicationTestBase::TearDown() { diff --git a/mojo/public/cpp/application/lib/application_test_main.cc b/mojo/public/cpp/application/lib/application_test_main.cc index 6cdfb0d..1c1395c 100644 --- a/mojo/public/cpp/application/lib/application_test_main.cc +++ b/mojo/public/cpp/application/lib/application_test_main.cc @@ -21,14 +21,14 @@ MojoResult MojoMain(MojoHandle shell_handle) { // Construct an ApplicationImpl just for the GTEST commandline arguments. // GTEST command line arguments are supported amid application arguments: - // $ mojo_shell 'mojo:example_apptests arg1 --gtest_filter=foo arg2' + // $ mojo_shell mojo:example_apptests + // --args-for='mojo:example_apptests arg1 --gtest_filter=foo arg2' mojo::ApplicationDelegate dummy_application_delegate; mojo::ApplicationImpl app(&dummy_application_delegate, shell_handle); MOJO_CHECK(app.WaitForInitialize()); // InitGoogleTest expects (argc + 1) elements, including a terminating NULL. // It also removes GTEST arguments from |argv| and updates the |argc| count. - // TODO(msw): Provide tests access to these actual command line arguments. const std::vector<std::string>& args = app.args(); MOJO_CHECK(args.size() < static_cast<size_t>(std::numeric_limits<int>::max())); @@ -40,6 +40,7 @@ MojoResult MojoMain(MojoHandle shell_handle) { testing::InitGoogleTest(&argc, const_cast<char**>(&(argv[0]))); mojo::test::SetShellHandle(app.UnbindShell()); + mojo::test::InitializeArgs(argc, argv); } int result = RUN_ALL_TESTS(); diff --git a/mojo/public/dart/src/types.dart b/mojo/public/dart/src/types.dart index 4353d74..1dc3572 100644 --- a/mojo/public/dart/src/types.dart +++ b/mojo/public/dart/src/types.dart @@ -122,6 +122,7 @@ class MojoHandleSignals { static const int NONE = 0; static const int READABLE = 1 << 0; static const int WRITABLE = 1 << 1; + static const int PEER_CLOSED = 1 << 2; static const int READWRITE = READABLE | WRITABLE; static bool isNone(int mask) => mask == NONE; diff --git a/mojo/public/go/system/impl/mojo_types.go b/mojo/public/go/system/impl/mojo_types.go index 01d518e..bd82898 100644 --- a/mojo/public/go/system/impl/mojo_types.go +++ b/mojo/public/go/system/impl/mojo_types.go @@ -57,6 +57,7 @@ const ( MOJO_HANDLE_SIGNAL_NONE MojoHandleSignals = 0 MOJO_HANDLE_SIGNAL_READABLE = 1 << 0 MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1 + MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2 MOJO_WRITE_MESSAGE_FLAG_NONE MojoWriteMessageFlags = 0 MOJO_READ_MESSAGE_FLAG_NONE MojoReadMessageFlags = 0 diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn index e56f9b5..70aa60e 100644 --- a/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/mojo/public/interfaces/bindings/tests/BUILD.gn @@ -11,6 +11,7 @@ mojom("test_interfaces") { "no_module.mojom", "rect.mojom", "regression_tests.mojom", + "regression_tests_import.mojom", "sample_factory.mojom", "sample_import.mojom", "sample_import2.mojom", diff --git a/mojo/public/interfaces/bindings/tests/regression_tests.mojom b/mojo/public/interfaces/bindings/tests/regression_tests.mojom index 313f1f4..4a85b0a 100644 --- a/mojo/public/interfaces/bindings/tests/regression_tests.mojom +++ b/mojo/public/interfaces/bindings/tests/regression_tests.mojom @@ -7,6 +7,8 @@ [JavaPackage="org.chromium.mojo.bindings.test.mojom.regression_tests"] module regression_tests; +import "regression_tests_import.mojom"; + interface CheckMethodWithEmptyResponse { WithouParameterAndEmptyResponse() => (); WithParameterAndEmptyResponse(bool b) => (); @@ -52,3 +54,7 @@ struct A { struct B { A? a; }; + +[Client=InterfaceWithClientImportedClient] +interface InterfaceWithClientImported { +}; diff --git a/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom b/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom new file mode 100644 index 0000000..fbed983 --- /dev/null +++ b/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom @@ -0,0 +1,11 @@ +// 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. + +// Module containing entities for regression tests of the generator. Entities +// must never be modified, instead new entity must be added to add new tests. +[JavaPackage="org.chromium.mojo.bindings.test.mojom.regression_tests_import"] +module regression_tests_import; + +interface InterfaceWithClientImportedClient { +}; diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java index d6c8e7d..caf619a 100644 --- a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java +++ b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java @@ -33,6 +33,7 @@ public interface Core { private static final int FLAG_NONE = 0; private static final int FLAG_READABLE = 1 << 0; private static final int FLAG_WRITABLE = 1 << 1; + private static final int FLAG_PEER_CLOSED = 1 << 2; /** * Immutable signals. @@ -64,6 +65,16 @@ public interface Core { } /** + * Change the peer closed bit of this signal. + * + * @param peerClosed the new value of the peer closed bit. + * @return this. + */ + public HandleSignals setPeerClosed(boolean peerClosed) { + return setFlag(FLAG_PEER_CLOSED, peerClosed); + } + + /** * @return a signal with no bit set. */ public static HandleSignals none() { diff --git a/mojo/public/js/core.js b/mojo/public/js/core.js index 9dcb20f..4a67567 100644 --- a/mojo/public/js/core.js +++ b/mojo/public/js/core.js @@ -55,6 +55,7 @@ var DEADLINE_INDEFINITE; var HANDLE_SIGNAL_NONE; var HANDLE_SIGNAL_READABLE; var HANDLE_SIGNAL_WRITABLE; +var HANDLE_SIGNAL_PEER_CLOSED; /** * MojoCreateDataMessageOptions: Used to specify creation parameters for a data diff --git a/mojo/public/mojo_application.gni b/mojo/public/mojo_application.gni index 83b96a2..05ec369 100644 --- a/mojo/public/mojo_application.gni +++ b/mojo/public/mojo_application.gni @@ -125,3 +125,62 @@ template("mojo_native_application") { outputs = [ "${root_out_dir}/${output}" ] } } + +if (is_android) { + # Declares an Android Mojo application consisting of an .so file and a + # corresponding .dex.jar file. + # + # Variables: + # input_so: the .so file to bundle + # input_dex_jar: the .dex.jar file to bundle + # output_name (optional): override for the output file name + template("mojo_android_application") { + assert(defined(invoker.input_so)) + assert(defined(invoker.input_dex_jar)) + + zip_action_name = "${target_name}_zip" + zip_action_output = "$target_gen_dir/${target_name}.zip" + action(zip_action_name) { + script = "//build/android/gn/zip.py" + + inputs = [ + invoker.input_so, + invoker.input_dex_jar, + ] + + output = zip_action_output + outputs = [ output ] + + rebase_inputs = rebase_path(inputs, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--inputs=$rebase_inputs", + "--output=$rebase_output", + ] + } + + if (defined(invoker.output_name)) { + mojo_output = "$target_out_dir/" + invoker.output_name + ".mojo" + } else { + mojo_output = "$target_out_dir/" + target_name + ".mojo" + } + + action(target_name) { + script = "//mojo/public/tools/prepend.py" + + input = zip_action_output + inputs = [ input ] + + output = mojo_output + outputs = [ output ] + + rebase_input = rebase_path(input, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--input=$rebase_input", + "--output=$rebase_output", + "--line=#!mojo:android_handler", + ] + } + } +} diff --git a/mojo/public/mojo_public.gyp b/mojo/public/mojo_public.gyp index f19e263..83e27d8 100644 --- a/mojo/public/mojo_public.gyp +++ b/mojo/public/mojo_public.gyp @@ -237,11 +237,9 @@ ], 'dependencies': [ 'mojo_application_bindings', - 'mojo_application_bindings_mojom', ], 'export_dependent_settings': [ 'mojo_application_bindings', - 'mojo_application_bindings_mojom', ], }, { @@ -331,6 +329,7 @@ 'interfaces/bindings/tests/no_module.mojom', 'interfaces/bindings/tests/rect.mojom', 'interfaces/bindings/tests/regression_tests.mojom', + 'interfaces/bindings/tests/regression_tests_import.mojom', 'interfaces/bindings/tests/sample_factory.mojom', 'interfaces/bindings/tests/sample_import.mojom', 'interfaces/bindings/tests/sample_import2.mojom', diff --git a/mojo/public/python/mojo/bindings/descriptor.py b/mojo/public/python/mojo/bindings/descriptor.py index f190d2b..0df0bd6 100644 --- a/mojo/public/python/mojo/bindings/descriptor.py +++ b/mojo/public/python/mojo/bindings/descriptor.py @@ -72,7 +72,7 @@ class SerializableType(Type): """ raise NotImplementedError() - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): """ Deserialize a value of this type. @@ -106,7 +106,7 @@ class NumericType(SerializableType): def Serialize(self, value, data_offset, data, handle_offset): return (value, []) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): return value @@ -161,21 +161,31 @@ class PointerType(SerializableType): return (0, []) return self.SerializePointer(value, data_offset, data, handle_offset) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): if value == 0: if not self.nullable: raise serialization.DeserializationException( 'Trying to deserialize null for non nullable type.') return None - pointed_data = buffer(data, value) - (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(pointed_data) - return self.DeserializePointer(size, nb_elements, pointed_data, handles) + if value % 8 != 0: + raise serialization.DeserializationException( + 'Pointer alignment is incorrect.') + sub_context = context.GetSubContext(value) + if len(sub_context.data) < serialization.HEADER_STRUCT.size: + raise serialization.DeserializationException( + 'Available data too short to contain header.') + (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from( + sub_context.data) + if len(sub_context.data) < size or size < serialization.HEADER_STRUCT.size: + raise serialization.DeserializationException('Header size is incorrect.') + sub_context.ClaimMemory(0, size) + return self.DeserializePointer(size, nb_elements, sub_context) def SerializePointer(self, value, data_offset, data, handle_offset): """Serialize the not null value.""" raise NotImplementedError() - def DeserializePointer(self, size, nb_elements, data, handles): + def DeserializePointer(self, size, nb_elements, context): raise NotImplementedError() @@ -204,9 +214,8 @@ class StringType(PointerType): return self._array_type.SerializeArray( string_array, data_offset, data, handle_offset) - def DeserializePointer(self, size, nb_elements, data, handles): - string_array = self._array_type.DeserializeArray( - size, nb_elements, data, handles) + def DeserializePointer(self, size, nb_elements, context): + string_array = self._array_type.DeserializeArray(size, nb_elements, context) return unicode(string_array.tostring(), 'utf8') @@ -226,14 +235,13 @@ class BaseHandleType(SerializableType): return (-1, []) return (handle_offset, [handle]) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): if value == -1: if not self.nullable: raise serialization.DeserializationException( 'Trying to deserialize null for non nullable type.') return self.FromHandle(mojo.system.Handle()) - # TODO(qsr) validate handle order - return self.FromHandle(handles[value]) + return self.FromHandle(context.ClaimHandle(value)) def FromHandle(self, handle): raise NotImplementedError() @@ -326,12 +334,18 @@ class BaseArrayType(PointerType): """Serialize the not null array.""" raise NotImplementedError() - def DeserializePointer(self, size, nb_elements, data, handles): - if self.length != 0 and size != self.length: + def DeserializePointer(self, size, nb_elements, context): + if self.length != 0 and nb_elements != self.length: raise serialization.DeserializationException('Incorrect array size') - return self.DeserializeArray(size, nb_elements, data, handles) + if (size < + serialization.HEADER_STRUCT.size + self.SizeForLength(nb_elements)): + raise serialization.DeserializationException('Incorrect array size') + return self.DeserializeArray(size, nb_elements, context) + + def DeserializeArray(self, size, nb_elements, context): + raise NotImplementedError() - def DeserializeArray(self, size, nb_elements, data, handles): + def SizeForLength(self, nb_elements): raise NotImplementedError() @@ -351,9 +365,8 @@ class BooleanArrayType(BaseArrayType): converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups]) return _SerializeNativeArray(converted, data_offset, data, len(value)) - def DeserializeArray(self, size, nb_elements, data, handles): - converted = self._array_type.DeserializeArray( - size, nb_elements, data, handles) + def DeserializeArray(self, size, nb_elements, context): + converted = self._array_type.DeserializeArray(size, nb_elements, context) elements = list(itertools.islice( itertools.chain.from_iterable( [_ConvertByteToBooleans(x, 8) for x in converted]), @@ -361,6 +374,9 @@ class BooleanArrayType(BaseArrayType): nb_elements)) return elements + def SizeForLength(self, nb_elements): + return (nb_elements + 7) // 8 + class GenericArrayType(BaseArrayType): """Type object for arrays of pointers.""" @@ -400,18 +416,22 @@ class GenericArrayType(BaseArrayType): *to_pack) return (data_offset, returned_handles) - def DeserializeArray(self, size, nb_elements, data, handles): + def DeserializeArray(self, size, nb_elements, context): values = struct.unpack_from( '%d%s' % (nb_elements, self.sub_type.GetTypeCode()), - buffer(data, serialization.HEADER_STRUCT.size)) + buffer(context.data, serialization.HEADER_STRUCT.size)) result = [] - position = serialization.HEADER_STRUCT.size + sub_context = context.GetSubContext(serialization.HEADER_STRUCT.size) for value in values: - result.append( - self.sub_type.Deserialize(value, buffer(data, position), handles)) - position += self.sub_type.GetByteSize() + result.append(self.sub_type.Deserialize( + value, + sub_context)) + sub_context = sub_context.GetSubContext(self.sub_type.GetByteSize()) return result + def SizeForLength(self, nb_elements): + return nb_elements * self.sub_type.GetByteSize(); + class NativeArrayType(BaseArrayType): """Type object for arrays of native types.""" @@ -419,6 +439,7 @@ class NativeArrayType(BaseArrayType): def __init__(self, typecode, nullable=False, length=0): BaseArrayType.__init__(self, nullable, length) self.array_typecode = typecode + self.element_size = struct.calcsize('<%s' % self.array_typecode) def Convert(self, value): if value is None: @@ -431,13 +452,16 @@ class NativeArrayType(BaseArrayType): def SerializeArray(self, value, data_offset, data, handle_offset): return _SerializeNativeArray(value, data_offset, data, len(value)) - def DeserializeArray(self, size, nb_elements, data, handles): + def DeserializeArray(self, size, nb_elements, context): result = array.array(self.array_typecode) - result.fromstring(buffer(data, + result.fromstring(buffer(context.data, serialization.HEADER_STRUCT.size, size - serialization.HEADER_STRUCT.size)) return result + def SizeForLength(self, nb_elements): + return nb_elements * self.element_size + class StructType(PointerType): """Type object for structs.""" @@ -469,8 +493,8 @@ class StructType(PointerType): data.extend(new_data) return (data_offset, new_handles) - def DeserializePointer(self, size, nb_elements, data, handles): - return self.struct_type.Deserialize(data, handles) + def DeserializePointer(self, size, nb_elements, context): + return self.struct_type.Deserialize(context) class MapType(SerializableType): @@ -511,8 +535,8 @@ class MapType(SerializableType): s = self.struct(keys=keys, values=values) return self.struct_type.Serialize(s, data_offset, data, handle_offset) - def Deserialize(self, value, data, handles): - s = self.struct_type.Deserialize(value, data, handles) + def Deserialize(self, value, context): + s = self.struct_type.Deserialize(value, context) if s: if len(s.keys) != len(s.values): raise serialization.DeserializationException( @@ -590,7 +614,7 @@ class FieldGroup(object): def Serialize(self, obj, data_offset, data, handle_offset): raise NotImplementedError() - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): raise NotImplementedError() @@ -615,8 +639,8 @@ class SingleFieldGroup(FieldGroup, FieldDescriptor): value = getattr(obj, self.name) return self.field_type.Serialize(value, data_offset, data, handle_offset) - def Deserialize(self, value, data, handles): - entity = self.field_type.Deserialize(value, data, handles) + def Deserialize(self, value, context): + entity = self.field_type.Deserialize(value, context) return { self.name: entity } @@ -640,7 +664,7 @@ class BooleanGroup(FieldGroup): [getattr(obj, field.name) for field in self.GetDescriptors()]) return (value, []) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): values = itertools.izip_longest([x.name for x in self.descriptors], _ConvertByteToBooleans(value), fillvalue=False) @@ -663,7 +687,7 @@ def _ConvertBooleansToByte(booleans): def _ConvertByteToBooleans(value, min_size=0): - "Unpack an integer into a list of booleans.""" + """Unpack an integer into a list of booleans.""" res = [] while value: res.append(bool(value&1)) diff --git a/mojo/public/python/mojo/bindings/reflection.py b/mojo/public/python/mojo/bindings/reflection.py index 5ca38bf..9668c2a3 100644 --- a/mojo/public/python/mojo/bindings/reflection.py +++ b/mojo/public/python/mojo/bindings/reflection.py @@ -117,10 +117,10 @@ class MojoStructType(type): return self._fields dictionary['AsDict'] = AsDict - def Deserialize(cls, data, handles): + def Deserialize(cls, context): result = cls.__new__(cls) fields = {} - serialization_object.Deserialize(fields, data, handles) + serialization_object.Deserialize(fields, context) result._fields = fields return result dictionary['Deserialize'] = classmethod(Deserialize) @@ -476,8 +476,9 @@ def _ProxyMethodCall(method): try: assert message.header.message_type == method.ordinal payload = message.payload - response = method.response_struct.Deserialize(payload.data, - payload.handles) + response = method.response_struct.Deserialize( + serialization.RootDeserializationContext(payload.data, + payload.handles)) as_dict = response.AsDict() if len(as_dict) == 1: value = as_dict.values()[0] @@ -533,7 +534,8 @@ def _StubAccept(methods): method = methods_by_ordinal[header.message_type] payload = message.payload parameters = method.parameters_struct.Deserialize( - payload.data, payload.handles).AsDict() + serialization.RootDeserializationContext( + payload.data, payload.handles)).AsDict() response = getattr(self.impl, method.name)(**parameters) if header.expects_response: def SendResponse(response): diff --git a/mojo/public/python/mojo/bindings/serialization.py b/mojo/public/python/mojo/bindings/serialization.py index 2c0478f..b5ea1bd 100644 --- a/mojo/public/python/mojo/bindings/serialization.py +++ b/mojo/public/python/mojo/bindings/serialization.py @@ -21,6 +21,68 @@ class DeserializationException(Exception): pass +class DeserializationContext(object): + + def ClaimHandle(self, handle): + raise NotImplementedError() + + def ClaimMemory(self, start, size): + raise NotImplementedError() + + def GetSubContext(self, offset): + raise NotImplementedError() + + def IsInitialContext(self): + raise NotImplementedError() + + +class RootDeserializationContext(DeserializationContext): + def __init__(self, data, handles): + if isinstance(data, buffer): + self.data = data + else: + self.data = buffer(data) + self._handles = handles + self._next_handle = 0; + self._next_memory = 0; + + def ClaimHandle(self, handle): + if handle < self._next_handle: + raise DeserializationException('Accessing handles out of order.') + self._next_handle = handle + 1 + return self._handles[handle] + + def ClaimMemory(self, start, size): + if start < self._next_memory: + raise DeserializationException('Accessing buffer out of order.') + self._next_memory = start + size + + def GetSubContext(self, offset): + return _ChildDeserializationContext(self, offset) + + def IsInitialContext(self): + return True + + +class _ChildDeserializationContext(DeserializationContext): + def __init__(self, parent, offset): + self._parent = parent + self._offset = offset + self.data = buffer(parent.data, offset) + + def ClaimHandle(self, handle): + return self._parent.ClaimHandle(handle) + + def ClaimMemory(self, start, size): + return self._parent.ClaimMemory(self._offset + start, size) + + def GetSubContext(self, offset): + return self._parent.GetSubContext(self._offset + offset) + + def IsInitialContext(self): + return False + + class Serialization(object): """ Helper class to serialize/deserialize a struct. @@ -78,18 +140,23 @@ class Serialization(object): self._GetMainStruct().pack_into(data, HEADER_STRUCT.size, *to_pack) return (data, handles) - def Deserialize(self, fields, data, handles): - if not isinstance(data, buffer): - data = buffer(data) - (_, version) = HEADER_STRUCT.unpack_from(data) + def Deserialize(self, fields, context): + if len(context.data) < HEADER_STRUCT.size: + raise DeserializationException( + 'Available data too short to contain header.') + (size, version) = HEADER_STRUCT.unpack_from(context.data) + if len(context.data) < size or size < HEADER_STRUCT.size: + raise DeserializationException('Header size is incorrect.') + if context.IsInitialContext(): + context.ClaimMemory(0, size) version_struct = self._GetStruct(version) - entitities = version_struct.unpack_from(data, HEADER_STRUCT.size) + entitities = version_struct.unpack_from(context.data, HEADER_STRUCT.size) filtered_groups = self._GetGroups(version) position = HEADER_STRUCT.size for (group, value) in zip(filtered_groups, entitities): position = position + NeededPaddingForAlignment(position, group.GetByteSize()) - fields.update(group.Deserialize(value, buffer(data, position), handles)) + fields.update(group.Deserialize(value, context.GetSubContext(position))) position += group.GetByteSize() diff --git a/mojo/public/python/mojo/c_core.pxd b/mojo/public/python/mojo/c_core.pxd index 1526dfe..fe10fff 100644 --- a/mojo/public/python/mojo/c_core.pxd +++ b/mojo/public/python/mojo/c_core.pxd @@ -56,6 +56,7 @@ cdef extern from "mojo/public/c/system/core.h" nogil: const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE + const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED # functions.h MojoTimeTicks MojoGetTimeTicksNow() diff --git a/mojo/public/python/mojo/system.pyx b/mojo/public/python/mojo/system.pyx index 4507d4d..f0a814a 100644 --- a/mojo/public/python/mojo/system.pyx +++ b/mojo/public/python/mojo/system.pyx @@ -53,6 +53,7 @@ DEADLINE_INDEFINITE = c_core.MOJO_DEADLINE_INDEFINITE HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE +HANDLE_SIGNAL_PEER_CLOSED = c_core.MOJO_HANDLE_SIGNAL_PEER_CLOSED WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py index 4bede9a..19f4631 100644 --- a/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py @@ -429,9 +429,14 @@ class Generator(generator.Generator): exports = self.GetJinjaExports() exports.update({'interface': interface}) if interface.client: - for client in self.module.interfaces: - if client.name == interface.client: - exports.update({'client': client}) + all_interfaces = [] + self.module.interfaces + for each in self.module.imports: + all_interfaces += each['module'].interfaces + interfaces_by_name = dict((x.name, x) for x in all_interfaces) + assert interface.client in interfaces_by_name, ( + 'Unable to find interface %s declared as client of %s.' % + (interface.client, interface.name)) + exports.update({'client': interfaces_by_name[interface.client]}) return exports @UseJinja('java_templates/enum.java.tmpl', filters=java_filters) diff --git a/mojo/public/tools/bindings/generators/mojom_python_generator.py b/mojo/public/tools/bindings/generators/mojom_python_generator.py index f93da09..33bfdd5 100644 --- a/mojo/public/tools/bindings/generators/mojom_python_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_python_generator.py @@ -8,6 +8,7 @@ import re from itertools import ifilter import mojom.generate.generator as generator +import mojom.generate.data as data import mojom.generate.module as mojom from mojom.generate.template_expander import UseJinja @@ -318,8 +319,9 @@ class Generator(generator.Generator): """ interfaces = self.module.interfaces all_interfaces = [] + interfaces - for each in self.module.imports: - all_interfaces += each['module'].interfaces + for each in self.GetImports(): + all_interfaces += [data.KindFromImport(x, each) for x in + each['module'].interfaces]; interfaces_by_name = dict((x.name, x) for x in all_interfaces) for interface in interfaces: if interface.client: diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py index 7dc9067..cb3b1d1 100755 --- a/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -93,36 +93,19 @@ class MojomProcessor(object): def __init__(self, should_generate): self._should_generate = should_generate self._processed_files = {} + self._parsed_files = {} - def ProcessFile(self, args, remaining_args, generator_modules, filename, - _imported_filename_stack=None): - # Memoized results. - if filename in self._processed_files: - return self._processed_files[filename] - - if _imported_filename_stack is None: - _imported_filename_stack = [] - - # Ensure we only visit each file once. - if filename in _imported_filename_stack: - print "%s: Error: Circular dependency" % filename + \ - MakeImportStackMessage(_imported_filename_stack + [filename]) - sys.exit(1) + def ProcessFile(self, args, remaining_args, generator_modules, filename): + self._ParseFileAndImports(filename, args.import_directories, []) - try: - with open(filename) as f: - source = f.read() - except IOError as e: - print "%s: Error: %s" % (e.filename, e.strerror) + \ - MakeImportStackMessage(_imported_filename_stack + [filename]) - sys.exit(1) + return self._GenerateModule(args, remaining_args, generator_modules, + filename) - try: - tree = Parse(source, filename) - except Error as e: - full_stack = _imported_filename_stack + [filename] - print str(e) + MakeImportStackMessage(full_stack) - sys.exit(1) + def _GenerateModule(self, args, remaining_args, generator_modules, filename): + # Return the already-generated module. + if filename in self._processed_files: + return self._processed_files[filename] + tree = self._parsed_files[filename] dirname, name = os.path.split(filename) mojom = Translate(tree, name) @@ -135,9 +118,8 @@ class MojomProcessor(object): import_filename = FindImportFile(dirname, import_data['filename'], args.import_directories) - import_data['module'] = self.ProcessFile( - args, remaining_args, generator_modules, import_filename, - _imported_filename_stack=_imported_filename_stack + [filename]) + import_data['module'] = self._GenerateModule( + args, remaining_args, generator_modules, import_filename) module = OrderedModuleFromData(mojom) @@ -162,6 +144,42 @@ class MojomProcessor(object): self._processed_files[filename] = module return module + def _ParseFileAndImports(self, filename, import_directories, + imported_filename_stack): + # Ignore already-parsed files. + if filename in self._parsed_files: + return + + if filename in imported_filename_stack: + print "%s: Error: Circular dependency" % filename + \ + MakeImportStackMessage(imported_filename_stack + [filename]) + sys.exit(1) + + try: + with open(filename) as f: + source = f.read() + except IOError as e: + print "%s: Error: %s" % (e.filename, e.strerror) + \ + MakeImportStackMessage(imported_filename_stack + [filename]) + sys.exit(1) + + try: + tree = Parse(source, filename) + except Error as e: + full_stack = imported_filename_stack + [filename] + print str(e) + MakeImportStackMessage(full_stack) + sys.exit(1) + + dirname = os.path.split(filename)[0] + for imp_entry in tree.import_list: + import_filename = FindImportFile(dirname, + imp_entry.import_filename, import_directories) + self._ParseFileAndImports(import_filename, import_directories, + imported_filename_stack + [filename]) + + self._parsed_files[filename] = tree + + def main(): parser = argparse.ArgumentParser( description="Generate bindings from mojom files.") diff --git a/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi b/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi index 68348fb..512e22f 100644 --- a/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi +++ b/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi @@ -13,6 +13,10 @@ '<!@(python <(DEPTH)/mojo/public/tools/bindings/mojom_list_outputs.py --basedir <(mojom_base_output_dir) <@(mojom_files))', ], }, + # Given mojom files as inputs, generate sources. These sources will be + # exported to another target (via dependent_settings) to be compiled. This + # keeps code generation separate from compilation, allowing the same sources + # to be compiled with multiple toolchains - target, NaCl, etc. 'actions': [ { 'action_name': '<(_target_name)_mojom_bindings_generator', @@ -39,10 +43,11 @@ '--java_output_directory=<(java_out_dir)', ], 'message': 'Generating Mojo bindings from <@(mojom_files)', - 'process_outputs_as_sources': 1, } ], 'direct_dependent_settings': { + # A target directly depending on this action will compile the generated + # sources. 'sources': [ '<@(mojom_generated_outputs)', ], @@ -51,6 +56,9 @@ '<(DEPTH)', '<(SHARED_INTERMEDIATE_DIR)', ], + # Make sure the generated header files are available for any static library + # that depends on a static library that depends on this generator. + 'hard_dependency': 1, 'direct_dependent_settings': { # Include paths needed to find the generated header files and their # transitive dependancies when using the library. @@ -59,11 +67,10 @@ '<(SHARED_INTERMEDIATE_DIR)', ], 'variables': { - 'generated_src_dirs': [ - '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', - ], + 'generated_src_dirs': [ + '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', + ], }, } }, - 'hard_dependency': 1, } diff --git a/mojo/public/tools/prepend.py b/mojo/public/tools/prepend.py new file mode 100755 index 0000000..de70a82 --- /dev/null +++ b/mojo/public/tools/prepend.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# +# 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. + +""" +Prepends a given file with a given line. This can be used to add a shebang line +to a generated file. +""" + +import optparse +import os +import shutil +import sys + + +def main(): + parser = optparse.OptionParser() + parser.add_option('--input', help='The file to prepend the line to.') + parser.add_option('--line', help='The line to be prepended.') + parser.add_option('--output', help='The output file.') + + options, _ = parser.parse_args() + input_path = options.input + output_path = options.output + line = options.line + + # Warning - this reads all of the input file into memory. + with open(output_path, 'w') as output_file: + output_file.write(line + '\n') + with open(input_path, 'r') as input_file: + shutil.copyfileobj(input_file, output_file) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/mojo/services/public/cpp/geometry/BUILD.gn b/mojo/services/public/cpp/geometry/BUILD.gn index 1556d06..bf2b577 100644 --- a/mojo/services/public/cpp/geometry/BUILD.gn +++ b/mojo/services/public/cpp/geometry/BUILD.gn @@ -6,4 +6,6 @@ source_set("geometry") { sources = [ "geometry_util.h", ] + + deps = [ "//mojo/services/public/interfaces/geometry" ] } diff --git a/mojo/services/public/cpp/network/BUILD.gn b/mojo/services/public/cpp/network/BUILD.gn index 045c0b7..f8db162 100644 --- a/mojo/services/public/cpp/network/BUILD.gn +++ b/mojo/services/public/cpp/network/BUILD.gn @@ -3,15 +3,6 @@ # found in the LICENSE file. source_set("network") { - deps = [ - "//base", - "//mojo/application", - "//mojo/common", - "//mojo/environment:chromium", - "//mojo/public/c/system:for_component", - "//mojo/services/public/interfaces/network", - ] - sources = [ "udp_socket_wrapper.cc", "udp_socket_wrapper.h", @@ -20,4 +11,14 @@ source_set("network") { "web_socket_write_queue.cc", "web_socket_write_queue.h", ] + + deps = [ + "//base", + "//mojo/application", + "//mojo/common", + "//mojo/environment:chromium", + "//mojo/public/c/system:for_component", + "//mojo/public/cpp/system", + "//mojo/services/public/interfaces/network", + ] } diff --git a/mojo/services/public/interfaces/gpu/BUILD.gn b/mojo/services/public/interfaces/gpu/BUILD.gn index efb72a5..8fe2f9c 100644 --- a/mojo/services/public/interfaces/gpu/BUILD.gn +++ b/mojo/services/public/interfaces/gpu/BUILD.gn @@ -9,6 +9,7 @@ mojom("gpu") { "command_buffer.mojom", "gpu.mojom", "gpu_capabilities.mojom", + "viewport_parameter_listener.mojom", ] deps = [ diff --git a/mojo/services/public/interfaces/gpu/gpu.mojom b/mojo/services/public/interfaces/gpu/gpu.mojom index c3d473d..a765c1c 100644 --- a/mojo/services/public/interfaces/gpu/gpu.mojom +++ b/mojo/services/public/interfaces/gpu/gpu.mojom @@ -6,8 +6,12 @@ module mojo; import "mojo/services/public/interfaces/geometry/geometry.mojom"; import "mojo/services/public/interfaces/gpu/command_buffer.mojom"; +import "mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom"; interface Gpu { - CreateOnscreenGLES2Context(uint64 native_viewport_id, Size? size, CommandBuffer&? gles2_client); + CreateOnscreenGLES2Context(uint64 native_viewport_id, + Size? size, + CommandBuffer&? gles2_client, + ViewportParameterListener? listener); CreateOffscreenGLES2Context(CommandBuffer&? gles2_client); }; diff --git a/mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom b/mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom new file mode 100644 index 0000000..5afa931 --- /dev/null +++ b/mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom @@ -0,0 +1,12 @@ +// 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. + +module mojo; + +interface ViewportParameterListener { + // These parameters describe the refresh rate of the viewport. The viewport + // refreshes every |interval| time ticks. The phase of the refresh is + // indicated by |timebase|, which is synchronized with MojoGetTimeTicksNow. + OnVSyncParametersUpdated(int64 timebase, int64 interval); +}; diff --git a/mojo/services/public/interfaces/surfaces/surfaces.mojom b/mojo/services/public/interfaces/surfaces/surfaces.mojom index 21149ab..0df7ea4c 100644 --- a/mojo/services/public/interfaces/surfaces/surfaces.mojom +++ b/mojo/services/public/interfaces/surfaces/surfaces.mojom @@ -6,6 +6,7 @@ module mojo; import "mojo/services/public/interfaces/geometry/geometry.mojom"; import "mojo/services/public/interfaces/gpu/command_buffer.mojom"; +import "mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom"; import "mojo/services/public/interfaces/surfaces/quads.mojom"; import "mojo/services/public/interfaces/surfaces/surface_id.mojom"; @@ -61,11 +62,15 @@ interface Surface { // connection's namespace in the upper 32 bits. CreateSurface(SurfaceId id, Size size); - // The client can only submit frames to surfaces created with this connection. - SubmitFrame(SurfaceId id, Frame frame); + // The client can only submit frames to surfaces created with this + // connection. After the submitted frame is drawn for the first time, the + // surface will respond to the SubmitFrame message. Clients should use this + // acknowledgement to ratelimit frame submissions. + SubmitFrame(SurfaceId id, Frame frame) => (); DestroySurface(SurfaceId id); CreateGLES2BoundSurface(CommandBuffer gles2_client, SurfaceId id, - Size size); + Size size, + ViewportParameterListener& listener); }; diff --git a/mojo/services/public/mojo_services_public.gyp b/mojo/services/public/mojo_services_public.gyp index 701d7e5..aab34f97 100644 --- a/mojo/services/public/mojo_services_public.gyp +++ b/mojo/services/public/mojo_services_public.gyp @@ -83,6 +83,7 @@ 'interfaces/gpu/command_buffer.mojom', 'interfaces/gpu/gpu.mojom', 'interfaces/gpu/gpu_capabilities.mojom', + 'interfaces/gpu/viewport_parameter_listener.mojom', ], 'includes': [ '../../public/tools/bindings/mojom_bindings_generator.gypi' ], 'dependencies': [ |