enter.h revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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
24namespace ppapi {
25namespace 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
44namespace 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.
55template <bool lock_on_entry>
56struct LockOnEntry;
57
58template <>
59struct 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
73template <>
74struct 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.
84class 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
172template<typename ResourceT, bool lock_on_entry = true>
173class 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.
210template<typename ResourceT>
211class 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
225class 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
243class 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
260template<typename ApiT, bool lock_on_entry = true>
261class 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
291template<typename ApiT>
292class EnterInstanceAPINoLock : public EnterInstanceAPI<ApiT, false> {
293 public:
294  explicit EnterInstanceAPINoLock(PP_Instance instance)
295      : EnterInstanceAPI<ApiT, false>(instance) {
296  }
297};
298
299// EnterResourceCreation -------------------------------------------------------
300
301class 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
314class 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