Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(447)

Side by Side Diff: ppapi/utility/completion_callback_factory.h

Issue 10696157: Add support for threadsafe completion callback factory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 5 #ifndef PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
6 #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 6 #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
7 7
8 #include "ppapi/cpp/completion_callback.h" 8 #include "ppapi/cpp/completion_callback.h"
9 #include "ppapi/utility/non_thread_safe_ref_count.h" 9 #include "ppapi/utility/completion_callback_factory_thread_traits.h"
10 10
11 /// @file 11 /// @file
12 /// This file defines the API to create CompletionCallback objects that are 12 /// This file defines the API to create CompletionCallback objects that are
13 /// bound to member functions. 13 /// bound to member functions.
14 namespace pp { 14 namespace pp {
15 15
16 // TypeUnwrapper -------------------------------------------------------------- 16 // TypeUnwrapper --------------------------------------------------------------
17 17
18 namespace internal { 18 namespace internal {
19 19
(...skipping 16 matching lines...) Expand all
36 36
37 /// CompletionCallbackFactory<T> may be used to create CompletionCallback 37 /// CompletionCallbackFactory<T> may be used to create CompletionCallback
38 /// objects that are bound to member functions. 38 /// objects that are bound to member functions.
39 /// 39 ///
40 /// If a factory is destroyed, then any pending callbacks will be cancelled 40 /// If a factory is destroyed, then any pending callbacks will be cancelled
41 /// preventing any bound member functions from being called. The CancelAll() 41 /// preventing any bound member functions from being called. The CancelAll()
42 /// method allows pending callbacks to be cancelled without destroying the 42 /// method allows pending callbacks to be cancelled without destroying the
43 /// factory. 43 /// factory.
44 /// 44 ///
45 /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't 45 /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't
46 /// thread safe, but you can make it more thread-friendly by passing a 46 /// thread safe, but it is somewhat thread-friendly when used with a
47 /// thread-safe refcounting class as the second template element. However, it 47 /// thread-safe traits class as the second template element. However, it
48 /// only guarantees safety for creating a callback from another thread, the 48 /// only guarantees safety for creating a callback from another thread, the
49 /// callback itself needs to execute on the same thread as the thread that 49 /// callback itself needs to execute on the same thread as the thread that
50 /// creates/destroys the factory. With this restriction, it is safe to create 50 /// creates/destroys the factory. With this restriction, it is safe to create
51 /// the <code>CompletionCallbackFactory</code> on the main thread, create 51 /// the <code>CompletionCallbackFactory</code> on the main thread, create
52 /// callbacks from any thread and pass them to CallOnMainThread(). 52 /// callbacks from any thread and pass them to CallOnMainThread().
53 /// 53 ///
54 /// <strong>Example: </strong> 54 /// <strong>Example: </strong>
55 /// 55 ///
56 /// @code 56 /// @code
57 /// class MyClass { 57 /// class MyClass {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 /// As with regular completion callbacks, you can optionally add up to three 178 /// As with regular completion callbacks, you can optionally add up to three
179 /// bound arguments. These are passed following the output argument. 179 /// bound arguments. These are passed following the output argument.
180 /// 180 ///
181 /// Your callback may take the output argument as a copy (common for small 181 /// Your callback may take the output argument as a copy (common for small
182 /// types like integers, a const reference (common for structures and 182 /// types like integers, a const reference (common for structures and
183 /// resources to avoid an extra copy), or as a non-const reference. One 183 /// resources to avoid an extra copy), or as a non-const reference. One
184 /// optimization you can do if your callback function may take large arrays 184 /// optimization you can do if your callback function may take large arrays
185 /// is to accept your output argument as a non-const reference and to swap() 185 /// is to accept your output argument as a non-const reference and to swap()
186 /// the argument with a vector of your own to store it. This means you don't 186 /// the argument with a vector of your own to store it. This means you don't
187 /// have to copy the buffer to consume it. 187 /// have to copy the buffer to consume it.
188 template <typename T, typename RefCount = NonThreadSafeRefCount> 188 template <typename T, typename ThreadTraits = ThreadSafeThreadTraits>
189 class CompletionCallbackFactory { 189 class CompletionCallbackFactory {
190 public: 190 public:
191 191
192 /// This constructor creates a <code>CompletionCallbackFactory</code> 192 /// This constructor creates a <code>CompletionCallbackFactory</code>
193 /// bound to an object. If the constructor is called without an argument, 193 /// bound to an object. If the constructor is called without an argument,
194 /// the default value of <code>NULL</code> is used. The user then must call 194 /// the default value of <code>NULL</code> is used. The user then must call
195 /// Initialize() to initialize the object. 195 /// Initialize() to initialize the object.
196 /// 196 ///
197 /// param[in] object Optional parameter. An object whose member functions 197 /// param[in] object Optional parameter. An object whose member functions
198 /// are to be bound to CompletionCallbacks created by this 198 /// are to be bound to CompletionCallbacks created by this
199 /// <code>CompletionCallbackFactory</code>. The default value of this 199 /// <code>CompletionCallbackFactory</code>. The default value of this
200 /// parameter is <code>NULL</code>. 200 /// parameter is <code>NULL</code>.
201 explicit CompletionCallbackFactory(T* object = NULL) 201 explicit CompletionCallbackFactory(T* object = NULL)
202 : object_(object) { 202 : object_(object) {
203 // Assume that we don't need to lock since construction should be complete
204 // before the pointer is used on another thread.
203 InitBackPointer(); 205 InitBackPointer();
204 } 206 }
205 207
206 /// Destructor. 208 /// Destructor.
207 ~CompletionCallbackFactory() { 209 ~CompletionCallbackFactory() {
210 // Assume that we don't need to lock since this object should not be used
211 // from multiple threads during destruction.
208 ResetBackPointer(); 212 ResetBackPointer();
209 } 213 }
210 214
211 /// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from 215 /// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from
212 /// this factory. 216 /// this factory.
213 void CancelAll() { 217 void CancelAll() {
218 ThreadTraits::AutoLock lock(lock_);
219
214 ResetBackPointer(); 220 ResetBackPointer();
215 InitBackPointer(); 221 InitBackPointer();
216 } 222 }
223
217 /// Initialize() binds the <code>CallbackFactory</code> to a particular 224 /// Initialize() binds the <code>CallbackFactory</code> to a particular
218 /// object. Use this when the object is not available at 225 /// object. Use this when the object is not available at
219 /// <code>CallbackFactory</code> creation, and the <code>NULL</code> default 226 /// <code>CallbackFactory</code> creation, and the <code>NULL</code> default
220 /// is passed to the constructor. The object may only be initialized once, 227 /// is passed to the constructor. The object may only be initialized once,
221 /// either by the constructor, or by a call to Initialize(). 228 /// either by the constructor, or by a call to Initialize().
222 /// 229 ///
230 /// This class may not be used on any thread until initialization is complete.
231 ///
223 /// @param[in] object The object whose member functions are to be bound to 232 /// @param[in] object The object whose member functions are to be bound to
224 /// the <code>CompletionCallback</code> created by this 233 /// the <code>CompletionCallback</code> created by this
225 /// <code>CompletionCallbackFactory</code>. 234 /// <code>CompletionCallbackFactory</code>.
226 void Initialize(T* object) { 235 void Initialize(T* object) {
227 PP_DCHECK(object); 236 PP_DCHECK(object);
228 PP_DCHECK(!object_); // May only initialize once! 237 PP_DCHECK(!object_); // May only initialize once!
229 object_ = object; 238 object_ = object;
230 } 239 }
231 240
232 /// GetObject() returns the object that was passed at initialization to 241 /// GetObject() returns the object that was passed at initialization to
233 /// Intialize(). 242 /// Intialize().
234 /// 243 ///
235 /// @return the object passed to the constructor or Intialize(). 244 /// @return the object passed to the constructor or Intialize().
236 T* GetObject() { 245 T* GetObject() {
237 return object_; 246 return object_;
238 } 247 }
239 248
240 /// NewCallback allocates a new, single-use <code>CompletionCallback</code>. 249 /// NewCallback allocates a new, single-use <code>CompletionCallback</code>.
241 /// The <code>CompletionCallback</code> must be run in order for the memory 250 /// The <code>CompletionCallback</code> must be run in order for the memory
242 /// allocated by the methods to be freed. 251 /// allocated by the methods to be freed.
243 /// 252 ///
244 /// @param[in] method The method to be invoked upon completion of the 253 /// @param[in] method The method to be invoked upon completion of the
245 /// operation. 254 /// operation.
246 /// 255 ///
247 /// @return A <code>CompletionCallback</code>. 256 /// @return A <code>CompletionCallback</code>.
248 template <typename Method> 257 template <typename Method>
249 CompletionCallback NewCallback(Method method) { 258 CompletionCallback NewCallback(Method method) {
250 PP_DCHECK(object_);
251 return NewCallbackHelper(new Dispatcher0<Method>(method)); 259 return NewCallbackHelper(new Dispatcher0<Method>(method));
252 } 260 }
253 261
254 /// NewOptionalCallback() allocates a new, single-use 262 /// NewOptionalCallback() allocates a new, single-use
255 /// <code>CompletionCallback</code> that might not run if the method 263 /// <code>CompletionCallback</code> that might not run if the method
256 /// taking it can complete synchronously. Thus, if after passing the 264 /// taking it can complete synchronously. Thus, if after passing the
257 /// CompletionCallback to a Pepper method, the method does not return 265 /// CompletionCallback to a Pepper method, the method does not return
258 /// PP_OK_COMPLETIONPENDING, then you should manually call the 266 /// PP_OK_COMPLETIONPENDING, then you should manually call the
259 /// CompletionCallback's Run method, or memory will be leaked. 267 /// CompletionCallback's Run method, or memory will be leaked.
260 /// 268 ///
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 /// @param[in] method The method to be invoked upon completion of the 303 /// @param[in] method The method to be invoked upon completion of the
296 /// operation. Method should be of type: 304 /// operation. Method should be of type:
297 /// <code>void (T::*)(int32_t result, const A& a)</code> 305 /// <code>void (T::*)(int32_t result, const A& a)</code>
298 /// 306 ///
299 /// @param[in] a Passed to <code>method</code> when the completion callback 307 /// @param[in] a Passed to <code>method</code> when the completion callback
300 /// runs. 308 /// runs.
301 /// 309 ///
302 /// @return A <code>CompletionCallback</code>. 310 /// @return A <code>CompletionCallback</code>.
303 template <typename Method, typename A> 311 template <typename Method, typename A>
304 CompletionCallback NewCallback(Method method, const A& a) { 312 CompletionCallback NewCallback(Method method, const A& a) {
305 PP_DCHECK(object_);
306 return NewCallbackHelper(new Dispatcher1<Method, A>(method, a)); 313 return NewCallbackHelper(new Dispatcher1<Method, A>(method, a));
307 } 314 }
308 315
309 /// NewOptionalCallback() allocates a new, single-use 316 /// NewOptionalCallback() allocates a new, single-use
310 /// <code>CompletionCallback</code> that might not run if the method 317 /// <code>CompletionCallback</code> that might not run if the method
311 /// taking it can complete synchronously. Thus, if after passing the 318 /// taking it can complete synchronously. Thus, if after passing the
312 /// CompletionCallback to a Pepper method, the method does not return 319 /// CompletionCallback to a Pepper method, the method does not return
313 /// PP_OK_COMPLETIONPENDING, then you should manually call the 320 /// PP_OK_COMPLETIONPENDING, then you should manually call the
314 /// CompletionCallback's Run method, or memory will be leaked. 321 /// CompletionCallback's Run method, or memory will be leaked.
315 /// 322 ///
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 /// 369 ///
363 /// @param[in] a Passed to <code>method</code> when the completion callback 370 /// @param[in] a Passed to <code>method</code> when the completion callback
364 /// runs. 371 /// runs.
365 /// 372 ///
366 /// @param[in] b Passed to <code>method</code> when the completion callback 373 /// @param[in] b Passed to <code>method</code> when the completion callback
367 /// runs. 374 /// runs.
368 /// 375 ///
369 /// @return A <code>CompletionCallback</code>. 376 /// @return A <code>CompletionCallback</code>.
370 template <typename Method, typename A, typename B> 377 template <typename Method, typename A, typename B>
371 CompletionCallback NewCallback(Method method, const A& a, const B& b) { 378 CompletionCallback NewCallback(Method method, const A& a, const B& b) {
372 PP_DCHECK(object_);
373 return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b)); 379 return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b));
374 } 380 }
375 381
376 /// NewOptionalCallback() allocates a new, single-use 382 /// NewOptionalCallback() allocates a new, single-use
377 /// <code>CompletionCallback</code> that might not run if the method 383 /// <code>CompletionCallback</code> that might not run if the method
378 /// taking it can complete synchronously. Thus, if after passing the 384 /// taking it can complete synchronously. Thus, if after passing the
379 /// CompletionCallback to a Pepper method, the method does not return 385 /// CompletionCallback to a Pepper method, the method does not return
380 /// PP_OK_COMPLETIONPENDING, then you should manually call the 386 /// PP_OK_COMPLETIONPENDING, then you should manually call the
381 /// CompletionCallback's Run method, or memory will be leaked. 387 /// CompletionCallback's Run method, or memory will be leaked.
382 /// 388 ///
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 /// @param[in] b Passed to <code>method</code> when the completion callback 450 /// @param[in] b Passed to <code>method</code> when the completion callback
445 /// runs. 451 /// runs.
446 /// 452 ///
447 /// @param[in] c Passed to <code>method</code> when the completion callback 453 /// @param[in] c Passed to <code>method</code> when the completion callback
448 /// runs. 454 /// runs.
449 /// 455 ///
450 /// @return A <code>CompletionCallback</code>. 456 /// @return A <code>CompletionCallback</code>.
451 template <typename Method, typename A, typename B, typename C> 457 template <typename Method, typename A, typename B, typename C>
452 CompletionCallback NewCallback(Method method, const A& a, const B& b, 458 CompletionCallback NewCallback(Method method, const A& a, const B& b,
453 const C& c) { 459 const C& c) {
454 PP_DCHECK(object_);
455 return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c)); 460 return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c));
456 } 461 }
457 462
458 /// NewOptionalCallback() allocates a new, single-use 463 /// NewOptionalCallback() allocates a new, single-use
459 /// <code>CompletionCallback</code> that might not run if the method 464 /// <code>CompletionCallback</code> that might not run if the method
460 /// taking it can complete synchronously. Thus, if after passing the 465 /// taking it can complete synchronously. Thus, if after passing the
461 /// CompletionCallback to a Pepper method, the method does not return 466 /// CompletionCallback to a Pepper method, the method does not return
462 /// PP_OK_COMPLETIONPENDING, then you should manually call the 467 /// PP_OK_COMPLETIONPENDING, then you should manually call the
463 /// CompletionCallback's Run method, or memory will be leaked. 468 /// CompletionCallback's Run method, or memory will be leaked.
464 /// 469 ///
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 typename internal::TypeUnwrapper<Output>::StorageType, 520 typename internal::TypeUnwrapper<Output>::StorageType,
516 void (T::*)(int32_t, Output, A, B, C), 521 void (T::*)(int32_t, Output, A, B, C),
517 typename internal::TypeUnwrapper<A>::StorageType, 522 typename internal::TypeUnwrapper<A>::StorageType,
518 typename internal::TypeUnwrapper<B>::StorageType, 523 typename internal::TypeUnwrapper<B>::StorageType,
519 typename internal::TypeUnwrapper<C>::StorageType>(method, a, b, c)); 524 typename internal::TypeUnwrapper<C>::StorageType>(method, a, b, c));
520 } 525 }
521 526
522 private: 527 private:
523 class BackPointer { 528 class BackPointer {
524 public: 529 public:
525 typedef CompletionCallbackFactory<T, RefCount> FactoryType; 530 typedef CompletionCallbackFactory<T, ThreadTraits> FactoryType;
526 531
527 explicit BackPointer(FactoryType* factory) 532 explicit BackPointer(FactoryType* factory)
528 : factory_(factory) { 533 : factory_(factory) {
529 } 534 }
530 535
531 void AddRef() { 536 void AddRef() {
532 ref_.AddRef(); 537 ref_.AddRef();
533 } 538 }
534 539
535 void Release() { 540 void Release() {
536 if (ref_.Release() == 0) 541 if (ref_.Release() == 0)
537 delete this; 542 delete this;
538 } 543 }
539 544
540 void DropFactory() { 545 void DropFactory() {
541 factory_ = NULL; 546 factory_ = NULL;
542 } 547 }
543 548
544 T* GetObject() { 549 T* GetObject() {
545 return factory_ ? factory_->GetObject() : NULL; 550 return factory_ ? factory_->GetObject() : NULL;
546 } 551 }
547 552
548 private: 553 private:
549 RefCount ref_; 554 typename ThreadTraits::RefCount ref_;
550 FactoryType* factory_; 555 FactoryType* factory_;
551 }; 556 };
552 557
553 template <typename Dispatcher> 558 template <typename Dispatcher>
554 class CallbackData { 559 class CallbackData {
555 public: 560 public:
556 // Takes ownership of the given dispatcher pointer. 561 // Takes ownership of the given dispatcher pointer.
557 CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher) 562 CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher)
558 : back_pointer_(back_pointer), 563 : back_pointer_(back_pointer),
559 dispatcher_(dispatcher) { 564 dispatcher_(dispatcher) {
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
810 } 815 }
811 private: 816 private:
812 Method method_; 817 Method method_;
813 A a_; 818 A a_;
814 B b_; 819 B b_;
815 C c_; 820 C c_;
816 821
817 typename Traits::StorageType output_; 822 typename Traits::StorageType output_;
818 }; 823 };
819 824
825 // Creates the back pointer object and takes a reference to it. This assumes
826 // either that the lock is held or that it is not needed.
820 void InitBackPointer() { 827 void InitBackPointer() {
821 back_pointer_ = new BackPointer(this); 828 back_pointer_ = new BackPointer(this);
822 back_pointer_->AddRef(); 829 back_pointer_->AddRef();
823 } 830 }
824 831
832 // Releases our reference to the back pointer object and clears the pointer.
833 // This assumes either that the lock is held or that it is not needed.
825 void ResetBackPointer() { 834 void ResetBackPointer() {
826 back_pointer_->DropFactory(); 835 back_pointer_->DropFactory();
827 back_pointer_->Release(); 836 back_pointer_->Release();
837 back_pointer_ = NULL;
828 } 838 }
829 839
830 // Takes ownership of the dispatcher pointer, which should be heap allocated. 840 // Takes ownership of the dispatcher pointer, which should be heap allocated.
831 template <typename Dispatcher> 841 template <typename Dispatcher>
832 CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) { 842 CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) {
843 ThreadTraits::AutoLock lock(lock_);
844
833 PP_DCHECK(object_); // Expects a non-null object! 845 PP_DCHECK(object_); // Expects a non-null object!
834 return CompletionCallback( 846 return CompletionCallback(
835 &CallbackData<Dispatcher>::Thunk, 847 &CallbackData<Dispatcher>::Thunk,
836 new CallbackData<Dispatcher>(back_pointer_, dispatcher)); 848 new CallbackData<Dispatcher>(back_pointer_, dispatcher));
837 } 849 }
838 850
839 // Takes ownership of the dispatcher pointer, which should be heap allocated. 851 // Takes ownership of the dispatcher pointer, which should be heap allocated.
840 template <typename Dispatcher> CompletionCallbackWithOutput< 852 template <typename Dispatcher> CompletionCallbackWithOutput<
841 typename internal::TypeUnwrapper< 853 typename internal::TypeUnwrapper<
842 typename Dispatcher::OutputType>::StorageType> 854 typename Dispatcher::OutputType>::StorageType>
843 NewCallbackWithOutputHelper(Dispatcher* dispatcher) { 855 NewCallbackWithOutputHelper(Dispatcher* dispatcher) {
856 ThreadTraits::AutoLock lock(lock_);
857
844 PP_DCHECK(object_); // Expects a non-null object! 858 PP_DCHECK(object_); // Expects a non-null object!
845 CallbackData<Dispatcher>* data = 859 CallbackData<Dispatcher>* data =
846 new CallbackData<Dispatcher>(back_pointer_, dispatcher); 860 new CallbackData<Dispatcher>(back_pointer_, dispatcher);
847 861
848 return CompletionCallbackWithOutput<typename Dispatcher::OutputType>( 862 return CompletionCallbackWithOutput<typename Dispatcher::OutputType>(
849 &CallbackData<Dispatcher>::Thunk, 863 &CallbackData<Dispatcher>::Thunk,
850 data, 864 data,
851 data->dispatcher()->output()); 865 data->dispatcher()->output());
852 } 866 }
853 867
854 // Disallowed: 868 // Disallowed:
855 CompletionCallbackFactory(const CompletionCallbackFactory&); 869 CompletionCallbackFactory(const CompletionCallbackFactory&);
856 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&); 870 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&);
857 871
872 // Never changed once initialized so does not need protection by the lock.
858 T* object_; 873 T* object_;
874
875 // Protects the back pointer.
876 typename ThreadTraits::Lock lock_;
877
878 // Protected by the lock. This will get reset when you do CancelAll, for
879 // example.
859 BackPointer* back_pointer_; 880 BackPointer* back_pointer_;
860 }; 881 };
861 882
862 } // namespace pp 883 } // namespace pp
863 884
864 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 885 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698