OLD | NEW |
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/thunk/enter.h" | 5 #include "ppapi/thunk/enter.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
11 #include "base/synchronization/lock.h" | 11 #include "base/synchronization/lock.h" |
12 #include "ppapi/c/pp_errors.h" | |
13 #include "ppapi/shared_impl/ppapi_globals.h" | 12 #include "ppapi/shared_impl/ppapi_globals.h" |
14 #include "ppapi/shared_impl/tracked_callback.h" | 13 #include "ppapi/shared_impl/tracked_callback.h" |
15 #include "ppapi/thunk/ppb_instance_api.h" | 14 #include "ppapi/thunk/ppb_instance_api.h" |
16 #include "ppapi/thunk/resource_creation_api.h" | 15 #include "ppapi/thunk/resource_creation_api.h" |
17 | 16 |
18 namespace ppapi { | 17 namespace ppapi { |
19 namespace { | 18 namespace { |
20 | 19 |
21 bool IsMainThread() { | 20 bool IsMainThread() { |
22 return | 21 return |
23 PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread(); | 22 PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread(); |
24 } | 23 } |
25 | 24 |
26 bool CurrentThreadHandlingBlockingMessage() { | 25 bool CurrentThreadHandlingBlockingMessage() { |
27 ppapi::MessageLoopShared* current = | 26 ppapi::MessageLoopShared* current = |
28 PpapiGlobals::Get()->GetCurrentMessageLoop(); | 27 PpapiGlobals::Get()->GetCurrentMessageLoop(); |
29 return current && current->CurrentlyHandlingBlockingMessage(); | 28 return current && current->CurrentlyHandlingBlockingMessage(); |
30 } | 29 } |
31 | 30 |
32 } // namespace | 31 } // namespace |
33 | 32 |
34 namespace thunk { | 33 namespace thunk { |
35 | 34 |
36 namespace subtle { | 35 namespace subtle { |
37 | 36 |
38 EnterBase::EnterBase() | 37 EnterBase::EnterBase() {} |
39 : resource_(NULL), | |
40 retval_(PP_OK) { | |
41 PpapiGlobals::Get()->MarkPluginIsActive(); | |
42 } | |
43 | 38 |
44 EnterBase::EnterBase(PP_Resource resource) | 39 EnterBase::EnterBase(PP_Resource resource) : resource_(GetResource(resource)) {} |
45 : resource_(GetResource(resource)), | |
46 retval_(PP_OK) { | |
47 PpapiGlobals::Get()->MarkPluginIsActive(); | |
48 } | |
49 | 40 |
50 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id) | 41 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id) |
51 : resource_(GetSingletonResource(instance, resource_id)), | 42 : resource_(GetSingletonResource(instance, resource_id)) { |
52 retval_(PP_OK) { | 43 if (!resource_) |
53 PpapiGlobals::Get()->MarkPluginIsActive(); | 44 retval_ = PP_ERROR_BADARGUMENT; |
54 } | 45 } |
55 | 46 |
56 EnterBase::EnterBase(PP_Resource resource, | 47 EnterBase::EnterBase(PP_Resource resource, |
57 const PP_CompletionCallback& callback) | 48 const PP_CompletionCallback& callback) |
58 : resource_(GetResource(resource)), | 49 : EnterBase(resource) { |
59 retval_(PP_OK) { | |
60 callback_ = new TrackedCallback(resource_, callback); | 50 callback_ = new TrackedCallback(resource_, callback); |
61 PpapiGlobals::Get()->MarkPluginIsActive(); | |
62 } | 51 } |
63 | 52 |
64 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id, | 53 EnterBase::EnterBase(PP_Instance instance, |
| 54 SingletonResourceID resource_id, |
65 const PP_CompletionCallback& callback) | 55 const PP_CompletionCallback& callback) |
66 : resource_(GetSingletonResource(instance, resource_id)), | 56 : EnterBase(instance, resource_id) { |
67 retval_(PP_OK) { | |
68 if (!resource_) | |
69 retval_ = PP_ERROR_BADARGUMENT; | |
70 callback_ = new TrackedCallback(resource_, callback); | 57 callback_ = new TrackedCallback(resource_, callback); |
71 PpapiGlobals::Get()->MarkPluginIsActive(); | |
72 } | 58 } |
73 | 59 |
74 EnterBase::~EnterBase() { | 60 EnterBase::~EnterBase() { |
75 // callback_ is cleared any time it is run, scheduled to be run, or once we | 61 // callback_ is cleared any time it is run, scheduled to be run, or once we |
76 // know it will be completed asynchronously. So by this point it should be | 62 // know it will be completed asynchronously. So by this point it should be |
77 // NULL. | 63 // null. |
78 DCHECK(!callback_.get()) | 64 DCHECK(!callback_) << "|callback_| is not null. Did you forget to call " |
79 << "|callback_| is not NULL. Did you forget to call " | 65 "|EnterBase::SetResult| in the interface's thunk?"; |
80 "|EnterBase::SetResult| in the interface's thunk?"; | |
81 } | 66 } |
82 | 67 |
83 int32_t EnterBase::SetResult(int32_t result) { | 68 int32_t EnterBase::SetResult(int32_t result) { |
84 if (!callback_.get()) { | 69 if (!callback_) { |
85 // It doesn't make sense to call SetResult if there is no callback. | 70 // It doesn't make sense to call SetResult if there is no callback. |
86 NOTREACHED(); | 71 NOTREACHED(); |
87 retval_ = result; | 72 retval_ = result; |
88 return result; | 73 return result; |
89 } | 74 } |
90 if (result == PP_OK_COMPLETIONPENDING) { | 75 if (result == PP_OK_COMPLETIONPENDING) { |
91 retval_ = result; | 76 retval_ = result; |
92 if (callback_->is_blocking()) { | 77 if (callback_->is_blocking()) { |
93 DCHECK(!IsMainThread()); // We should have returned an error before this. | 78 DCHECK(!IsMainThread()); // We should have returned an error before this. |
94 retval_ = callback_->BlockUntilComplete(); | 79 retval_ = callback_->BlockUntilComplete(); |
95 } else { | 80 } else { |
96 // The callback is not blocking and the operation will complete | 81 // The callback is not blocking and the operation will complete |
97 // asynchronously, so there's nothing to do. | 82 // asynchronously, so there's nothing to do. |
98 retval_ = result; | 83 retval_ = result; |
99 } | 84 } |
100 } else { | 85 } else { |
101 // The function completed synchronously. | 86 // The function completed synchronously. |
102 if (callback_->is_required()) { | 87 if (callback_->is_required()) { |
103 // This is a required callback, so we must issue it asynchronously. | 88 // This is a required callback, so we must issue it asynchronously. |
104 callback_->PostRun(result); | 89 callback_->PostRun(result); |
105 retval_ = PP_OK_COMPLETIONPENDING; | 90 retval_ = PP_OK_COMPLETIONPENDING; |
106 } else { | 91 } else { |
107 // The callback is blocking or optional, so all we need to do is mark | 92 // The callback is blocking or optional, so all we need to do is mark |
108 // the callback as completed so that it won't be issued later. | 93 // the callback as completed so that it won't be issued later. |
109 callback_->MarkAsCompleted(); | 94 callback_->MarkAsCompleted(); |
110 retval_ = result; | 95 retval_ = result; |
111 } | 96 } |
112 } | 97 } |
113 callback_ = NULL; | 98 callback_ = nullptr; |
114 return retval_; | 99 return retval_; |
115 } | 100 } |
116 | 101 |
117 // static | 102 // static |
118 Resource* EnterBase::GetResource(PP_Resource resource) { | 103 Resource* EnterBase::GetResource(PP_Resource resource) { |
119 return PpapiGlobals::Get()->GetResourceTracker()->GetResource(resource); | 104 return PpapiGlobals::Get()->GetResourceTracker()->GetResource(resource); |
120 } | 105 } |
121 | 106 |
122 // static | 107 // static |
123 Resource* EnterBase::GetSingletonResource(PP_Instance instance, | 108 Resource* EnterBase::GetSingletonResource(PP_Instance instance, |
124 SingletonResourceID resource_id) { | 109 SingletonResourceID resource_id) { |
125 PPB_Instance_API* ppb_instance = | 110 PPB_Instance_API* ppb_instance = |
126 PpapiGlobals::Get()->GetInstanceAPI(instance); | 111 PpapiGlobals::Get()->GetInstanceAPI(instance); |
127 if (!ppb_instance) | 112 if (!ppb_instance) |
128 return NULL; | 113 return nullptr; |
129 | 114 |
130 return ppb_instance->GetSingletonResource(instance, resource_id); | 115 return ppb_instance->GetSingletonResource(instance, resource_id); |
131 } | 116 } |
132 | 117 |
133 void EnterBase::SetStateForCallbackError(bool report_error) { | 118 void EnterBase::SetStateForCallbackError(bool report_error) { |
134 if (PpapiGlobals::Get()->IsHostGlobals()) { | 119 if (PpapiGlobals::Get()->IsHostGlobals()) { |
135 // In-process plugins can't make PPAPI calls off the main thread. | 120 // In-process plugins can't make PPAPI calls off the main thread. |
136 CHECK(IsMainThread()); | 121 CHECK(IsMainThread()); |
137 } | 122 } |
138 if (callback_.get()) { | 123 if (callback_) { |
139 if (callback_->is_blocking() && IsMainThread()) { | 124 if (callback_->is_blocking() && IsMainThread()) { |
140 // Blocking callbacks are never allowed on the main thread. | 125 // Blocking callbacks are never allowed on the main thread. |
141 callback_->MarkAsCompleted(); | 126 callback_->MarkAsCompleted(); |
142 callback_ = NULL; | 127 callback_ = nullptr; |
143 retval_ = PP_ERROR_BLOCKS_MAIN_THREAD; | 128 retval_ = PP_ERROR_BLOCKS_MAIN_THREAD; |
144 if (report_error) { | 129 if (report_error) { |
145 std::string message( | 130 std::string message( |
146 "Blocking callbacks are not allowed on the main thread."); | 131 "Blocking callbacks are not allowed on the main thread."); |
147 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 132 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, |
148 std::string(), message); | 133 std::string(), message); |
149 } | 134 } |
150 } else if (callback_->is_blocking() && | 135 } else if (callback_->is_blocking() && |
151 CurrentThreadHandlingBlockingMessage()) { | 136 CurrentThreadHandlingBlockingMessage()) { |
152 // Blocking callbacks are not allowed while handling a blocking message. | 137 // Blocking callbacks are not allowed while handling a blocking message. |
153 callback_->MarkAsCompleted(); | 138 callback_->MarkAsCompleted(); |
154 callback_ = NULL; | 139 callback_ = nullptr; |
155 retval_ = PP_ERROR_WOULD_BLOCK_THREAD; | 140 retval_ = PP_ERROR_WOULD_BLOCK_THREAD; |
156 if (report_error) { | 141 if (report_error) { |
157 std::string message("Blocking callbacks are not allowed while handling " | 142 std::string message("Blocking callbacks are not allowed while handling " |
158 "a blocking message from JavaScript."); | 143 "a blocking message from JavaScript."); |
159 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 144 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, |
160 std::string(), message); | 145 std::string(), message); |
161 } | 146 } |
162 } else if (!IsMainThread() && | 147 } else if (!IsMainThread() && |
163 callback_->has_null_target_loop() && | 148 callback_->has_null_target_loop() && |
164 !callback_->is_blocking()) { | 149 !callback_->is_blocking()) { |
165 // On a non-main thread, there must be a valid target loop for non- | 150 // On a non-main thread, there must be a valid target loop for non- |
166 // blocking callbacks, or we will have no place to run them. | 151 // blocking callbacks, or we will have no place to run them. |
167 | 152 |
168 // If the callback is required, there's no nice way to tell the plugin. | 153 // If the callback is required, there's no nice way to tell the plugin. |
169 // We can't run their callback asynchronously without a message loop, and | 154 // We can't run their callback asynchronously without a message loop, and |
170 // the plugin won't expect any return code other than | 155 // the plugin won't expect any return code other than |
171 // PP_OK_COMPLETIONPENDING. So we crash to make the problem more obvious. | 156 // PP_OK_COMPLETIONPENDING. So we crash to make the problem more obvious. |
172 if (callback_->is_required()) { | 157 if (callback_->is_required()) { |
173 std::string message("Attempted to use a required callback, but there " | 158 std::string message("Attempted to use a required callback, but there " |
174 "is no attached message loop on which to run the " | 159 "is no attached message loop on which to run the " |
175 "callback."); | 160 "callback."); |
176 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 161 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, |
177 std::string(), message); | 162 std::string(), message); |
178 LOG(FATAL) << message; | 163 LOG(FATAL) << message; |
179 } | 164 } |
180 | 165 |
181 callback_->MarkAsCompleted(); | 166 callback_->MarkAsCompleted(); |
182 callback_ = NULL; | 167 callback_ = nullptr; |
183 retval_ = PP_ERROR_NO_MESSAGE_LOOP; | 168 retval_ = PP_ERROR_NO_MESSAGE_LOOP; |
184 if (report_error) { | 169 if (report_error) { |
185 std::string message( | 170 std::string message( |
186 "The calling thread must have a message loop attached."); | 171 "The calling thread must have a message loop attached."); |
187 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 172 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, |
188 std::string(), message); | 173 std::string(), message); |
189 } | 174 } |
190 } | 175 } |
191 } | 176 } |
192 } | 177 } |
193 | 178 |
194 void EnterBase::ClearCallback() { | 179 void EnterBase::ClearCallback() { |
195 callback_ = NULL; | 180 callback_ = nullptr; |
196 } | 181 } |
197 | 182 |
198 void EnterBase::SetStateForResourceError(PP_Resource pp_resource, | 183 void EnterBase::SetStateForResourceError(PP_Resource pp_resource, |
199 Resource* resource_base, | 184 Resource* resource_base, |
200 void* object, | 185 void* object, |
201 bool report_error) { | 186 bool report_error) { |
202 // Check for callback errors. If we get any, SetStateForCallbackError will | 187 // Check for callback errors. If we get any, SetStateForCallbackError will |
203 // emit a log message. But we also want to check for resource errors. If there | 188 // emit a log message. But we also want to check for resource errors. If there |
204 // are both kinds of errors, we'll emit two log messages and return | 189 // are both kinds of errors, we'll emit two log messages and return |
205 // PP_ERROR_BADRESOURCE. | 190 // PP_ERROR_BADRESOURCE. |
206 SetStateForCallbackError(report_error); | 191 SetStateForCallbackError(report_error); |
207 | 192 |
208 if (object) | 193 if (object) |
209 return; // Everything worked. | 194 return; // Everything worked. |
210 | 195 |
211 if (callback_.get() && callback_->is_required()) { | 196 if (callback_ && callback_->is_required()) { |
212 callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADRESOURCE)); | 197 callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADRESOURCE)); |
213 callback_ = NULL; | 198 callback_ = nullptr; |
214 retval_ = PP_OK_COMPLETIONPENDING; | 199 retval_ = PP_OK_COMPLETIONPENDING; |
215 } else { | 200 } else { |
216 if (callback_.get()) | 201 if (callback_) |
217 callback_->MarkAsCompleted(); | 202 callback_->MarkAsCompleted(); |
218 callback_ = NULL; | 203 callback_ = nullptr; |
219 retval_ = PP_ERROR_BADRESOURCE; | 204 retval_ = PP_ERROR_BADRESOURCE; |
220 } | 205 } |
221 | 206 |
222 // We choose to silently ignore the error when the pp_resource is null | 207 // We choose to silently ignore the error when the pp_resource is null |
223 // because this is a pretty common case and we don't want to have lots | 208 // because this is a pretty common case and we don't want to have lots |
224 // of errors in the log. This should be an obvious case to debug. | 209 // of errors in the log. This should be an obvious case to debug. |
225 if (report_error && pp_resource) { | 210 if (report_error && pp_resource) { |
226 std::string message; | 211 std::string message; |
227 if (resource_base) { | 212 if (resource_base) { |
228 message = base::StringPrintf( | 213 message = base::StringPrintf( |
(...skipping 14 matching lines...) Expand all Loading... |
243 bool report_error) { | 228 bool report_error) { |
244 // Check for callback errors. If we get any, SetStateForCallbackError will | 229 // Check for callback errors. If we get any, SetStateForCallbackError will |
245 // emit a log message. But we also want to check for instance errors. If there | 230 // emit a log message. But we also want to check for instance errors. If there |
246 // are both kinds of errors, we'll emit two log messages and return | 231 // are both kinds of errors, we'll emit two log messages and return |
247 // PP_ERROR_BADARGUMENT. | 232 // PP_ERROR_BADARGUMENT. |
248 SetStateForCallbackError(report_error); | 233 SetStateForCallbackError(report_error); |
249 | 234 |
250 if (object) | 235 if (object) |
251 return; // Everything worked. | 236 return; // Everything worked. |
252 | 237 |
253 if (callback_.get() && callback_->is_required()) { | 238 if (callback_ && callback_->is_required()) { |
254 callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADARGUMENT)); | 239 callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADARGUMENT)); |
255 callback_ = NULL; | 240 callback_ = nullptr; |
256 retval_ = PP_OK_COMPLETIONPENDING; | 241 retval_ = PP_OK_COMPLETIONPENDING; |
257 } else { | 242 } else { |
258 if (callback_.get()) | 243 if (callback_) |
259 callback_->MarkAsCompleted(); | 244 callback_->MarkAsCompleted(); |
260 callback_ = NULL; | 245 callback_ = nullptr; |
261 retval_ = PP_ERROR_BADARGUMENT; | 246 retval_ = PP_ERROR_BADARGUMENT; |
262 } | 247 } |
263 | 248 |
264 // We choose to silently ignore the error when the pp_instance is null as | 249 // We choose to silently ignore the error when the pp_instance is null as |
265 // for PP_Resources above. | 250 // for PP_Resources above. |
266 if (report_error && pp_instance) { | 251 if (report_error && pp_instance) { |
267 std::string message; | 252 std::string message; |
268 message = base::StringPrintf( | 253 message = base::StringPrintf( |
269 "0x%X is not a valid instance ID.", | 254 "0x%X is not a valid instance ID.", |
270 pp_instance); | 255 pp_instance); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 : EnterBase(), | 312 : EnterBase(), |
328 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) { | 313 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) { |
329 SetStateForFunctionError(instance, functions_, true); | 314 SetStateForFunctionError(instance, functions_, true); |
330 } | 315 } |
331 | 316 |
332 EnterResourceCreationNoLock::~EnterResourceCreationNoLock() { | 317 EnterResourceCreationNoLock::~EnterResourceCreationNoLock() { |
333 } | 318 } |
334 | 319 |
335 } // namespace thunk | 320 } // namespace thunk |
336 } // namespace ppapi | 321 } // namespace ppapi |
OLD | NEW |