| 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" | 12 #include "ppapi/c/pp_errors.h" |
| 13 #include "ppapi/shared_impl/ppapi_globals.h" | 13 #include "ppapi/shared_impl/ppapi_globals.h" |
| 14 #include "ppapi/shared_impl/tracked_callback.h" | 14 #include "ppapi/shared_impl/tracked_callback.h" |
| 15 #include "ppapi/thunk/ppb_instance_api.h" | 15 #include "ppapi/thunk/ppb_instance_api.h" |
| 16 #include "ppapi/thunk/resource_creation_api.h" | 16 #include "ppapi/thunk/resource_creation_api.h" |
| 17 | 17 |
| 18 namespace ppapi { | 18 namespace ppapi { |
| 19 namespace { | 19 namespace { |
| 20 | 20 |
| 21 bool IsMainThread() { | 21 bool IsMainThread() { |
| 22 return | 22 return PpapiGlobals::Get() |
| 23 PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread(); | 23 ->GetMainThreadMessageLoop() |
| 24 ->BelongsToCurrentThread(); |
| 24 } | 25 } |
| 25 | 26 |
| 26 } // namespace | 27 } // namespace |
| 27 | 28 |
| 28 namespace thunk { | 29 namespace thunk { |
| 29 | 30 |
| 30 namespace subtle { | 31 namespace subtle { |
| 31 | 32 |
| 32 EnterBase::EnterBase() | 33 EnterBase::EnterBase() : resource_(NULL), retval_(PP_OK) { |
| 33 : resource_(NULL), | |
| 34 retval_(PP_OK) { | |
| 35 PpapiGlobals::Get()->MarkPluginIsActive(); | 34 PpapiGlobals::Get()->MarkPluginIsActive(); |
| 36 } | 35 } |
| 37 | 36 |
| 38 EnterBase::EnterBase(PP_Resource resource) | 37 EnterBase::EnterBase(PP_Resource resource) |
| 39 : resource_(GetResource(resource)), | 38 : resource_(GetResource(resource)), retval_(PP_OK) { |
| 40 retval_(PP_OK) { | |
| 41 PpapiGlobals::Get()->MarkPluginIsActive(); | 39 PpapiGlobals::Get()->MarkPluginIsActive(); |
| 42 } | 40 } |
| 43 | 41 |
| 44 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id) | 42 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id) |
| 45 : resource_(GetSingletonResource(instance, resource_id)), | 43 : resource_(GetSingletonResource(instance, resource_id)), retval_(PP_OK) { |
| 46 retval_(PP_OK) { | |
| 47 PpapiGlobals::Get()->MarkPluginIsActive(); | 44 PpapiGlobals::Get()->MarkPluginIsActive(); |
| 48 } | 45 } |
| 49 | 46 |
| 50 EnterBase::EnterBase(PP_Resource resource, | 47 EnterBase::EnterBase(PP_Resource resource, |
| 51 const PP_CompletionCallback& callback) | 48 const PP_CompletionCallback& callback) |
| 52 : resource_(GetResource(resource)), | 49 : resource_(GetResource(resource)), retval_(PP_OK) { |
| 53 retval_(PP_OK) { | |
| 54 callback_ = new TrackedCallback(resource_, callback); | 50 callback_ = new TrackedCallback(resource_, callback); |
| 55 PpapiGlobals::Get()->MarkPluginIsActive(); | 51 PpapiGlobals::Get()->MarkPluginIsActive(); |
| 56 } | 52 } |
| 57 | 53 |
| 58 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id, | 54 EnterBase::EnterBase(PP_Instance instance, |
| 55 SingletonResourceID resource_id, |
| 59 const PP_CompletionCallback& callback) | 56 const PP_CompletionCallback& callback) |
| 60 : resource_(GetSingletonResource(instance, resource_id)), | 57 : resource_(GetSingletonResource(instance, resource_id)), retval_(PP_OK) { |
| 61 retval_(PP_OK) { | |
| 62 if (!resource_) | 58 if (!resource_) |
| 63 retval_ = PP_ERROR_BADARGUMENT; | 59 retval_ = PP_ERROR_BADARGUMENT; |
| 64 callback_ = new TrackedCallback(resource_, callback); | 60 callback_ = new TrackedCallback(resource_, callback); |
| 65 PpapiGlobals::Get()->MarkPluginIsActive(); | 61 PpapiGlobals::Get()->MarkPluginIsActive(); |
| 66 } | 62 } |
| 67 | 63 |
| 68 EnterBase::~EnterBase() { | 64 EnterBase::~EnterBase() { |
| 69 // callback_ is cleared any time it is run, scheduled to be run, or once we | 65 // callback_ is cleared any time it is run, scheduled to be run, or once we |
| 70 // know it will be completed asynchronously. So by this point it should be | 66 // know it will be completed asynchronously. So by this point it should be |
| 71 // NULL. | 67 // NULL. |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 } | 127 } |
| 132 if (callback_.get()) { | 128 if (callback_.get()) { |
| 133 if (callback_->is_blocking() && IsMainThread()) { | 129 if (callback_->is_blocking() && IsMainThread()) { |
| 134 // Blocking callbacks are never allowed on the main thread. | 130 // Blocking callbacks are never allowed on the main thread. |
| 135 callback_->MarkAsCompleted(); | 131 callback_->MarkAsCompleted(); |
| 136 callback_ = NULL; | 132 callback_ = NULL; |
| 137 retval_ = PP_ERROR_BLOCKS_MAIN_THREAD; | 133 retval_ = PP_ERROR_BLOCKS_MAIN_THREAD; |
| 138 if (report_error) { | 134 if (report_error) { |
| 139 std::string message( | 135 std::string message( |
| 140 "Blocking callbacks are not allowed on the main thread."); | 136 "Blocking callbacks are not allowed on the main thread."); |
| 141 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 137 PpapiGlobals::Get()->BroadcastLogWithSource( |
| 142 std::string(), message); | 138 0, PP_LOGLEVEL_ERROR, std::string(), message); |
| 143 } | 139 } |
| 144 } else if (!IsMainThread() && | 140 } else if (!IsMainThread() && callback_->has_null_target_loop() && |
| 145 callback_->has_null_target_loop() && | |
| 146 !callback_->is_blocking()) { | 141 !callback_->is_blocking()) { |
| 147 // On a non-main thread, there must be a valid target loop for non- | 142 // On a non-main thread, there must be a valid target loop for non- |
| 148 // blocking callbacks, or we will have no place to run them. | 143 // blocking callbacks, or we will have no place to run them. |
| 149 | 144 |
| 150 // If the callback is required, there's no nice way to tell the plugin. | 145 // If the callback is required, there's no nice way to tell the plugin. |
| 151 // We can't run their callback asynchronously without a message loop, and | 146 // We can't run their callback asynchronously without a message loop, and |
| 152 // the plugin won't expect any return code other than | 147 // the plugin won't expect any return code other than |
| 153 // PP_OK_COMPLETIONPENDING. So we crash to make the problem more obvious. | 148 // PP_OK_COMPLETIONPENDING. So we crash to make the problem more obvious. |
| 154 if (callback_->is_required()) { | 149 if (callback_->is_required()) { |
| 155 std::string message("Attempted to use a required callback, but there " | 150 std::string message( |
| 156 "is no attached message loop on which to run the " | 151 "Attempted to use a required callback, but there " |
| 157 "callback."); | 152 "is no attached message loop on which to run the " |
| 158 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 153 "callback."); |
| 159 std::string(), message); | 154 PpapiGlobals::Get()->BroadcastLogWithSource( |
| 155 0, PP_LOGLEVEL_ERROR, std::string(), message); |
| 160 LOG(FATAL) << message; | 156 LOG(FATAL) << message; |
| 161 } | 157 } |
| 162 | 158 |
| 163 callback_->MarkAsCompleted(); | 159 callback_->MarkAsCompleted(); |
| 164 callback_ = NULL; | 160 callback_ = NULL; |
| 165 retval_ = PP_ERROR_NO_MESSAGE_LOOP; | 161 retval_ = PP_ERROR_NO_MESSAGE_LOOP; |
| 166 if (report_error) { | 162 if (report_error) { |
| 167 std::string message( | 163 std::string message( |
| 168 "The calling thread must have a message loop attached."); | 164 "The calling thread must have a message loop attached."); |
| 169 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 165 PpapiGlobals::Get()->BroadcastLogWithSource( |
| 170 std::string(), message); | 166 0, PP_LOGLEVEL_ERROR, std::string(), message); |
| 171 } | 167 } |
| 172 } | 168 } |
| 173 } | 169 } |
| 174 } | 170 } |
| 175 | 171 |
| 176 void EnterBase::ClearCallback() { | 172 void EnterBase::ClearCallback() { callback_ = NULL; } |
| 177 callback_ = NULL; | |
| 178 } | |
| 179 | 173 |
| 180 void EnterBase::SetStateForResourceError(PP_Resource pp_resource, | 174 void EnterBase::SetStateForResourceError(PP_Resource pp_resource, |
| 181 Resource* resource_base, | 175 Resource* resource_base, |
| 182 void* object, | 176 void* object, |
| 183 bool report_error) { | 177 bool report_error) { |
| 184 // Check for callback errors. If we get any, SetStateForCallbackError will | 178 // Check for callback errors. If we get any, SetStateForCallbackError will |
| 185 // emit a log message. But we also want to check for resource errors. If there | 179 // emit a log message. But we also want to check for resource errors. If there |
| 186 // are both kinds of errors, we'll emit two log messages and return | 180 // are both kinds of errors, we'll emit two log messages and return |
| 187 // PP_ERROR_BADRESOURCE. | 181 // PP_ERROR_BADRESOURCE. |
| 188 SetStateForCallbackError(report_error); | 182 SetStateForCallbackError(report_error); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 201 retval_ = PP_ERROR_BADRESOURCE; | 195 retval_ = PP_ERROR_BADRESOURCE; |
| 202 } | 196 } |
| 203 | 197 |
| 204 // We choose to silently ignore the error when the pp_resource is null | 198 // We choose to silently ignore the error when the pp_resource is null |
| 205 // because this is a pretty common case and we don't want to have lots | 199 // because this is a pretty common case and we don't want to have lots |
| 206 // of errors in the log. This should be an obvious case to debug. | 200 // of errors in the log. This should be an obvious case to debug. |
| 207 if (report_error && pp_resource) { | 201 if (report_error && pp_resource) { |
| 208 std::string message; | 202 std::string message; |
| 209 if (resource_base) { | 203 if (resource_base) { |
| 210 message = base::StringPrintf( | 204 message = base::StringPrintf( |
| 211 "0x%X is not the correct type for this function.", | 205 "0x%X is not the correct type for this function.", pp_resource); |
| 212 pp_resource); | |
| 213 } else { | 206 } else { |
| 214 message = base::StringPrintf( | 207 message = |
| 215 "0x%X is not a valid resource ID.", | 208 base::StringPrintf("0x%X is not a valid resource ID.", pp_resource); |
| 216 pp_resource); | |
| 217 } | 209 } |
| 218 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 210 PpapiGlobals::Get()->BroadcastLogWithSource( |
| 219 std::string(), message); | 211 0, PP_LOGLEVEL_ERROR, std::string(), message); |
| 220 } | 212 } |
| 221 } | 213 } |
| 222 | 214 |
| 223 void EnterBase::SetStateForFunctionError(PP_Instance pp_instance, | 215 void EnterBase::SetStateForFunctionError(PP_Instance pp_instance, |
| 224 void* object, | 216 void* object, |
| 225 bool report_error) { | 217 bool report_error) { |
| 226 // Check for callback errors. If we get any, SetStateForCallbackError will | 218 // Check for callback errors. If we get any, SetStateForCallbackError will |
| 227 // emit a log message. But we also want to check for instance errors. If there | 219 // emit a log message. But we also want to check for instance errors. If there |
| 228 // are both kinds of errors, we'll emit two log messages and return | 220 // are both kinds of errors, we'll emit two log messages and return |
| 229 // PP_ERROR_BADARGUMENT. | 221 // PP_ERROR_BADARGUMENT. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 240 if (callback_.get()) | 232 if (callback_.get()) |
| 241 callback_->MarkAsCompleted(); | 233 callback_->MarkAsCompleted(); |
| 242 callback_ = NULL; | 234 callback_ = NULL; |
| 243 retval_ = PP_ERROR_BADARGUMENT; | 235 retval_ = PP_ERROR_BADARGUMENT; |
| 244 } | 236 } |
| 245 | 237 |
| 246 // We choose to silently ignore the error when the pp_instance is null as | 238 // We choose to silently ignore the error when the pp_instance is null as |
| 247 // for PP_Resources above. | 239 // for PP_Resources above. |
| 248 if (report_error && pp_instance) { | 240 if (report_error && pp_instance) { |
| 249 std::string message; | 241 std::string message; |
| 250 message = base::StringPrintf( | 242 message = |
| 251 "0x%X is not a valid instance ID.", | 243 base::StringPrintf("0x%X is not a valid instance ID.", pp_instance); |
| 252 pp_instance); | 244 PpapiGlobals::Get()->BroadcastLogWithSource( |
| 253 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR, | 245 0, PP_LOGLEVEL_ERROR, std::string(), message); |
| 254 std::string(), message); | |
| 255 } | 246 } |
| 256 } | 247 } |
| 257 | 248 |
| 258 } // namespace subtle | 249 } // namespace subtle |
| 259 | 250 |
| 260 EnterInstance::EnterInstance(PP_Instance instance) | 251 EnterInstance::EnterInstance(PP_Instance instance) |
| 261 : EnterBase(), | 252 : EnterBase(), functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { |
| 262 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { | |
| 263 SetStateForFunctionError(instance, functions_, true); | 253 SetStateForFunctionError(instance, functions_, true); |
| 264 } | 254 } |
| 265 | 255 |
| 266 EnterInstance::EnterInstance(PP_Instance instance, | 256 EnterInstance::EnterInstance(PP_Instance instance, |
| 267 const PP_CompletionCallback& callback) | 257 const PP_CompletionCallback& callback) |
| 268 : EnterBase(0 /* resource */, callback), | 258 : EnterBase(0 /* resource */, callback), |
| 269 // TODO(dmichael): This means that the callback_ we get is not associated | 259 // TODO(dmichael): This means that the callback_ we get is not associated |
| 270 // even with the instance, but we should handle that for | 260 // even with the instance, but we should handle that for |
| 271 // MouseLock (maybe others?). | 261 // MouseLock (maybe others?). |
| 272 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { | 262 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { |
| 273 SetStateForFunctionError(instance, functions_, true); | 263 SetStateForFunctionError(instance, functions_, true); |
| 274 } | 264 } |
| 275 | 265 |
| 276 EnterInstance::~EnterInstance() { | 266 EnterInstance::~EnterInstance() {} |
| 277 } | |
| 278 | 267 |
| 279 EnterInstanceNoLock::EnterInstanceNoLock(PP_Instance instance) | 268 EnterInstanceNoLock::EnterInstanceNoLock(PP_Instance instance) |
| 280 : EnterBase(), | 269 : EnterBase(), functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { |
| 281 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { | |
| 282 SetStateForFunctionError(instance, functions_, true); | 270 SetStateForFunctionError(instance, functions_, true); |
| 283 } | 271 } |
| 284 | 272 |
| 285 EnterInstanceNoLock::EnterInstanceNoLock( | 273 EnterInstanceNoLock::EnterInstanceNoLock(PP_Instance instance, |
| 286 PP_Instance instance, | 274 const PP_CompletionCallback& callback) |
| 287 const PP_CompletionCallback& callback) | |
| 288 : EnterBase(0 /* resource */, callback), | 275 : EnterBase(0 /* resource */, callback), |
| 289 // TODO(dmichael): This means that the callback_ we get is not associated | 276 // TODO(dmichael): This means that the callback_ we get is not associated |
| 290 // even with the instance, but we should handle that for | 277 // even with the instance, but we should handle that for |
| 291 // MouseLock (maybe others?). | 278 // MouseLock (maybe others?). |
| 292 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { | 279 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) { |
| 293 SetStateForFunctionError(instance, functions_, true); | 280 SetStateForFunctionError(instance, functions_, true); |
| 294 } | 281 } |
| 295 | 282 |
| 296 EnterInstanceNoLock::~EnterInstanceNoLock() { | 283 EnterInstanceNoLock::~EnterInstanceNoLock() {} |
| 297 } | |
| 298 | 284 |
| 299 EnterResourceCreation::EnterResourceCreation(PP_Instance instance) | 285 EnterResourceCreation::EnterResourceCreation(PP_Instance instance) |
| 300 : EnterBase(), | 286 : EnterBase(), |
| 301 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) { | 287 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) { |
| 302 SetStateForFunctionError(instance, functions_, true); | 288 SetStateForFunctionError(instance, functions_, true); |
| 303 } | 289 } |
| 304 | 290 |
| 305 EnterResourceCreation::~EnterResourceCreation() { | 291 EnterResourceCreation::~EnterResourceCreation() {} |
| 306 } | |
| 307 | 292 |
| 308 EnterResourceCreationNoLock::EnterResourceCreationNoLock(PP_Instance instance) | 293 EnterResourceCreationNoLock::EnterResourceCreationNoLock(PP_Instance instance) |
| 309 : EnterBase(), | 294 : EnterBase(), |
| 310 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) { | 295 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) { |
| 311 SetStateForFunctionError(instance, functions_, true); | 296 SetStateForFunctionError(instance, functions_, true); |
| 312 } | 297 } |
| 313 | 298 |
| 314 EnterResourceCreationNoLock::~EnterResourceCreationNoLock() { | 299 EnterResourceCreationNoLock::~EnterResourceCreationNoLock() {} |
| 315 } | |
| 316 | 300 |
| 317 } // namespace thunk | 301 } // namespace thunk |
| 318 } // namespace ppapi | 302 } // namespace ppapi |
| OLD | NEW |