diff options
author | viettrungluu <viettrungluu@chromium.org> | 2015-02-06 15:15:32 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-06 23:16:17 +0000 |
commit | c2e11810044fe5ff1c1b8588103671925a5b74fe (patch) | |
tree | 21d27627d9f117013d375c6977e8a1bbf23fad9c /third_party/mojo | |
parent | 37bacf082d54dafe0dc8b6d1ba10e294374f8036 (diff) | |
download | chromium_src-c2e11810044fe5ff1c1b8588103671925a5b74fe.zip chromium_src-c2e11810044fe5ff1c1b8588103671925a5b74fe.tar.gz chromium_src-c2e11810044fe5ff1c1b8588103671925a5b74fe.tar.bz2 |
Update mojo sdk to rev 8d45c89c30b230843c5bd6dd0693a555750946c0
[Taken over from blundell's https://codereview.chromium.org/901843003/,
PS3.]
Adapt to de-clienting of Surface.
Have nacl_listener pass a SimplePlatformSupport instance to
mojo::embedder::Init to satisfy the DCHECK introduced in
https://codereview.chromium.org/898623002/diff/40001/mojo/edk/embedder/embedder.cc.
[Additional fix backported from
https://codereview.chromium.org/898423002/.]
Fix mojo::embedder::CreateChannel(): the evaluation order between the
channel_info->channel_id and channel_info.release() is undefined.
TBR=blundell@chromium.org
NOPRESUBMIT=true
Review URL: https://codereview.chromium.org/904103003
Cr-Commit-Position: refs/heads/master@{#315128}
Diffstat (limited to 'third_party/mojo')
91 files changed, 1453 insertions, 932 deletions
diff --git a/third_party/mojo/src/mojo/edk/DEPS b/third_party/mojo/src/mojo/edk/DEPS deleted file mode 100644 index 9a51b60..0000000 --- a/third_party/mojo/src/mojo/edk/DEPS +++ /dev/null @@ -1,7 +0,0 @@ -include_rules = [ - "-mojo", - "+mojo/edk", - "+mojo/public", - - "+third_party/ashmem", -] diff --git a/third_party/mojo/src/mojo/edk/embedder/DEPS b/third_party/mojo/src/mojo/edk/embedder/DEPS deleted file mode 100644 index c3a0d22..0000000 --- a/third_party/mojo/src/mojo/edk/embedder/DEPS +++ /dev/null @@ -1,11 +0,0 @@ -include_rules = [ - "+mojo/edk/system/system_impl_export.h", -] - -specific_include_rules = { - # Implementation files may freely access mojo/edk/system, but we don't want to - # leak implementation details through the headers. - ".*\.cc": [ - "+mojo/edk/system", - ] -} diff --git a/third_party/mojo/src/mojo/edk/embedder/channel_init.cc b/third_party/mojo/src/mojo/edk/embedder/channel_init.cc index 9a0bfce..0b6d76c 100644 --- a/third_party/mojo/src/mojo/edk/embedder/channel_init.cc +++ b/third_party/mojo/src/mojo/edk/embedder/channel_init.cc @@ -15,6 +15,9 @@ ChannelInit::ChannelInit() : channel_info_(nullptr), weak_factory_(this) { } ChannelInit::~ChannelInit() { + // TODO(vtl): This is likely leaky in common scenarios (we're on the main + // thread, which outlives the I/O thread, and we're destroyed after the I/O + // thread is destroyed. if (channel_info_) DestroyChannel(channel_info_); } @@ -22,14 +25,12 @@ ChannelInit::~ChannelInit() { ScopedMessagePipeHandle ChannelInit::Init( base::PlatformFile file, scoped_refptr<base::TaskRunner> io_thread_task_runner) { - DCHECK(!io_thread_task_runner_); // Should only init once. - io_thread_task_runner_ = io_thread_task_runner; ScopedMessagePipeHandle message_pipe = - CreateChannel( - ScopedPlatformHandle(PlatformHandle(file)), io_thread_task_runner, - base::Bind(&ChannelInit::OnCreatedChannel, weak_factory_.GetWeakPtr(), - io_thread_task_runner), - base::MessageLoop::current()->message_loop_proxy()).Pass(); + CreateChannel(ScopedPlatformHandle(PlatformHandle(file)), + io_thread_task_runner, + base::Bind(&ChannelInit::OnCreatedChannel, + weak_factory_.GetWeakPtr()), + base::MessageLoop::current()->task_runner()).Pass(); return message_pipe.Pass(); } @@ -40,7 +41,6 @@ void ChannelInit::WillDestroySoon() { // static void ChannelInit::OnCreatedChannel(base::WeakPtr<ChannelInit> self, - scoped_refptr<base::TaskRunner> io_thread, ChannelInfo* channel) { // If |self| was already destroyed, shut the channel down. if (!self) { @@ -48,6 +48,7 @@ void ChannelInit::OnCreatedChannel(base::WeakPtr<ChannelInit> self, return; } + DCHECK(!self->channel_info_); self->channel_info_ = channel; } diff --git a/third_party/mojo/src/mojo/edk/embedder/channel_init.h b/third_party/mojo/src/mojo/edk/embedder/channel_init.h index 59b6694..478da41 100644 --- a/third_party/mojo/src/mojo/edk/embedder/channel_init.h +++ b/third_party/mojo/src/mojo/edk/embedder/channel_init.h @@ -28,7 +28,7 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelInit { ~ChannelInit(); // Initializes the channel. This takes ownership of |file|. Returns the - // primordial MessagePipe for the channel. + // primordial |MessagePipe| for the channel. mojo::ScopedMessagePipeHandle Init( base::PlatformFile file, scoped_refptr<base::TaskRunner> io_thread_task_runner); @@ -41,11 +41,8 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelInit { // established. (This is a static method that takes a weak pointer to self, // since we want to destroy the channel even if we're destroyed.) static void OnCreatedChannel(base::WeakPtr<ChannelInit> self, - scoped_refptr<base::TaskRunner> io_thread, ChannelInfo* channel); - scoped_refptr<base::TaskRunner> io_thread_task_runner_; - // If non-null the channel has been established. ChannelInfo* channel_info_; diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc index 1d12c1e..0150dcb 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc @@ -4,6 +4,7 @@ #include "mojo/edk/embedder/embedder.h" +#include "base/atomicops.h" #include "base/bind.h" #include "base/location.h" #include "base/logging.h" @@ -25,42 +26,25 @@ namespace embedder { namespace { -// Helper for |CreateChannel...()|. Returns 0 on failure. Called on the channel -// creation thread. -system::ChannelId MakeChannel( - ScopedPlatformHandle platform_handle, - scoped_refptr<system::ChannelEndpoint> channel_endpoint) { - DCHECK(platform_handle.is_valid()); - - // Create and initialize a |system::Channel|. - DCHECK(internal::g_core); - scoped_refptr<system::Channel> channel = - new system::Channel(internal::g_core->platform_support()); - channel->Init(system::RawChannel::Create(platform_handle.Pass())); - channel->SetBootstrapEndpoint(channel_endpoint); - - DCHECK(internal::g_channel_manager); - return internal::g_channel_manager->AddChannel( - channel, base::MessageLoopProxy::current()); -} - -// Helper for |CreateChannel()|. Called on the channel creation thread. -void CreateChannelHelper( - ScopedPlatformHandle platform_handle, - scoped_ptr<ChannelInfo> channel_info, - scoped_refptr<system::ChannelEndpoint> channel_endpoint, - DidCreateChannelCallback callback, - scoped_refptr<base::TaskRunner> callback_thread_task_runner) { - channel_info->channel_id = - MakeChannel(platform_handle.Pass(), channel_endpoint); - - // Hand the channel back to the embedder. - if (callback_thread_task_runner) { - callback_thread_task_runner->PostTask( - FROM_HERE, base::Bind(callback, channel_info.release())); - } else { - callback.Run(channel_info.release()); - } +// TODO(vtl): For now, we need this to be thread-safe (since theoretically we +// currently support multiple channel creation threads -- possibly one per +// channel). Eventually, we won't need it to be thread-safe (we'll require a +// single I/O thread), and eventually we won't need it at all. Remember to +// remove the base/atomicops.h include. +system::ChannelId MakeChannelId() { + // Note that |AtomicWord| is signed. + static base::subtle::AtomicWord counter = 0; + + base::subtle::AtomicWord new_counter_value = + base::subtle::NoBarrier_AtomicIncrement(&counter, 1); + // Don't allow the counter to wrap. Note that any (strictly) positive value is + // a valid |ChannelId| (and |NoBarrier_AtomicIncrement()| returns the value + // post-increment). + CHECK_GT(new_counter_value, 0); + // Use "negative" values for these IDs, so that we'll also be able to use + // "positive" "process identifiers" (see connection_manager.h) as IDs (and + // they won't conflict). + return static_cast<system::ChannelId>(-new_counter_value); } } // namespace @@ -68,16 +52,24 @@ void CreateChannelHelper( namespace internal { // Declared in embedder_internal.h. +PlatformSupport* g_platform_support = nullptr; system::Core* g_core = nullptr; system::ChannelManager* g_channel_manager = nullptr; } // namespace internal void Init(scoped_ptr<PlatformSupport> platform_support) { + DCHECK(platform_support); + + DCHECK(!internal::g_platform_support); + internal::g_platform_support = platform_support.release(); + DCHECK(!internal::g_core); - internal::g_core = new system::Core(platform_support.Pass()); + internal::g_core = new system::Core(internal::g_platform_support); + DCHECK(!internal::g_channel_manager); - internal::g_channel_manager = new system::ChannelManager(); + internal::g_channel_manager = + new system::ChannelManager(internal::g_platform_support); } Configuration* GetConfiguration() { @@ -99,8 +91,9 @@ ScopedMessagePipeHandle CreateChannelOnIOThread( ScopedMessagePipeHandle rv( MessagePipeHandle(internal::g_core->AddDispatcher(dispatcher))); - *channel_info = - new ChannelInfo(MakeChannel(platform_handle.Pass(), channel_endpoint)); + *channel_info = new ChannelInfo(MakeChannelId()); + internal::g_channel_manager->CreateChannelOnIOThread( + (*channel_info)->channel_id, platform_handle.Pass(), channel_endpoint); return rv.Pass(); } @@ -126,14 +119,16 @@ ScopedMessagePipeHandle CreateChannel( scoped_ptr<ChannelInfo> channel_info(new ChannelInfo()); if (rv.is_valid()) { - io_thread_task_runner->PostTask( - FROM_HERE, - base::Bind(&CreateChannelHelper, base::Passed(&platform_handle), - base::Passed(&channel_info), channel_endpoint, callback, - callback_thread_task_runner)); + system::ChannelId channel_id = MakeChannelId(); + channel_info->channel_id = channel_id; + internal::g_channel_manager->CreateChannel( + channel_id, platform_handle.Pass(), channel_endpoint, + io_thread_task_runner, + base::Bind(callback, base::Unretained(channel_info.release())), + callback_thread_task_runner); } else { - (callback_thread_task_runner.get() ? callback_thread_task_runner - : io_thread_task_runner) + (callback_thread_task_runner ? callback_thread_task_runner + : io_thread_task_runner) ->PostTask(FROM_HERE, base::Bind(callback, channel_info.release())); } diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.h b/third_party/mojo/src/mojo/edk/embedder/embedder.h index 987c6879..cc0ad26 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder.h +++ b/third_party/mojo/src/mojo/edk/embedder/embedder.h @@ -20,13 +20,12 @@ namespace embedder { struct Configuration; class PlatformSupport; -// Must be called first, or just after setting configuration parameters, -// to initialize the (global, singleton) system. +// Must be called first, or just after setting configuration parameters, to +// initialize the (global, singleton) system. MOJO_SYSTEM_IMPL_EXPORT void Init(scoped_ptr<PlatformSupport> platform_support); -// Returns the global configuration. In general there should be no need to -// change the configuration, but if you do so this must be done before calling -// |Init()|. +// Returns the global configuration. In general, you should not need to change +// the configuration, but if you do you must do it before calling |Init()|. MOJO_SYSTEM_IMPL_EXPORT Configuration* GetConfiguration(); // A "channel" is a connection on top of an OS "pipe", on top of which Mojo @@ -64,8 +63,6 @@ MOJO_SYSTEM_IMPL_EXPORT Configuration* GetConfiguration(); // // The destruction functions are similarly synchronous and asynchronous, // respectively, and take the |ChannelInfo*| produced by the creation functions. -// -// TODO(vtl): Figure out channel teardown. // Creates a channel; must only be called from the I/O thread. |platform_handle| // should be a handle to a connected OS "pipe". Eventually (even on failure), @@ -95,6 +92,9 @@ CreateChannel(ScopedPlatformHandle platform_handle, // should be the value provided to the callback to |CreateChannel()| (or // returned by |CreateChannelOnIOThread()|). If called from the I/O thread, this // will complete synchronously (in particular, it will post no tasks). +// TODO(vtl): If called from some other thread, it'll post tasks to the I/O +// thread. This is obviously potentially problematic if you want to shut the I/O +// thread down. MOJO_SYSTEM_IMPL_EXPORT void DestroyChannel(ChannelInfo* channel_info); // Inform the channel that it will soon be destroyed (doing so is optional). diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h b/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h index ab8388a..536e0db 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h +++ b/third_party/mojo/src/mojo/edk/embedder/embedder_internal.h @@ -19,12 +19,14 @@ class ChannelManager; class Core; // Repeat a typedef in mojo/edk/system/channel_manager.h, to avoid including it. -typedef uintptr_t ChannelId; +typedef uint64_t ChannelId; } // namespace system namespace embedder { +class PlatformSupport; + // This is a type that's opaque to users of the embedder API (which only // gives/takes |ChannelInfo*|s). We make it a struct to make it // template-friendly. @@ -37,6 +39,9 @@ struct ChannelInfo { namespace internal { +// Instance of |PlatformSupport| to use. +extern PlatformSupport* g_platform_support; + // Instance of |Core| used by the system functions (|Mojo...()|). extern system::Core* g_core; diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc b/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc index ed4ea2e..fd1c04c 100644 --- a/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc +++ b/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc @@ -44,7 +44,7 @@ class ScopedTestChannel { ScopedPlatformHandle platform_handle) : io_thread_task_runner_(io_thread_task_runner), bootstrap_message_pipe_(MOJO_HANDLE_INVALID), - did_create_channel_event_(true, false), + did_create_channel_event_(true, false), // Manual reset. channel_info_(nullptr) { bootstrap_message_pipe_ = CreateChannel(platform_handle.Pass(), io_thread_task_runner_, @@ -58,7 +58,11 @@ class ScopedTestChannel { // Destructor: Shuts down the channel. (As noted above, for this to happen, // the I/O thread must be alive and pumping messages.) - ~ScopedTestChannel() { DestroyChannel(channel_info_); } + ~ScopedTestChannel() { + // |WaitForChannelCreationCompletion()| must be called before destruction. + CHECK(did_create_channel_event_.IsSignaled()); + DestroyChannel(channel_info_); + } // Waits for channel creation to be completed. void WaitForChannelCreationCompletion() { did_create_channel_event_.Wait(); } diff --git a/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc b/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc index defab41..3412626 100644 --- a/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc +++ b/third_party/mojo/src/mojo/edk/embedder/test_embedder.cc @@ -54,6 +54,11 @@ bool Shutdown() { bool rv = system::internal::ShutdownCheckNoLeaks(internal::g_core); delete internal::g_core; internal::g_core = nullptr; + + CHECK(internal::g_platform_support); + delete internal::g_platform_support; + internal::g_platform_support = nullptr; + return rv; } diff --git a/third_party/mojo/src/mojo/edk/js/DEPS b/third_party/mojo/src/mojo/edk/js/DEPS deleted file mode 100644 index c350edf..0000000 --- a/third_party/mojo/src/mojo/edk/js/DEPS +++ /dev/null @@ -1,5 +0,0 @@ -include_rules = [ - "+base", - "+gin", - "+v8", -] diff --git a/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp.mojom b/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp.mojom index 69f67b6..688b22b 100644 --- a/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp.mojom +++ b/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp.mojom @@ -44,8 +44,9 @@ interface CppSide { BackPointerResponse(EchoArgsList arg); }; -[Client=CppSide] interface JsSide { + SetCppSide(CppSide cpp); + Ping(); Echo(int32 numIterations, EchoArgs arg); BitFlip(EchoArgs arg); diff --git a/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.cc b/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.cc index 1da70c2..3675f97 100644 --- a/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.cc +++ b/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.cc @@ -193,11 +193,11 @@ void CheckCorruptedEchoArgsList(const js_to_cpp::EchoArgsListPtr& list) { // run_loop(). class CppSideConnection : public js_to_cpp::CppSide { public: - CppSideConnection() : - run_loop_(NULL), - js_side_(NULL), - mishandled_messages_(0) { - } + CppSideConnection() + : run_loop_(nullptr), + js_side_(nullptr), + mishandled_messages_(0), + binding_(this) {} ~CppSideConnection() override {} void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; } @@ -206,6 +206,12 @@ class CppSideConnection : public js_to_cpp::CppSide { void set_js_side(js_to_cpp::JsSide* js_side) { js_side_ = js_side; } js_to_cpp::JsSide* js_side() { return js_side_; } + void Bind(InterfaceRequest<js_to_cpp::CppSide> request) { + binding_.Bind(request.Pass()); + // Keep the pipe open even after validation errors. + binding_.internal_router()->EnableTestingMode(); + } + // js_to_cpp::CppSide: void StartTest() override { NOTREACHED(); } @@ -229,6 +235,7 @@ class CppSideConnection : public js_to_cpp::CppSide { base::RunLoop* run_loop_; js_to_cpp::JsSide* js_side_; int mishandled_messages_; + mojo::Binding<js_to_cpp::CppSide> binding_; private: DISALLOW_COPY_AND_ASSIGN(CppSideConnection); @@ -363,21 +370,22 @@ class JsToCppTest : public testing::Test { void RunTest(const std::string& test, CppSideConnection* cpp_side) { cpp_side->set_run_loop(&run_loop_); - MessagePipe pipe; - js_to_cpp::JsSidePtr js_side = - MakeProxy<js_to_cpp::JsSide>(pipe.handle0.Pass()); - js_side.set_client(cpp_side); - - js_side.internal_state()->router_for_testing()->EnableTestingMode(); + js_to_cpp::JsSidePtr js_side; + auto js_side_proxy = GetProxy(&js_side); cpp_side->set_js_side(js_side.get()); + js_to_cpp::CppSidePtr cpp_side_ptr; + cpp_side->Bind(GetProxy(&cpp_side_ptr)); + + js_side->SetCppSide(cpp_side_ptr.Pass()); gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode, gin::ArrayBufferAllocator::SharedInstance()); gin::IsolateHolder instance; MojoRunnerDelegate delegate; gin::ShellRunner runner(&delegate, instance.isolate()); - delegate.Start(&runner, pipe.handle1.release().value(), test); + delegate.Start(&runner, js_side_proxy.PassMessagePipe().release().value(), + test); run_loop_.Run(); } diff --git a/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.js b/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.js index 140ad4c..ddecc4b 100644 --- a/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.js +++ b/third_party/mojo/src/mojo/edk/js/tests/js_to_cpp_tests.js @@ -5,11 +5,13 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [ 'console', 'mojo/edk/js/tests/js_to_cpp.mojom', + 'mojo/public/js/bindings', 'mojo/public/js/connection', 'mojo/public/js/connector', 'mojo/public/js/core', -], function (console, jsToCpp, connection, connector, core) { - var retainedConnection; +], function (console, jsToCpp, bindings, connection, connector, core) { + var retainedJsSide; + var retainedJsSideStub; var sampleData; var sampleMessage; var BAD_VALUE = 13; @@ -25,6 +27,11 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [ JsSideConnection.prototype = Object.create(jsToCpp.JsSide.stubClass.prototype); + JsSideConnection.prototype.setCppSide = function(cppSide) { + this.cppSide_ = cppSide; + this.cppSide_.startTest(); + }; + JsSideConnection.prototype.ping = function (arg) { this.cppSide_.pingResponse(); }; @@ -203,13 +210,7 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [ }, null); } - function createCppSideConnection(handle, stubClass, proxyClass) { - var c = new connection.Connection(handle, stubClass, proxyClass); - c.local.cppSide_ = c.remote; - return c; - } - - return function(handle) { + return function(jsSideRequestHandle) { var i; sampleData = new Uint8Array(DATA_PIPE_PARAMS.capacityNumBytes); for (i = 0; i < sampleData.length; ++i) { @@ -219,8 +220,9 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [ for (i = 0; i < sampleMessage.length; ++i) { sampleMessage[i] = 255 - i; } - retainedConnection = createCppSideConnection( - handle, JsSideConnection,jsToCpp.CppSide.proxyClass); - retainedConnection.remote.startTest(); + retainedJsSideStub = + connection.bindHandleToStub(jsSideRequestHandle, jsToCpp.JsSide); + retainedJsSide = new JsSideConnection; + bindings.StubBindings(retainedJsSideStub).delegate = retainedJsSide; }; }); diff --git a/third_party/mojo/src/mojo/edk/system/BUILD.gn b/third_party/mojo/src/mojo/edk/system/BUILD.gn index 12fa225..d9dc930 100644 --- a/third_party/mojo/src/mojo/edk/system/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/system/BUILD.gn @@ -123,6 +123,14 @@ component("system") { allow_circular_includes_from = [ "../embedder" ] } +group("tests") { + testonly = true + deps = [ + ":mojo_system_unittests", + ":mojo_message_pipe_perftests", + ] +} + mojo_edk_source_set("test_utils") { testonly = true @@ -137,7 +145,6 @@ mojo_edk_source_set("test_utils") { ] } -# GYP version: mojo/edk/mojo_edk.gyp:mojo_system_unittests test("mojo_system_unittests") { sources = [ "../test/multiprocess_test_helper_unittest.cc", @@ -184,7 +191,6 @@ test("mojo_system_unittests") { allow_circular_includes_from = [ "../embedder:embedder_unittests" ] } -# GYP version: mojo/edk/mojo_edk.gyp:mojo_message_pipe_perftests test("mojo_message_pipe_perftests") { sources = [ "message_pipe_perftest.cc", diff --git a/third_party/mojo/src/mojo/edk/system/DEPS b/third_party/mojo/src/mojo/edk/system/DEPS deleted file mode 100644 index 4ef4138..0000000 --- a/third_party/mojo/src/mojo/edk/system/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+crypto", -] diff --git a/third_party/mojo/src/mojo/edk/system/channel.h b/third_party/mojo/src/mojo/edk/system/channel.h index 3961859..93ba87a 100644 --- a/third_party/mojo/src/mojo/edk/system/channel.h +++ b/third_party/mojo/src/mojo/edk/system/channel.h @@ -54,8 +54,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel : public base::RefCountedThreadSafe<Channel>, public RawChannel::Delegate { public: - // |platform_support| (typically owned by |Core|) must remain alive until - // after |Shutdown()| is called. + // |platform_support| must remain alive until after |Shutdown()| is called. explicit Channel(embedder::PlatformSupport* platform_support); // This must be called on the creation thread before any other methods are @@ -65,7 +64,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // Sets the channel manager associated with this channel. This should be set // at most once and only called before |WillShutdownSoon()| (and - // |Shutdown()|). + // |Shutdown()|). (This is called by the channel manager when adding a + // channel; this should not be called before the channel is managed by the + // channel manager.) void SetChannelManager(ChannelManager* channel_manager); // This must be called on the creation thread before destruction (which can diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager.cc b/third_party/mojo/src/mojo/edk/system/channel_manager.cc index 4e58f89..c2fe8a5 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_manager.cc @@ -5,8 +5,10 @@ #include "mojo/edk/system/channel_manager.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/location.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/task_runner.h" namespace mojo { namespace system { @@ -26,7 +28,8 @@ void ShutdownChannelHelper(const ChannelInfo& channel_info) { } // namespace -ChannelManager::ChannelManager() { +ChannelManager::ChannelManager(embedder::PlatformSupport* platform_support) + : platform_support_(platform_support) { } ChannelManager::~ChannelManager() { @@ -35,24 +38,57 @@ ChannelManager::~ChannelManager() { ShutdownChannelHelper(map_elem.second); } -ChannelId ChannelManager::AddChannel( - scoped_refptr<Channel> channel, - scoped_refptr<base::TaskRunner> channel_thread_task_runner) { - ChannelId channel_id = GetChannelId(channel.get()); +void ChannelManager::CreateChannelOnIOThread( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint) { + DCHECK_NE(channel_id, kInvalidChannelId); + DCHECK(platform_handle.is_valid()); + DCHECK(bootstrap_channel_endpoint); + + // Create and initialize a |system::Channel|. + scoped_refptr<system::Channel> channel = + new system::Channel(platform_support_); + channel->Init(system::RawChannel::Create(platform_handle.Pass())); + channel->SetBootstrapEndpoint(bootstrap_channel_endpoint); { base::AutoLock locker(lock_); - DCHECK(channel_infos_.find(channel_id) == channel_infos_.end()); + CHECK(channel_infos_.find(channel_id) == channel_infos_.end()); channel_infos_[channel_id] = - ChannelInfo(channel, channel_thread_task_runner); + ChannelInfo(channel, base::MessageLoopProxy::current()); } channel->SetChannelManager(this); +} + +void ChannelManager::CreateChannel( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + base::Closure callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + DCHECK(io_thread_task_runner); + DCHECK(!callback.is_null()); + // (|callback_thread_task_runner| may be null.) - return channel_id; + io_thread_task_runner->PostTask( + FROM_HERE, + base::Bind(&ChannelManager::CreateChannelHelper, base::Unretained(this), + channel_id, base::Passed(&platform_handle), + bootstrap_channel_endpoint, callback, + callback_thread_task_runner)); +} + +scoped_refptr<Channel> ChannelManager::GetChannel(ChannelId channel_id) const { + base::AutoLock locker(lock_); + auto it = channel_infos_.find(channel_id); + DCHECK(it != channel_infos_.end()); + return it->second.channel; } void ChannelManager::WillShutdownChannel(ChannelId channel_id) { - GetChannelInfo(channel_id).channel->WillShutdownSoon(); + GetChannel(channel_id)->WillShutdownSoon(); } void ChannelManager::ShutdownChannel(ChannelId channel_id) { @@ -67,11 +103,18 @@ void ChannelManager::ShutdownChannel(ChannelId channel_id) { ShutdownChannelHelper(channel_info); } -ChannelInfo ChannelManager::GetChannelInfo(ChannelId channel_id) { - base::AutoLock locker(lock_); - auto it = channel_infos_.find(channel_id); - DCHECK(it != channel_infos_.end()); - return it->second; +void ChannelManager::CreateChannelHelper( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, + base::Closure callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner) { + CreateChannelOnIOThread(channel_id, platform_handle.Pass(), + bootstrap_channel_endpoint); + if (callback_thread_task_runner) + callback_thread_task_runner->PostTask(FROM_HERE, callback); + else + callback.Run(); } } // namespace system diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager.h b/third_party/mojo/src/mojo/edk/system/channel_manager.h index bb6371b..35a4f27 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager.h +++ b/third_party/mojo/src/mojo/edk/system/channel_manager.h @@ -11,35 +11,71 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" -#include "base/task_runner.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/channel.h" #include "mojo/edk/system/channel_info.h" +namespace base { +class TaskRunner; +} + namespace mojo { + +namespace embedder { +class PlatformSupport; +} + namespace system { // IDs for |Channel|s managed by a |ChannelManager|. (IDs should be thought of // as specific to a given |ChannelManager|.) 0 is never a valid ID. -// -// Note: We currently just use the pointer of the |Channel| casted to a -// |uintptr_t|, but we reserve the right to change this. -typedef uintptr_t ChannelId; +typedef uint64_t ChannelId; + +const ChannelId kInvalidChannelId = 0; // This class manages and "owns" |Channel|s (which typically connect to other -// processes) for a given process. This class is thread-safe. +// processes) for a given process. This class is thread-safe, except as +// specifically noted. class MOJO_SYSTEM_IMPL_EXPORT ChannelManager { public: - ChannelManager(); + // |*platform_support| must remain alive longer than this object. + explicit ChannelManager(embedder::PlatformSupport* platform_support); ~ChannelManager(); - // Adds |channel| to the set of |Channel|s managed by this |ChannelManager|; - // |channel_thread_task_runner| should be the task runner for |channel|'s - // creation (a.k.a. I/O) thread. |channel| should either already be - // initialized. It should not be managed by any |ChannelManager| yet. Returns - // the ID for the added channel. - ChannelId AddChannel( - scoped_refptr<Channel> channel, - scoped_refptr<base::TaskRunner> channel_thread_task_runner); + // Creates a |Channel| and adds it to the set of channels managed by this + // |ChannelManager|. |channel_id| should be a valid |ChannelId| (i.e., + // nonzero) not "assigned" to any other |Channel| being managed by this + // |ChannelManager|. + // TODO(vtl): Currently, this should be called on any I/O thread (which will + // become the new channel's "channel thread"). Eventually, the channel manager + // will have an assigned I/O thread, on which this must be called. + // TODO(vtl): Probably this should return a message pipe dispatcher (for the + // bootstrap message pipe) instead. + void CreateChannelOnIOThread( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint); + + // Like |CreateChannelOnIOThread()|, but may be called from any thread. On + // completion, will call |callback| ("on" |io_thread_task_runner| if + // |callback_thread_task_runner| is null else by posting to using + // |callback_thread_task_runner|). Note: This will always post a task to the + // I/O thread, even if |io_thread_task_runner| is the task runner for the + // current thread. + // TODO(vtl): The |io_thread_task_runner| argument is temporary (we should use + // the channel manager's I/O thread). + // TODO(vtl): Probably this should return a message pipe dispatcher (for the + // bootstrap message pipe) instead. + void CreateChannel( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, + scoped_refptr<base::TaskRunner> io_thread_task_runner, + base::Closure callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner); + + // Gets the |Channel| with the given ID (which must exist). + scoped_refptr<Channel> GetChannel(ChannelId channel_id) const; // Informs the channel manager (and thus channel) that it will be shutdown // soon (by calling |ShutdownChannel()|). Calling this is optional (and may in @@ -50,28 +86,26 @@ class MOJO_SYSTEM_IMPL_EXPORT ChannelManager { // Shuts down the channel specified by the given ID. It is up to the caller to // guarantee that this is only called once per channel (that was added using - // |AddChannel()|). If called from the chanel's creation thread (i.e., - // |base::MessageLoopProxy::current()| is the channel thread's |TaskRunner|), - // this will complete synchronously. + // |CreateChannelOnIOThread()|). If called from the channel's creation thread + // (i.e., |base::MessageLoopProxy::current()| is the channel thread's + // |TaskRunner|), this will complete synchronously. void ShutdownChannel(ChannelId channel_id); private: - // Gets the ID for a given channel. - // - // Note: This is currently a static method and thus may be called under - // |lock_|. If this is ever made non-static (i.e., made specific to a given - // |ChannelManager|), those call sites may have to changed. - static ChannelId GetChannelId(const Channel* channel) { - return reinterpret_cast<ChannelId>(channel); - } - - // Gets the |ChannelInfo| for the channel specified by the given ID. (This - // should *not* be called under lock.) - ChannelInfo GetChannelInfo(ChannelId channel_id); + void CreateChannelHelper( + ChannelId channel_id, + embedder::ScopedPlatformHandle platform_handle, + scoped_refptr<system::ChannelEndpoint> bootstrap_channel_endpoint, + base::Closure callback, + scoped_refptr<base::TaskRunner> callback_thread_task_runner); + + embedder::PlatformSupport* const platform_support_; // Note: |Channel| methods should not be called under |lock_|. - base::Lock lock_; // Protects the members below. + mutable base::Lock lock_; // Protects the members below. + // TODO(vtl): Once we give the |ChannelManager| one single I/O thread, we can + // get rid of |ChannelInfo| (and just have ref pointers to |Channel|s). base::hash_map<ChannelId, ChannelInfo> channel_infos_; DISALLOW_COPY_AND_ASSIGN(ChannelManager); diff --git a/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc index 52f3f0e..c5aa503 100644 --- a/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/channel_manager_unittest.cc @@ -17,6 +17,8 @@ #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/simple_platform_support.h" #include "mojo/edk/system/channel.h" +#include "mojo/edk/system/channel_endpoint.h" +#include "mojo/edk/system/message_pipe_dispatcher.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { @@ -42,19 +44,20 @@ class ChannelManagerTest : public testing::Test { }; TEST_F(ChannelManagerTest, Basic) { - ChannelManager cm; - - // Hang on to a ref to the |Channel|, so that we can check that the - // |ChannelManager| takes/releases refs to it. - scoped_refptr<Channel> ch(new Channel(platform_support())); - ASSERT_TRUE(ch->HasOneRef()); + ChannelManager cm(platform_support()); embedder::PlatformChannelPair channel_pair; - ch->Init(RawChannel::Create(channel_pair.PassServerHandle())); - ChannelId id = cm.AddChannel(ch, base::MessageLoopProxy::current()); - EXPECT_NE(id, 0u); - // |ChannelManager| should take a ref. + scoped_refptr<ChannelEndpoint> cep; + scoped_refptr<MessagePipeDispatcher> d = + MessagePipeDispatcher::CreateRemoteMessagePipe(&cep); + const ChannelId id = 1; + cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle(), cep); + cep = nullptr; + + scoped_refptr<Channel> ch = cm.GetChannel(id); + EXPECT_TRUE(ch); + // |ChannelManager| should have a ref. EXPECT_FALSE(ch->HasOneRef()); cm.WillShutdownChannel(id); @@ -65,30 +68,34 @@ TEST_F(ChannelManagerTest, Basic) { // On the "I/O" thread, so shutdown should happen synchronously. // |ChannelManager| should have given up its ref. EXPECT_TRUE(ch->HasOneRef()); + + EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } TEST_F(ChannelManagerTest, TwoChannels) { - ChannelManager cm; - - // Hang on to a ref to each |Channel|, so that we can check that the - // |ChannelManager| takes/releases refs to them. - scoped_refptr<Channel> ch1(new Channel(platform_support())); - ASSERT_TRUE(ch1->HasOneRef()); - scoped_refptr<Channel> ch2(new Channel(platform_support())); - ASSERT_TRUE(ch2->HasOneRef()); + ChannelManager cm(platform_support()); embedder::PlatformChannelPair channel_pair; - ch1->Init(RawChannel::Create(channel_pair.PassServerHandle())); - ch2->Init(RawChannel::Create(channel_pair.PassClientHandle())); - ChannelId id1 = cm.AddChannel(ch1, base::MessageLoopProxy::current()); - EXPECT_NE(id1, 0u); - EXPECT_FALSE(ch1->HasOneRef()); + scoped_refptr<ChannelEndpoint> cep1; + scoped_refptr<MessagePipeDispatcher> d1 = + MessagePipeDispatcher::CreateRemoteMessagePipe(&cep1); + const ChannelId id1 = 1; + cm.CreateChannelOnIOThread(id1, channel_pair.PassServerHandle(), cep1); + cep1 = nullptr; + + scoped_refptr<ChannelEndpoint> cep2; + scoped_refptr<MessagePipeDispatcher> d2 = + MessagePipeDispatcher::CreateRemoteMessagePipe(&cep2); + const ChannelId id2 = 2; + cm.CreateChannelOnIOThread(id2, channel_pair.PassClientHandle(), cep2); + cep2 = nullptr; - ChannelId id2 = cm.AddChannel(ch2, base::MessageLoopProxy::current()); - EXPECT_NE(id2, 0u); - EXPECT_NE(id2, id1); - EXPECT_FALSE(ch2->HasOneRef()); + scoped_refptr<Channel> ch1 = cm.GetChannel(id1); + EXPECT_TRUE(ch1); + + scoped_refptr<Channel> ch2 = cm.GetChannel(id2); + EXPECT_TRUE(ch2); // Calling |WillShutdownChannel()| multiple times (on |id1|) is okay. cm.WillShutdownChannel(id1); @@ -100,45 +107,47 @@ TEST_F(ChannelManagerTest, TwoChannels) { EXPECT_TRUE(ch1->HasOneRef()); cm.ShutdownChannel(id2); EXPECT_TRUE(ch2->HasOneRef()); + + EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); + EXPECT_EQ(MOJO_RESULT_OK, d2->Close()); } class OtherThread : public base::SimpleThread { public: - // Note: We rely on the main thread keeping *exactly one* reference to - // |channel|. + // Note: There should be no other refs to the channel identified by + // |channel_id| outside the channel manager. OtherThread(scoped_refptr<base::TaskRunner> task_runner, ChannelManager* channel_manager, - Channel* channel, + ChannelId channel_id, base::Closure quit_closure) : base::SimpleThread("other_thread"), task_runner_(task_runner), channel_manager_(channel_manager), - channel_(channel), + channel_id_(channel_id), quit_closure_(quit_closure) {} ~OtherThread() override {} private: void Run() override { - // See comment above constructor. - ASSERT_TRUE(channel_->HasOneRef()); + // TODO(vtl): Once we have a way of creating a channel from off the I/O + // thread, do that here instead. - ChannelId id = channel_manager_->AddChannel(make_scoped_refptr(channel_), - task_runner_); - EXPECT_NE(id, 0u); - // |ChannelManager| should take a ref. - EXPECT_FALSE(channel_->HasOneRef()); + // You can use any unique, nonzero value as the ID. + scoped_refptr<Channel> ch = channel_manager_->GetChannel(channel_id_); + // |ChannelManager| should have a ref. + EXPECT_FALSE(ch->HasOneRef()); - channel_manager_->WillShutdownChannel(id); + channel_manager_->WillShutdownChannel(channel_id_); // |ChannelManager| should still have a ref. - EXPECT_FALSE(channel_->HasOneRef()); + EXPECT_FALSE(ch->HasOneRef()); - channel_manager_->ShutdownChannel(id); + channel_manager_->ShutdownChannel(channel_id_); // This doesn't happen synchronously, so we "wait" until it does. - // TODO(vtl): Possibly |Channel| should provide some notification of being + // TODO(vtl): Probably |Channel| should provide some notification of being // shut down. base::TimeTicks start_time(base::TimeTicks::Now()); for (;;) { - if (channel_->HasOneRef()) + if (ch->HasOneRef()) break; // Check, instead of assert, since if things go wrong, dying is more @@ -153,29 +162,32 @@ class OtherThread : public base::SimpleThread { scoped_refptr<base::TaskRunner> task_runner_; ChannelManager* channel_manager_; - Channel* channel_; + ChannelId channel_id_; base::Closure quit_closure_; DISALLOW_COPY_AND_ASSIGN(OtherThread); }; TEST_F(ChannelManagerTest, CallsFromOtherThread) { - ChannelManager cm; - - // Hang on to a ref to the |Channel|, so that we can check that the - // |ChannelManager| takes/releases refs to it. - scoped_refptr<Channel> ch(new Channel(platform_support())); - ASSERT_TRUE(ch->HasOneRef()); + ChannelManager cm(platform_support()); embedder::PlatformChannelPair channel_pair; - ch->Init(RawChannel::Create(channel_pair.PassServerHandle())); + + scoped_refptr<ChannelEndpoint> cep; + scoped_refptr<MessagePipeDispatcher> d = + MessagePipeDispatcher::CreateRemoteMessagePipe(&cep); + const ChannelId id = 1; + cm.CreateChannelOnIOThread(id, channel_pair.PassServerHandle(), cep); + cep = nullptr; base::RunLoop run_loop; - OtherThread thread(base::MessageLoopProxy::current(), &cm, ch.get(), + OtherThread thread(base::MessageLoopProxy::current(), &cm, id, run_loop.QuitClosure()); thread.Start(); run_loop.Run(); thread.Join(); + + EXPECT_EQ(MOJO_RESULT_OK, d->Close()); } } // namespace diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc index f46c386..2894c65 100644 --- a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc +++ b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc @@ -58,6 +58,11 @@ bool ArePlatformHandlesConnected(const embedder::PlatformHandle& h1, return true; } +bool IsValidSlaveProcessIdentifier(ProcessIdentifier process_identifier) { + return process_identifier != kInvalidProcessIdentifier && + process_identifier != kMasterProcessIdentifier; +} + class TestSlaveInfo : public embedder::SlaveInfo { public: explicit TestSlaveInfo(const std::string& name) : name_(name) {} @@ -200,13 +205,15 @@ TEST_F(ConnectionManagerTest, BasicConnectSlaves) { EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); - ProcessIdentifier peer1; + ProcessIdentifier peer1 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h1; EXPECT_TRUE(slave1.Connect(connection_id, &peer1, &h1)); + EXPECT_TRUE(IsValidSlaveProcessIdentifier(peer1)); EXPECT_TRUE(h1.is_valid()); - ProcessIdentifier peer2; + ProcessIdentifier peer2 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h2; EXPECT_TRUE(slave2.Connect(connection_id, &peer2, &h2)); + EXPECT_TRUE(IsValidSlaveProcessIdentifier(peer2)); EXPECT_TRUE(h2.is_valid()); // TODO(vtl): If/when I add the ability to get one's own process identifier, @@ -285,9 +292,10 @@ TEST_F(ConnectionManagerTest, SlaveCancelConnect) { EXPECT_TRUE(slave2.AllowConnect(connection_id)); EXPECT_TRUE(slave1.CancelConnect(connection_id)); - ProcessIdentifier peer2; + ProcessIdentifier peer2 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h2; EXPECT_FALSE(slave2.Connect(connection_id, &peer2, &h2)); + EXPECT_EQ(kInvalidProcessIdentifier, peer2); EXPECT_FALSE(h2.is_valid()); slave1.Shutdown(); @@ -320,9 +328,10 @@ TEST_F(ConnectionManagerTest, ErrorRemovePending) { master_process_delegate().RunUntilNotified(); EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); - ProcessIdentifier peer2; + ProcessIdentifier peer2 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h2; EXPECT_FALSE(slave2.Connect(connection_id, &peer2, &h2)); + EXPECT_EQ(kInvalidProcessIdentifier, peer2); EXPECT_FALSE(h2.is_valid()); slave2.Shutdown(); @@ -343,13 +352,15 @@ TEST_F(ConnectionManagerTest, ConnectSlaveToSelf) { // Currently, the connect-to-self case is signalled by the master not sending // back a handle. - ProcessIdentifier peer1; + ProcessIdentifier peer1 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h1; EXPECT_TRUE(slave.Connect(connection_id, &peer1, &h1)); + EXPECT_TRUE(IsValidSlaveProcessIdentifier(peer1)); EXPECT_FALSE(h1.is_valid()); - ProcessIdentifier peer2; + ProcessIdentifier peer2 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h2; EXPECT_TRUE(slave.Connect(connection_id, &peer2, &h2)); + EXPECT_TRUE(IsValidSlaveProcessIdentifier(peer2)); EXPECT_FALSE(h2.is_valid()); EXPECT_EQ(peer1, peer2); @@ -374,10 +385,10 @@ TEST_F(ConnectionManagerTest, ConnectSlavesTwice) { EXPECT_TRUE(slave1.AllowConnect(connection_id)); EXPECT_TRUE(slave2.AllowConnect(connection_id)); - ProcessIdentifier peer1; + ProcessIdentifier peer1 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h1; EXPECT_TRUE(slave1.Connect(connection_id, &peer1, &h1)); - ProcessIdentifier peer2; + ProcessIdentifier peer2 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h2; EXPECT_TRUE(slave2.Connect(connection_id, &peer2, &h2)); @@ -395,9 +406,9 @@ TEST_F(ConnectionManagerTest, ConnectSlavesTwice) { h1.reset(); h2.reset(); - ProcessIdentifier second_peer2; + ProcessIdentifier second_peer2 = kInvalidProcessIdentifier; EXPECT_TRUE(slave2.Connect(connection_id, &second_peer2, &h2)); - ProcessIdentifier second_peer1; + ProcessIdentifier second_peer1 = kInvalidProcessIdentifier; EXPECT_TRUE(slave1.Connect(connection_id, &second_peer1, &h1)); EXPECT_EQ(peer1, second_peer1); @@ -421,13 +432,15 @@ TEST_F(ConnectionManagerTest, ConnectMasterToSlave) { EXPECT_TRUE(master.AllowConnect(connection_id)); EXPECT_TRUE(slave.AllowConnect(connection_id)); - ProcessIdentifier master_peer; + ProcessIdentifier master_peer = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle master_h; EXPECT_TRUE(master.Connect(connection_id, &master_peer, &master_h)); + EXPECT_TRUE(IsValidSlaveProcessIdentifier(master_peer)); EXPECT_TRUE(master_h.is_valid()); - ProcessIdentifier slave_peer; + ProcessIdentifier slave_peer = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle slave_h; EXPECT_TRUE(slave.Connect(connection_id, &slave_peer, &slave_h)); + EXPECT_EQ(kMasterProcessIdentifier, slave_peer); EXPECT_TRUE(slave_h.is_valid()); EXPECT_NE(master_peer, slave_peer); @@ -447,13 +460,15 @@ TEST_F(ConnectionManagerTest, ConnectMasterToSelf) { // Currently, the connect-to-self case is signalled by the master not sending // back a handle. - ProcessIdentifier peer1; + ProcessIdentifier peer1 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h1; EXPECT_TRUE(master.Connect(connection_id, &peer1, &h1)); + EXPECT_EQ(kMasterProcessIdentifier, peer1); EXPECT_FALSE(h1.is_valid()); - ProcessIdentifier peer2; + ProcessIdentifier peer2 = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h2; EXPECT_TRUE(master.Connect(connection_id, &peer2, &h2)); + EXPECT_EQ(kMasterProcessIdentifier, peer2); EXPECT_FALSE(h2.is_valid()); EXPECT_EQ(peer1, peer2); @@ -474,9 +489,10 @@ TEST_F(ConnectionManagerTest, MasterCancelConnect) { EXPECT_TRUE(slave.AllowConnect(connection_id)); EXPECT_TRUE(master.CancelConnect(connection_id)); - ProcessIdentifier peer; + ProcessIdentifier peer = kInvalidProcessIdentifier; embedder::ScopedPlatformHandle h; EXPECT_FALSE(slave.Connect(connection_id, &peer, &h)); + EXPECT_EQ(kInvalidProcessIdentifier, peer); EXPECT_FALSE(h.is_valid()); slave.Shutdown(); diff --git a/third_party/mojo/src/mojo/edk/system/core.cc b/third_party/mojo/src/mojo/edk/system/core.cc index 6189e50..4460088 100644 --- a/third_party/mojo/src/mojo/edk/system/core.cc +++ b/third_party/mojo/src/mojo/edk/system/core.cc @@ -78,8 +78,8 @@ namespace system { // held. // TODO(vtl): This should take a |scoped_ptr<PlatformSupport>| as a parameter. -Core::Core(scoped_ptr<embedder::PlatformSupport> platform_support) - : platform_support_(platform_support.Pass()) { +Core::Core(embedder::PlatformSupport* platform_support) + : platform_support_(platform_support) { } Core::~Core() { @@ -469,7 +469,7 @@ MojoResult Core::CreateSharedBuffer( return result; scoped_refptr<SharedBufferDispatcher> dispatcher; - result = SharedBufferDispatcher::Create(platform_support(), validated_options, + result = SharedBufferDispatcher::Create(platform_support_, validated_options, num_bytes, &dispatcher); if (result != MOJO_RESULT_OK) { DCHECK(!dispatcher); diff --git a/third_party/mojo/src/mojo/edk/system/core.h b/third_party/mojo/src/mojo/edk/system/core.h index 0ff9c01..7833193c 100644 --- a/third_party/mojo/src/mojo/edk/system/core.h +++ b/third_party/mojo/src/mojo/edk/system/core.h @@ -39,7 +39,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { // --------------------------------------------------------------------------- // These methods are only to be used by via the embedder API (and internally): - explicit Core(scoped_ptr<embedder::PlatformSupport> platform_support); + + // |*platform_support| must outlive this object. + explicit Core(embedder::PlatformSupport* platform_support); virtual ~Core(); // Adds |dispatcher| to the handle table, returning the handle for it. Returns @@ -59,12 +61,19 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { base::Callback<void(MojoResult)> callback); embedder::PlatformSupport* platform_support() const { - return platform_support_.get(); + return platform_support_; } // --------------------------------------------------------------------------- - // System calls implementation: + // The following methods are essentially implementations of the Mojo Core + // functions of the Mojo API, with the C interface translated to C++ by + // "mojo/edk/embedder/entrypoints.cc". The best way to understand the contract + // of these methods is to look at the header files defining the corresponding + // API functions, referenced below. + + // These methods correspond to the API functions defined in + // "mojo/public/c/system/functions.h": MojoTimeTicks GetTimeTicksNow(); MojoResult Close(MojoHandle handle); MojoResult Wait(MojoHandle handle, @@ -77,6 +86,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoDeadline deadline, UserPointer<uint32_t> result_index, UserPointer<MojoHandleSignalsState> signals_states); + + // These methods correspond to the API functions defined in + // "mojo/public/c/system/message_pipe.h": MojoResult CreateMessagePipe( UserPointer<const MojoCreateMessagePipeOptions> options, UserPointer<MojoHandle> message_pipe_handle0, @@ -93,6 +105,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { UserPointer<MojoHandle> handles, UserPointer<uint32_t> num_handles, MojoReadMessageFlags flags); + + // These methods correspond to the API functions defined in + // "mojo/public/c/system/data_pipe.h": MojoResult CreateDataPipe( UserPointer<const MojoCreateDataPipeOptions> options, UserPointer<MojoHandle> data_pipe_producer_handle, @@ -117,6 +132,9 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoReadDataFlags flags); MojoResult EndReadData(MojoHandle data_pipe_consumer_handle, uint32_t num_bytes_read); + + // These methods correspond to the API functions defined in + // "mojo/public/c/system/buffer.h": MojoResult CreateSharedBuffer( UserPointer<const MojoCreateSharedBufferOptions> options, uint64_t num_bytes, @@ -146,7 +164,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { uint32_t* result_index, HandleSignalsState* signals_states); - const scoped_ptr<embedder::PlatformSupport> platform_support_; + embedder::PlatformSupport* const platform_support_; // TODO(vtl): |handle_table_lock_| should be a reader-writer lock (if only we // had them). diff --git a/third_party/mojo/src/mojo/edk/system/core_test_base.cc b/third_party/mojo/src/mojo/edk/system/core_test_base.cc index b81a051..7196886d 100644 --- a/third_party/mojo/src/mojo/edk/system/core_test_base.cc +++ b/third_party/mojo/src/mojo/edk/system/core_test_base.cc @@ -9,7 +9,6 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ref_counted.h" -#include "mojo/edk/embedder/simple_platform_support.h" #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/core.h" #include "mojo/edk/system/dispatcher.h" @@ -173,7 +172,7 @@ CoreTestBase::~CoreTestBase() { } void CoreTestBase::SetUp() { - core_ = new Core(make_scoped_ptr(new embedder::SimplePlatformSupport())); + core_ = new Core(&platform_support_); } void CoreTestBase::TearDown() { diff --git a/third_party/mojo/src/mojo/edk/system/core_test_base.h b/third_party/mojo/src/mojo/edk/system/core_test_base.h index c2b5ee2..26b7925 100644 --- a/third_party/mojo/src/mojo/edk/system/core_test_base.h +++ b/third_party/mojo/src/mojo/edk/system/core_test_base.h @@ -5,9 +5,9 @@ #ifndef MOJO_EDK_SYSTEM_CORE_TEST_BASE_H_ #define MOJO_EDK_SYSTEM_CORE_TEST_BASE_H_ -#include "base/compiler_specific.h" #include "base/macros.h" #include "base/synchronization/lock.h" +#include "mojo/edk/embedder/simple_platform_support.h" #include "mojo/public/c/system/types.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,6 +38,7 @@ class CoreTestBase : public testing::Test { Core* core() { return core_; } private: + embedder::SimplePlatformSupport platform_support_; Core* core_; DISALLOW_COPY_AND_ASSIGN(CoreTestBase); diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc index b78dfb6..4d7deae 100644 --- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc +++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc @@ -20,9 +20,14 @@ namespace mojo { namespace system { -const ProcessIdentifier kFirstProcessIdentifier = 1; -const ProcessIdentifier kMasterProcessIdentifier = - static_cast<ProcessIdentifier>(-1); +const ProcessIdentifier kFirstSlaveProcessIdentifier = 2; + +static_assert(kMasterProcessIdentifier != kInvalidProcessIdentifier, + "Bad master process identifier"); +static_assert(kFirstSlaveProcessIdentifier != kInvalidProcessIdentifier, + "Bad first slave process identifier"); +static_assert(kMasterProcessIdentifier != kFirstSlaveProcessIdentifier, + "Master and first slave process identifiers are the same"); // MasterConnectionManager::Helper --------------------------------------------- @@ -218,7 +223,7 @@ MasterConnectionManager::MasterConnectionManager() : creation_thread_task_runner_(base::MessageLoop::current()->task_runner()), master_process_delegate_(), private_thread_("MasterConnectionManagerPrivateThread"), - next_process_identifier_(kFirstProcessIdentifier) { + next_process_identifier_(kFirstSlaveProcessIdentifier) { DCHECK(creation_thread_task_runner_); AssertOnCreationThread(); // Just make sure this assertion works correctly. } diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h index dcec9c2..978d9fe 100644 --- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h +++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h @@ -30,6 +30,9 @@ class SlaveInfo; namespace system { +// The master process will always have this "process identifier". +const ProcessIdentifier kMasterProcessIdentifier = 1; + // The |ConnectionManager| implementation for the master process. // // Objects of this class must be created, initialized (via |Init()|), shut down diff --git a/third_party/mojo/src/mojo/edk/test/BUILD.gn b/third_party/mojo/src/mojo/edk/test/BUILD.gn index b130440..3a15663 100644 --- a/third_party/mojo/src/mojo/edk/test/BUILD.gn +++ b/third_party/mojo/src/mojo/edk/test/BUILD.gn @@ -76,6 +76,20 @@ mojo_edk_source_set("test_support_impl") { # Public SDK test targets follow. These targets are not defined within the # public SDK itself as running the unittests requires the EDK. +# TODO(vtl): These don't really belong here. (They should be converted to +# apptests, but even apart from that these targets belong somewhere else.) + +group("public_tests") { + testonly = true + deps = [ + ":mojo_public_application_unittests", + ":mojo_public_bindings_unittests", + ":mojo_public_environment_unittests", + ":mojo_public_system_perftests", + ":mojo_public_system_unittests", + ":mojo_public_utility_unittests", + ] +} test("mojo_public_application_unittests") { deps = [ diff --git a/third_party/mojo/src/mojo/public/DEPS b/third_party/mojo/src/mojo/public/DEPS deleted file mode 100644 index 0c679b9..0000000 --- a/third_party/mojo/src/mojo/public/DEPS +++ /dev/null @@ -1,6 +0,0 @@ -include_rules = [ - "-base", - "-build", - "-mojo", - "+mojo/public", -] diff --git a/third_party/mojo/src/mojo/public/VERSION b/third_party/mojo/src/mojo/public/VERSION index 55ad309..63d6820 100644 --- a/third_party/mojo/src/mojo/public/VERSION +++ b/third_party/mojo/src/mojo/public/VERSION @@ -1 +1 @@ -126532ce21c5c3c55a1e1693731411cb60169efd
\ No newline at end of file +8d45c89c30b230843c5bd6dd0693a555750946c0
\ No newline at end of file diff --git a/third_party/mojo/src/mojo/public/c/DEPS b/third_party/mojo/src/mojo/public/c/DEPS deleted file mode 100644 index 5272770..0000000 --- a/third_party/mojo/src/mojo/public/c/DEPS +++ /dev/null @@ -1,16 +0,0 @@ -include_rules = [ - # Require explicit dependencies in each directory. - "-mojo/public", - # But everyone can depend on the C system headers. - "+mojo/public/c/system", -] - -specific_include_rules = { - r".*_(unit|perf)test\.cc": [ - "+testing", - # Our test harness is C++, so allow the use of C++: - "+mojo/public/cpp/system", - "+mojo/public/cpp/test_support", - "+mojo/public/cpp/utility", - ], -} diff --git a/third_party/mojo/src/mojo/public/c/gles2/DEPS b/third_party/mojo/src/mojo/public/c/gles2/DEPS deleted file mode 100644 index 3887457..0000000 --- a/third_party/mojo/src/mojo/public/c/gles2/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/public/c/environment", -] diff --git a/third_party/mojo/src/mojo/public/c/system/buffer.h b/third_party/mojo/src/mojo/public/c/system/buffer.h index 97bc340..45d2c2d 100644 --- a/third_party/mojo/src/mojo/public/c/system/buffer.h +++ b/third_party/mojo/src/mojo/public/c/system/buffer.h @@ -169,9 +169,9 @@ MOJO_SYSTEM_EXPORT MojoResult MojoMapBuffer(MojoHandle buffer_handle, MojoMapBufferFlags flags); // Unmaps a buffer pointer that was mapped by |MojoMapBuffer()|. |buffer| must -// have been the result of |MojoMapBuffer()| (not some pointer strictly inside +// have been the result of |MojoMapBuffer()| (not some other pointer inside // the mapped memory), and the entire mapping will be removed (partial unmapping -// is not supported). A mapping may only be unmapped exactly once. +// is not supported). A mapping may only be unmapped once. // // Returns: // |MOJO_RESULT_OK| on success. diff --git a/third_party/mojo/src/mojo/public/c/system/data_pipe.h b/third_party/mojo/src/mojo/public/c/system/data_pipe.h index 089ead3..86126c1 100644 --- a/third_party/mojo/src/mojo/public/c/system/data_pipe.h +++ b/third_party/mojo/src/mojo/public/c/system/data_pipe.h @@ -81,8 +81,8 @@ const MojoWriteDataFlags MOJO_WRITE_DATA_FLAG_ALL_OR_NONE = 1 << 0; // elements. // |MOJO_READ_DATA_FLAG_QUERY| - Query the number of elements available to // read. For use with |MojoReadData()| only. Mutually exclusive with -// |MOJO_READ_DATA_FLAG_DISCARD| and |MOJO_READ_DATA_FLAG_ALL_OR_NONE| is -// ignored if this flag is set. +// |MOJO_READ_DATA_FLAG_DISCARD|, and |MOJO_READ_DATA_FLAG_ALL_OR_NONE| +// is ignored if this flag is set. // |MOJO_READ_DATA_FLAG_PEEK| - Read elements without removing them. For use // with |MojoReadData()| only. Mutually exclusive with // |MOJO_READ_DATA_FLAG_DISCARD| and |MOJO_READ_DATA_FLAG_QUERY|. @@ -264,8 +264,8 @@ MOJO_SYSTEM_EXPORT MojoResult // available to future reads. // // If flags has |MOJO_READ_DATA_FLAG_DISCARD| set, it discards up to -// |*num_bytes| (which again be a multiple of the element size) bytes of data, -// setting |*num_bytes| to the amount actually discarded. If flags has +// |*num_bytes| (which again must be a multiple of the element size) bytes of +// data, setting |*num_bytes| to the amount actually discarded. If flags has // |MOJO_READ_DATA_FLAG_ALL_OR_NONE|, it will either discard exactly // |*num_bytes| bytes of data or none. In this case, |MOJO_READ_DATA_FLAG_QUERY| // must not be set, and |elements| is ignored (and should typically be set to diff --git a/third_party/mojo/src/mojo/public/c/system/functions.h b/third_party/mojo/src/mojo/public/c/system/functions.h index 5e0a0c4..c53a4ed 100644 --- a/third_party/mojo/src/mojo/public/c/system/functions.h +++ b/third_party/mojo/src/mojo/public/c/system/functions.h @@ -9,8 +9,6 @@ #ifndef MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_ #define MOJO_PUBLIC_C_SYSTEM_FUNCTIONS_H_ -// Note: This header should be compilable as C. - #include "mojo/public/c/system/system_export.h" #include "mojo/public/c/system/types.h" @@ -25,9 +23,12 @@ extern "C" { // operation's success/failure. E.g., a separate |flags| parameter may control // whether a given "in/out" parameter is used for input, output, or both.) -// Platform-dependent monotonically increasing tick count representing "right -// now." The resolution of this clock is ~1-15ms. Resolution varies depending -// on hardware/operating system configuration. +// Returns the time, in microseconds, since some undefined point in the past. +// The values are only meaningful relative to other values that were obtained +// from the same device without an intervening system restart. Such values are +// guaranteed to be monotonically-increasing with the passage of real time. +// Although the units are microseconds, the resolution of the clock may vary and +// is typically in the range of ~1-15 ms. MOJO_SYSTEM_EXPORT MojoTimeTicks MojoGetTimeTicksNow(void); // Closes the given |handle|. @@ -71,7 +72,7 @@ MOJO_SYSTEM_EXPORT MojoResult MojoClose(MojoHandle handle); // end of a message pipe and the other end is closed). // // If there are multiple waiters (on different threads, obviously) waiting on -// the same handle and signal, and that signal becomes is satisfied, all waiters +// the same handle and signal, and that signal becomes satisfied, all waiters // will be awoken. MOJO_SYSTEM_EXPORT MojoResult MojoWait(MojoHandle handle, diff --git a/third_party/mojo/src/mojo/public/c/system/message_pipe.h b/third_party/mojo/src/mojo/public/c/system/message_pipe.h index 97d8887..d42c3fc 100644 --- a/third_party/mojo/src/mojo/public/c/system/message_pipe.h +++ b/third_party/mojo/src/mojo/public/c/system/message_pipe.h @@ -90,8 +90,6 @@ extern "C" { // |*options| is invalid). // |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has // been reached. -// -// TODO(vtl): Add an options struct pointer argument. MOJO_SYSTEM_EXPORT MojoResult MojoCreateMessagePipe( const struct MojoCreateMessagePipeOptions* options, // Optional. MojoHandle* message_pipe_handle0, // Out. @@ -118,7 +116,7 @@ MOJO_SYSTEM_EXPORT MojoResult MojoCreateMessagePipe( // latter case). // |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed. // Note that closing an endpoint is not necessarily synchronous (e.g., -// across processes), so this function may be succeed even if the other +// across processes), so this function may succeed even if the other // endpoint has been closed (in which case the message would be dropped). // |MOJO_RESULT_UNIMPLEMENTED| if an unsupported flag was set in |*options|. // |MOJO_RESULT_BUSY| if some handle to be sent is currently in use. @@ -133,37 +131,37 @@ MOJO_SYSTEM_EXPORT MojoResult uint32_t num_handles, MojoWriteMessageFlags flags); -// Reads a message from the message pipe endpoint given by -// |message_pipe_handle|; also usable to query the size of the next message or -// discard the next message. |bytes|/|*num_bytes| indicate the buffer/buffer -// size to receive the message data (if any) and |handles|/|*num_handles| -// indicate the buffer/maximum handle count to receive the attached handles (if -// any). -// -// |num_bytes| and |num_handles| are optional "in-out" parameters. If non-null, -// on return |*num_bytes| and |*num_handles| will usually indicate the number -// of bytes and number of attached handles in the "next" message, respectively, -// whether that message was read or not. (If null, the number of bytes/handles -// is treated as zero.) +// Reads the next message from a message pipe, or indicates the size of the +// message if it cannot fit in the provided buffers. The message will be read +// in its entirety or not at all; if it is not, it will remain enqueued unless +// the |MOJO_READ_MESSAGE_FLAG_MAY_DISCARD| flag was passed. At most one +// message will be consumed from the queue, and the return value will indicate +// whether a message was successfully read. // -// If |bytes| is null, then |*num_bytes| must be zero, and similarly for -// |handles| and |*num_handles|. +// |num_bytes| and |num_handles| are optional in/out parameters that on input +// must be set to the sizes of the |bytes| and |handles| arrays, and on output +// will be set to the actual number of bytes or handles contained in the +// message (even if the message was not retrieved due to being too large). +// Either |num_bytes| or |num_handles| may be null if the message is not +// expected to contain the corresponding type of data, but such a call would +// fail with |MOJO_RESULT_RESOURCE_EXHAUSTED| if the message in fact did +// contain that type of data. // -// Partial reads are NEVER done. Either a full read is done and |MOJO_RESULT_OK| -// returned, or the read is NOT done and |MOJO_RESULT_RESOURCE_EXHAUSTED| is -// returned (if |MOJO_READ_MESSAGE_FLAG_MAY_DISCARD| was set, the message is -// also discarded in this case). +// |bytes| and |handles| will receive the contents of the message, if it is +// retrieved. Either or both may be null, in which case the corresponding size +// parameter(s) must also be set to zero or passed as null. // // Returns: // |MOJO_RESULT_OK| on success (i.e., a message was actually read). // |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid. // |MOJO_RESULT_FAILED_PRECONDITION| if the other endpoint has been closed. -// |MOJO_RESULT_RESOURCE_EXHAUSTED| if one of the buffers to receive the -// message/attached handles (|bytes|/|*num_bytes| or -// |handles|/|*num_handles|) was too small. (TODO(vtl): Reconsider this -// error code; should distinguish this from the hitting-system-limits -// case.) +// |MOJO_RESULT_RESOURCE_EXHAUSTED| if the message was too large to fit in the +// provided buffer(s). The message will have been left in the queue or +// discarded, depending on flags. // |MOJO_RESULT_SHOULD_WAIT| if no message was available to be read. +// +// TODO(vtl): Reconsider the |MOJO_RESULT_RESOURCE_EXHAUSTED| error code; should +// distinguish this from the hitting-system-limits case. MOJO_SYSTEM_EXPORT MojoResult MojoReadMessage(MojoHandle message_pipe_handle, void* bytes, // Optional out. diff --git a/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc b/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc index 2f3ef62..71e61f4 100644 --- a/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc +++ b/third_party/mojo/src/mojo/public/c/system/tests/core_unittest.cc @@ -109,6 +109,9 @@ TEST(CoreTest, BasicMessagePipe) { EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, state.satisfied_signals); EXPECT_EQ(kSignalAll, state.satisfiable_signals); + // Last parameter is optional. + EXPECT_EQ(MOJO_RESULT_OK, MojoWait(h0, MOJO_HANDLE_SIGNAL_WRITABLE, 0, NULL)); + // Try to read. buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, diff --git a/third_party/mojo/src/mojo/public/c/system/types.h b/third_party/mojo/src/mojo/public/c/system/types.h index a88b024..9f85fbb 100644 --- a/third_party/mojo/src/mojo/public/c/system/types.h +++ b/third_party/mojo/src/mojo/public/c/system/types.h @@ -17,7 +17,8 @@ // TODO(vtl): Notes: Use of undefined flags will lead to undefined behavior // (typically they'll be ignored), not necessarily an error. -// |MojoTimeTicks|: Used to specify time ticks. Value is in microseconds. +// |MojoTimeTicks|: A time delta, in microseconds, the meaning of which is +// source-dependent. typedef int64_t MojoTimeTicks; diff --git a/third_party/mojo/src/mojo/public/cpp/DEPS b/third_party/mojo/src/mojo/public/cpp/DEPS deleted file mode 100644 index 74acd7c..0000000 --- a/third_party/mojo/src/mojo/public/cpp/DEPS +++ /dev/null @@ -1,18 +0,0 @@ -include_rules = [ - # Require explicit dependencies in each directory. - "-mojo/public", - # But everyone can depend on the C and C++ system headers. - "+mojo/public/c/system", - "+mojo/public/cpp/system", - # Ditto for the C environment headers (but not the C++ environment, since it - # has dependencies of its own). - "+mojo/public/c/environment", -] - -specific_include_rules = { - r".*_(unit|perf)test\.cc": [ - "+testing", - "+mojo/public/cpp/test_support", - "+mojo/public/cpp/utility", - ], -} diff --git a/third_party/mojo/src/mojo/public/cpp/README.md b/third_party/mojo/src/mojo/public/cpp/README.md index 8f03d98..4404c24 100644 --- a/third_party/mojo/src/mojo/public/cpp/README.md +++ b/third_party/mojo/src/mojo/public/cpp/README.md @@ -8,7 +8,7 @@ subdirectories of the same name, under mojo/public/c/). Typically, these wrappers provide increased convenience and/or type-safety. Other subdirectories provide support (static) libraries of various sorts. In -this case, the organization is to have the public interface for the library in +this case, the organization is to have the public interface for the library defined in header files in the subdirectory itself and the implementation of the library at a lower level, under a lib (sub)subdirectory. A developer should be able to substitute their own implementation of any such support library, and diff --git a/third_party/mojo/src/mojo/public/cpp/application/DEPS b/third_party/mojo/src/mojo/public/cpp/application/DEPS deleted file mode 100644 index 503eebc..0000000 --- a/third_party/mojo/src/mojo/public/cpp/application/DEPS +++ /dev/null @@ -1,11 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/bindings", - "+mojo/public/cpp/environment", - "+mojo/public/interfaces/application", - "+mojo/public/interfaces/service_provider", -] -specific_include_rules = { - r"application_test_base\.h": [ - "+testing/gtest/include/gtest", - ], -}
\ No newline at end of file diff --git a/third_party/mojo/src/mojo/public/cpp/application/application_impl.h b/third_party/mojo/src/mojo/public/cpp/application/application_impl.h index bb92307..46d368d 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/application_impl.h +++ b/third_party/mojo/src/mojo/public/cpp/application/application_impl.h @@ -79,20 +79,15 @@ class ApplicationImpl : public Application { // Block until the Application is initialized, if it is not already. void WaitForInitialize(); - // Unbinds the Shell and Application connections. Must be called after - // Initialize. + // Unbinds the Shell and Application connections. Can be used to re-bind the + // handles to another implementation of ApplicationImpl, for instance when + // running apptests. void UnbindConnections(InterfaceRequest<Application>* application_request, ShellPtr* shell); // Quits the main run loop for this application. static void Terminate(); - protected: - // Application implementation. - void AcceptConnection(const String& requestor_url, - InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services) override; - private: class ShellPtrWatcher; @@ -103,11 +98,15 @@ class ApplicationImpl : public Application { Terminate(); } + // Application implementation. + void AcceptConnection(const String& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services) override; + void RequestQuit() override; typedef std::vector<internal::ServiceRegistry*> ServiceRegistryList; - bool initialized_; ServiceRegistryList incoming_service_registries_; ServiceRegistryList outgoing_service_registries_; ApplicationDelegate* delegate_; diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/DEPS b/third_party/mojo/src/mojo/public/cpp/application/lib/DEPS deleted file mode 100644 index a04ed0f..0000000 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/utility", -] diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc index 4d1f8dc..c66dbb5 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_impl.cc @@ -26,8 +26,7 @@ class ApplicationImpl::ShellPtrWatcher : public ErrorHandler { ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate, InterfaceRequest<Application> request) - : initialized_(false), - delegate_(delegate), + : delegate_(delegate), binding_(this, request.Pass()), shell_watch_(nullptr) { } diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc index 72058a4..ba6dd3f 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/application_test_base.cc @@ -42,7 +42,7 @@ class ShellAndArgumentGrabber : public Application { void WaitForInitialize() { // Initialize is always the first call made on Application. - binding_.WaitForIncomingMethodCall(); + MOJO_CHECK(binding_.WaitForIncomingMethodCall()); } private: diff --git a/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc b/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc index d934a16..01c6c70 100644 --- a/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc +++ b/third_party/mojo/src/mojo/public/cpp/application/lib/service_registry.cc @@ -18,8 +18,10 @@ ServiceRegistry::ServiceRegistry( InterfaceRequest<ServiceProvider> local_services) : application_impl_(application_impl), url_(url), - local_binding_(this, local_services.Pass()), + local_binding_(this), remote_service_provider_(remote_services.Pass()) { + if (local_services.is_pending()) + local_binding_.Bind(local_services.Pass()); } ServiceRegistry::ServiceRegistry() diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/DEPS b/third_party/mojo/src/mojo/public/cpp/bindings/DEPS deleted file mode 100644 index 2a0496e..0000000 --- a/third_party/mojo/src/mojo/public/cpp/bindings/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/environment", -] diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/lib/DEPS b/third_party/mojo/src/mojo/public/cpp/bindings/lib/DEPS deleted file mode 100644 index b809b58..0000000 --- a/third_party/mojo/src/mojo/public/cpp/bindings/lib/DEPS +++ /dev/null @@ -1,5 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/bindings", - "+mojo/public/cpp/environment", - "+mojo/public/cpp/system", -] diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/string.h b/third_party/mojo/src/mojo/public/cpp/bindings/string.h index ba0d8fa8..e0ed4ba 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/string.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/string.h @@ -13,6 +13,9 @@ namespace mojo { +// A UTF-8 encoded character string that can be null. Provides functions that +// are similar to std::string, along with access to the underlying std::string +// object. class String { public: typedef internal::String_Data Data_; diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/struct_ptr.h b/third_party/mojo/src/mojo/public/cpp/bindings/struct_ptr.h index a420fa5..04a8130 100644 --- a/third_party/mojo/src/mojo/public/cpp/bindings/struct_ptr.h +++ b/third_party/mojo/src/mojo/public/cpp/bindings/struct_ptr.h @@ -25,6 +25,7 @@ class StructHelper { } // namespace internal +// Smart pointer wrapping a mojom structure with move-only semantics. template <typename Struct> class StructPtr { MOJO_MOVE_ONLY_TYPE(StructPtr) diff --git a/third_party/mojo/src/mojo/public/cpp/bindings/tests/DEPS b/third_party/mojo/src/mojo/public/cpp/bindings/tests/DEPS deleted file mode 100644 index b99d520..0000000 --- a/third_party/mojo/src/mojo/public/cpp/bindings/tests/DEPS +++ /dev/null @@ -1,4 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/environment", - "+mojo/public/interfaces/bindings/tests", -] diff --git a/third_party/mojo/src/mojo/public/cpp/environment/DEPS b/third_party/mojo/src/mojo/public/cpp/environment/DEPS deleted file mode 100644 index 04346d9..0000000 --- a/third_party/mojo/src/mojo/public/cpp/environment/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/bindings/callback.h", -] diff --git a/third_party/mojo/src/mojo/public/cpp/environment/lib/DEPS b/third_party/mojo/src/mojo/public/cpp/environment/lib/DEPS deleted file mode 100644 index 1889e1f..0000000 --- a/third_party/mojo/src/mojo/public/cpp/environment/lib/DEPS +++ /dev/null @@ -1,4 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/environment", - "+mojo/public/cpp/utility", -] diff --git a/third_party/mojo/src/mojo/public/cpp/test_support/DEPS b/third_party/mojo/src/mojo/public/cpp/test_support/DEPS deleted file mode 100644 index 6dc5394..0000000 --- a/third_party/mojo/src/mojo/public/cpp/test_support/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/public/c/test_support", -] diff --git a/third_party/mojo/src/mojo/public/cpp/utility/DEPS b/third_party/mojo/src/mojo/public/cpp/utility/DEPS deleted file mode 100644 index a9dfbd1..0000000 --- a/third_party/mojo/src/mojo/public/cpp/utility/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo/public/cpp/bindings/callback.h" -] diff --git a/third_party/mojo/src/mojo/public/cpp/utility/run_loop.h b/third_party/mojo/src/mojo/public/cpp/utility/run_loop.h index 5ebe63e..4673eaa 100644 --- a/third_party/mojo/src/mojo/public/cpp/utility/run_loop.h +++ b/third_party/mojo/src/mojo/public/cpp/utility/run_loop.h @@ -15,6 +15,8 @@ namespace mojo { class RunLoopHandler; +// Watches handles for signals and calls event handlers when they occur. Also +// executes delayed tasks. This class should only be used by a single thread. class RunLoop { public: RunLoop(); @@ -31,8 +33,17 @@ class RunLoop { // created. static RunLoop* current(); - // Registers a RunLoopHandler for the specified handle. Only one handler can - // be registered for a specified handle. + // Registers a RunLoopHandler for the specified handle. It is an error to + // register more than one handler for a handle, and crashes the process. + // + // The handler's OnHandleReady() method is invoked after one of the signals in + // |handle_signals| occurs. Note that the handler remains registered until + // explicitly removed or an error occurs. + // + // The handler's OnHandleError() method is invoked if the deadline elapses, an + // error is detected, or the RunLoop is being destroyed. The handler is + // automatically unregistered before calling OnHandleError(), so it will not + // receive any further notifications. void AddHandler(RunLoopHandler* handler, const Handle& handle, MojoHandleSignals handle_signals, diff --git a/third_party/mojo/src/mojo/public/dart/DEPS b/third_party/mojo/src/mojo/public/dart/DEPS deleted file mode 100644 index 53d0007..0000000 --- a/third_party/mojo/src/mojo/public/dart/DEPS +++ /dev/null @@ -1,4 +0,0 @@ -include_rules = [ - "+dart", - "+base", -]
\ No newline at end of file diff --git a/third_party/mojo/src/mojo/public/dart/core.dart b/third_party/mojo/src/mojo/public/dart/core.dart index ecd671d..6cdbe26 100644 --- a/third_party/mojo/src/mojo/public/dart/core.dart +++ b/third_party/mojo/src/mojo/public/dart/core.dart @@ -16,6 +16,5 @@ part 'src/event_stream.dart'; part 'src/handle.dart'; part 'src/handle_watcher.dart'; part 'src/message_pipe.dart'; -part 'src/timer_impl.dart'; part 'src/timer_queue.dart'; part 'src/types.dart'; diff --git a/third_party/mojo/src/mojo/public/dart/rules.gni b/third_party/mojo/src/mojo/public/dart/rules.gni new file mode 100644 index 0000000..aea59e3 --- /dev/null +++ b/third_party/mojo/src/mojo/public/dart/rules.gni @@ -0,0 +1,112 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Rules to generate python packaged applications for Dart + +import("../mojo_sdk.gni") + +template("dart_package") { + action(target_name) { + script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_root) + + inputs = invoker.sources + + deps = [] + zip_inputs = [] + + if (defined(invoker.deps)) { + deps += invoker.deps + foreach(d, invoker.deps) { + dep_name = get_label_info(d, "name") + dep_target_out_dir = get_label_info(d, "target_out_dir") + zip_inputs += [ "$dep_target_out_dir/$dep_name.dartzip" ] + } + } + + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + + output = "$target_out_dir/$target_name.dartzip" + outputs = [ + output, + ] + + rebase_base_dir = + rebase_path(get_label_info(":$target_name", "dir"), root_build_dir) + rebase_inputs = rebase_path(inputs, root_build_dir) + rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--base-dir=$rebase_base_dir", + "--inputs=$rebase_inputs", + "--zip-inputs=$rebase_zip_inputs", + "--output=$rebase_output", + ] + } +} + +# Use this template to generate a .mojo dart application. One of the source +# files should be named main.dart and contain a main function as the +# entry point. Dependencies of dart_packaged_application targets should be +# either mojom targets (and specified using the mojom_deps variable) or +# dart_package targets. +template("dart_packaged_application") { + package_name = "${target_name}_package" + package_output = "$target_out_dir/$package_name.dartzip" + + if (defined(invoker.output_name)) { + mojo_output = "$root_out_dir/" + invoker.output_name + ".mojo" + } else { + mojo_output = "$root_out_dir/" + target_name + ".mojo" + } + + dart_package(package_name) { + sources = invoker.sources + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.mojom_deps)) { + mojom_deps = invoker.mojom_deps + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + } + + action(target_name) { + script = rebase_path("mojo/public/tools/prepend.py", ".", mojo_root) + + input = package_output + inputs = [ + input, + ] + + output = mojo_output + outputs = [ + output, + ] + + deps = [ + ":$package_name", + ] + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.mojom_deps)) { + deps += invoker.mojom_deps + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + + 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 mojo:dart_content_handler", + ] + } +} diff --git a/third_party/mojo/src/mojo/public/dart/src/application.dart b/third_party/mojo/src/mojo/public/dart/src/application.dart index 55002f5e..2819625 100644 --- a/third_party/mojo/src/mojo/public/dart/src/application.dart +++ b/third_party/mojo/src/mojo/public/dart/src/application.dart @@ -33,7 +33,7 @@ class _ApplicationImpl extends application_mojom.Application { void requestQuit() => _application._requestQuitAndClose(); - void close() => shell.close(); + void close({bool nodefer: false}) => shell.close(); } // TODO(zra): Better documentation and examples. diff --git a/third_party/mojo/src/mojo/public/dart/src/codec.dart b/third_party/mojo/src/mojo/public/dart/src/codec.dart index 7ad8370..268daee 100644 --- a/third_party/mojo/src/mojo/public/dart/src/codec.dart +++ b/third_party/mojo/src/mojo/public/dart/src/codec.dart @@ -18,6 +18,12 @@ const int kElementNullable = (1 << 1); bool isArrayNullable(int nullability) => (nullability & kArrayNullable) > 0; bool isElementNullable(int nullability) => (nullability & kElementNullable) > 0; +class MojoCodecError { + final String message; + MojoCodecError(this.message); + String toString() => message; +} + class _EncoderBuffer { ByteData buffer; List<core.MojoHandle> handles; @@ -88,7 +94,7 @@ class Encoder { void encodeUint8(int value, int offset) { if (value < 0) { - throw '$kErrorUnsigned: $val'; + throw new MojoCodecError('$kErrorUnsigned: $val'); } _buffer.buffer.setUint8(_base + offset, value); } @@ -98,7 +104,7 @@ class Encoder { void encodeUint16(int value, int offset) { if (value < 0) { - throw '$kErrorUnsigned: $val'; + throw new MojoCodecError('$kErrorUnsigned: $val'); } _buffer.buffer.setUint16(_base + offset, value, Endianness.LITTLE_ENDIAN); } @@ -108,7 +114,7 @@ class Encoder { void encodeUint32(int value, int offset) { if (value < 0) { - throw '$kErrorUnsigned: $val'; + throw new MojoCodecError('$kErrorUnsigned: $val'); } _buffer.buffer.setUint32(_base + offset, value, Endianness.LITTLE_ENDIAN); } @@ -118,7 +124,7 @@ class Encoder { void encodeUint64(int value, int offset) { if (value < 0) { - throw '$kErrorUnsigned: $val'; + throw new MojoCodecError('$kErrorUnsigned: $val'); } _buffer.buffer.setUint64(_base + offset, value, Endianness.LITTLE_ENDIAN); } @@ -176,14 +182,16 @@ class Encoder { void encodeNullPointer(int offset, bool nullable) { if (!nullable) { - throw 'Trying to encode a null pointer for a non-nullable type'; + throw new MojoCodecError( + 'Trying to encode a null pointer for a non-nullable type'); } _buffer.buffer.setUint64(_base + offset, 0, Endianness.LITTLE_ENDIAN); } void encodeInvalideHandle(int offset, bool nullable) { if (!nullable) { - throw 'Trying to encode a null pointer for a non-nullable type'; + throw new MojoCodecError( + 'Trying to encode a null pointer for a non-nullable type'); } _buffer.buffer.setInt32(_base + offset, -1, Endianness.LITTLE_ENDIAN); } @@ -207,7 +215,8 @@ class Encoder { int elementSize, int length, int offset, int expectedLength) { if ((expectedLength != kUnspecifiedArrayLength) && (expectedLength != length)) { - throw 'Trying to encode a fixed array of incorrect length'; + throw new MojoCodecError( + 'Trying to encode a fixed array of incorrect length'); } return encoderForArrayByTotalSize(length * elementSize, length, offset); } @@ -226,7 +235,8 @@ class Encoder { } if ((expectedLength != kUnspecifiedArrayLength) && (expectedLength != value.length)) { - throw 'Trying to encode a fixed array of incorrect size.'; + throw new MojoCodecError( + 'Trying to encode a fixed array of incorrect size.'); } var bytes = new Uint8List((value.length + 7) ~/ kAlignment); for (int i = 0; i < bytes.length; ++i) { @@ -411,34 +421,34 @@ class Encoder { } void appendInt8Array(List<int> value) => - appendBytes(new Uint8List.view(new Int8List.fromList(value))); + appendBytes(new Uint8List.view(new Int8List.fromList(value).buffer)); void appendUint8Array(List<int> value) => appendBytes(new Uint8List.fromList(value)); void appendInt16Array(List<int> value) => - appendBytes(new Uint8List.view(new Int16List.fromList(value))); + appendBytes(new Uint8List.view(new Int16List.fromList(value).buffer)); void appendUint16Array(List<int> value) => - appendBytes(new Uint8List.view(new Uint16List.fromList(value))); + appendBytes(new Uint8List.view(new Uint16List.fromList(value).buffer)); void appendInt32Array(List<int> value) => - appendBytes(new Uint8List.view(new Int32List.fromList(value))); + appendBytes(new Uint8List.view(new Int32List.fromList(value).buffer)); void appendUint32Array(List<int> value) => - appendBytes(new Uint8List.view(new Uint32List.fromList(value))); + appendBytes(new Uint8List.view(new Uint32List.fromList(value).buffer)); void appendInt64Array(List<int> value) => - appendBytes(new Uint8List.view(new Int64List.fromList(value))); + appendBytes(new Uint8List.view(new Int64List.fromList(value).buffer)); void appendUint64Array(List<int> value) => - appendBytes(new Uint8List.view(new Uint64List.fromList(value))); + appendBytes(new Uint8List.view(new Uint64List.fromList(value).buffer)); void appendFloatArray(List<int> value) => - appendBytes(new Uint8List.view(new Float32List.fromList(value))); + appendBytes(new Uint8List.view(new Float32List.fromList(value).buffer)); void appendDoubleArray(List<int> value) => - appendBytes(new Uint8List.view(new Float64List.fromList(value))); + appendBytes(new Uint8List.view(new Float64List.fromList(value).buffer)); Encoder encoderForMap(int offset) { encodePointerToNextUnclaimed(offset); @@ -447,16 +457,59 @@ class Encoder { } +class _Validator { + final int _maxMemory; + final int _numberOfHandles; + int _minNextClaimedHandle = 0; + int _minNextMemory = 0; + + _Validator(this._maxMemory, this._numberOfHandles); + + void claimHandle(int handle) { + if (handle < _minNextClaimedHandle) { + throw new MojoCodecError('Trying to access handle out of order.'); + } + if (handle >= _numberOfHandles) { + throw new MojoCodecError('Trying to access non present handle.'); + } + _minNextClaimedHandle = handle + 1; + } + + void claimMemory(int start, int end) { + if ((start % kAlignment) != 0) { + throw new MojoCodecError('Incorrect starting alignment: $start.'); + } + if (start < _minNextMemory) { + throw new MojoCodecError('Trying to access memory out of order.'); + } + if (end < start) { + throw new MojoCodecError('Incorrect memory range.'); + } + if (end > _maxMemory) { + throw new MojoCodecError('Trying to access out of range memory.'); + } + _minNextMemory = align(end); + } +} + + class Decoder { + _Validator _validator; Message _message; int _base = 0; - Decoder(this._message, [this._base = 0]); + Decoder(this._message, [this._base = 0, this._validator = null]) { + if (_validator == null) { + _validator = new _Validator( + _message.buffer.lengthInBytes, _message.handles.length); + } + } - Decoder getDecoderAtPosition(int offset) => new Decoder(_message, offset); + Decoder getDecoderAtPosition(int offset) => + new Decoder(_message, offset, _validator); - factory Decoder.atOffset(Decoder d, int offset) => - new Decoder(d._message, offset); + factory Decoder.atOffset(Decoder d, int offset, _Validator validator) => + new Decoder(d._message, offset, validator); ByteData get _buffer => _message.buffer; List<core.MojoHandle> get _handles => _message.handles; @@ -487,10 +540,12 @@ class Decoder { int index = decodeInt32(offset); if (index == -1) { if (!nullable) { - throw 'Trying to decode an invalid handle from a non-nullable type.'; + throw new MojoCodecError( + 'Trying to decode an invalid handle from a non-nullable type.'); } return new core.MojoHandle(core.MojoHandle.INVALID); } + _validator.claimHandle(index); return _handles[index]; } @@ -524,17 +579,26 @@ class Decoder { int pointerOffset = decodeUint64(offset); if (pointerOffset == 0) { if (!nullable) { - throw 'Trying to decode a null pointer for a non-nullable type'; + throw new MojoCodecError( + 'Trying to decode a null pointer for a non-nullable type'); } return null; } int newPosition = (basePosition + pointerOffset); - return new Decoder.atOffset(this, newPosition); + return new Decoder.atOffset(this, newPosition, _validator); } DataHeader decodeDataHeader() { + _validator.claimMemory(_base, _base + DataHeader.kHeaderSize); int size = decodeUint32(DataHeader.kSizeOffset); int numFields = decodeUint32(DataHeader.kNumFieldsOffset); + if (size < 0) { + throw new MojoCodecError('Negative size.'); + } + if (numFields < 0) { + throw new MojoCodecError('Negative number of fields.'); + } + _validator.claimMemory(_base + DataHeader.kHeaderSize, _base + size); return new DataHeader(size, numFields); } @@ -542,11 +606,13 @@ class Decoder { DataHeader decodeDataHeaderForBoolArray(int expectedLength) { var header = decodeDataHeader(); if (header.size < DataHeader.kHeaderSize + (header.numFields + 7) ~/ 8) { - throw 'Array header is incorrect'; + throw new MojoCodecError('Array header is incorrect'); } if ((expectedLength != kUnspecifiedArrayLength) && (header.numFields != expectedLength)) { - throw 'Incorrect array length'; + throw new MojoCodecError( + 'Incorrect array length. Expected $expectedLength, but got ' + '${header.numFields}.'); } return header; } @@ -576,11 +642,14 @@ class Decoder { DataHeader decodeDataHeaderForArray(int elementSize, int expectedLength) { var header = decodeDataHeader(); if (header.size < DataHeader.kHeaderSize + header.numFields * elementSize) { - throw 'Array header is incorrect: $header, elementSize = $elementSize'; + throw new MojoCodecError( + 'Array header is incorrect: $header, elementSize = $elementSize'); } if ((expectedLength != kUnspecifiedArrayLength) && (header.numFields != expectedLength)) { - throw 'Incorrect array length.'; + throw new MojoCodecError( + 'Incorrect array length. Expected $expectedLength, but got ' + '${header.numFields}'); } return header; } @@ -588,11 +657,11 @@ class Decoder { DataHeader decodeDataHeaderForPointerArray(int expectedLength) => decodeDataHeaderForArray(kPointerSize, expectedLength); - List<int> decodeArray(Function arrayViewer, - int elementSize, - int offset, - int nullability, - int expectedLength) { + List decodeArray(Function arrayViewer, + int elementSize, + int offset, + int nullability, + int expectedLength) { Decoder d = decodePointer(offset, isArrayNullable(nullability)); if (d == null) { return null; @@ -728,4 +797,17 @@ class Decoder { } return _stringOfUtf8(bytes); } + + DataHeader decodeDataHeaderForMap() { + var header = decodeDataHeader(); + if (header.size != kMapStructHeader.size) { + throw new MojoCodecError( + 'Incorrect header for map. The size is incorrect.'); + } + if (header.numFields != kMapStructHeader.numFields) { + throw new MojoCodecError( + 'Incorrect header for map. The number of fields is incorrect.'); + } + return header; + } } diff --git a/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart b/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart index 3d14f6c..da688d4 100644 --- a/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart +++ b/third_party/mojo/src/mojo/public/dart/src/handle_watcher.dart @@ -19,11 +19,6 @@ class _MojoHandleWatcherNatives { // The MojoHandleWatcher sends a stream of events to application isolates that // register Mojo handles with it. Application isolates make the following calls: // -// Start() - Starts up the MojoHandleWatcher isolate. Should be called only once -// per VM process. -// -// Stop() - Causes the MojoHandleWatcher isolate to exit. -// // add(handle, port, signals) - Instructs the MojoHandleWatcher isolate to add // 'handle' to the set of handles it watches, and to notify the calling // isolate only for the events specified by 'signals' using the send port @@ -291,7 +286,9 @@ class MojoHandleWatcher { return new MojoResult(result); } - static Future<Isolate> Start() { + // Starts up the MojoHandleWatcher isolate. Should be called only once + // per VM process. + static Future<Isolate> _start() { // Make a control message pipe, MojoMessagePipe pipe = new MojoMessagePipe(); int consumerHandle = pipe.endpoints[0].handle.h; @@ -305,7 +302,9 @@ class MojoHandleWatcher { return Isolate.spawn(_handleWatcherIsolate, consumerHandle); } - static void Stop() { + // Causes the MojoHandleWatcher isolate to exit. Should be called only + // once per VM process. + static void _stop() { // Create a port for notification that the handle watcher has shutdown. var shutdownReceivePort = new ReceivePort(); var shutdownSendPort = shutdownReceivePort.sendPort; @@ -339,7 +338,7 @@ class MojoHandleWatcher { return _sendControlData(mojoHandle, null, _encodeCommand(REMOVE)); } - static MojoResult timer(SendPort port, int deadline) { + static MojoResult timer(Object ignored, SendPort port, int deadline) { // The deadline will be unwrapped before sending to the handle watcher. return _sendControlData( new MojoHandle(deadline), port, _encodeCommand(TIMER)); diff --git a/third_party/mojo/src/mojo/public/dart/src/message.dart b/third_party/mojo/src/mojo/public/dart/src/message.dart index 2cdda8a..918d219 100644 --- a/third_party/mojo/src/mojo/public/dart/src/message.dart +++ b/third_party/mojo/src/mojo/public/dart/src/message.dart @@ -35,12 +35,18 @@ class MessageHeader { MessageHeader.fromMessage(Message message) { var decoder = new Decoder(message); _header = decoder.decodeDataHeader(); + if (_header.size < kSimpleMessageSize) { + throw new MojoCodecError( + 'Incorrect message size. Got: ${_header.size} ' + 'wanted $kSimpleMessageSize'); + } type = decoder.decodeUint32(kMessageTypeOffset); flags = decoder.decodeUint32(kMessageFlagsOffset); if (mustHaveRequestId(flags)) { if (_header.size < kMessageWithRequestIdSize) { - throw 'Incorrect message size. Got: ${_header.size} ' + - 'wanted $kMessageWithRequestIdSize'; + throw new MojoCodecError( + 'Incorrect message size. Got: ${_header.size} ' + 'wanted $kMessageWithRequestIdSize'); } requestId = decoder.decodeUint64(kMessageRequestIdOffset); } else { @@ -63,6 +69,35 @@ class MessageHeader { ServiceMessage get serviceMessage => new ServiceMessage(this); String toString() => "MessageHeader($_header, $type, $flags, $requestId)"; + + bool validateHeaderFlags(expectedFlags) => + (flags & (kMessageExpectsResponse | kMessageIsResponse)) == expectedFlags; + + bool validateHeader(int expectedType, int expectedFlags) => + (type == expectedType) && validateHeaderFlags(expectedFlags); + + static void _validateDataHeader(DataHeader dataHeader) { + if (dataHeader.numFields < kSimpleMessageNumFields) { + throw 'Incorrect number of fields, expecting at least ' + '$kSimpleMessageNumFields, but got: ${dataHeader.numFields}.'; + } + if (dataHeader.size < kSimpleMessageSize) { + throw 'Incorrect message size, expecting at least $kSimpleMessageSize, ' + 'but got: ${dataHeader.size}'; + } + if ((dataHeader.numFields == kSimpleMessageSize) && + (dataHeader.size != kSimpleMessageSize)) { + throw 'Incorrect message size for a message with $kSimpleMessageNumFields' + ' fields, expecting $kSimpleMessageSize, ' + 'but got ${dataHeader.size}'; + } + if ((dataHeader.numFields == kMessageWithRequestIdNumFields) && + (dataHeader.size != kMessageWithRequestIdSize)) { + throw 'Incorrect message size for a message with ' + '$kMessageWithRequestIdNumFields fields, expecting ' + '$kMessageWithRequestIdSize, but got ${dataHeader.size}'; + } + } } diff --git a/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart b/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart index 325be42..7733d33 100644 --- a/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart +++ b/third_party/mojo/src/mojo/public/dart/src/message_pipe.dart @@ -49,9 +49,11 @@ class MojoMessagePipeEndpoint { return status; } + int dataLengthInBytes = (data == null) ? 0 : data.lengthInBytes; + // If numBytes has the default value, use the full length of the data. - int dataNumBytes = (numBytes == -1) ? data.lengthInBytes : numBytes; - if (dataNumBytes > data.lengthInBytes) { + int dataNumBytes = (numBytes == -1) ? dataLengthInBytes : numBytes; + if (dataNumBytes > dataLengthInBytes) { status = MojoResult.INVALID_ARGUMENT; return status; } diff --git a/third_party/mojo/src/mojo/public/dart/src/proxy.dart b/third_party/mojo/src/mojo/public/dart/src/proxy.dart index f662f3a..1186232 100644 --- a/third_party/mojo/src/mojo/public/dart/src/proxy.dart +++ b/third_party/mojo/src/mojo/public/dart/src/proxy.dart @@ -47,8 +47,8 @@ abstract class Proxy extends core.MojoEventStreamListener { var header = new MessageHeader(name); var serviceMessage = message.serializeWithHeader(header); endpoint.write(serviceMessage.buffer, - serviceMessage.buffer.lengthInBytes, - serviceMessage.handles); + serviceMessage.buffer.lengthInBytes, + serviceMessage.handles); if (!endpoint.status.isOk) { throw "message pipe write failed"; } @@ -66,8 +66,8 @@ abstract class Proxy extends core.MojoEventStreamListener { var header = new MessageHeader.withRequestId(name, flags, id); var serviceMessage = message.serializeWithHeader(header); endpoint.write(serviceMessage.buffer, - serviceMessage.buffer.lengthInBytes, - serviceMessage.handles); + serviceMessage.buffer.lengthInBytes, + serviceMessage.handles); if (!endpoint.status.isOk) { throw "message pipe write failed"; } diff --git a/third_party/mojo/src/mojo/public/dart/src/service_provider.dart b/third_party/mojo/src/mojo/public/dart/src/service_provider.dart index deac6bc..6b07f2e 100644 --- a/third_party/mojo/src/mojo/public/dart/src/service_provider.dart +++ b/third_party/mojo/src/mojo/public/dart/src/service_provider.dart @@ -30,10 +30,11 @@ class ServiceProvider extends service_provider.ServiceProvider { _proxy.connectToService(name, pipe.endpoints[1]); } - close() { + close({bool nodefer : false}) { if (_proxy != null) { _proxy.close(); _proxy = null; } + super.close(nodefer: nodefer); } } diff --git a/third_party/mojo/src/mojo/public/dart/src/stub.dart b/third_party/mojo/src/mojo/public/dart/src/stub.dart index b4ab293..8238736 100644 --- a/third_party/mojo/src/mojo/public/dart/src/stub.dart +++ b/third_party/mojo/src/mojo/public/dart/src/stub.dart @@ -20,6 +20,9 @@ abstract class Stub extends core.MojoEventStreamListener { // Query how many bytes are available. var result = endpoint.query(); assert(result.status.isOk || result.status.isResourceExhausted); + if (result.bytesRead == 0) { + throw new MojoCodecError('Unexpected empty message.'); + } // Read the data and view as a message. var bytes = new ByteData(result.bytesRead); @@ -41,7 +44,7 @@ abstract class Stub extends core.MojoEventStreamListener { response.buffer.lengthInBytes, response.handles); if (!endpoint.status.isOk) { - throw "message pipe write failed: ${endpoint.status}"; + throw 'message pipe write failed: ${endpoint.status}'; } if (_isClosing && (_outstandingResponseFutures == 0)) { // This was the final response future for which we needed to send @@ -63,9 +66,12 @@ abstract class Stub extends core.MojoEventStreamListener { throw 'Unexpected write signal in client.'; } - void close() { + // NB: |nodefer| should only be true when calling close() while handling an + // exception thrown from handleRead(), e.g. when we receive a malformed + // message. + void close({bool nodefer : false}) { if (!isOpen) return; - if (isInHandler || (_outstandingResponseFutures > 0)) { + if (!nodefer && (isInHandler || (_outstandingResponseFutures > 0))) { // Either close() is being called from within handleRead() or // handleWrite(), or close() is being called while there are outstanding // response futures. Defer the actual close until all response futures diff --git a/third_party/mojo/src/mojo/public/dart/src/timer_impl.dart b/third_party/mojo/src/mojo/public/dart/src/timer_impl.dart deleted file mode 100644 index 61fee6d..0000000 --- a/third_party/mojo/src/mojo/public/dart/src/timer_impl.dart +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This code is adapted from the Timer implementation in the standalone Dart VM -// for use in the Mojo embedder. - -part of core; - -// Timer heap implemented as a array-based binary heap[0]. -// This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n)) -// `add`. -// -// To ensure the timers are ordered by insertion time, the _Timer class has a -// `_id` field set when added to the heap. -// -// [0] http://en.wikipedia.org/wiki/Binary_heap -class _TimerHeap { - List<_Timer> _list; - int _used = 0; - - _TimerHeap([int initSize = 7]) - : _list = new List<_Timer>(initSize); - - bool get isEmpty => _used == 0; - bool get isNotEmpty => _used > 0; - - _Timer get first => _list[0]; - - bool isFirst(_Timer timer) => timer._indexOrNext == 0; - - void add(_Timer timer) { - if (_used == _list.length) { - _resize(); - } - timer._indexOrNext = _used++; - _list[timer._indexOrNext] = timer; - _bubbleUp(timer); - } - - _Timer removeFirst() { - var f = first; - remove(f); - return f; - } - - void remove(_Timer timer) { - _used--; - timer._id = -1; - if (isEmpty) { - _list[0] = null; - timer._indexOrNext = null; - return; - } - var last = _list[_used]; - if (!identical(last, timer)) { - last._indexOrNext = timer._indexOrNext; - _list[last._indexOrNext] = last; - if (last._compareTo(timer) < 0) { - _bubbleUp(last); - } else { - _bubbleDown(last); - } - } - _list[_used] = null; - timer._indexOrNext = null; - } - - void _resize() { - var newList = new List(_list.length * 2 + 1); - newList.setRange(0, _used, _list); - _list = newList; - } - - void _bubbleUp(_Timer timer) { - while (!isFirst(timer)) { - Timer parent = _parent(timer); - if (timer._compareTo(parent) < 0) { - _swap(timer, parent); - } else { - break; - } - } - } - - void _bubbleDown(_Timer timer) { - while (true) { - int leftIndex = _leftChildIndex(timer._indexOrNext); - int rightIndex = _rightChildIndex(timer._indexOrNext); - _Timer newest = timer; - if (leftIndex < _used && _list[leftIndex]._compareTo(newest) < 0) { - newest = _list[leftIndex]; - } - if (rightIndex < _used && _list[rightIndex]._compareTo(newest) < 0) { - newest = _list[rightIndex]; - } - if (identical(newest, timer)) { - // We are where we should be, break. - break; - } - _swap(newest, timer); - } - } - - void _swap(_Timer first, _Timer second) { - int tmp = first._indexOrNext; - first._indexOrNext = second._indexOrNext; - second._indexOrNext = tmp; - _list[first._indexOrNext] = first; - _list[second._indexOrNext] = second; - } - - Timer _parent(_Timer timer) => _list[_parentIndex(timer._indexOrNext)]; - Timer _leftChild(_Timer timer) => _list[_leftChildIndex(timer._indexOrNext)]; - Timer _rightChild(_Timer timer) => - _list[_rightChildIndex(timer._indexOrNext)]; - - static int _parentIndex(int index) => (index - 1) ~/ 2; - static int _leftChildIndex(int index) => 2 * index + 1; - static int _rightChildIndex(int index) => 2 * index + 2; -} - -class _Timer implements Timer { - // Disables the timer. - static const int _NO_TIMER = -1; - - // Timers are ordered by wakeup time. - static _TimerHeap _heap = new _TimerHeap(); - static _Timer _firstZeroTimer; - static _Timer _lastZeroTimer; - static int _idCount = 0; - - static RawReceivePort _receivePort; - static SendPort _sendPort; - static bool _handlingCallbacks = false; - - Function _callback; - int _milliSeconds; - int _wakeupTime = 0; - var _indexOrNext; - int _id = -1; - - static Timer _createTimer(void callback(Timer timer), - int milliSeconds, - bool repeating) { - _Timer timer = new _Timer._internal(); - timer._callback = callback; - if (milliSeconds > 0) { - // Add one because DateTime.now() is assumed to round down - // to nearest millisecond, not up, so that time + duration is before - // duration milliseconds from now. Using micosecond timers like - // Stopwatch allows detecting that the timer fires early. - timer._wakeupTime = - new DateTime.now().millisecondsSinceEpoch + 1 + milliSeconds; - } - timer._milliSeconds = repeating ? milliSeconds : -1; - if (timer._addTimerToHeap()) { - // The new timer is the first in queue. Update event handler. - _notifyEventHandler(); - } - return timer; - } - - factory _Timer(int milliSeconds, void callback(Timer timer)) { - return _createTimer(callback, milliSeconds, false); - } - - factory _Timer.periodic(int milliSeconds, void callback(Timer timer)) { - return _createTimer(callback, milliSeconds, true); - } - - _Timer._internal() {} - - bool get _isInHeap => _id >= 0; - - void _clear() { - _callback = null; - } - - int _compareTo(_Timer other) { - int c = _wakeupTime - other._wakeupTime; - if (c != 0) return c; - return _id - other._id; - } - - bool get _repeating => _milliSeconds >= 0; - - bool get isActive => _callback != null; - - // Cancels a set timer. The timer is removed from the timer list and if - // the given timer is the earliest timer the native timer is reset. - void cancel() { - _clear(); - if (!_isInHeap) return; - assert(_wakeupTime != 0); - bool update = (_firstZeroTimer == null) && _heap.isFirst(this); - _heap.remove(this); - if (update) { - _notifyEventHandler(); - } - } - - void _advanceWakeupTime() { - assert(_milliSeconds >= 0); - _wakeupTime += _milliSeconds; - } - - // Adds a timer to the timer list. Timers with the same wakeup time are - // enqueued in order and notified in FIFO order. - bool _addTimerToHeap() { - if (_wakeupTime == 0) { - if (_firstZeroTimer == null) { - _lastZeroTimer = this; - _firstZeroTimer = this; - return true; - } else { - _lastZeroTimer._indexOrNext = this; - _lastZeroTimer = this; - return false; - } - } else { - _id = _idCount++; - _heap.add(this); - return _firstZeroTimer == null && _heap.isFirst(this); - } - } - - - static void _notifyEventHandler() { - if (_handlingCallbacks) { - // While we are already handling callbacks we will not notify the event - // handler. _handleTimeout will call _notifyEventHandler once all pending - // timers are processed. - return; - } - - if (_firstZeroTimer == null && _heap.isEmpty) { - // No pending timers: Close the receive port and let the event handler - // know. - if (_receivePort != null) { - MojoHandleWatcher.timer(_sendPort, _NO_TIMER); - _shutdownTimerHandler(); - } - } else { - if (_receivePort == null) { - // Create a receive port and register a message handler for the timer - // events. - _createTimerHandler(); - } - if (_firstZeroTimer != null) { - _sendPort.send(null); - } else { - MojoHandleWatcher.timer(_sendPort, _heap.first._wakeupTime); - } - } - } - - static void _handleTimeout(_) { - int currentTime = new DateTime.now().millisecondsSinceEpoch; - // Collect all pending timers. - var timer = _firstZeroTimer; - var nextTimer = _lastZeroTimer; - _firstZeroTimer = null; - _lastZeroTimer = null; - while (_heap.isNotEmpty && _heap.first._wakeupTime <= currentTime) { - var next = _heap.removeFirst(); - if (timer == null) { - nextTimer = next; - timer = next; - } else { - nextTimer._indexOrNext = next; - nextTimer = next; - } - } - - // Trigger all of the pending timers. New timers added as part of the - // callbacks will be enqueued now and notified in the next spin at the - // earliest. - _handlingCallbacks = true; - try { - while (timer != null) { - var next = timer._indexOrNext; - timer._indexOrNext = null; - // One of the timers in the pending_timers list can cancel - // one of the later timers which will set the callback to - // null. - if (timer._callback != null) { - var callback = timer._callback; - if (!timer._repeating) { - // Mark timer as inactive. - timer._callback = null; - } - callback(timer); - // Re-insert repeating timer if not canceled. - if (timer._repeating && timer._callback != null) { - timer._advanceWakeupTime(); - timer._addTimerToHeap(); - } - } - timer = next; - } - } finally { - _handlingCallbacks = false; - _notifyEventHandler(); - } - } - - // Creates a receive port and registers the timer handler on that - // receive port. - static void _createTimerHandler() { - if(_receivePort == null) { - _receivePort = new RawReceivePort(_handleTimeout); - _sendPort = _receivePort.sendPort; - } - } - - static void _shutdownTimerHandler() { - _receivePort.close(); - _receivePort = null; - _sendPort = null; - } -} - -// Provide a closure which will allocate a Timer object to be able to hook -// up the Timer interface in dart:isolate with the implementation here. -_getTimerFactoryClosure() { - return (int milliSeconds, void callback(Timer timer), bool repeating) { - if (repeating) { - return new _Timer.periodic(milliSeconds, callback); - } - return new _Timer(milliSeconds, callback); - }; -} diff --git a/third_party/mojo/src/mojo/public/go/bindings/decoder.go b/third_party/mojo/src/mojo/public/go/bindings/decoder.go index 2dccd0a..3f3cce9 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/decoder.go +++ b/third_party/mojo/src/mojo/public/go/bindings/decoder.go @@ -185,6 +185,7 @@ func (d *Decoder) ReadUint8() (uint8, error) { if err := ensureElementBitSizeAndCapacity(d.state(), 8); err != nil { return 0, err } + d.state().alignOffsetToBytes() value := d.buf[d.state().offset] d.state().skipBytes(1) d.state().elementsProcessed++ @@ -202,6 +203,7 @@ func (d *Decoder) ReadUint16() (uint16, error) { if err := ensureElementBitSizeAndCapacity(d.state(), 16); err != nil { return 0, err } + d.state().alignOffsetToBytes() d.state().offset = align(d.state().offset, 2) value := binary.LittleEndian.Uint16(d.buf[d.state().offset:]) d.state().skipBytes(2) @@ -220,6 +222,7 @@ func (d *Decoder) ReadUint32() (uint32, error) { if err := ensureElementBitSizeAndCapacity(d.state(), 32); err != nil { return 0, err } + d.state().alignOffsetToBytes() d.state().offset = align(d.state().offset, 4) value := binary.LittleEndian.Uint32(d.buf[d.state().offset:]) d.state().skipBytes(4) @@ -238,6 +241,7 @@ func (d *Decoder) ReadUint64() (uint64, error) { if err := ensureElementBitSizeAndCapacity(d.state(), 64); err != nil { return 0, err } + d.state().alignOffsetToBytes() d.state().offset = align(d.state().offset, 8) value := binary.LittleEndian.Uint64(d.buf[d.state().offset:]) d.state().skipBytes(8) @@ -300,16 +304,59 @@ func (d *Decoder) ReadPointer() (uint64, error) { if newEnd%8 != 0 { return 0, fmt.Errorf("incorrect pointer data alignment: %d", newEnd) } - d.claimData(d.end - int(newEnd)) + d.claimData(int(newEnd) - d.end) return pointer, nil } -// ReadMessagePipeHandle reads a message pipe handle. -func (d *Decoder) ReadMessagePipeHandle() (system.MessagePipeHandle, error) { +// ReadUntypedHandle reads an untyped handle. +func (d *Decoder) ReadUntypedHandle() (system.UntypedHandle, error) { handleIndex, err := d.ReadUint32() if err != nil { return nil, err } - untypedHandle, err := d.claimHandle(int(handleIndex)) - return untypedHandle.ToMessagePipeHandle(), err + if handleIndex == ^uint32(0) { + return &InvalidHandle{}, nil + } + return d.claimHandle(int(handleIndex)) +} + +// ReadHandle reads a handle. +func (d *Decoder) ReadHandle() (system.Handle, error) { + return d.ReadUntypedHandle() +} + +// ReadMessagePipeHandle reads a message pipe handle. +func (d *Decoder) ReadMessagePipeHandle() (system.MessagePipeHandle, error) { + if handle, err := d.ReadUntypedHandle(); err != nil { + return nil, err + } else { + return handle.ToMessagePipeHandle(), nil + } +} + +// ReadConsumerHandle reads a data pipe consumer handle. +func (d *Decoder) ReadConsumerHandle() (system.ConsumerHandle, error) { + if handle, err := d.ReadUntypedHandle(); err != nil { + return nil, err + } else { + return handle.ToConsumerHandle(), nil + } +} + +// ReadProducerHandle reads a data pipe producer handle. +func (d *Decoder) ReadProducerHandle() (system.ProducerHandle, error) { + if handle, err := d.ReadUntypedHandle(); err != nil { + return nil, err + } else { + return handle.ToProducerHandle(), nil + } +} + +// ReadSharedBufferHandle reads a shared buffer handle. +func (d *Decoder) ReadSharedBufferHandle() (system.SharedBufferHandle, error) { + if handle, err := d.ReadUntypedHandle(); err != nil { + return nil, err + } else { + return handle.ToSharedBufferHandle(), nil + } } diff --git a/third_party/mojo/src/mojo/public/go/bindings/encoder.go b/third_party/mojo/src/mojo/public/go/bindings/encoder.go index 210d9b0..5ea1a50 100644 --- a/third_party/mojo/src/mojo/public/go/bindings/encoder.go +++ b/third_party/mojo/src/mojo/public/go/bindings/encoder.go @@ -36,6 +36,13 @@ type encodingState struct { elementsProcessed uint32 } +func (s *encodingState) alignOffsetToBytes() { + if s.bitOffset > 0 { + s.offset++ + s.bitOffset = 0 + } +} + func (s *encodingState) skipBits(count uint32) { s.bitOffset += count s.offset += int(s.bitOffset >> 3) // equal to s.bitOffset / 8 @@ -63,16 +70,6 @@ type Encoder struct { stateStack []encodingState } -func align(size, alignment int) int { - return ((size - 1) | (alignment - 1)) + 1 -} - -// bytesForBits returns minimum number of bytes required to store provided -// number of bits. -func bytesForBits(bits uint64) int { - return int((bits + 7) / 8) -} - func ensureElementBitSizeAndCapacity(state *encodingState, bitSize uint32) error { if state == nil { return fmt.Errorf("empty state stack") @@ -213,6 +210,7 @@ func (e *Encoder) WriteUint8(value uint8) error { if err := ensureElementBitSizeAndCapacity(e.state(), 8); err != nil { return err } + e.state().alignOffsetToBytes() e.buf[e.state().offset] = value e.state().skipBytes(1) e.state().elementsProcessed++ @@ -229,6 +227,7 @@ func (e *Encoder) WriteUint16(value uint16) error { if err := ensureElementBitSizeAndCapacity(e.state(), 16); err != nil { return err } + e.state().alignOffsetToBytes() e.state().offset = align(e.state().offset, 2) binary.LittleEndian.PutUint16(e.buf[e.state().offset:], value) e.state().skipBytes(2) @@ -246,6 +245,7 @@ func (e *Encoder) WriteUint32(value uint32) error { if err := ensureElementBitSizeAndCapacity(e.state(), 32); err != nil { return err } + e.state().alignOffsetToBytes() e.state().offset = align(e.state().offset, 4) binary.LittleEndian.PutUint32(e.buf[e.state().offset:], value) e.state().skipBytes(4) @@ -263,6 +263,7 @@ func (e *Encoder) WriteUint64(value uint64) error { if err := ensureElementBitSizeAndCapacity(e.state(), 64); err != nil { return err } + e.state().alignOffsetToBytes() e.state().offset = align(e.state().offset, 8) binary.LittleEndian.PutUint64(e.buf[e.state().offset:], value) e.state().skipBytes(8) diff --git a/third_party/mojo/src/mojo/public/go/bindings/invalid_handle.go b/third_party/mojo/src/mojo/public/go/bindings/invalid_handle.go new file mode 100644 index 0000000..1acc645 --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/invalid_handle.go @@ -0,0 +1,97 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +import ( + "mojo/public/go/system" +) + +// InvalidHandle is a handle that will always be invalid. +type InvalidHandle struct { +} + +func (h *InvalidHandle) Close() system.MojoResult { + return system.MOJO_RESULT_INVALID_ARGUMENT +} + +func (h *InvalidHandle) IsValid() bool { + return false +} + +func (h *InvalidHandle) NativeHandle() system.MojoHandle { + return system.MOJO_HANDLE_INVALID +} + +func (h *InvalidHandle) ReleaseNativeHandle() system.MojoHandle { + return system.MOJO_HANDLE_INVALID +} + +func (h *InvalidHandle) ToUntypedHandle() system.UntypedHandle { + return h +} + +func (h *InvalidHandle) Wait(signals system.MojoHandleSignals, deadline system.MojoDeadline) (system.MojoResult, system.MojoHandleSignalsState) { + return system.MOJO_RESULT_INVALID_ARGUMENT, system.MojoHandleSignalsState{} +} + +func (h *InvalidHandle) ToConsumerHandle() system.ConsumerHandle { + return h +} + +func (h *InvalidHandle) ToProducerHandle() system.ProducerHandle { + return h +} + +func (h *InvalidHandle) ToMessagePipeHandle() system.MessagePipeHandle { + return h +} + +func (h *InvalidHandle) ToSharedBufferHandle() system.SharedBufferHandle { + return h +} + +func (h *InvalidHandle) ReadData(flags system.MojoReadDataFlags) (system.MojoResult, []byte) { + return system.MOJO_RESULT_INVALID_ARGUMENT, nil +} + +func (h *InvalidHandle) BeginReadData(numBytes int, flags system.MojoReadDataFlags) (system.MojoResult, []byte) { + return system.MOJO_RESULT_INVALID_ARGUMENT, nil +} + +func (h *InvalidHandle) EndReadData(numBytesRead int) system.MojoResult { + return system.MOJO_RESULT_INVALID_ARGUMENT +} + +func (h *InvalidHandle) WriteData(data []byte, flags system.MojoWriteDataFlags) (system.MojoResult, int) { + return system.MOJO_RESULT_INVALID_ARGUMENT, 0 +} + +func (h *InvalidHandle) BeginWriteData(numBytes int, flags system.MojoWriteDataFlags) (system.MojoResult, []byte) { + return system.MOJO_RESULT_INVALID_ARGUMENT, nil +} + +func (h *InvalidHandle) EndWriteData(numBytesWritten int) system.MojoResult { + return system.MOJO_RESULT_INVALID_ARGUMENT +} + +func (h *InvalidHandle) ReadMessage(flags system.MojoReadMessageFlags) (system.MojoResult, []byte, []system.UntypedHandle) { + return system.MOJO_RESULT_INVALID_ARGUMENT, nil, nil +} + +func (h *InvalidHandle) WriteMessage(bytes []byte, handles []system.UntypedHandle, flags system.MojoWriteMessageFlags) system.MojoResult { + return system.MOJO_RESULT_INVALID_ARGUMENT +} + +func (h *InvalidHandle) DuplicateBufferHandle(opts *system.DuplicateBufferHandleOptions) (system.MojoResult, system.SharedBufferHandle) { + return system.MOJO_RESULT_INVALID_ARGUMENT, nil +} + +func (h *InvalidHandle) MapBuffer(offset uint64, numBytes int, flags system.MojoMapBufferFlags) (system.MojoResult, []byte) { + return system.MOJO_RESULT_INVALID_ARGUMENT, nil +} + +func (h *InvalidHandle) UnmapBuffer(buffer []byte) system.MojoResult { + return system.MOJO_RESULT_INVALID_ARGUMENT +} diff --git a/third_party/mojo/src/mojo/public/go/bindings/util.go b/third_party/mojo/src/mojo/public/go/bindings/util.go new file mode 100644 index 0000000..8d51ddb --- /dev/null +++ b/third_party/mojo/src/mojo/public/go/bindings/util.go @@ -0,0 +1,20 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package bindings + +func align(size, alignment int) int { + return ((size - 1) | (alignment - 1)) + 1 +} + +// bytesForBits returns minimum number of bytes required to store provided +// number of bits. +func bytesForBits(bits uint64) int { + return int((bits + 7) / 8) +} + +// StringPointer converts provided string to *string. +func StringPointer(s string) *string { + return &s +} diff --git a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom index 40fa9a6..dc4f05e 100644 --- a/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom +++ b/third_party/mojo/src/mojo/public/interfaces/bindings/tests/test_structs.mojom @@ -22,7 +22,7 @@ struct EmptyStruct { // Used to verify that struct fields which don't specify a default are // initialized to: false for bool, 0 for numbers, and null for strings, -// handles, and structs. The "?" nullable suffix shouldn't have any +// handles, and structs. The "?" nullable suffix shouldn't have any // impact on initial field values. struct NoDefaultFieldValues { @@ -58,7 +58,7 @@ struct NoDefaultFieldValues { }; // Used to verify that struct fields with an explicit default value -// are initialized correctly. The "?" nullable suffix shouldn't have any +// are initialized correctly. The "?" nullable suffix shouldn't have any // impact on initial field values. struct DefaultFieldValues { @@ -140,6 +140,18 @@ struct MapValueTypes { map<string, array<map<string, string>>> f8; }; +// Used to verify that various array types can be encoded and decoded +// successfully. + +struct ArrayValueTypes { + array<int8> f0; + array<int16> f1; + array<int32> f2; + array<int64> f3; + array<float> f4; + array<double> f5; +}; + // Used to verify that various float and double values can be encoded and // decoded correctly. @@ -189,18 +201,18 @@ struct IntegerNumberValues { const int32 V13 = 1234567890; const int32 V14 = 2147483647; - // The limits for JavaScript integers are +/- (2^53 - 1). + // The limits for JavaScript integers are +/- (2^53 - 1). const int64 V15 = -9007199254740991; // Number.MIN_SAFE_INTEGER const int64 V16 = -1; const int64 V17 = 0; const int64 V18 = 1234567890123456; const int64 V19 = 9007199254740991; // Number.MAX_SAFE_INTEGER - int8 f0 = V0; + int8 f0 = V0; int8 f1 = V1; - int8 f2 = V2; - int8 f3 = V3; - int8 f4 = V4; + int8 f2 = V2; + int8 f3 = V3; + int8 f4 = V4; int16 f5 = V5; int16 f6 = V6; @@ -237,14 +249,14 @@ struct UnsignedNumberValues { const uint32 V7 = 1234567890; const uint32 V8 = 0xFFFFFFFF; - // The limits for JavaScript integers are +/- (2^53 - 1). + // The limits for JavaScript integers are +/- (2^53 - 1). const uint64 V9 = 0; const uint64 V10 = 1234567890123456; const uint64 V11 = 9007199254740991; // Number.MAX_SAFE_INTEGER - uint8 f0 = V0; + uint8 f0 = V0; uint8 f1 = V1; - uint8 f2 = V2; + uint8 f2 = V2; uint16 f3 = V3; uint16 f4 = V4; diff --git a/third_party/mojo/src/mojo/public/tests/DEPS b/third_party/mojo/src/mojo/public/tests/DEPS deleted file mode 100644 index 0669117..0000000 --- a/third_party/mojo/src/mojo/public/tests/DEPS +++ /dev/null @@ -1,3 +0,0 @@ -include_rules = [ - "+mojo", -] diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl index 952c0dc..a73ad8e 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/interface_definition.tmpl @@ -17,7 +17,7 @@ abstract class {{interface|name}} implements core.Listener { {{interface|name}}.unbound() : stub = new {{interface|name}}Stub.unbound(); - void close() => stub.close(); + void close({bool nodefer : false}) => stub.close(nodefer: nodefer); StreamSubscription<int> listen() => stub.listen(); @@ -76,7 +76,7 @@ class {{interface|name}}Proxy extends bindings.Proxy implements {{interface|name {%- endif %} {%- endfor %} default: - throw new Exception("Unexpected message name"); + throw new bindings.MojoCodecError("Unexpected message name"); break; } } @@ -183,7 +183,7 @@ class {{interface|name}}Stub extends bindings.Stub { break; {%- endfor %} default: - throw new Exception("Unexpected message name"); + throw new bindings.MojoCodecError("Unexpected message name"); break; } return null; diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl index f5b62a9..f65298f 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/dart_templates/struct_definition.tmpl @@ -50,12 +50,13 @@ if (decoder{{level+1}} == null) { List<{{kind.key_kind|dart_type}}> keys{{level}}; List<{{kind.value_kind|dart_type}}> values{{level}}; { - {{decode('keys'~level, kind.key_kind|array, 'DataHeader.HEADER_SIZE', 0, level+1)|indent(4)}} + {{decode('keys'~level, kind.key_kind|array, 'bindings.DataHeader.kHeaderSize', 0, level+1)|indent(4)}} } { {{decode('values'~level, kind.value_kind|array('keys'~level~'.length'), 'bindings.DataHeader.kHeaderSize + bindings.kPointerSize', 0, level+1)|indent(4)}} } - {{variable}} = new Map<{{kind.key_kind|dart_type}}, {{kind.value_kind|dart_type}}>.fromIterables(keys, values); + {{variable}} = new Map<{{kind.key_kind|dart_type}}, {{kind.value_kind|dart_type}}>.fromIterables( + keys{{level}}, values{{level}}); {%- else %} var si{{level+1}} = decoder{{level+1}}.decodeDataHeaderForPointerArray({{kind|array_expected_length}}); {{variable}} = new {{kind|dart_type}}(si{{level+1}}.numFields); @@ -105,11 +106,13 @@ class {{struct|name}} extends bindings.Struct { return null; } {{struct|name}} result = new {{struct|name}}(); -{%- if not struct.bytes %} - decoder0.decodeDataHeader(); -{%- else %} + var mainDataHeader = decoder0.decodeDataHeader(); -{%- endif %} + if ((mainDataHeader.size < kStructSize) || + (mainDataHeader.numFields < {{struct.packed.packed_fields|length}})) { + throw new bindings.MojoCodecError('Malformed header'); + } + {%- for byte in struct.bytes %} {%- for packed_field in byte.packed_fields %} if (mainDataHeader.numFields > {{packed_field.ordinal}}) { diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl new file mode 100644 index 0000000..8c58c4c --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/go_templates/source.tmpl @@ -0,0 +1,11 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is autogenerated by: +// mojo/public/tools/bindings/mojom_bindings_generator.py +// For: +// {{module.path}} +// + +package {{package}} diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py index 3251095..d971b53 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_dart_generator.py @@ -69,9 +69,9 @@ _kind_to_dart_decl_type = { _spec_to_decode_method = { mojom.BOOL.spec: 'decodeBool', - mojom.DCPIPE.spec: 'decodeHandle', + mojom.DCPIPE.spec: 'decodeConsumerHandle', mojom.DOUBLE.spec: 'decodeDouble', - mojom.DPPIPE.spec: 'decodeHandle', + mojom.DPPIPE.spec: 'decodeProducerHandle', mojom.FLOAT.spec: 'decodeFloat', mojom.HANDLE.spec: 'decodeHandle', mojom.INT16.spec: 'decodeInt16', @@ -95,9 +95,9 @@ _spec_to_decode_method = { _spec_to_encode_method = { mojom.BOOL.spec: 'encodeBool', - mojom.DCPIPE.spec: 'encodeHandle', + mojom.DCPIPE.spec: 'encodeConsumerHandle', mojom.DOUBLE.spec: 'encodeDouble', - mojom.DPPIPE.spec: 'encodeHandle', + mojom.DPPIPE.spec: 'encodeProducerHandle', mojom.FLOAT.spec: 'encodeFloat', mojom.HANDLE.spec: 'encodeHandle', mojom.INT16.spec: 'encodeInt16', diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py new file mode 100644 index 0000000..3f7c938 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_go_generator.py @@ -0,0 +1,51 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +'''Generates Go source files from a mojom.Module.''' + +import os + +from mojom.generate.template_expander import UseJinja + +import mojom.generate.generator as generator +import mojom.generate.module as mojom + +def GetPackage(module): + if module.namespace: + return module.namespace.split('.')[-1] + return 'mojom' + +def GetPackagePath(module): + path = 'mojom' + for i in module.namespace.split('.'): + path = os.path.join(path, i) + return path + +class Generator(generator.Generator): + go_filters = {} + + def GetParameters(self): + return { + 'package': GetPackage(self.module), + } + + @UseJinja('go_templates/source.tmpl', filters=go_filters) + def GenerateSource(self): + return self.GetParameters() + + def GenerateFiles(self, args): + self.Write(self.GenerateSource(), os.path.join("go", "src", "gen", + GetPackagePath(self.module), '%s.go' % self.module.name)) + + def GetJinjaParameters(self): + return { + 'lstrip_blocks': True, + 'trim_blocks': True, + } + + def GetGlobals(self): + return { + 'namespace': self.module.namespace, + 'module': self.module, + } diff --git a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py index 276d5af..ad8980d 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/generators/mojom_java_generator.py @@ -15,6 +15,7 @@ import zipfile from jinja2 import contextfilter +import mojom.fileutil as fileutil import mojom.generate.generator as generator import mojom.generate.module as mojom from mojom.generate.template_expander import UseJinja @@ -212,7 +213,7 @@ def EncodeMethod(context, kind, variable, offset, bit): return 'encode(%s)' % ', '.join(params) def GetPackage(module): - if 'JavaPackage' in module.attributes: + if module.attributes and 'JavaPackage' in module.attributes: return ParseStringAttribute(module.attributes['JavaPackage']) # Default package. if module.namespace: @@ -356,7 +357,7 @@ def GetStructFromMethod(method): False, generator.GetStructFromMethod(method)) def GetConstantsMainEntityName(module): - if 'JavaConstantsClassName' in module.attributes: + if module.attributes and 'JavaConstantsClassName' in module.attributes: return ParseStringAttribute(module.attributes['JavaConstantsClassName']) # This constructs the name of the embedding classes for module level constants # by extracting the mojom's filename and prepending it to Constants. @@ -471,12 +472,7 @@ class Generator(generator.Generator): return exports def DoGenerateFiles(self): - if not os.path.exists(self.output_dir): - try: - os.makedirs(self.output_dir) - except: - # Ignore errors on directory creation. - pass + fileutil.EnsureDirectoryExists(self.output_dir) # Keep this above the others as .GetStructs() changes the state of the # module, annotating structs with required information. diff --git a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni index 6fc89c1..3e0ca4f 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni +++ b/third_party/mojo/src/mojo/public/tools/bindings/mojom.gni @@ -73,6 +73,7 @@ template("mojom") { "$generator_root/generators/dart_templates/module.lib.tmpl", "$generator_root/generators/dart_templates/module_definition.tmpl", "$generator_root/generators/dart_templates/struct_definition.tmpl", + "$generator_root/generators/go_templates/source.tmpl", "$generator_root/generators/java_templates/constant_definition.tmpl", "$generator_root/generators/java_templates/constants.java.tmpl", "$generator_root/generators/java_templates/enum.java.tmpl", @@ -93,6 +94,7 @@ template("mojom") { "$generator_root/generators/python_templates/module.py.tmpl", "$generator_root/generators/mojom_cpp_generator.py", "$generator_root/generators/mojom_dart_generator.py", + "$generator_root/generators/mojom_go_generator.py", "$generator_root/generators/mojom_js_generator.py", "$generator_root/generators/mojom_java_generator.py", "$generator_root/generators/mojom_python_generator.py", @@ -117,6 +119,7 @@ template("mojom") { ] generator_dart_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.dart" ] + generator_dart_zip_output = "$target_out_dir/$target_name.dartzip" generator_java_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ] generator_js_outputs = [ "{{source_gen_dir}}/{{source_name_part}}.mojom.js" ] @@ -209,7 +212,10 @@ template("mojom") { if (defined(invoker.deps)) { deps += invoker.deps } - data_deps = [ ":${target_name}_python" ] + data_deps = [ + ":${target_name}_python", + ":${target_name}_dart", + ] if (defined(invoker.mojo_sdk_deps)) { foreach(sdk_dep, invoker.mojo_sdk_deps) { # Check that the SDK dep was not mistakenly given as an absolute path. @@ -277,6 +283,42 @@ template("mojom") { ] } + action("${target_name}_dart") { + script = rebase_path("mojo/public/tools/gn/zip.py", ".", mojo_root) + + inputs = process_file_template(invoker.sources, generator_dart_outputs) + + deps = [] + zip_inputs = [] + + foreach(d, all_deps) { + # Resolve the name, so that a target //mojo/something becomes + # //mojo/something:something and we can append "_dart" to get the dart + # dependency name. + full_name = get_label_info(d, "label_no_toolchain") + dep_name = get_label_info(d, "name") + dep_target_out_dir = get_label_info(d, "target_out_dir") + deps += [ "${full_name}_dart" ] + zip_inputs += [ "$dep_target_out_dir/$dep_name.dartzip" ] + } + + output = generator_dart_zip_output + outputs = [ + output, + ] + + rebase_base_dir = rebase_path("$root_build_dir/gen/", root_build_dir) + rebase_inputs = rebase_path(inputs, root_build_dir) + rebase_zip_inputs = rebase_path(zip_inputs, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--base-dir=$rebase_base_dir", + "--inputs=$rebase_inputs", + "--zip-inputs=$rebase_zip_inputs", + "--output=$rebase_output", + ] + } + if (is_android) { import("//build/config/android/rules.gni") diff --git a/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py b/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py index 2d1802c..0498838 100755 --- a/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -34,6 +34,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "pylib")) from mojom.error import Error +import mojom.fileutil as fileutil from mojom.generate.data import OrderedModuleFromData from mojom.parse.parser import Parse from mojom.parse.translate import Translate @@ -50,9 +51,12 @@ def LoadGenerators(generators_string): if generator_name.lower() == "c++": generator_name = os.path.join(script_dir, "generators", "mojom_cpp_generator.py") - if generator_name.lower() == "dart": + elif generator_name.lower() == "dart": generator_name = os.path.join(script_dir, "generators", "mojom_dart_generator.py") + elif generator_name.lower() == "go": + generator_name = os.path.join(script_dir, "generators", + "mojom_go_generator.py") elif generator_name.lower() == "javascript": generator_name = os.path.join(script_dir, "generators", "mojom_js_generator.py") @@ -191,7 +195,7 @@ def main(): help="output directory for generated files") parser.add_argument("-g", "--generators", dest="generators_string", metavar="GENERATORS", - default="c++,dart,javascript,java,python", + default="c++,dart,go,javascript,java,python", help="comma-separated list of generators") parser.add_argument("--debug_print_intermediate", action="store_true", help="print the intermediate representation") @@ -204,8 +208,7 @@ def main(): generator_modules = LoadGenerators(args.generators_string) - if not os.path.exists(args.output_dir): - os.makedirs(args.output_dir) + fileutil.EnsureDirectoryExists(args.output_dir) processor = MojomProcessor(lambda filename: filename in args.filename) for filename in args.filename: diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/fileutil.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/fileutil.py new file mode 100644 index 0000000..b321e9f --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/fileutil.py @@ -0,0 +1,18 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import errno +import os.path + +def EnsureDirectoryExists(path, always_try_to_create=False): + """A wrapper for os.makedirs that does not error if the directory already + exists. A different process could be racing to create this directory.""" + + if not os.path.exists(path) or always_try_to_create: + try: + os.makedirs(path) + except OSError as e: + # There may have been a race to create this directory. + if e.errno != errno.EEXIST: + raise diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py index 6d34a40..3a41593 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/data.py @@ -42,6 +42,10 @@ def istr(index, string): rv.__index__ = index return rv +def AddOptional(dictionary, key, value): + if value is not None: + dictionary[key] = value; + builtin_values = frozenset([ "double.INFINITY", "double.NEGATIVE_INFINITY", @@ -186,15 +190,19 @@ def ImportFromData(module, data): return import_item def StructToData(struct): - return { + data = { istr(0, 'name'): struct.name, - istr(1, 'fields'): map(FieldToData, struct.fields) + istr(1, 'fields'): map(FieldToData, struct.fields), + # TODO(yzshen): EnumToData() and ConstantToData() are missing. + istr(2, 'enums'): [], + istr(3, 'constants'): [] } + AddOptional(data, istr(4, 'attributes'), struct.attributes) + return data def StructFromData(module, data): struct = mojom.Struct(module=module) struct.name = data['name'] - struct.attributes = data['attributes'] struct.spec = 'x:' + module.namespace + '.' + struct.name module.kinds[struct.spec] = struct struct.enums = map(lambda enum: @@ -203,13 +211,16 @@ def StructFromData(module, data): ConstantFromData(module, constant, struct), data['constants']) # Stash fields data here temporarily. struct.fields_data = data['fields'] + struct.attributes = data.get('attributes') return struct def UnionToData(union): - return { + data = { istr(0, 'name'): union.name, istr(1, 'fields'): map(FieldToData, union.fields) } + AddOptional(data, istr(2, 'attributes'), union.attributes) + return data def UnionFromData(module, data): union = mojom.Union(module=module) @@ -218,6 +229,7 @@ def UnionFromData(module, data): module.kinds[union.spec] = union # Stash fields data here temporarily. union.fields_data = data['fields'] + union.attributes = data.get('attributes') return union def FieldToData(field): @@ -225,10 +237,9 @@ def FieldToData(field): istr(0, 'name'): field.name, istr(1, 'kind'): KindToData(field.kind) } - if field.ordinal != None: - data[istr(2, 'ordinal')] = field.ordinal - if field.default != None: - data[istr(3, 'default')] = field.default + AddOptional(data, istr(2, 'ordinal'), field.ordinal) + AddOptional(data, istr(3, 'default'), field.default) + AddOptional(data, istr(4, 'attributes'), field.attributes) return data def FieldFromData(module, data, struct): @@ -239,6 +250,7 @@ def FieldFromData(module, data, struct): field.ordinal = data.get('ordinal') field.default = FixupExpression( module, data.get('default'), (module.namespace, struct.name), field.kind) + field.attributes = data.get('attributes') return field def ParameterToData(parameter): @@ -246,10 +258,9 @@ def ParameterToData(parameter): istr(0, 'name'): parameter.name, istr(1, 'kind'): parameter.kind.spec } - if parameter.ordinal != None: - data[istr(2, 'ordinal')] = parameter.ordinal - if parameter.default != None: - data[istr(3, 'default')] = parameter.default + AddOptional(data, istr(2, 'ordinal'), parameter.ordinal) + AddOptional(data, istr(3, 'default'), parameter.default) + AddOptional(data, istr(4, 'attributes'), parameter.attributes) return data def ParameterFromData(module, data, interface): @@ -259,6 +270,7 @@ def ParameterFromData(module, data, interface): module.kinds, data['kind'], (module.namespace, interface.name)) parameter.ordinal = data.get('ordinal') parameter.default = data.get('default') + parameter.attributes = data.get('attributes') return parameter def MethodToData(method): @@ -266,36 +278,39 @@ def MethodToData(method): istr(0, 'name'): method.name, istr(1, 'parameters'): map(ParameterToData, method.parameters) } - if method.ordinal != None: - data[istr(2, 'ordinal')] = method.ordinal - if method.response_parameters != None: - data[istr(3, 'response_parameters')] = map( + if method.response_parameters is not None: + data[istr(2, 'response_parameters')] = map( ParameterToData, method.response_parameters) + AddOptional(data, istr(3, 'ordinal'), method.ordinal) + AddOptional(data, istr(4, 'attributes'), method.attributes) return data def MethodFromData(module, data, interface): method = mojom.Method(interface, data['name'], ordinal=data.get('ordinal')) - method.default = data.get('default') method.parameters = map(lambda parameter: ParameterFromData(module, parameter, interface), data['parameters']) if data.has_key('response_parameters'): method.response_parameters = map( lambda parameter: ParameterFromData(module, parameter, interface), data['response_parameters']) + method.attributes = data.get('attributes') return method def InterfaceToData(interface): - return { + data = { istr(0, 'name'): interface.name, - istr(1, 'client'): interface.client, - istr(2, 'methods'): map(MethodToData, interface.methods) + istr(1, 'methods'): map(MethodToData, interface.methods), + # TODO(yzshen): EnumToData() and ConstantToData() are missing. + istr(2, 'enums'): [], + istr(3, 'constants'): [] } + AddOptional(data, istr(4, 'attributes'), interface.attributes) + return data def InterfaceFromData(module, data): interface = mojom.Interface(module=module) interface.name = data['name'] interface.spec = 'x:' + module.namespace + '.' + interface.name - interface.client = data['client'] if data.has_key('client') else None module.kinds[interface.spec] = interface interface.enums = map(lambda enum: EnumFromData(module, enum, interface), data['enums']) @@ -303,6 +318,7 @@ def InterfaceFromData(module, data): ConstantFromData(module, constant, interface), data['constants']) # Stash methods data here temporarily. interface.methods_data = data['methods'] + interface.attributes = data.get('attributes') return interface def EnumFieldFromData(module, enum, data, parent_kind): @@ -314,10 +330,11 @@ def EnumFieldFromData(module, enum, data, parent_kind): # vice versa? if parent_kind: field.value = FixupExpression( - module, data['value'], (module.namespace, parent_kind.name), enum) + module, data.get('value'), (module.namespace, parent_kind.name), enum) else: field.value = FixupExpression( - module, data['value'], (module.namespace, ), enum) + module, data.get('value'), (module.namespace, ), enum) + field.attributes = data.get('attributes') value = mojom.EnumValue(module, enum, field) module.values[value.GetSpec()] = value return field @@ -330,10 +347,11 @@ def EnumFromData(module, data, parent_kind): name = parent_kind.name + '.' + name enum.spec = 'x:%s.%s' % (module.namespace, name) enum.parent_kind = parent_kind - enum.fields = map( lambda field: EnumFieldFromData(module, enum, field, parent_kind), data['fields']) + enum.attributes = data.get('attributes') + module.kinds[enum.spec] = enum return enum @@ -353,13 +371,20 @@ def ConstantFromData(module, data, parent_kind): return constant def ModuleToData(module): - return { + data = { istr(0, 'name'): module.name, istr(1, 'namespace'): module.namespace, - istr(2, 'structs'): map(StructToData, module.structs), - istr(3, 'interfaces'): map(InterfaceToData, module.interfaces), + # TODO(yzshen): Imports information is missing. + istr(2, 'imports'): [], + istr(3, 'structs'): map(StructToData, module.structs), istr(4, 'unions'): map(UnionToData, module.unions), + istr(5, 'interfaces'): map(InterfaceToData, module.interfaces), + # TODO(yzshen): EnumToData() and ConstantToData() are missing. + istr(6, 'enums'): [], + istr(7, 'constants'): [] } + AddOptional(data, istr(8, 'attributes'), module.attributes) + return data def ModuleFromData(data): module = mojom.Module() @@ -371,12 +396,12 @@ def ModuleFromData(data): module.name = data['name'] module.namespace = data['namespace'] - module.attributes = data['attributes'] # Imports must come first, because they add to module.kinds which is used # by by the others. module.imports = map( lambda import_data: ImportFromData(module, import_data), data['imports']) + module.attributes = data.get('attributes') # First pass collects kinds. module.enums = map( diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py index af14ead..401c399 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -9,6 +9,7 @@ import os.path import re import module as mojom +import mojom.fileutil as fileutil import pack def GetStructFromMethod(method): @@ -50,8 +51,7 @@ def CamelCaseToAllCaps(camel_case): def WriteFile(contents, full_path): # Make sure the containing directory exists. full_dir = os.path.dirname(full_path) - if not os.path.exists(full_dir): - os.makedirs(full_dir) + fileutil.EnsureDirectoryExists(full_dir) # Dump the data to disk. with open(full_path, "w+") as f: diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py index 8e52924..8a0f56b 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/module.py @@ -130,6 +130,10 @@ PRIMITIVES = ( ) +ATTRIBUTE_MIN_VERSION = 'MinVersion' +ATTRIBUTE_CLIENT = 'Client' + + class NamedValue(object): def __init__(self, module, parent_kind, name): self.module = module @@ -174,11 +178,18 @@ class Constant(object): class Field(object): - def __init__(self, name=None, kind=None, ordinal=None, default=None): + def __init__(self, name=None, kind=None, ordinal=None, default=None, + attributes=None): self.name = name self.kind = kind self.ordinal = ordinal self.default = default + self.attributes = attributes + + @property + def min_version(self): + return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ + if self.attributes else None class Struct(ReferenceKind): @@ -186,8 +197,9 @@ class Struct(ReferenceKind): ReferenceKind.AddSharedProperty('module') ReferenceKind.AddSharedProperty('imported_from') ReferenceKind.AddSharedProperty('fields') + ReferenceKind.AddSharedProperty('attributes') - def __init__(self, name=None, module=None): + def __init__(self, name=None, module=None, attributes=None): if name is not None: spec = 'x:' + name else: @@ -197,9 +209,10 @@ class Struct(ReferenceKind): self.module = module self.imported_from = None self.fields = [] + self.attributes = attributes - def AddField(self, name, kind, ordinal=None, default=None): - field = Field(name, kind, ordinal, default) + def AddField(self, name, kind, ordinal=None, default=None, attributes=None): + field = Field(name, kind, ordinal, default, attributes) self.fields.append(field) return field @@ -209,8 +222,9 @@ class Union(ReferenceKind): ReferenceKind.AddSharedProperty('module') ReferenceKind.AddSharedProperty('imported_from') ReferenceKind.AddSharedProperty('fields') + ReferenceKind.AddSharedProperty('attributes') - def __init__(self, name=None, module=None): + def __init__(self, name=None, module=None, attributes=None): if name is not None: spec = 'x:' + name else: @@ -220,9 +234,10 @@ class Union(ReferenceKind): self.module = module self.imported_from = None self.fields = [] + self.attributes = attributes - def AddField(self, name, kind, ordinal=None): - field = Field(name, kind, ordinal, default=None) + def AddField(self, name, kind, ordinal=None, attributes=None): + field = Field(name, kind, ordinal, None, attributes) self.fields.append(field) return field @@ -287,42 +302,57 @@ class InterfaceRequest(ReferenceKind): class Parameter(object): - def __init__(self, name=None, kind=None, ordinal=None, default=None): + def __init__(self, name=None, kind=None, ordinal=None, default=None, + attributes=None): self.name = name self.ordinal = ordinal self.kind = kind self.default = default + self.attributes = attributes + + @property + def min_version(self): + return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ + if self.attributes else None class Method(object): - def __init__(self, interface, name, ordinal=None): + def __init__(self, interface, name, ordinal=None, attributes=None): self.interface = interface self.name = name self.ordinal = ordinal self.parameters = [] self.response_parameters = None + self.attributes = attributes - def AddParameter(self, name, kind, ordinal=None, default=None): - parameter = Parameter(name, kind, ordinal, default) + def AddParameter(self, name, kind, ordinal=None, default=None, + attributes=None): + parameter = Parameter(name, kind, ordinal, default, attributes) self.parameters.append(parameter) return parameter - def AddResponseParameter(self, name, kind, ordinal=None, default=None): + def AddResponseParameter(self, name, kind, ordinal=None, default=None, + attributes=None): if self.response_parameters == None: self.response_parameters = [] - parameter = Parameter(name, kind, ordinal, default) + parameter = Parameter(name, kind, ordinal, default, attributes) self.response_parameters.append(parameter) return parameter + @property + def min_version(self): + return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ + if self.attributes else None + class Interface(ReferenceKind): ReferenceKind.AddSharedProperty('module') ReferenceKind.AddSharedProperty('name') ReferenceKind.AddSharedProperty('imported_from') - ReferenceKind.AddSharedProperty('client') ReferenceKind.AddSharedProperty('methods') + ReferenceKind.AddSharedProperty('attributes') - def __init__(self, name=None, client=None, module=None): + def __init__(self, name=None, module=None, attributes=None): if name is not None: spec = 'x:' + name else: @@ -331,23 +361,33 @@ class Interface(ReferenceKind): self.module = module self.name = name self.imported_from = None - self.client = client self.methods = [] + self.attributes = attributes - def AddMethod(self, name, ordinal=None): - method = Method(self, name, ordinal=ordinal) + def AddMethod(self, name, ordinal=None, attributes=None): + method = Method(self, name, ordinal, attributes) self.methods.append(method) return method + @property + def client(self): + return self.attributes.get(ATTRIBUTE_CLIENT) if self.attributes else None + class EnumField(object): - def __init__(self, name=None, value=None): + def __init__(self, name=None, value=None, attributes=None): self.name = name self.value = value + self.attributes = attributes + + @property + def min_version(self): + return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ + if self.attributes else None class Enum(Kind): - def __init__(self, name=None, module=None): + def __init__(self, name=None, module=None, attributes=None): self.module = module self.name = name self.imported_from = None @@ -357,10 +397,11 @@ class Enum(Kind): spec = None Kind.__init__(self, spec) self.fields = [] + self.attributes = attributes class Module(object): - def __init__(self, name=None, namespace=None): + def __init__(self, name=None, namespace=None, attributes=None): self.name = name self.path = name self.namespace = namespace @@ -368,19 +409,20 @@ class Module(object): self.unions = [] self.interfaces = [] self.kinds = {} + self.attributes = attributes - def AddInterface(self, name): - interface = Interface(name, module=self) + def AddInterface(self, name, attributes=None): + interface = Interface(name, self, attributes) self.interfaces.append(interface) return interface - def AddStruct(self, name): - struct = Struct(name, module=self) + def AddStruct(self, name, attributes=None): + struct = Struct(name, self, attributes) self.structs.append(struct) return struct - def AddUnion(self, name): - union = Union(name, module=self) + def AddUnion(self, name, attributes=None): + union = Union(name, self, attributes) self.unions.append(union) return union diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py index 8f7bb3b..37d79eb 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/generate/pack.py @@ -65,6 +65,7 @@ class PackedField(object): self.size = self.GetSizeForKind(field.kind) self.offset = None self.bit = None + self.min_version = None # Returns the pad necessary to reserve space for alignment of |size|. @@ -103,6 +104,47 @@ class PackedStruct(object): ordinal += 1 src_fields.sort(key=lambda field: field.ordinal) + # Set |min_version| for each field. + # + # TODO(yzshen): We are in the middle of converting the |num_fields| field in + # encoded structs to |version|. In order to make code using |num_fields| and + # |version| work together, for structs without any [MinVersion] annotation, + # each field will be treated as if [MinVersion=ordinal+1] is set: + # + # struct Foo { + # int32 field_0; + # int32 field_1; + # } + # + # is treated as: + # + # struct Foo { + # [MinVersion=1] int32 field_0; + # [MinVersion=2] int32 field_1; + # } + # + # This way |num_fields| is the same value as |version|. + # + # This trick needs to be removed once the conversion is done. + + if any(packed_field.field.min_version is not None + for packed_field in src_fields): + # This struct has fields that explicitly set [MinVersion]. Assume that it + # is only handled by code that understands versioning. + next_min_version = 0 + for packed_field in src_fields: + if packed_field.field.min_version is None: + assert next_min_version == 0 + else: + assert packed_field.field.min_version >= next_min_version + next_min_version = packed_field.field.min_version + packed_field.min_version = next_min_version + else: + next_min_version = 1 + for packed_field in src_fields: + packed_field.min_version = next_min_version + next_min_version += 1 + src_field = src_fields[0] src_field.offset = 0 src_field.bit = 0 diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/translate.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/translate.py index 88bd269..8fbc86d 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/translate.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom/parse/translate.py @@ -55,9 +55,13 @@ def _MapKind(kind): return map_to_kind[kind] return 'x:' + kind +def _AddOptional(dictionary, key, value): + if value is not None: + dictionary[key] = value; + def _AttributeListToDict(attribute_list): if attribute_list is None: - return {} + return None assert isinstance(attribute_list, ast.AttributeList) # TODO(vtl): Check for duplicate keys here. return dict([(attribute.key, attribute.value) @@ -66,12 +70,17 @@ def _AttributeListToDict(attribute_list): def _EnumToDict(enum): def EnumValueToDict(enum_value): assert isinstance(enum_value, ast.EnumValue) - return {'name': enum_value.name, - 'value': enum_value.value} + data = {'name': enum_value.name} + _AddOptional(data, 'value', enum_value.value) + _AddOptional(data, 'attributes', + _AttributeListToDict(enum_value.attribute_list)) + return data assert isinstance(enum, ast.Enum) - return {'name': enum.name, + data = {'name': enum.name, 'fields': map(EnumValueToDict, enum.enum_value_list)} + _AddOptional(data, 'attributes', _AttributeListToDict(enum.attribute_list)) + return data def _ConstToDict(const): assert isinstance(const, ast.Const) @@ -88,71 +97,90 @@ class _MojomBuilder(object): def StructToDict(struct): def StructFieldToDict(struct_field): assert isinstance(struct_field, ast.StructField) - return {'name': struct_field.name, - 'kind': _MapKind(struct_field.typename), - 'ordinal': struct_field.ordinal.value \ - if struct_field.ordinal else None, - 'default': struct_field.default_value} + data = {'name': struct_field.name, + 'kind': _MapKind(struct_field.typename)} + _AddOptional(data, 'ordinal', + struct_field.ordinal.value + if struct_field.ordinal else None) + _AddOptional(data, 'default', struct_field.default_value) + _AddOptional(data, 'attributes', + _AttributeListToDict(struct_field.attribute_list)) + return data assert isinstance(struct, ast.Struct) - return {'name': struct.name, - 'attributes': _AttributeListToDict(struct.attribute_list), + data = {'name': struct.name, 'fields': _MapTreeForType(StructFieldToDict, struct.body, ast.StructField), 'enums': _MapTreeForType(_EnumToDict, struct.body, ast.Enum), 'constants': _MapTreeForType(_ConstToDict, struct.body, ast.Const)} + _AddOptional(data, 'attributes', + _AttributeListToDict(struct.attribute_list)) + return data def UnionToDict(union): def UnionFieldToDict(union_field): assert isinstance(union_field, ast.UnionField) - return {'name': union_field.name, - 'kind': _MapKind(union_field.typename), - 'ordinal': union_field.ordinal.value \ - if union_field.ordinal else None} + data = {'name': union_field.name, + 'kind': _MapKind(union_field.typename)} + _AddOptional(data, 'ordinal', + union_field.ordinal.value + if union_field.ordinal else None) + _AddOptional(data, 'attributes', + _AttributeListToDict(union_field.attribute_list)) + return data + assert isinstance(union, ast.Union) - return {'name': union.name, + data = {'name': union.name, 'fields': _MapTreeForType(UnionFieldToDict, union.body, ast.UnionField)} + _AddOptional(data, 'attributes', + _AttributeListToDict(union.attribute_list)) + return data def InterfaceToDict(interface): def MethodToDict(method): def ParameterToDict(param): assert isinstance(param, ast.Parameter) - return {'name': param.name, - 'kind': _MapKind(param.typename), - 'ordinal': param.ordinal.value if param.ordinal else None} + data = {'name': param.name, + 'kind': _MapKind(param.typename)} + _AddOptional(data, 'ordinal', + param.ordinal.value if param.ordinal else None) + _AddOptional(data, 'attributes', + _AttributeListToDict(param.attribute_list)) + return data assert isinstance(method, ast.Method) - rv = {'name': method.name, - 'parameters': map(ParameterToDict, method.parameter_list), - 'ordinal': method.ordinal.value if method.ordinal else None} + data = {'name': method.name, + 'parameters': map(ParameterToDict, method.parameter_list)} if method.response_parameter_list is not None: - rv['response_parameters'] = map(ParameterToDict, - method.response_parameter_list) - return rv + data['response_parameters'] = map(ParameterToDict, + method.response_parameter_list) + _AddOptional(data, 'ordinal', + method.ordinal.value if method.ordinal else None) + _AddOptional(data, 'attributes', + _AttributeListToDict(method.attribute_list)) + return data assert isinstance(interface, ast.Interface) - attributes = _AttributeListToDict(interface.attribute_list) - return {'name': interface.name, - 'attributes': attributes, - 'client': attributes.get('Client'), + data = {'name': interface.name, 'methods': _MapTreeForType(MethodToDict, interface.body, ast.Method), 'enums': _MapTreeForType(_EnumToDict, interface.body, ast.Enum), 'constants': _MapTreeForType(_ConstToDict, interface.body, ast.Const)} + _AddOptional(data, 'attributes', + _AttributeListToDict(interface.attribute_list)) + return data assert isinstance(tree, ast.Mojom) self.mojom['name'] = name self.mojom['namespace'] = tree.module.name[1] if tree.module else '' self.mojom['imports'] = \ [{'filename': imp.import_filename} for imp in tree.import_list] - self.mojom['attributes'] = \ - _AttributeListToDict(tree.module.attribute_list) if tree.module else {} self.mojom['structs'] = \ _MapTreeForType(StructToDict, tree.definition_list, ast.Struct) - self.mojom['union'] = \ + self.mojom['unions'] = \ _MapTreeForType(UnionToDict, tree.definition_list, ast.Union) self.mojom['interfaces'] = \ _MapTreeForType(InterfaceToDict, tree.definition_list, ast.Interface) @@ -160,6 +188,9 @@ class _MojomBuilder(object): _MapTreeForType(_EnumToDict, tree.definition_list, ast.Enum) self.mojom['constants'] = \ _MapTreeForType(_ConstToDict, tree.definition_list, ast.Const) + _AddOptional(self.mojom, 'attributes', + _AttributeListToDict(tree.module.attribute_list) + if tree.module else None) return self.mojom diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/fileutil_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/fileutil_unittest.py new file mode 100644 index 0000000..d56faad --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/fileutil_unittest.py @@ -0,0 +1,55 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import imp +import os.path +import shutil +import sys +import tempfile +import unittest + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + +try: + imp.find_module("mojom") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) +from mojom import fileutil + + +class FileUtilTest(unittest.TestCase): + + def testEnsureDirectoryExists(self): + """Test that EnsureDirectoryExists fuctions correctly.""" + + temp_dir = tempfile.mkdtemp() + try: + self.assertTrue(os.path.exists(temp_dir)) + + # Directory does not exist, yet. + full = os.path.join(temp_dir, "foo", "bar") + self.assertFalse(os.path.exists(full)) + + # Create the directory. + fileutil.EnsureDirectoryExists(full) + self.assertTrue(os.path.exists(full)) + + # Trying to create it again does not cause an error. + fileutil.EnsureDirectoryExists(full) + self.assertTrue(os.path.exists(full)) + + # Bypass check for directory existence to tickle error handling that + # occurs in response to a race. + fileutil.EnsureDirectoryExists(full, always_try_to_create=True) + self.assertTrue(os.path.exists(full)) + finally: + shutil.rmtree(temp_dir) diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/data_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/data_unittest.py index 9ad63c1..90c90e3 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/data_unittest.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/data_unittest.py @@ -32,7 +32,6 @@ class DataTest(unittest.TestCase): module = mojom.Module('test_module', 'test_namespace') struct_data = { 'name': 'SomeStruct', - 'attributes': [], 'enums': [], 'constants': [], 'fields': [ @@ -41,9 +40,6 @@ class DataTest(unittest.TestCase): {'name': 'field3', 'kind': 'i32', 'default': 15}]} struct = data.StructFromData(module, struct_data) - del struct_data['attributes'] - del struct_data['enums'] - del struct_data['constants'] struct.fields = map(lambda field: data.FieldFromData(module, field, struct), struct.fields_data) self.assertEquals(struct_data, data.StructToData(struct)) diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py new file mode 100644 index 0000000..329e242 --- /dev/null +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/generate/pack_unittest.py @@ -0,0 +1,54 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import imp +import os.path +import sys +import unittest + + +def _GetDirAbove(dirname): + """Returns the directory "above" this file containing |dirname| (which must + also be "above" this file).""" + path = os.path.abspath(__file__) + while True: + path, tail = os.path.split(path) + assert tail + if tail == dirname: + return path + + +try: + imp.find_module("mojom") +except ImportError: + sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) +from mojom.generate import pack +from mojom.generate import module as mojom + + +# TODO(yzshen): Move tests in pack_tests.py here. +class PackTest(unittest.TestCase): + + def testMinVersion(self): + """Tests that |min_version| is properly set for packed fields.""" + struct = mojom.Struct('test') + struct.AddField('field_2', mojom.BOOL, 2) + struct.AddField('field_0', mojom.INT32, 0) + struct.AddField('field_1', mojom.INT64, 1) + ps = pack.PackedStruct(struct) + + self.assertEquals("field_0", ps.packed_fields[0].field.name) + self.assertEquals("field_2", ps.packed_fields[1].field.name) + self.assertEquals("field_1", ps.packed_fields[2].field.name) + + self.assertEquals(1, ps.packed_fields[0].min_version) + self.assertEquals(3, ps.packed_fields[1].min_version) + self.assertEquals(2, ps.packed_fields[2].min_version) + + struct.fields[0].attributes = {'MinVersion': 1} + ps = pack.PackedStruct(struct) + + self.assertEquals(0, ps.packed_fields[0].min_version) + self.assertEquals(1, ps.packed_fields[1].min_version) + self.assertEquals(0, ps.packed_fields[2].min_version) diff --git a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py index 20704dc..29dd906 100644 --- a/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py +++ b/third_party/mojo/src/mojo/public/tools/bindings/pylib/mojom_tests/parse/translate_unittest.py @@ -54,11 +54,10 @@ class TranslateTest(unittest.TestCase): ast.UnionField("b", None, None, "string")]))]) expected = [{ "name": "SomeUnion", - "fields": [ - {"kind": "i32", "name": "a", "ordinal": None}, - {"kind": "s", "name": "b", "ordinal": None}]}] + "fields": [{"kind": "i32", "name": "a"}, + {"kind": "s", "name": "b"}]}] actual = translate.Translate(tree, "mojom_tree") - self.assertEquals(actual["union"], expected) + self.assertEquals(actual["unions"], expected) if __name__ == "__main__": |