summaryrefslogtreecommitdiffstats
path: root/webkit/plugins/ppapi/callbacks.cc
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-21 00:45:43 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-21 00:45:43 +0000
commit64264efa8b4a0bf37b19042f295f9990a7f388c9 (patch)
tree5e7cbf44e04f00388078da62d6e0eed878da3d6d /webkit/plugins/ppapi/callbacks.cc
parentc85b0ba71b5a55647b01de9d345e46896979033d (diff)
downloadchromium_src-64264efa8b4a0bf37b19042f295f9990a7f388c9.zip
chromium_src-64264efa8b4a0bf37b19042f295f9990a7f388c9.tar.gz
chromium_src-64264efa8b4a0bf37b19042f295f9990a7f388c9.tar.bz2
Properly cancel PPAPI callbacks.
This sets up infrastructure to properly cancel PPAPI callbacks (which have particular semantics), and converts a couple things to use them. BUG= TEST=test_shell_tests and PPAPI tests Review URL: http://codereview.chromium.org/5562008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69773 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins/ppapi/callbacks.cc')
-rw-r--r--webkit/plugins/ppapi/callbacks.cc155
1 files changed, 155 insertions, 0 deletions
diff --git a/webkit/plugins/ppapi/callbacks.cc b/webkit/plugins/ppapi/callbacks.cc
new file mode 100644
index 0000000..69cd2e8
--- /dev/null
+++ b/webkit/plugins/ppapi/callbacks.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2010 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 "webkit/plugins/ppapi/callbacks.h"
+
+#include <algorithm>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "ppapi/c/pp_completion_callback.h"
+#include "ppapi/c/pp_errors.h"
+
+namespace webkit {
+namespace ppapi {
+
+// CallbackTracker -------------------------------------------------------------
+
+CallbackTracker::CallbackTracker() {
+}
+
+void CallbackTracker::AbortAll() {
+ // Iterate over a copy since |Abort()| calls |Remove()| (indirectly).
+ // TODO(viettrungluu): This obviously isn't so efficient.
+ CallbackSetMap pending_callbacks_copy = pending_callbacks_;
+ for (CallbackSetMap::iterator it1 = pending_callbacks_copy.begin();
+ it1 != pending_callbacks_copy.end(); ++it1) {
+ for (CallbackSet::iterator it2 = it1->second.begin();
+ it2 != it1->second.end(); ++it2) {
+ (*it2)->Abort();
+ }
+ }
+}
+
+void CallbackTracker::PostAbortForResource(PP_Resource resource_id) {
+ CHECK(resource_id != 0);
+ CallbackSetMap::iterator it1 = pending_callbacks_.find(resource_id);
+ if (it1 == pending_callbacks_.end())
+ return;
+ for (CallbackSet::iterator it2 = it1->second.begin();
+ it2 != it1->second.end(); ++it2) {
+ // Post the abort.
+ (*it2)->PostAbort();
+ }
+}
+
+CallbackTracker::~CallbackTracker() {
+ // All callbacks must be aborted before destruction.
+ CHECK_EQ(0u, pending_callbacks_.size());
+}
+
+void CallbackTracker::Add(
+ const scoped_refptr<TrackedCallback>& tracked_callback) {
+ PP_Resource resource_id = tracked_callback->resource_id();
+ DCHECK(pending_callbacks_[resource_id].find(tracked_callback) ==
+ pending_callbacks_[resource_id].end());
+ pending_callbacks_[resource_id].insert(tracked_callback);
+}
+
+void CallbackTracker::Remove(
+ const scoped_refptr<TrackedCallback>& tracked_callback) {
+ CallbackSetMap::iterator map_it =
+ pending_callbacks_.find(tracked_callback->resource_id());
+ DCHECK(map_it != pending_callbacks_.end());
+ CallbackSet::iterator it = map_it->second.find(tracked_callback);
+ DCHECK(it != map_it->second.end());
+ map_it->second.erase(it);
+
+ // If there are no pending callbacks left for this ID, get rid of the entry.
+ if (map_it->second.empty())
+ pending_callbacks_.erase(map_it);
+}
+
+// TrackedCallback -------------------------------------------------------------
+
+TrackedCallback::TrackedCallback(const scoped_refptr<CallbackTracker>& tracker,
+ PP_Resource resource_id)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(abort_impl_factory_(this)),
+ tracker_(tracker),
+ resource_id_(resource_id),
+ completed_(false),
+ aborted_(false) {
+ tracker_->Add(make_scoped_refptr(this));
+}
+
+void TrackedCallback::Abort() {
+ if (!completed()) {
+ aborted_ = true;
+ AbortImpl();
+ }
+}
+
+void TrackedCallback::PostAbort() {
+ if (!completed()) {
+ aborted_ = true;
+ // Post a task for the abort (only if necessary).
+ if (abort_impl_factory_.empty()) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ abort_impl_factory_.NewRunnableMethod(&TrackedCallback::AbortImpl));
+ }
+ }
+}
+
+TrackedCallback::~TrackedCallback() {
+ // The tracker must ensure that the callback is completed (maybe abortively).
+ DCHECK(completed_);
+}
+
+void TrackedCallback::MarkAsCompleted() {
+ DCHECK(!completed());
+
+ // We will be removed; maintain a reference to ensure we won't be deleted
+ // until we're done.
+ scoped_refptr<TrackedCallback> thiz = this;
+ completed_ = true;
+ tracker_->Remove(thiz);
+ tracker_ = NULL;
+}
+
+// TrackedCompletionCallback ---------------------------------------------------
+
+TrackedCompletionCallback::TrackedCompletionCallback(
+ const scoped_refptr<CallbackTracker>& tracker,
+ PP_Resource resource_id,
+ const PP_CompletionCallback& callback)
+ : TrackedCallback(tracker, resource_id),
+ callback_(callback) {
+}
+
+void TrackedCompletionCallback::Run(int32_t result) {
+ if (!completed()) {
+ // Cancel any pending calls.
+ abort_impl_factory_.RevokeAll();
+
+ // Copy |callback_| and look at |aborted()| now, since |MarkAsCompleted()|
+ // may delete us.
+ PP_CompletionCallback callback = callback_;
+ if (aborted())
+ result = PP_ERROR_ABORTED;
+
+ // Do this before running the callback in case of reentrancy (which
+ // shouldn't happen, but avoid strange failures).
+ MarkAsCompleted();
+ PP_RunCompletionCallback(&callback, result);
+ }
+}
+
+void TrackedCompletionCallback::AbortImpl() {
+ Run(PP_ERROR_ABORTED);
+}
+
+} // namespace ppapi
+} // namespace webkit