Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(337)

Side by Side Diff: ppapi/shared_impl/tracked_callback.cc

Issue 10910099: PPAPI: Make CompletionCallbacks work right on background threads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ppapi/shared_impl/tracked_callback.h ('k') | ppapi/tests/test_case.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ppapi/shared_impl/tracked_callback.h" 5 #include "ppapi/shared_impl/tracked_callback.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/synchronization/lock.h" 11 #include "base/synchronization/lock.h"
12 #include "ppapi/c/dev/ppb_message_loop_dev.h" 12 #include "ppapi/c/dev/ppb_message_loop_dev.h"
13 #include "ppapi/c/pp_completion_callback.h" 13 #include "ppapi/c/pp_completion_callback.h"
14 #include "ppapi/c/pp_errors.h" 14 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/shared_impl/callback_tracker.h" 15 #include "ppapi/shared_impl/callback_tracker.h"
16 #include "ppapi/shared_impl/ppapi_globals.h" 16 #include "ppapi/shared_impl/ppapi_globals.h"
17 #include "ppapi/shared_impl/ppb_message_loop_shared.h"
17 #include "ppapi/shared_impl/proxy_lock.h" 18 #include "ppapi/shared_impl/proxy_lock.h"
18 #include "ppapi/shared_impl/resource.h" 19 #include "ppapi/shared_impl/resource.h"
19 20
20 namespace ppapi { 21 namespace ppapi {
21 22
23 namespace {
24
25 bool IsMainThread() {
26 return
27 PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread();
28 }
29
30 } // namespace
31
22 // TrackedCallback ------------------------------------------------------------- 32 // TrackedCallback -------------------------------------------------------------
23 33
24 // Note: don't keep a Resource* since it may go out of scope before us. 34 // Note: don't keep a Resource* since it may go out of scope before us.
25 TrackedCallback::TrackedCallback( 35 TrackedCallback::TrackedCallback(
26 Resource* resource, 36 Resource* resource,
27 const PP_CompletionCallback& callback) 37 const PP_CompletionCallback& callback)
28 : is_scheduled_(false), 38 : is_scheduled_(false),
29 resource_id_(resource ? resource->pp_resource() : 0), 39 resource_id_(resource ? resource->pp_resource() : 0),
30 completed_(false), 40 completed_(false),
31 aborted_(false), 41 aborted_(false),
32 callback_(callback), 42 callback_(callback),
43 target_loop_(PpapiGlobals::Get()->GetCurrentMessageLoop()),
33 result_for_blocked_callback_(PP_OK) { 44 result_for_blocked_callback_(PP_OK) {
45 // Note that target_loop_ may be NULL at this point, if the plugin has not
46 // attached a loop to this thread, or if this is an in-process plugin.
47 // The Enter class should handle checking this for us.
48
34 // TODO(dmichael): Add tracking at the instance level, for callbacks that only 49 // TODO(dmichael): Add tracking at the instance level, for callbacks that only
35 // have an instance (e.g. for MouseLock). 50 // have an instance (e.g. for MouseLock).
36 if (resource) { 51 if (resource) {
37 tracker_ = PpapiGlobals::Get()->GetCallbackTrackerForInstance( 52 tracker_ = PpapiGlobals::Get()->GetCallbackTrackerForInstance(
38 resource->pp_instance()); 53 resource->pp_instance());
39 tracker_->Add(make_scoped_refptr(this)); 54 tracker_->Add(make_scoped_refptr(this));
40 } 55 }
41 56
42 base::Lock* proxy_lock = PpapiGlobals::Get()->GetProxyLock(); 57 base::Lock* proxy_lock = PpapiGlobals::Get()->GetProxyLock();
43 // We only need a ConditionVariable if the lock is valid (i.e., we're out-of- 58 if (proxy_lock) {
44 // process) and the callback is blocking. 59 // If the proxy_lock is valid, we're running out-of-process, and locking
45 if (proxy_lock && is_blocking()) 60 // is enabled.
46 operation_completed_condvar_.reset(new base::ConditionVariable(proxy_lock)); 61 if (is_blocking()) {
62 // This is a blocking completion callback, so we will need a condition
63 // variable for blocking & signalling the calling thread.
64 operation_completed_condvar_.reset(
65 new base::ConditionVariable(proxy_lock));
66 } else {
67 // It's a non-blocking callback, so we should have a MessageLoopResource
68 // to dispatch to. Note that we don't error check here, though. Later,
69 // EnterResource::SetResult will check to make sure the callback is valid
70 // and take appropriate action.
71 }
72 }
47 } 73 }
48 74
49 TrackedCallback::~TrackedCallback() { 75 TrackedCallback::~TrackedCallback() {
50 } 76 }
51 77
52 void TrackedCallback::Abort() { 78 void TrackedCallback::Abort() {
53 // It doesn't make sense to abort a callback that's not associated with a
54 // resource.
55 DCHECK(resource_id_);
56 Run(PP_ERROR_ABORTED); 79 Run(PP_ERROR_ABORTED);
57 } 80 }
58 81
59 void TrackedCallback::PostAbort() { 82 void TrackedCallback::PostAbort() {
60 PostRun(PP_ERROR_ABORTED); 83 PostRun(PP_ERROR_ABORTED);
61 } 84 }
62 85
63 void TrackedCallback::Run(int32_t result) { 86 void TrackedCallback::Run(int32_t result) {
64 // Only allow the callback to be run once. Note that this also covers the case 87 // Only allow the callback to be run once. Note that this also covers the case
65 // where the callback was previously Aborted because its associated Resource 88 // where the callback was previously Aborted because its associated Resource
66 // went away. The callback may live on for a while because of a reference from 89 // went away. The callback may live on for a while because of a reference from
67 // a Closure. But when the Closure runs, Run() quietly does nothing, and the 90 // a Closure. But when the Closure runs, Run() quietly does nothing, and the
68 // callback will go away when all referring Closures go away. 91 // callback will go away when all referring Closures go away.
69 if (completed()) 92 if (completed())
70 return; 93 return;
71 if (result == PP_ERROR_ABORTED) 94 if (result == PP_ERROR_ABORTED)
72 aborted_ = true; 95 aborted_ = true;
73 96
74 // Copy |callback_| and look at |aborted()| now, since |MarkAsCompleted()|
75 // may delete us.
76 PP_CompletionCallback callback = callback_;
77 // Note that this call of Run() may have been scheduled prior to Abort() or 97 // Note that this call of Run() may have been scheduled prior to Abort() or
78 // PostAbort() being called. If we have been told to Abort, that always 98 // PostAbort() being called. If we have been told to Abort, that always
79 // trumps a result that was scheduled before. 99 // trumps a result that was scheduled before, so we should make sure to pass
100 // PP_ERROR_ABORTED.
80 if (aborted()) 101 if (aborted())
81 result = PP_ERROR_ABORTED; 102 result = PP_ERROR_ABORTED;
82 103
83 if (is_blocking()) { 104 if (is_blocking()) {
84 // If the condition variable is invalid, there are two possibilities. One, 105 // If the condition variable is invalid, there are two possibilities. One,
85 // we're running in-process, in which case the call should have come in on 106 // we're running in-process, in which case the call should have come in on
86 // the main thread and we should have returned PP_ERROR_BLOCKS_MAIN_THREAD 107 // the main thread and we should have returned PP_ERROR_BLOCKS_MAIN_THREAD
87 // well before this. Otherwise, this callback was not created as a 108 // well before this. Otherwise, this callback was not created as a
88 // blocking callback. Either way, there's some internal error. 109 // blocking callback. Either way, there's some internal error.
89 if (!operation_completed_condvar_.get()) { 110 if (!operation_completed_condvar_.get()) {
90 NOTREACHED(); 111 NOTREACHED();
91 return; 112 return;
92 } 113 }
93 result_for_blocked_callback_ = result; 114 result_for_blocked_callback_ = result;
94 // Retain ourselves, since MarkAsCompleted will remove us from the 115 // Retain ourselves, since MarkAsCompleted will remove us from the
95 // tracker. Then MarkAsCompleted before waking up the blocked thread, 116 // tracker. Then MarkAsCompleted before waking up the blocked thread,
96 // which could potentially re-enter. 117 // which could potentially re-enter.
97 scoped_refptr<TrackedCallback> thiz(this); 118 scoped_refptr<TrackedCallback> thiz(this);
98 MarkAsCompleted(); 119 MarkAsCompleted();
99 // Wake up the blocked thread. See BlockUntilComplete for where the thread 120 // Wake up the blocked thread. See BlockUntilComplete for where the thread
100 // Wait()s. 121 // Wait()s.
101 operation_completed_condvar_->Signal(); 122 operation_completed_condvar_->Signal();
102 } else { 123 } else {
124 // If there's a target_loop_, and we're not on the right thread, we need to
125 // post to target_loop_.
126 if (target_loop_ &&
127 target_loop_ != PpapiGlobals::Get()->GetCurrentMessageLoop()) {
128 PostRun(result);
129 return;
130 }
131 // Copy |callback_| now, since |MarkAsCompleted()| may delete us.
132 PP_CompletionCallback callback = callback_;
103 // Do this before running the callback in case of reentrancy (which 133 // Do this before running the callback in case of reentrancy (which
104 // shouldn't happen, but avoid strange failures). 134 // shouldn't happen, but avoid strange failures).
105 MarkAsCompleted(); 135 MarkAsCompleted();
106 // TODO(dmichael): Associate a message loop with the callback; if it's not 136 // TODO(dmichael): Associate a message loop with the callback; if it's not
107 // the same as the current thread's loop, then post it to the right loop. 137 // the same as the current thread's loop, then post it to the right loop.
108 CallWhileUnlocked(PP_RunCompletionCallback, &callback, result); 138 CallWhileUnlocked(PP_RunCompletionCallback, &callback, result);
109 } 139 }
110 } 140 }
111 141
112 void TrackedCallback::PostRun(int32_t result) { 142 void TrackedCallback::PostRun(int32_t result) {
113 if (completed()) { 143 if (completed()) {
114 NOTREACHED(); 144 NOTREACHED();
115 return; 145 return;
116 } 146 }
117 if (result == PP_ERROR_ABORTED) 147 if (result == PP_ERROR_ABORTED)
118 aborted_ = true; 148 aborted_ = true;
119 // We might abort when there's already a scheduled callback, but callers 149 // We might abort when there's already a scheduled callback, but callers
120 // should never try to PostRun more than once otherwise. 150 // should never try to PostRun more than once otherwise.
121 DCHECK(result == PP_ERROR_ABORTED || !is_scheduled_); 151 DCHECK(result == PP_ERROR_ABORTED || !is_scheduled_);
122 152
123 base::Closure callback_closure( 153 base::Closure callback_closure(
124 RunWhileLocked(base::Bind(&TrackedCallback::Run, this, result))); 154 RunWhileLocked(base::Bind(&TrackedCallback::Run, this, result)));
125 MessageLoop::current()->PostTask(FROM_HERE, callback_closure); 155 if (!target_loop_) {
156 // We must be running in-process and on the main thread (the Enter
157 // classes protect against having a null target_loop_ otherwise).
158 DCHECK(IsMainThread());
159 DCHECK(PpapiGlobals::Get()->IsHostGlobals());
160 MessageLoop::current()->PostTask(FROM_HERE, callback_closure);
161 } else {
162 target_loop_->PostClosure(FROM_HERE, callback_closure, 0);
163 }
126 is_scheduled_ = true; 164 is_scheduled_ = true;
127 } 165 }
128 166
129 // static 167 // static
130 bool TrackedCallback::IsPending( 168 bool TrackedCallback::IsPending(
131 const scoped_refptr<TrackedCallback>& callback) { 169 const scoped_refptr<TrackedCallback>& callback) {
132 if (!callback.get()) 170 if (!callback.get())
133 return false; 171 return false;
134 return !callback->completed(); 172 return !callback->completed();
135 } 173 }
(...skipping 23 matching lines...) Expand all
159 // until we're done. 197 // until we're done.
160 scoped_refptr<TrackedCallback> thiz = this; 198 scoped_refptr<TrackedCallback> thiz = this;
161 completed_ = true; 199 completed_ = true;
162 // We may not have a valid resource, in which case we're not in the tracker. 200 // We may not have a valid resource, in which case we're not in the tracker.
163 if (resource_id_) 201 if (resource_id_)
164 tracker_->Remove(thiz); 202 tracker_->Remove(thiz);
165 tracker_ = NULL; 203 tracker_ = NULL;
166 } 204 }
167 205
168 } // namespace ppapi 206 } // namespace ppapi
OLDNEW
« no previous file with comments | « ppapi/shared_impl/tracked_callback.h ('k') | ppapi/tests/test_case.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698