diff options
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/common/bindings_support_impl.cc | 65 | ||||
-rw-r--r-- | mojo/common/bindings_support_impl.h | 39 | ||||
-rw-r--r-- | mojo/common/handle_watcher.cc | 26 | ||||
-rw-r--r-- | mojo/common/handle_watcher.h | 4 | ||||
-rw-r--r-- | mojo/common/handle_watcher_unittest.cc | 33 | ||||
-rw-r--r-- | mojo/mojo.gyp | 5 | ||||
-rw-r--r-- | mojo/public/bindings/lib/bindings_support.h | 28 | ||||
-rw-r--r-- | mojo/public/bindings/lib/connector.cc | 41 | ||||
-rw-r--r-- | mojo/public/bindings/lib/connector.h | 7 | ||||
-rw-r--r-- | mojo/public/tests/simple_bindings_support.cc | 47 | ||||
-rw-r--r-- | mojo/public/tests/simple_bindings_support.h | 13 | ||||
-rw-r--r-- | mojo/shell/context.cc | 2 | ||||
-rw-r--r-- | mojo/shell/context.h | 2 |
13 files changed, 231 insertions, 81 deletions
diff --git a/mojo/common/bindings_support_impl.cc b/mojo/common/bindings_support_impl.cc new file mode 100644 index 0000000..9cec141 --- /dev/null +++ b/mojo/common/bindings_support_impl.cc @@ -0,0 +1,65 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/common/bindings_support_impl.h" + +#include "base/atomic_ref_count.h" +#include "base/bind.h" +#include "mojo/common/handle_watcher.h" + +namespace mojo { +namespace common { + +// Context is used to track the number of HandleWatcher objects in use by a +// particular BindingsSupportImpl instance. +class BindingsSupportImpl::Context + : public base::RefCountedThreadSafe<BindingsSupportImpl::Context> { + public: + void CallOnHandleReady(HandleWatcher* watcher, + AsyncWaitCallback* callback, + MojoResult result) { + delete watcher; + callback->OnHandleReady(result); + } + + private: + friend class base::RefCountedThreadSafe<Context>; + virtual ~Context() {} +}; + +BindingsSupportImpl::BindingsSupportImpl() + : context_(new Context()) { +} + +BindingsSupportImpl::~BindingsSupportImpl() { + // All HandleWatcher instances created through this interface should have + // been destroyed. + DCHECK(context_->HasOneRef()); +} + +BindingsSupport::AsyncWaitID BindingsSupportImpl::AsyncWait( + Handle handle, + MojoWaitFlags flags, + AsyncWaitCallback* callback) { + // This instance will be deleted when done or cancelled. + HandleWatcher* watcher = new HandleWatcher(); + + // TODO(darin): Standardize on mojo::Handle instead of MojoHandle? + watcher->Start(handle.value, + flags, + MOJO_DEADLINE_INDEFINITE, + base::Bind(&Context::CallOnHandleReady, + context_, + watcher, + callback)); + return watcher; +} + +void BindingsSupportImpl::CancelWait(AsyncWaitID async_wait_id) { + HandleWatcher* watcher = static_cast<HandleWatcher*>(async_wait_id); + delete watcher; +} + +} // namespace common +} // namespace mojo diff --git a/mojo/common/bindings_support_impl.h b/mojo/common/bindings_support_impl.h new file mode 100644 index 0000000..1178644 --- /dev/null +++ b/mojo/common/bindings_support_impl.h @@ -0,0 +1,39 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_COMMON_BINDINGS_SUPPORT_IMPL_H_ +#define MOJO_COMMON_BINDINGS_SUPPORT_IMPL_H_ + +#include "mojo/public/bindings/lib/bindings_support.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "mojo/common/mojo_common_export.h" + +namespace mojo { +namespace common { + +class MOJO_COMMON_EXPORT BindingsSupportImpl + : NON_EXPORTED_BASE(public BindingsSupport) { + public: + BindingsSupportImpl(); + virtual ~BindingsSupportImpl(); + + // BindingsSupport methods: + virtual AsyncWaitID AsyncWait(Handle handle, MojoWaitFlags flags, + AsyncWaitCallback* callback) OVERRIDE; + virtual void CancelWait(AsyncWaitID async_wait_id) OVERRIDE; + + private: + class Context; + scoped_refptr<Context> context_; + + DISALLOW_COPY_AND_ASSIGN(BindingsSupportImpl); +}; + +} // namespace common +} // namespace mojo + +#endif // MOJO_COMMON_BINDINGS_SUPPORT_IMPL_H_ diff --git a/mojo/common/handle_watcher.cc b/mojo/common/handle_watcher.cc index 1fef74a..a159185 100644 --- a/mojo/common/handle_watcher.cc +++ b/mojo/common/handle_watcher.cc @@ -47,7 +47,7 @@ class WatcherThreadManager { WatcherID StartWatching(MojoHandle handle, MojoWaitFlags wait_flags, base::TimeTicks deadline, - const base::Closure& callback); + const base::Callback<void(MojoResult)>& callback); // Stops watching a handle. void StopWatching(WatcherID watcher_id); @@ -65,7 +65,7 @@ class WatcherThreadManager { MojoHandle handle; MojoWaitFlags wait_flags; base::TimeTicks deadline; - base::Closure callback; + base::Callback<void(MojoResult)> callback; scoped_refptr<base::MessageLoopProxy> message_loop; }; @@ -138,10 +138,11 @@ WatcherThreadManager* WatcherThreadManager::GetInstance() { return &instance.Get(); } -WatcherID WatcherThreadManager::StartWatching(MojoHandle handle, - MojoWaitFlags wait_flags, - base::TimeTicks deadline, - const base::Closure& callback) { +WatcherID WatcherThreadManager::StartWatching( + MojoHandle handle, + MojoWaitFlags wait_flags, + base::TimeTicks deadline, + const base::Callback<void(MojoResult)>& callback) { WatcherID id = 0; { static int next_id = 0; @@ -264,7 +265,8 @@ void WatcherThreadManager::RemoveAndNotify(WatcherID id, MojoResult result) { to_notify = i->second; id_to_callback_.erase(i); } - to_notify.message_loop->PostTask(FROM_HERE, to_notify.callback); + to_notify.message_loop->PostTask(FROM_HERE, + base::Bind(to_notify.callback, result)); } void WatcherThreadManager::RemoveHandle(MojoHandle handle) { @@ -328,7 +330,7 @@ struct HandleWatcher::StartState { WatcherID watcher_id; // Callback to notify when done. - base::Closure callback; + base::Callback<void(MojoResult)> callback; // When Start() is invoked a callback is passed to WatcherThreadManager // using a WeakRef from |weak_refactory_|. The callback invokes @@ -354,7 +356,7 @@ HandleWatcher::~HandleWatcher() { void HandleWatcher::Start(MojoHandle handle, MojoWaitFlags wait_flags, MojoDeadline deadline, - const base::Closure& callback) { + const base::Callback<void(MojoResult)>& callback) { DCHECK_NE(MOJO_HANDLE_INVALID, handle); DCHECK_NE(MOJO_WAIT_FLAG_NONE, wait_flags); @@ -379,10 +381,12 @@ void HandleWatcher::Stop() { WatcherThreadManager::GetInstance()->StopWatching(old_state->watcher_id); } -void HandleWatcher::OnHandleReady() { +void HandleWatcher::OnHandleReady(MojoResult result) { DCHECK(start_state_.get()); scoped_ptr<StartState> old_state(start_state_.Pass()); - old_state->callback.Run(); + old_state->callback.Run(result); + + // NOTE: We may have been deleted during callback execution. } // static diff --git a/mojo/common/handle_watcher.h b/mojo/common/handle_watcher.h index 8e04aa7..a6a73ea 100644 --- a/mojo/common/handle_watcher.h +++ b/mojo/common/handle_watcher.h @@ -38,7 +38,7 @@ class MOJO_COMMON_EXPORT HandleWatcher { void Start(MojoHandle handle, MojoWaitFlags wait_flags, MojoDeadline deadline, - const base::Closure& callback); + const base::Callback<void(MojoResult)>& callback); // Stops listening. Does nothing if not in the process of listening. void Stop(); @@ -54,7 +54,7 @@ class MOJO_COMMON_EXPORT HandleWatcher { struct StartState; // See description of |StartState::weak_factory| for details. - void OnHandleReady(); + void OnHandleReady(MojoResult result); // If non-NULL Start() has been invoked. scoped_ptr<StartState> start_state_; diff --git a/mojo/common/handle_watcher_unittest.cc b/mojo/common/handle_watcher_unittest.cc index ae1a175..a10585a 100644 --- a/mojo/common/handle_watcher_unittest.cc +++ b/mojo/common/handle_watcher_unittest.cc @@ -32,6 +32,14 @@ void RunUntilIdle() { run_loop.RunUntilIdle(); } +void DeleteWatcherAndForwardResult( + HandleWatcher* watcher, + base::Callback<void(MojoResult)> next_callback, + MojoResult result) { + delete watcher; + next_callback.Run(result); +} + // Helper class to manage the callback and running the message loop waiting for // message to be received. Typical usage is something like: // Schedule callback returned from GetCallback(). @@ -59,17 +67,22 @@ class CallbackHelper { run_loop.Run(); } - base::Closure GetCallback() { + base::Callback<void(MojoResult)> GetCallback() { return base::Bind(&CallbackHelper::OnCallback, weak_factory_.GetWeakPtr()); } void Start(HandleWatcher* watcher, MojoHandle handle) { + StartWithCallback(watcher, handle, GetCallback()); + } + + void StartWithCallback(HandleWatcher* watcher, MojoHandle handle, + const base::Callback<void(MojoResult)>& callback) { watcher->Start(handle, MOJO_WAIT_FLAG_READABLE, MOJO_DEADLINE_INDEFINITE, - GetCallback()); + callback); } private: - void OnCallback() { + void OnCallback(MojoResult result) { got_callback_ = true; if (run_loop_) run_loop_->Quit(); @@ -275,6 +288,20 @@ TEST_F(HandleWatcherTest, Deadline) { EXPECT_FALSE(callback_helper3.got_callback()); } +TEST_F(HandleWatcherTest, DeleteInCallback) { + ScopedMessagePipe test_pipe; + CallbackHelper callback_helper; + + HandleWatcher* watcher = new HandleWatcher(); + callback_helper.StartWithCallback(watcher, test_pipe.handle_1(), + base::Bind(&DeleteWatcherAndForwardResult, + watcher, + callback_helper.GetCallback())); + WriteToHandle(test_pipe.handle_0()); + callback_helper.RunUntilGotCallback(); + EXPECT_TRUE(callback_helper.got_callback()); +} + } // namespace test } // namespace common } // namespace mojo diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index a01aa88..3e71fe2 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -69,6 +69,8 @@ 'mojo_system', ], 'sources': [ + 'common/bindings_support_impl.cc', + 'common/bindings_support_impl.h', 'common/handle_watcher.cc', 'common/handle_watcher.h', 'common/scoped_message_pipe.cc', @@ -217,6 +219,7 @@ '../base/base.gyp:base', '../net/net.gyp:net', '../url/url.gyp:url_lib', + 'mojo_bindings', 'mojo_system', 'mojo_utility', 'native_viewport', @@ -257,6 +260,7 @@ '../base/base.gyp:base', '../ui/gl/gl.gyp:gl', '../url/url.gyp:url_lib', + 'mojo_common_lib', 'mojo_shell_lib', 'mojo_system', ], @@ -478,6 +482,7 @@ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../ui/gfx/gfx.gyp:gfx', '../ui/gl/gl.gyp:gl', + 'mojo_common_lib', 'mojo_jni_headers', 'mojo_shell_lib', ], diff --git a/mojo/public/bindings/lib/bindings_support.h b/mojo/public/bindings/lib/bindings_support.h index 15aa65b..a1979f6 100644 --- a/mojo/public/bindings/lib/bindings_support.h +++ b/mojo/public/bindings/lib/bindings_support.h @@ -15,22 +15,30 @@ class BindingsSupport { public: class AsyncWaitCallback { public: + virtual ~AsyncWaitCallback() {} virtual void OnHandleReady(MojoResult result) = 0; }; - // Asynchronously call MojoWait on a background thread, and return the result - // to the current thread via the given AsyncWaitCallback. - virtual bool AsyncWait(Handle handle, - MojoWaitFlags flags, - MojoDeadline deadline, - AsyncWaitCallback* callback) = 0; - - // Cancel an existing call to AsyncWait with the given callback. The - // callback's OnHandleReady method should not be called in this case. - virtual void CancelWait(AsyncWaitCallback* callback) = 0; + typedef void* AsyncWaitID; static void Set(BindingsSupport* support); static BindingsSupport* Get(); + + // Asynchronously call MojoWait on a background thread, and pass the result + // of MojoWait to the given AsyncWaitCallback on the current thread. Returns + // an AsyncWaitID that can be used with CancelWait to stop waiting. This + // identifier becomes invalid once the callback runs. + virtual AsyncWaitID AsyncWait(Handle handle, + MojoWaitFlags flags, + AsyncWaitCallback* callback) = 0; + + // Cancel an existing call to AsyncWait with the given AsyncWaitID. The + // corresponding AsyncWaitCallback's OnHandleReady method will not be called + // in this case. + virtual void CancelWait(AsyncWaitID id) = 0; + + protected: + virtual ~BindingsSupport() {} }; } // namespace mojo diff --git a/mojo/public/bindings/lib/connector.cc b/mojo/public/bindings/lib/connector.cc index f72bca3..3185536 100644 --- a/mojo/public/bindings/lib/connector.cc +++ b/mojo/public/bindings/lib/connector.cc @@ -20,10 +20,6 @@ Connector::Connector(Handle message_pipe) } Connector::~Connector() { - if (read_callback_.IsPending()) - read_callback_.Cancel(); - if (write_callback_.IsPending()) - write_callback_.Cancel(); } void Connector::SetIncomingReceiver(MessageReceiver* receiver) { @@ -58,24 +54,18 @@ void Connector::OnHandleReady(Callback* callback, MojoResult result) { void Connector::WaitToReadMore() { read_callback_.SetOwnerToNotify(this); - - bool ok = BindingsSupport::Get()->AsyncWait(message_pipe_, - MOJO_WAIT_FLAG_READABLE, - MOJO_DEADLINE_INDEFINITE, - &read_callback_); - if (!ok) - error_ = true; + read_callback_.SetAsyncWaitID( + BindingsSupport::Get()->AsyncWait(message_pipe_, + MOJO_WAIT_FLAG_READABLE, + &read_callback_)); } void Connector::WaitToWriteMore() { write_callback_.SetOwnerToNotify(this); - - bool ok = BindingsSupport::Get()->AsyncWait(message_pipe_, - MOJO_WAIT_FLAG_WRITABLE, - MOJO_DEADLINE_INDEFINITE, - &write_callback_); - if (!ok) - error_ = true; + write_callback_.SetAsyncWaitID( + BindingsSupport::Get()->AsyncWait(message_pipe_, + MOJO_WAIT_FLAG_WRITABLE, + &write_callback_)); } void Connector::ReadMore() { @@ -140,7 +130,7 @@ void Connector::WriteOne(Message* message, bool* wait_to_write) { MojoResult rv = WriteMessage(message_pipe_, message->data, message->data->header.num_bytes, - message->handles.data(), + &message->handles[0], static_cast<uint32_t>(message->handles.size()), MOJO_WRITE_MESSAGE_FLAG_NONE); if (rv == MOJO_RESULT_OK) { @@ -155,12 +145,13 @@ void Connector::WriteOne(Message* message, bool* wait_to_write) { // ---------------------------------------------------------------------------- Connector::Callback::Callback() - : owner_(NULL) { + : owner_(NULL), + async_wait_id_(0) { } -void Connector::Callback::Cancel() { - owner_ = NULL; - BindingsSupport::Get()->CancelWait(this); +Connector::Callback::~Callback() { + if (owner_) + BindingsSupport::Get()->CancelWait(async_wait_id_); } void Connector::Callback::SetOwnerToNotify(Connector* owner) { @@ -168,8 +159,8 @@ void Connector::Callback::SetOwnerToNotify(Connector* owner) { owner_ = owner; } -bool Connector::Callback::IsPending() const { - return owner_ != NULL; +void Connector::Callback::SetAsyncWaitID(BindingsSupport::AsyncWaitID id) { + async_wait_id_ = id; } void Connector::Callback::OnHandleReady(MojoResult result) { diff --git a/mojo/public/bindings/lib/connector.h b/mojo/public/bindings/lib/connector.h index 808ab54..4953e82 100644 --- a/mojo/public/bindings/lib/connector.h +++ b/mojo/public/bindings/lib/connector.h @@ -42,15 +42,16 @@ class Connector : public MessageReceiver { class Callback : public BindingsSupport::AsyncWaitCallback { public: Callback(); + virtual ~Callback(); - void Cancel(); void SetOwnerToNotify(Connector* owner); - bool IsPending() const; + void SetAsyncWaitID(BindingsSupport::AsyncWaitID async_wait_id); virtual void OnHandleReady(MojoResult result) MOJO_OVERRIDE; private: Connector* owner_; + BindingsSupport::AsyncWaitID async_wait_id_; }; friend class Callback; @@ -69,6 +70,8 @@ class Connector : public MessageReceiver { Callback write_callback_; bool error_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(Connector); }; } // namespace mojo diff --git a/mojo/public/tests/simple_bindings_support.cc b/mojo/public/tests/simple_bindings_support.cc index 979474d..a59a66e 100644 --- a/mojo/public/tests/simple_bindings_support.cc +++ b/mojo/public/tests/simple_bindings_support.cc @@ -15,47 +15,52 @@ SimpleBindingsSupport::SimpleBindingsSupport() { SimpleBindingsSupport::~SimpleBindingsSupport() { BindingsSupport::Set(NULL); + + for (WaiterList::iterator it = waiters_.begin(); it != waiters_.end(); ++it) + delete *it; } -bool SimpleBindingsSupport::AsyncWait(Handle handle, - MojoWaitFlags flags, - MojoDeadline deadline, - AsyncWaitCallback* callback) { - Waiter waiter; - waiter.handle = handle; - waiter.flags = flags; - waiter.deadline = deadline; - waiter.callback = callback; +BindingsSupport::AsyncWaitID SimpleBindingsSupport::AsyncWait( + Handle handle, + MojoWaitFlags flags, + AsyncWaitCallback* callback) { + Waiter* waiter = new Waiter(); + waiter->handle = handle; + waiter->flags = flags; + waiter->callback = callback; waiters_.push_back(waiter); - return true; + return waiter; } -void SimpleBindingsSupport::CancelWait(AsyncWaitCallback* callback) { - std::list<Waiter>::iterator it = waiters_.begin(); +void SimpleBindingsSupport::CancelWait(AsyncWaitID async_wait_id) { + Waiter* waiter = static_cast<Waiter*>(async_wait_id); + + WaiterList::iterator it = waiters_.begin(); while (it != waiters_.end()) { - if (it->callback == callback) { - std::list<Waiter>::iterator doomed = it++; + if (*it == waiter) { + WaiterList::iterator doomed = it++; waiters_.erase(doomed); } else { ++it; } } + + delete waiter; } void SimpleBindingsSupport::Process() { typedef std::pair<AsyncWaitCallback*, MojoResult> Result; std::list<Result> results; - // TODO(darin): Honor given deadline. - - std::list<Waiter>::iterator it = waiters_.begin(); + WaiterList::iterator it = waiters_.begin(); while (it != waiters_.end()) { - const Waiter& waiter = *it; + Waiter* waiter = *it; MojoResult result; - if (IsReady(waiter.handle, waiter.flags, &result)) { - results.push_back(std::make_pair(waiter.callback, result)); - std::list<Waiter>::iterator doomed = it++; + if (IsReady(waiter->handle, waiter->flags, &result)) { + results.push_back(std::make_pair(waiter->callback, result)); + WaiterList::iterator doomed = it++; waiters_.erase(doomed); + delete waiter; } else { ++it; } diff --git a/mojo/public/tests/simple_bindings_support.h b/mojo/public/tests/simple_bindings_support.h index c22de82..59131ba 100644 --- a/mojo/public/tests/simple_bindings_support.h +++ b/mojo/public/tests/simple_bindings_support.h @@ -17,11 +17,10 @@ class SimpleBindingsSupport : public BindingsSupport { SimpleBindingsSupport(); virtual ~SimpleBindingsSupport(); - virtual bool AsyncWait(Handle handle, - MojoWaitFlags flags, - MojoDeadline deadline, - AsyncWaitCallback* callback) MOJO_OVERRIDE; - virtual void CancelWait(AsyncWaitCallback* callback) MOJO_OVERRIDE; + virtual AsyncWaitID AsyncWait(Handle handle, + MojoWaitFlags flags, + AsyncWaitCallback* callback) MOJO_OVERRIDE; + virtual void CancelWait(AsyncWaitID async_wait_id) MOJO_OVERRIDE; // This method is called by unit tests to check the status of any handles // that we are asynchronously waiting on and to dispatch callbacks for any @@ -34,11 +33,11 @@ class SimpleBindingsSupport : public BindingsSupport { struct Waiter { Handle handle; MojoWaitFlags flags; - MojoDeadline deadline; AsyncWaitCallback* callback; }; - std::list<Waiter> waiters_; + typedef std::list<Waiter*> WaiterList; + WaiterList waiters_; }; } // namespace test diff --git a/mojo/shell/context.cc b/mojo/shell/context.cc index c2e2f90..6a4be90 100644 --- a/mojo/shell/context.cc +++ b/mojo/shell/context.cc @@ -18,9 +18,11 @@ Context::Context() scoped_ptr<net::NetworkDelegate>(new NetworkDelegate()), storage_.profile_path()) { system::CoreImpl::Init(); + BindingsSupport::Set(&bindings_support_impl_); } Context::~Context() { + BindingsSupport::Set(NULL); } } // namespace shell diff --git a/mojo/shell/context.h b/mojo/shell/context.h index f2dec12..16c04b4 100644 --- a/mojo/shell/context.h +++ b/mojo/shell/context.h @@ -5,6 +5,7 @@ #ifndef MOJO_SHELL_CONTEXT_H_ #define MOJO_SHELL_CONTEXT_H_ +#include "mojo/common/bindings_support_impl.h" #include "mojo/shell/loader.h" #include "mojo/shell/storage.h" #include "mojo/shell/task_runners.h" @@ -34,6 +35,7 @@ class Context { TaskRunners task_runners_; Storage storage_; Loader loader_; + common::BindingsSupportImpl bindings_support_impl_; #if defined(OS_ANDROID) base::android::ScopedJavaGlobalRef<jobject> activity_; |