1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PPAPI_THUNK_ENTER_H_
#define PPAPI_THUNK_ENTER_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/resource.h"
#include "ppapi/shared_impl/resource_tracker.h"
#include "ppapi/shared_impl/singleton_resource_id.h"
#include "ppapi/shared_impl/tracked_callback.h"
#include "ppapi/thunk/ppapi_thunk_export.h"
#include "ppapi/thunk/ppb_instance_api.h"
#include "ppapi/thunk/resource_creation_api.h"
namespace ppapi {
namespace thunk {
// Enter* helper objects: These objects wrap a call from the C PPAPI into
// the internal implementation. They make sure the lock is acquired and will
// automatically set up some stuff for you.
//
// You should always check whether the enter succeeded before using the object.
// If this fails, then the instance or resource ID supplied was invalid.
//
// The |report_error| arguments to the constructor should indicate if errors
// should be logged to the console. If the calling function expects that the
// input values are correct (the normal case), this should be set to true. In
// some case like |IsFoo(PP_Resource)| the caller is questioning whether their
// handle is this type, and we don't want to report an error if it's not.
//
// Resource member functions: EnterResource
// Automatically interprets the given PP_Resource as a resource ID and sets
// up the resource object for you.
namespace subtle {
// This helps us define our RAII Enter classes easily. To make an RAII class
// which locks the proxy lock on construction and unlocks on destruction,
// inherit from |LockOnEntry<true>| before all other base classes. This ensures
// that the lock is acquired before any other base class's constructor can run,
// and that the lock is only released after all other destructors have run.
// (This order of initialization is guaranteed by C++98/C++11 12.6.2.10).
//
// For cases where you don't want to lock, inherit from |LockOnEntry<false>|.
// This allows us to share more code between Enter* and Enter*NoLock classes.
template <bool lock_on_entry>
struct LockOnEntry;
template <>
struct LockOnEntry<false> {
#if (!NDEBUG)
LockOnEntry() {
// You must already hold the lock to use Enter*NoLock.
ProxyLock::AssertAcquired();
}
~LockOnEntry() {
// You must not release the lock before leaving the scope of the
// Enter*NoLock.
ProxyLock::AssertAcquired();
}
#endif
};
template <>
struct LockOnEntry<true> {
LockOnEntry() {
ppapi::ProxyLock::Acquire();
}
~LockOnEntry() {
ppapi::ProxyLock::Release();
}
};
// Keep non-templatized since we need non-inline functions here.
class PPAPI_THUNK_EXPORT EnterBase {
public:
EnterBase();
explicit EnterBase(PP_Resource resource);
EnterBase(PP_Instance instance, SingletonResourceID resource_id);
EnterBase(PP_Resource resource, const PP_CompletionCallback& callback);
EnterBase(PP_Instance instance, SingletonResourceID resource_id,
const PP_CompletionCallback& callback);
virtual ~EnterBase();
// Sets the result for calls that use a completion callback. It handles making
// sure that "Required" callbacks are scheduled to run asynchronously and
// "Blocking" callbacks cause the caller to block. (Interface implementations,
// therefore, should not do any special casing based on the type of the
// callback.)
//
// Returns the "retval()". This is to support the typical usage of
// return enter.SetResult(...);
// without having to write a separate "return enter.retval();" line.
int32_t SetResult(int32_t result);
// Use this value as the return value for the function.
int32_t retval() const { return retval_; }
// All failure conditions cause retval_ to be set to an appropriate error
// code.
bool succeeded() const { return retval_ == PP_OK; }
bool failed() const { return !succeeded(); }
const scoped_refptr<TrackedCallback>& callback() { return callback_; }
protected:
// Helper function to return a Resource from a PP_Resource. Having this
// code be in the non-templatized base keeps us from having to instantiate
// it in every template.
static Resource* GetResource(PP_Resource resource);
// Helper function to return a Resource from a PP_Instance and singleton
// resource identifier.
static Resource* GetSingletonResource(PP_Instance instance,
SingletonResourceID resource_id);
void ClearCallback();
// Does error handling associated with entering a resource. The resource_base
// is the result of looking up the given pp_resource. The object is the
// result of converting the base to the desired object (converted to a void*
// so this function doesn't have to be templatized). The reason for passing
// both resource_base and object is that we can differentiate "bad resource
// ID" from "valid resource ID not of the correct type."
//
// This will set retval_ = PP_ERROR_BADRESOURCE if the object is invalid, and
// if report_error is set, log a message to the programmer.
void SetStateForResourceError(PP_Resource pp_resource,
Resource* resource_base,
void* object,
bool report_error);
// Same as SetStateForResourceError except for function API.
void SetStateForFunctionError(PP_Instance pp_instance,
void* object,
bool report_error);
// For Enter objects that need a resource, we'll store a pointer to the
// Resource object so that we don't need to look it up more than once. For
// Enter objects with no resource, this will be NULL.
Resource* resource_;
private:
bool CallbackIsValid() const;
// Checks whether the callback is valid (i.e., if it is either non-blocking,
// or blocking and we're on a background thread). If the callback is invalid,
// this will set retval_ = PP_ERROR_BLOCKS_MAIN_THREAD, and if report_error is
// set, it will log a message to the programmer.
void SetStateForCallbackError(bool report_error);
// Holds the callback. For Enter objects that aren't given a callback, this
// will be NULL.
scoped_refptr<TrackedCallback> callback_;
int32_t retval_;
};
} // namespace subtle
// EnterResource ---------------------------------------------------------------
template<typename ResourceT, bool lock_on_entry = true>
class EnterResource
: public subtle::LockOnEntry<lock_on_entry>, // Must be first; see above.
public subtle::EnterBase {
public:
EnterResource(PP_Resource resource, bool report_error)
: EnterBase(resource) {
Init(resource, report_error);
}
EnterResource(PP_Resource resource, const PP_CompletionCallback& callback,
bool report_error)
: EnterBase(resource, callback) {
Init(resource, report_error);
}
~EnterResource() {}
ResourceT* object() { return object_; }
Resource* resource() { return resource_; }
private:
void Init(PP_Resource resource, bool report_error) {
if (resource_)
object_ = resource_->GetAs<ResourceT>();
else
object_ = NULL;
// Validate the resource (note, if both are wrong, we will return
// PP_ERROR_BADRESOURCE; last in wins).
SetStateForResourceError(resource, resource_, object_, report_error);
}
ResourceT* object_;
DISALLOW_COPY_AND_ASSIGN(EnterResource);
};
// ----------------------------------------------------------------------------
// Like EnterResource but assumes the lock is already held.
template<typename ResourceT>
class EnterResourceNoLock : public EnterResource<ResourceT, false> {
public:
EnterResourceNoLock(PP_Resource resource, bool report_error)
: EnterResource<ResourceT, false>(resource, report_error) {
}
EnterResourceNoLock(PP_Resource resource,
const PP_CompletionCallback& callback,
bool report_error)
: EnterResource<ResourceT, false>(resource, callback, report_error) {
}
};
// EnterInstance ---------------------------------------------------------------
class PPAPI_THUNK_EXPORT EnterInstance
: public subtle::LockOnEntry<true>, // Must be first; see above.
public subtle::EnterBase {
public:
explicit EnterInstance(PP_Instance instance);
EnterInstance(PP_Instance instance,
const PP_CompletionCallback& callback);
~EnterInstance();
bool succeeded() const { return !!functions_; }
bool failed() const { return !functions_; }
PPB_Instance_API* functions() const { return functions_; }
private:
PPB_Instance_API* functions_;
};
class PPAPI_THUNK_EXPORT EnterInstanceNoLock
: public subtle::LockOnEntry<false>, // Must be first; see above.
public subtle::EnterBase {
public:
explicit EnterInstanceNoLock(PP_Instance instance);
EnterInstanceNoLock(PP_Instance instance,
const PP_CompletionCallback& callback);
~EnterInstanceNoLock();
PPB_Instance_API* functions() { return functions_; }
private:
PPB_Instance_API* functions_;
};
// EnterInstanceAPI ------------------------------------------------------------
template<typename ApiT, bool lock_on_entry = true>
class EnterInstanceAPI
: public subtle::LockOnEntry<lock_on_entry>, // Must be first; see above
public subtle::EnterBase {
public:
explicit EnterInstanceAPI(PP_Instance instance)
: EnterBase(instance, ApiT::kSingletonResourceID),
functions_(NULL) {
if (resource_)
functions_ = resource_->GetAs<ApiT>();
SetStateForFunctionError(instance, functions_, true);
}
EnterInstanceAPI(PP_Instance instance,
const PP_CompletionCallback& callback)
: EnterBase(instance, ApiT::kSingletonResourceID, callback),
functions_(NULL) {
if (resource_)
functions_ = resource_->GetAs<ApiT>();
SetStateForFunctionError(instance, functions_, true);
}
~EnterInstanceAPI() {}
bool succeeded() const { return !!functions_; }
bool failed() const { return !functions_; }
ApiT* functions() const { return functions_; }
private:
ApiT* functions_;
};
template<typename ApiT>
class EnterInstanceAPINoLock : public EnterInstanceAPI<ApiT, false> {
public:
explicit EnterInstanceAPINoLock(PP_Instance instance)
: EnterInstanceAPI<ApiT, false>(instance) {
}
};
// EnterResourceCreation -------------------------------------------------------
class PPAPI_THUNK_EXPORT EnterResourceCreation
: public subtle::LockOnEntry<true>, // Must be first; see above.
public subtle::EnterBase {
public:
explicit EnterResourceCreation(PP_Instance instance);
~EnterResourceCreation();
ResourceCreationAPI* functions() { return functions_; }
private:
ResourceCreationAPI* functions_;
};
class PPAPI_THUNK_EXPORT EnterResourceCreationNoLock
: public subtle::LockOnEntry<false>, // Must be first; see above.
public subtle::EnterBase {
public:
explicit EnterResourceCreationNoLock(PP_Instance instance);
~EnterResourceCreationNoLock();
ResourceCreationAPI* functions() { return functions_; }
private:
ResourceCreationAPI* functions_;
};
} // namespace thunk
} // namespace ppapi
#endif // PPAPI_THUNK_ENTER_H_
|