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

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 ///
223 /// @param[in] object The object whose member functions are to be bound to 230 /// @param[in] object The object whose member functions are to be bound to
224 /// the <code>CompletionCallback</code> created by this 231 /// the <code>CompletionCallback</code> created by this
225 /// <code>CompletionCallbackFactory</code>. 232 /// <code>CompletionCallbackFactory</code>.
226 void Initialize(T* object) { 233 void Initialize(T* object) {
227 PP_DCHECK(object); 234 PP_DCHECK(object);
viettrungluu 2012/07/10 22:47:58 Maybe you should have a comment about the non-thre
228 PP_DCHECK(!object_); // May only initialize once! 235 PP_DCHECK(!object_); // May only initialize once!
229 object_ = object; 236 object_ = object;
230 } 237 }
231 238
232 /// GetObject() returns the object that was passed at initialization to 239 /// GetObject() returns the object that was passed at initialization to
233 /// Intialize(). 240 /// Intialize().
234 /// 241 ///
235 /// @return the object passed to the constructor or Intialize(). 242 /// @return the object passed to the constructor or Intialize().
236 T* GetObject() { 243 T* GetObject() {
237 return object_; 244 return object_;
238 } 245 }
239 246
240 /// NewCallback allocates a new, single-use <code>CompletionCallback</code>. 247 /// NewCallback allocates a new, single-use <code>CompletionCallback</code>.
241 /// The <code>CompletionCallback</code> must be run in order for the memory 248 /// The <code>CompletionCallback</code> must be run in order for the memory
242 /// allocated by the methods to be freed. 249 /// allocated by the methods to be freed.
243 /// 250 ///
244 /// @param[in] method The method to be invoked upon completion of the 251 /// @param[in] method The method to be invoked upon completion of the
245 /// operation. 252 /// operation.
246 /// 253 ///
247 /// @return A <code>CompletionCallback</code>. 254 /// @return A <code>CompletionCallback</code>.
248 template <typename Method> 255 template <typename Method>
249 CompletionCallback NewCallback(Method method) { 256 CompletionCallback NewCallback(Method method) {
250 PP_DCHECK(object_); 257 PP_DCHECK(object_);
viettrungluu 2012/07/10 22:47:58 While you're here, I believe this dcheck is wholly
251 return NewCallbackHelper(new Dispatcher0<Method>(method)); 258 return NewCallbackHelper(new Dispatcher0<Method>(method));
252 } 259 }
253 260
254 /// NewOptionalCallback() allocates a new, single-use 261 /// NewOptionalCallback() allocates a new, single-use
255 /// <code>CompletionCallback</code> that might not run if the method 262 /// <code>CompletionCallback</code> that might not run if the method
256 /// taking it can complete synchronously. Thus, if after passing the 263 /// taking it can complete synchronously. Thus, if after passing the
257 /// CompletionCallback to a Pepper method, the method does not return 264 /// CompletionCallback to a Pepper method, the method does not return
258 /// PP_OK_COMPLETIONPENDING, then you should manually call the 265 /// PP_OK_COMPLETIONPENDING, then you should manually call the
259 /// CompletionCallback's Run method, or memory will be leaked. 266 /// CompletionCallback's Run method, or memory will be leaked.
260 /// 267 ///
(...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 302 /// @param[in] method The method to be invoked upon completion of the
296 /// operation. Method should be of type: 303 /// operation. Method should be of type:
297 /// <code>void (T::*)(int32_t result, const A& a)</code> 304 /// <code>void (T::*)(int32_t result, const A& a)</code>
298 /// 305 ///
299 /// @param[in] a Passed to <code>method</code> when the completion callback 306 /// @param[in] a Passed to <code>method</code> when the completion callback
300 /// runs. 307 /// runs.
301 /// 308 ///
302 /// @return A <code>CompletionCallback</code>. 309 /// @return A <code>CompletionCallback</code>.
303 template <typename Method, typename A> 310 template <typename Method, typename A>
304 CompletionCallback NewCallback(Method method, const A& a) { 311 CompletionCallback NewCallback(Method method, const A& a) {
305 PP_DCHECK(object_); 312 PP_DCHECK(object_);
viettrungluu 2012/07/10 22:47:58 "
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_); 379 PP_DCHECK(object_);
viettrungluu 2012/07/10 22:47:58 "
373 return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b)); 380 return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b));
374 } 381 }
375 382
376 /// NewOptionalCallback() allocates a new, single-use 383 /// NewOptionalCallback() allocates a new, single-use
377 /// <code>CompletionCallback</code> that might not run if the method 384 /// <code>CompletionCallback</code> that might not run if the method
378 /// taking it can complete synchronously. Thus, if after passing the 385 /// taking it can complete synchronously. Thus, if after passing the
379 /// CompletionCallback to a Pepper method, the method does not return 386 /// CompletionCallback to a Pepper method, the method does not return
380 /// PP_OK_COMPLETIONPENDING, then you should manually call the 387 /// PP_OK_COMPLETIONPENDING, then you should manually call the
381 /// CompletionCallback's Run method, or memory will be leaked. 388 /// CompletionCallback's Run method, or memory will be leaked.
382 /// 389 ///
(...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 451 /// @param[in] b Passed to <code>method</code> when the completion callback
445 /// runs. 452 /// runs.
446 /// 453 ///
447 /// @param[in] c Passed to <code>method</code> when the completion callback 454 /// @param[in] c Passed to <code>method</code> when the completion callback
448 /// runs. 455 /// runs.
449 /// 456 ///
450 /// @return A <code>CompletionCallback</code>. 457 /// @return A <code>CompletionCallback</code>.
451 template <typename Method, typename A, typename B, typename C> 458 template <typename Method, typename A, typename B, typename C>
452 CompletionCallback NewCallback(Method method, const A& a, const B& b, 459 CompletionCallback NewCallback(Method method, const A& a, const B& b,
453 const C& c) { 460 const C& c) {
454 PP_DCHECK(object_); 461 PP_DCHECK(object_);
viettrungluu 2012/07/10 22:47:58 "
455 return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c)); 462 return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c));
456 } 463 }
457 464
458 /// NewOptionalCallback() allocates a new, single-use 465 /// NewOptionalCallback() allocates a new, single-use
459 /// <code>CompletionCallback</code> that might not run if the method 466 /// <code>CompletionCallback</code> that might not run if the method
460 /// taking it can complete synchronously. Thus, if after passing the 467 /// taking it can complete synchronously. Thus, if after passing the
461 /// CompletionCallback to a Pepper method, the method does not return 468 /// CompletionCallback to a Pepper method, the method does not return
462 /// PP_OK_COMPLETIONPENDING, then you should manually call the 469 /// PP_OK_COMPLETIONPENDING, then you should manually call the
463 /// CompletionCallback's Run method, or memory will be leaked. 470 /// CompletionCallback's Run method, or memory will be leaked.
464 /// 471 ///
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 typename internal::TypeUnwrapper<Output>::StorageType, 522 typename internal::TypeUnwrapper<Output>::StorageType,
516 void (T::*)(int32_t, Output, A, B, C), 523 void (T::*)(int32_t, Output, A, B, C),
517 typename internal::TypeUnwrapper<A>::StorageType, 524 typename internal::TypeUnwrapper<A>::StorageType,
518 typename internal::TypeUnwrapper<B>::StorageType, 525 typename internal::TypeUnwrapper<B>::StorageType,
519 typename internal::TypeUnwrapper<C>::StorageType>(method, a, b, c)); 526 typename internal::TypeUnwrapper<C>::StorageType>(method, a, b, c));
520 } 527 }
521 528
522 private: 529 private:
523 class BackPointer { 530 class BackPointer {
524 public: 531 public:
525 typedef CompletionCallbackFactory<T, RefCount> FactoryType; 532 typedef CompletionCallbackFactory<T, ThreadTraits> FactoryType;
526 533
527 explicit BackPointer(FactoryType* factory) 534 explicit BackPointer(FactoryType* factory)
528 : factory_(factory) { 535 : factory_(factory) {
529 } 536 }
530 537
531 void AddRef() { 538 void AddRef() {
532 ref_.AddRef(); 539 ref_.AddRef();
533 } 540 }
534 541
535 void Release() { 542 void Release() {
536 if (ref_.Release() == 0) 543 if (ref_.Release() == 0)
537 delete this; 544 delete this;
538 } 545 }
539 546
540 void DropFactory() { 547 void DropFactory() {
541 factory_ = NULL; 548 factory_ = NULL;
viettrungluu 2012/07/10 22:47:58 *** It's not entirely obvious to me why factory_ d
542 } 549 }
543 550
544 T* GetObject() { 551 T* GetObject() {
545 return factory_ ? factory_->GetObject() : NULL; 552 return factory_ ? factory_->GetObject() : NULL;
viettrungluu 2012/07/10 22:47:58 But then I worry about this....
546 } 553 }
547 554
548 private: 555 private:
549 RefCount ref_; 556 typename ThreadTraits::RefCount ref_;
550 FactoryType* factory_; 557 FactoryType* factory_;
551 }; 558 };
552 559
553 template <typename Dispatcher> 560 template <typename Dispatcher>
554 class CallbackData { 561 class CallbackData {
555 public: 562 public:
556 // Takes ownership of the given dispatcher pointer. 563 // Takes ownership of the given dispatcher pointer.
557 CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher) 564 CallbackData(BackPointer* back_pointer, Dispatcher* dispatcher)
558 : back_pointer_(back_pointer), 565 : back_pointer_(back_pointer),
559 dispatcher_(dispatcher) { 566 dispatcher_(dispatcher) {
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
810 } 817 }
811 private: 818 private:
812 Method method_; 819 Method method_;
813 A a_; 820 A a_;
814 B b_; 821 B b_;
815 C c_; 822 C c_;
816 823
817 typename Traits::StorageType output_; 824 typename Traits::StorageType output_;
818 }; 825 };
819 826
827 // Creates the back pointer object and takes a reference to it. This assumes
828 // either that the lock is held or that it is not needed.
820 void InitBackPointer() { 829 void InitBackPointer() {
821 back_pointer_ = new BackPointer(this); 830 back_pointer_ = new BackPointer(this);
822 back_pointer_->AddRef(); 831 back_pointer_->AddRef();
823 } 832 }
824 833
834 // Releases our reference to the back pointer object and clears the pointer.
835 // This assumes either that the lock is held or that it is not needed.
825 void ResetBackPointer() { 836 void ResetBackPointer() {
826 back_pointer_->DropFactory(); 837 back_pointer_->DropFactory();
827 back_pointer_->Release(); 838 back_pointer_->Release();
839 back_pointer_ = NULL;
828 } 840 }
829 841
830 // Takes ownership of the dispatcher pointer, which should be heap allocated. 842 // Takes ownership of the dispatcher pointer, which should be heap allocated.
831 template <typename Dispatcher> 843 template <typename Dispatcher>
832 CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) { 844 CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) {
845 ThreadTraits::AutoLock lock(lock_);
846
833 PP_DCHECK(object_); // Expects a non-null object! 847 PP_DCHECK(object_); // Expects a non-null object!
834 return CompletionCallback( 848 return CompletionCallback(
835 &CallbackData<Dispatcher>::Thunk, 849 &CallbackData<Dispatcher>::Thunk,
836 new CallbackData<Dispatcher>(back_pointer_, dispatcher)); 850 new CallbackData<Dispatcher>(back_pointer_, dispatcher));
837 } 851 }
838 852
839 // Takes ownership of the dispatcher pointer, which should be heap allocated. 853 // Takes ownership of the dispatcher pointer, which should be heap allocated.
840 template <typename Dispatcher> CompletionCallbackWithOutput< 854 template <typename Dispatcher> CompletionCallbackWithOutput<
841 typename internal::TypeUnwrapper< 855 typename internal::TypeUnwrapper<
842 typename Dispatcher::OutputType>::StorageType> 856 typename Dispatcher::OutputType>::StorageType>
843 NewCallbackWithOutputHelper(Dispatcher* dispatcher) { 857 NewCallbackWithOutputHelper(Dispatcher* dispatcher) {
858 ThreadTraits::AutoLock lock(lock_);
859
844 PP_DCHECK(object_); // Expects a non-null object! 860 PP_DCHECK(object_); // Expects a non-null object!
845 CallbackData<Dispatcher>* data = 861 CallbackData<Dispatcher>* data =
846 new CallbackData<Dispatcher>(back_pointer_, dispatcher); 862 new CallbackData<Dispatcher>(back_pointer_, dispatcher);
847 863
848 return CompletionCallbackWithOutput<typename Dispatcher::OutputType>( 864 return CompletionCallbackWithOutput<typename Dispatcher::OutputType>(
849 &CallbackData<Dispatcher>::Thunk, 865 &CallbackData<Dispatcher>::Thunk,
850 data, 866 data,
851 data->dispatcher()->output()); 867 data->dispatcher()->output());
852 } 868 }
853 869
854 // Disallowed: 870 // Disallowed:
855 CompletionCallbackFactory(const CompletionCallbackFactory&); 871 CompletionCallbackFactory(const CompletionCallbackFactory&);
856 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&); 872 CompletionCallbackFactory& operator=(const CompletionCallbackFactory&);
857 873
858 T* object_; 874 T* object_;
viettrungluu 2012/07/10 22:47:58 Maybe this should have a comment that this is only
875
876 typename ThreadTraits::Lock lock_;
viettrungluu 2012/07/10 22:47:58 Probably should indicate that this protects back_p
877
859 BackPointer* back_pointer_; 878 BackPointer* back_pointer_;
860 }; 879 };
861 880
862 } // namespace pp 881 } // namespace pp
863 882
864 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_ 883 #endif // PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698