Chromium Code Reviews| Index: ppapi/shared_impl/tracked_callback.cc |
| diff --git a/ppapi/shared_impl/tracked_callback.cc b/ppapi/shared_impl/tracked_callback.cc |
| index 3b9e25f13c77d664b1228d91a2a489471fd2c471..65d94be8240b747cab103a155b68a438dcbaf903 100644 |
| --- a/ppapi/shared_impl/tracked_callback.cc |
| +++ b/ppapi/shared_impl/tracked_callback.cc |
| @@ -25,15 +25,12 @@ namespace ppapi { |
| TrackedCallback::TrackedCallback( |
| Resource* resource, |
| const PP_CompletionCallback& callback) |
| - : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), |
| + : is_scheduled_(false), |
| resource_id_(resource ? resource->pp_resource() : 0), |
| completed_(false), |
| aborted_(false), |
| callback_(callback), |
| result_for_blocked_callback_(PP_OK) { |
| - // We can only track this callback if the resource is valid. It can be NULL |
| - // in error conditions in the Enter* classes and for callbacks associated with |
| - // an instance. |
| // TODO(dmichael): Add tracking at the instance level, for callbacks that only |
| // have an instance (e.g. for MouseLock). |
| if (resource) { |
| @@ -53,97 +50,80 @@ TrackedCallback::~TrackedCallback() { |
| } |
| void TrackedCallback::Abort() { |
| - if (!completed()) { |
| - aborted_ = true; |
| - Run(PP_ERROR_ABORTED); |
| - } |
| -} |
| - |
| -void TrackedCallback::PostAbort() { |
| // It doesn't make sense to abort a callback that's not associated with a |
| // resource. |
|
dmichael (off chromium)
2012/09/14 21:30:36
It turns out it does make sense... ppapi_plugin_i
|
| - // TODO(dmichael): If we allow associating with an instance instead, we must |
| - // allow for aborts in the case of the instance being destroyed. |
| DCHECK(resource_id_); |
| + Run(PP_ERROR_ABORTED); |
| +} |
| - if (!completed() && !aborted_) { |
| - aborted_ = true; |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - RunWhileLocked(base::Bind(&TrackedCallback::Abort, |
| - weak_ptr_factory_.GetWeakPtr()))); |
| - } |
| +void TrackedCallback::PostAbort() { |
| + PostRun(PP_ERROR_ABORTED); |
| } |
| void TrackedCallback::Run(int32_t result) { |
| - if (!completed()) { |
| - // Cancel any pending calls. |
| - weak_ptr_factory_.InvalidateWeakPtrs(); |
| - |
| - // Copy |callback_| and look at |aborted()| now, since |MarkAsCompleted()| |
| - // may delete us. |
| - PP_CompletionCallback callback = callback_; |
| - if (aborted()) |
| - result = PP_ERROR_ABORTED; |
| - |
| - if (is_blocking()) { |
| - // If the condition variable is invalid, there are two possibilities. One, |
| - // we're running in-process, in which case the call should have come in on |
| - // the main thread and we should have returned PP_ERROR_BLOCKS_MAIN_THREAD |
| - // well before this. Otherwise, this callback was not created as a |
| - // blocking callback. Either way, there's some internal error. |
| - if (!operation_completed_condvar_.get()) { |
| - NOTREACHED(); |
| - return; |
| - } |
| - result_for_blocked_callback_ = result; |
| - // Retain ourselves, since MarkAsCompleted will remove us from the |
| - // tracker. Then MarkAsCompleted before waking up the blocked thread, |
| - // which could potentially re-enter. |
| - scoped_refptr<TrackedCallback> thiz(this); |
| - MarkAsCompleted(); |
| - // Wake up the blocked thread. See BlockUntilComplete for where the thread |
| - // Wait()s. |
| - operation_completed_condvar_->Signal(); |
| - } else { |
| - // Do this before running the callback in case of reentrancy (which |
| - // shouldn't happen, but avoid strange failures). |
| - MarkAsCompleted(); |
| - // TODO(dmichael): Associate a message loop with the callback; if it's not |
| - // the same as the current thread's loop, then post it to the right loop. |
| - CallWhileUnlocked(PP_RunCompletionCallback, &callback, result); |
| + // Only allow the callback to be run once. Note that this also covers the case |
| + // where the callback was previously Aborted because its associated Resource |
| + // went away. The callback may live on for a while because of a reference from |
| + // a Closure. But when the Closure runs, Run() quietly does nothing, and the |
| + // callback will go away when all referring Closures go away. |
| + if (completed()) |
| + return; |
| + if (result == PP_ERROR_ABORTED) |
| + aborted_ = true; |
| + |
| + // Copy |callback_| and look at |aborted()| now, since |MarkAsCompleted()| |
| + // may delete us. |
| + PP_CompletionCallback callback = callback_; |
| + // Note that this call of Run() may have been scheduled prior to Abort() or |
| + // PostAbort() being called. If we have been told to Abort, that always |
| + // trumps a result that was scheduled before. |
| + if (aborted()) |
| + result = PP_ERROR_ABORTED; |
| + |
| + if (is_blocking()) { |
| + // If the condition variable is invalid, there are two possibilities. One, |
| + // we're running in-process, in which case the call should have come in on |
| + // the main thread and we should have returned PP_ERROR_BLOCKS_MAIN_THREAD |
| + // well before this. Otherwise, this callback was not created as a |
| + // blocking callback. Either way, there's some internal error. |
| + if (!operation_completed_condvar_.get()) { |
| + NOTREACHED(); |
| + return; |
| } |
| + result_for_blocked_callback_ = result; |
| + // Retain ourselves, since MarkAsCompleted will remove us from the |
| + // tracker. Then MarkAsCompleted before waking up the blocked thread, |
| + // which could potentially re-enter. |
| + scoped_refptr<TrackedCallback> thiz(this); |
| + MarkAsCompleted(); |
| + // Wake up the blocked thread. See BlockUntilComplete for where the thread |
| + // Wait()s. |
| + operation_completed_condvar_->Signal(); |
| + } else { |
| + // Do this before running the callback in case of reentrancy (which |
| + // shouldn't happen, but avoid strange failures). |
| + MarkAsCompleted(); |
| + // TODO(dmichael): Associate a message loop with the callback; if it's not |
| + // the same as the current thread's loop, then post it to the right loop. |
| + CallWhileUnlocked(PP_RunCompletionCallback, &callback, result); |
| } |
| } |
| void TrackedCallback::PostRun(int32_t result) { |
| - DCHECK(!completed()); |
| - if (!completed()) { |
| - // There should be no pending calls. |
| - DCHECK(!weak_ptr_factory_.HasWeakPtrs()); |
| - weak_ptr_factory_.InvalidateWeakPtrs(); |
| - |
| - if (resource_id_) { |
| - // If it has a resource_id_, it's in the tracker, and may be aborted if |
| - // the resource is destroyed. |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - RunWhileLocked(base::Bind(&TrackedCallback::Run, |
| - weak_ptr_factory_.GetWeakPtr(), |
| - result))); |
| - } else { |
| - // There is no resource_id_ associated with this callback, so it can't be |
| - // aborted. We have the message loop retain the callback to make sure it |
| - // gets run. This can happen when EnterBase is given an invalid resource, |
| - // and in that case no resource or instance will retain this |
| - // TrackedCallback. |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - RunWhileLocked(base::Bind(&TrackedCallback::Run, |
| - this, |
| - result))); |
| - } |
| + if (completed()) { |
| + NOTREACHED(); |
| + return; |
| } |
| + if (result == PP_ERROR_ABORTED) |
| + aborted_ = true; |
| + // We might abort when there's already a scheduled callback, but callers |
| + // should never try to PostRun more than once otherwise. |
| + DCHECK(result == PP_ERROR_ABORTED || !is_scheduled_); |
| + |
| + base::Closure callback_closure( |
| + RunWhileLocked(base::Bind(&TrackedCallback::Run, this, result))); |
| + MessageLoop::current()->PostTask(FROM_HERE, callback_closure); |
| + is_scheduled_ = true; |
| } |
| // static |
| @@ -154,21 +134,6 @@ bool TrackedCallback::IsPending( |
| return !callback->completed(); |
| } |
| -// static |
| -void TrackedCallback::ClearAndRun(scoped_refptr<TrackedCallback>* callback, |
| - int32_t result) { |
| - scoped_refptr<TrackedCallback> temp; |
| - temp.swap(*callback); |
| - temp->Run(result); |
| -} |
| - |
| -// static |
| -void TrackedCallback::ClearAndAbort(scoped_refptr<TrackedCallback>* callback) { |
| - scoped_refptr<TrackedCallback> temp; |
| - temp.swap(*callback); |
| - temp->Abort(); |
| -} |
| - |
| int32_t TrackedCallback::BlockUntilComplete() { |
| // Note, we are already holding the proxy lock in all these methods, including |
| // this one (see ppapi/thunk/enter.cc for where it gets acquired). |