cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / ppapi / thunk / enter.cc
blobbd955b2ca8f81d0fc3177f1a586c42f3b6c525e5
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
3 // found in the LICENSE file.
5 #include "ppapi/thunk/enter.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/synchronization/lock.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/shared_impl/ppapi_globals.h"
14 #include "ppapi/shared_impl/tracked_callback.h"
15 #include "ppapi/thunk/ppb_instance_api.h"
16 #include "ppapi/thunk/resource_creation_api.h"
18 namespace ppapi {
19 namespace {
21 bool IsMainThread() {
22 return
23 PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread();
26 } // namespace
28 namespace thunk {
30 namespace subtle {
32 void AssertLockHeld() {
33 base::Lock* proxy_lock = PpapiGlobals::Get()->GetProxyLock();
34 // The lock is only valid in the plugin side of the proxy, so it only makes
35 // sense to assert there. Otherwise, silently succeed.
36 if (proxy_lock)
37 proxy_lock->AssertAcquired();
40 EnterBase::EnterBase()
41 : resource_(NULL),
42 retval_(PP_OK) {
45 EnterBase::EnterBase(PP_Resource resource)
46 : resource_(GetResource(resource)),
47 retval_(PP_OK) {
50 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id)
51 : resource_(GetSingletonResource(instance, resource_id)),
52 retval_(PP_OK) {
55 EnterBase::EnterBase(PP_Resource resource,
56 const PP_CompletionCallback& callback)
57 : resource_(GetResource(resource)),
58 retval_(PP_OK) {
59 callback_ = new TrackedCallback(resource_, callback);
62 EnterBase::EnterBase(PP_Instance instance, SingletonResourceID resource_id,
63 const PP_CompletionCallback& callback)
64 : resource_(GetSingletonResource(instance, resource_id)),
65 retval_(PP_OK) {
66 DCHECK(resource_ || !instance);
67 if (!resource_)
68 retval_ = PP_ERROR_BADARGUMENT;
69 callback_ = new TrackedCallback(resource_, callback);
72 EnterBase::~EnterBase() {
73 // callback_ is cleared any time it is run, scheduled to be run, or once we
74 // know it will be completed asynchronously. So by this point it should be
75 // NULL.
76 DCHECK(!callback_.get())
77 << "|callback_| is not NULL. Did you forget to call "
78 "|EnterBase::SetResult| in the interface's thunk?";
81 int32_t EnterBase::SetResult(int32_t result) {
82 if (!callback_.get()) {
83 // It doesn't make sense to call SetResult if there is no callback.
84 NOTREACHED();
85 retval_ = result;
86 return result;
88 if (result == PP_OK_COMPLETIONPENDING) {
89 retval_ = result;
90 if (callback_->is_blocking()) {
91 DCHECK(!IsMainThread()); // We should have returned an error before this.
92 retval_ = callback_->BlockUntilComplete();
93 } else {
94 // The callback is not blocking and the operation will complete
95 // asynchronously, so there's nothing to do.
96 retval_ = result;
98 } else {
99 // The function completed synchronously.
100 if (callback_->is_required()) {
101 // This is a required callback, so we must issue it asynchronously.
102 callback_->PostRun(result);
103 retval_ = PP_OK_COMPLETIONPENDING;
104 } else {
105 // The callback is blocking or optional, so all we need to do is mark
106 // the callback as completed so that it won't be issued later.
107 callback_->MarkAsCompleted();
108 retval_ = result;
111 callback_ = NULL;
112 return retval_;
115 // static
116 Resource* EnterBase::GetResource(PP_Resource resource) {
117 return PpapiGlobals::Get()->GetResourceTracker()->GetResource(resource);
120 // static
121 Resource* EnterBase::GetSingletonResource(PP_Instance instance,
122 SingletonResourceID resource_id) {
123 PPB_Instance_API* ppb_instance =
124 PpapiGlobals::Get()->GetInstanceAPI(instance);
125 if (!ppb_instance)
126 return NULL;
128 return ppb_instance->GetSingletonResource(instance, resource_id);
131 void EnterBase::SetStateForCallbackError(bool report_error) {
132 if (PpapiGlobals::Get()->IsHostGlobals()) {
133 // In-process plugins can't make PPAPI calls off the main thread.
134 CHECK(IsMainThread());
136 if (callback_.get()) {
137 if (callback_->is_blocking() && IsMainThread()) {
138 // Blocking callbacks are never allowed on the main thread.
139 callback_->MarkAsCompleted();
140 callback_ = NULL;
141 retval_ = PP_ERROR_BLOCKS_MAIN_THREAD;
142 if (report_error) {
143 std::string message(
144 "Blocking callbacks are not allowed on the main thread.");
145 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
146 std::string(), message);
148 } else if (!IsMainThread() &&
149 callback_->has_null_target_loop() &&
150 !callback_->is_blocking()) {
151 // On a non-main thread, there must be a valid target loop for non-
152 // blocking callbacks, or we will have no place to run them.
154 // If the callback is required, there's no nice way to tell the plugin.
155 // We can't run their callback asynchronously without a message loop, and
156 // the plugin won't expect any return code other than
157 // PP_OK_COMPLETIONPENDING. So we crash to make the problem more obvious.
158 if (callback_->is_required()) {
159 std::string message("Attempted to use a required callback, but there "
160 "is no attached message loop on which to run the "
161 "callback.");
162 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
163 std::string(), message);
164 LOG(FATAL) << message;
167 callback_->MarkAsCompleted();
168 callback_ = NULL;
169 retval_ = PP_ERROR_NO_MESSAGE_LOOP;
170 if (report_error) {
171 std::string message(
172 "The calling thread must have a message loop attached.");
173 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
174 std::string(), message);
180 void EnterBase::ClearCallback() {
181 callback_ = NULL;
184 void EnterBase::SetStateForResourceError(PP_Resource pp_resource,
185 Resource* resource_base,
186 void* object,
187 bool report_error) {
188 // Check for callback errors. If we get any, SetStateForCallbackError will
189 // emit a log message. But we also want to check for resource errors. If there
190 // are both kinds of errors, we'll emit two log messages and return
191 // PP_ERROR_BADRESOURCE.
192 SetStateForCallbackError(report_error);
194 if (object)
195 return; // Everything worked.
197 if (callback_.get() && callback_->is_required()) {
198 callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADRESOURCE));
199 callback_ = NULL;
200 retval_ = PP_OK_COMPLETIONPENDING;
201 } else {
202 if (callback_.get())
203 callback_->MarkAsCompleted();
204 callback_ = NULL;
205 retval_ = PP_ERROR_BADRESOURCE;
208 // We choose to silently ignore the error when the pp_resource is null
209 // because this is a pretty common case and we don't want to have lots
210 // of errors in the log. This should be an obvious case to debug.
211 if (report_error && pp_resource) {
212 std::string message;
213 if (resource_base) {
214 message = base::StringPrintf(
215 "0x%X is not the correct type for this function.",
216 pp_resource);
217 } else {
218 message = base::StringPrintf(
219 "0x%X is not a valid resource ID.",
220 pp_resource);
222 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
223 std::string(), message);
227 void EnterBase::SetStateForFunctionError(PP_Instance pp_instance,
228 void* object,
229 bool report_error) {
230 // Check for callback errors. If we get any, SetStateForCallbackError will
231 // emit a log message. But we also want to check for instance errors. If there
232 // are both kinds of errors, we'll emit two log messages and return
233 // PP_ERROR_BADARGUMENT.
234 SetStateForCallbackError(report_error);
236 if (object)
237 return; // Everything worked.
239 if (callback_.get() && callback_->is_required()) {
240 callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADARGUMENT));
241 callback_ = NULL;
242 retval_ = PP_OK_COMPLETIONPENDING;
243 } else {
244 if (callback_.get())
245 callback_->MarkAsCompleted();
246 callback_ = NULL;
247 retval_ = PP_ERROR_BADARGUMENT;
250 // We choose to silently ignore the error when the pp_instance is null as
251 // for PP_Resources above.
252 if (report_error && pp_instance) {
253 std::string message;
254 message = base::StringPrintf(
255 "0x%X is not a valid instance ID.",
256 pp_instance);
257 PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
258 std::string(), message);
262 } // namespace subtle
264 EnterInstance::EnterInstance(PP_Instance instance)
265 : EnterBase(),
266 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
267 SetStateForFunctionError(instance, functions_, true);
270 EnterInstance::EnterInstance(PP_Instance instance,
271 const PP_CompletionCallback& callback)
272 : EnterBase(0 /* resource */, callback),
273 // TODO(dmichael): This means that the callback_ we get is not associated
274 // even with the instance, but we should handle that for
275 // MouseLock (maybe others?).
276 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
277 SetStateForFunctionError(instance, functions_, true);
280 EnterInstance::~EnterInstance() {
283 EnterInstanceNoLock::EnterInstanceNoLock(PP_Instance instance)
284 : EnterBase(),
285 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
286 SetStateForFunctionError(instance, functions_, true);
289 EnterInstanceNoLock::EnterInstanceNoLock(
290 PP_Instance instance,
291 const PP_CompletionCallback& callback)
292 : EnterBase(0 /* resource */, callback),
293 // TODO(dmichael): This means that the callback_ we get is not associated
294 // even with the instance, but we should handle that for
295 // MouseLock (maybe others?).
296 functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
297 SetStateForFunctionError(instance, functions_, true);
300 EnterInstanceNoLock::~EnterInstanceNoLock() {
303 EnterResourceCreation::EnterResourceCreation(PP_Instance instance)
304 : EnterBase(),
305 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) {
306 SetStateForFunctionError(instance, functions_, true);
309 EnterResourceCreation::~EnterResourceCreation() {
312 EnterResourceCreationNoLock::EnterResourceCreationNoLock(PP_Instance instance)
313 : EnterBase(),
314 functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) {
315 SetStateForFunctionError(instance, functions_, true);
318 EnterResourceCreationNoLock::~EnterResourceCreationNoLock() {
321 } // namespace thunk
322 } // namespace ppapi