Index: extensions/browser/mojo/stash_backend.cc |
diff --git a/extensions/browser/mojo/stash_backend.cc b/extensions/browser/mojo/stash_backend.cc |
index da4842d3340035a88ce8c840ebb327c7705c2eb1..8fa2fbd850b97cb20aac473f8b2aac77cf5e7ab5 100644 |
--- a/extensions/browser/mojo/stash_backend.cc |
+++ b/extensions/browser/mojo/stash_backend.cc |
@@ -4,7 +4,11 @@ |
#include "extensions/browser/mojo/stash_backend.h" |
+#include "base/bind.h" |
+#include "third_party/mojo/src/mojo/public/cpp/environment/async_waiter.h" |
+ |
namespace extensions { |
+namespace { |
// An implementation of StashService that forwards calls to a StashBackend. |
class StashServiceImpl : public mojo::InterfaceImpl<StashService> { |
Ken Rockot(use gerrit already)
2015/02/06 04:21:27
Maybe nix the InterfaceImpl base and just implemen
Sam McNally
2015/02/06 05:48:22
Done.
|
@@ -24,7 +28,66 @@ class StashServiceImpl : public mojo::InterfaceImpl<StashService> { |
DISALLOW_COPY_AND_ASSIGN(StashServiceImpl); |
}; |
-StashBackend::StashBackend() : weak_factory_(this) { |
+StashServiceImpl::StashServiceImpl(base::WeakPtr<StashBackend> backend) |
+ : backend_(backend) { |
+} |
+ |
+StashServiceImpl::~StashServiceImpl() { |
+} |
+ |
+void StashServiceImpl::AddToStash( |
+ mojo::Array<StashedObjectPtr> stashed_objects) { |
+ if (!backend_) |
+ return; |
+ backend_->AddToStash(stashed_objects.Pass()); |
+} |
+ |
+void StashServiceImpl::RetrieveStash( |
+ const mojo::Callback<void(mojo::Array<StashedObjectPtr>)>& callback) { |
+ if (!backend_) { |
+ callback.Run(mojo::Array<StashedObjectPtr>(0)); |
+ return; |
+ } |
+ callback.Run(backend_->RetrieveStash()); |
+} |
+ |
+} // namespace |
+ |
+// A stash entry for a stashed object. This handles notifications if a handle |
+// within the stashed object is readable. |
+class StashBackend::StashEntry { |
+ public: |
+ // Construct a StashEntry for |stashed_object|. If |on_handle_readable| is |
+ // non-null, it will be invoked when any handle on |stashed_object| is |
+ // readable. |
+ StashEntry(StashedObjectPtr stashed_object, |
+ const base::Closure& on_handle_readable); |
+ ~StashEntry(); |
+ |
+ // Returns the stashed object. |
+ StashedObjectPtr Release(); |
+ |
+ // Cancels notifications for handles becoming readable. |
+ void CancelHandleNotifications(); |
+ |
+ private: |
+ // Invoked when a handle within |stashed_object_| is readable. |
+ void OnHandleReady(MojoResult result); |
+ |
+ // The waiters that are waiting for handles to be readable. |
+ std::vector<linked_ptr<mojo::AsyncWaiter>> waiters_; |
Ken Rockot(use gerrit already)
2015/02/06 04:21:27
Maybe use a ScopedVector for the waiters instead?
Sam McNally
2015/02/06 05:48:22
Done.
|
+ |
+ StashedObjectPtr stashed_object_; |
+ |
+ // If non-null, a callback to call when a handle contained within |
+ // |stashed_object_| is readable. |
+ const base::Closure on_handle_readable_; |
+}; |
+ |
+StashBackend::StashBackend(const base::Closure& on_handle_readable) |
+ : on_handle_readable_(on_handle_readable), |
+ has_notified_(false), |
+ weak_factory_(this) { |
} |
StashBackend::~StashBackend() { |
@@ -32,14 +95,22 @@ StashBackend::~StashBackend() { |
void StashBackend::AddToStash(mojo::Array<StashedObjectPtr> stashed_objects) { |
for (size_t i = 0; i < stashed_objects.size(); i++) { |
- stashed_objects_.push_back(stashed_objects[i].Pass()); |
+ stashed_objects_.push_back(linked_ptr<StashEntry>(new StashEntry( |
Ken Rockot(use gerrit already)
2015/02/06 04:21:27
Seems like stashed_objects_ could also be a Scoped
Sam McNally
2015/02/06 05:48:22
Done.
|
+ stashed_objects[i].Pass(), |
+ has_notified_ ? base::Closure() |
+ : base::Bind(&StashBackend::OnHandleReady, |
+ weak_factory_.GetWeakPtr())))); |
} |
} |
mojo::Array<StashedObjectPtr> StashBackend::RetrieveStash() { |
- if (stashed_objects_.is_null()) |
- stashed_objects_.resize(0); |
- return stashed_objects_.Pass(); |
+ has_notified_ = false; |
+ mojo::Array<StashedObjectPtr> result(0); |
+ for (auto& entry : stashed_objects_) { |
+ result.push_back(entry->Release()); |
+ } |
+ stashed_objects_.clear(); |
+ return result.Pass(); |
} |
void StashBackend::BindToRequest(mojo::InterfaceRequest<StashService> request) { |
@@ -47,27 +118,47 @@ void StashBackend::BindToRequest(mojo::InterfaceRequest<StashService> request) { |
&request); |
} |
-StashServiceImpl::StashServiceImpl(base::WeakPtr<StashBackend> backend) |
- : backend_(backend) { |
+void StashBackend::OnHandleReady() { |
+ DCHECK(!has_notified_); |
+ has_notified_ = true; |
+ for (auto& entry : stashed_objects_) { |
+ entry->CancelHandleNotifications(); |
+ } |
+ if (!on_handle_readable_.is_null()) |
+ on_handle_readable_.Run(); |
} |
-StashServiceImpl::~StashServiceImpl() { |
+StashBackend::StashEntry::StashEntry(StashedObjectPtr stashed_object, |
+ const base::Closure& on_handle_readable) |
+ : stashed_object_(stashed_object.Pass()), |
+ on_handle_readable_(on_handle_readable) { |
+ if (on_handle_readable_.is_null() || !stashed_object_->monitor_handles) |
+ return; |
+ |
+ for (size_t i = 0; i < stashed_object_->stashed_handles.size(); i++) { |
+ waiters_.push_back(linked_ptr<mojo::AsyncWaiter>(new mojo::AsyncWaiter( |
+ stashed_object_->stashed_handles[i].get(), MOJO_HANDLE_SIGNAL_READABLE, |
+ base::Bind(&StashBackend::StashEntry::OnHandleReady, |
+ base::Unretained(this))))); |
+ } |
} |
-void StashServiceImpl::AddToStash( |
- mojo::Array<StashedObjectPtr> stashed_objects) { |
- if (!backend_) |
- return; |
- backend_->AddToStash(stashed_objects.Pass()); |
+StashBackend::StashEntry::~StashEntry() { |
} |
-void StashServiceImpl::RetrieveStash( |
- const mojo::Callback<void(mojo::Array<StashedObjectPtr>)>& callback) { |
- if (!backend_) { |
- callback.Run(mojo::Array<StashedObjectPtr>(0)); |
+StashedObjectPtr StashBackend::StashEntry::Release() { |
+ waiters_.clear(); |
+ return stashed_object_.Pass(); |
+} |
+ |
+void StashBackend::StashEntry::CancelHandleNotifications() { |
+ waiters_.clear(); |
+} |
+ |
+void StashBackend::StashEntry::OnHandleReady(MojoResult result) { |
+ if (result != MOJO_RESULT_OK) |
return; |
- } |
- callback.Run(backend_->RetrieveStash()); |
+ on_handle_readable_.Run(); |
} |
} // namespace extensions |