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