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