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