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