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..5bab69c3ef832ede6e61e0b07b80513fb7c55830 100644 |
--- a/extensions/browser/mojo/stash_backend.cc |
+++ b/extensions/browser/mojo/stash_backend.cc |
@@ -4,27 +4,94 @@ |
#include "extensions/browser/mojo/stash_backend.h" |
+#include "base/bind.h" |
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.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> { |
+class StashServiceImpl : public StashService { |
public: |
- explicit StashServiceImpl(base::WeakPtr<StashBackend> backend); |
+ StashServiceImpl(mojo::InterfaceRequest<StashService> request, |
+ base::WeakPtr<StashBackend> backend); |
~StashServiceImpl() override; |
- // mojo::InterfaceImpl<StashService> overrides. |
+ // StashService overrides. |
void AddToStash(mojo::Array<StashedObjectPtr> stash) override; |
void RetrieveStash( |
const mojo::Callback<void(mojo::Array<StashedObjectPtr> stash)>& callback) |
override; |
private: |
+ mojo::StrongBinding<StashService> binding_; |
base::WeakPtr<StashBackend> backend_; |
DISALLOW_COPY_AND_ASSIGN(StashServiceImpl); |
}; |
-StashBackend::StashBackend() : weak_factory_(this) { |
+StashServiceImpl::StashServiceImpl(mojo::InterfaceRequest<StashService> request, |
+ base::WeakPtr<StashBackend> backend) |
+ : binding_(this, request.Pass()), 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. |
+ ScopedVector<mojo::AsyncWaiter> waiters_; |
+ |
+ 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,42 +99,69 @@ 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( |
+ new StashEntry(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) { |
- mojo::BindToRequest(new StashServiceImpl(weak_factory_.GetWeakPtr()), |
- &request); |
+ new StashServiceImpl(request.Pass(), weak_factory_.GetWeakPtr()); |
} |
-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(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 |