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