| Index: ppapi/utility/completion_callback_factory.h
|
| diff --git a/ppapi/utility/completion_callback_factory.h b/ppapi/utility/completion_callback_factory.h
|
| index d521f4b5d92bb38b45b78ce3684217d68f3cab07..68da18207590cbce91e1553420c608f7c33f6a16 100644
|
| --- a/ppapi/utility/completion_callback_factory.h
|
| +++ b/ppapi/utility/completion_callback_factory.h
|
| @@ -6,7 +6,7 @@
|
| #define PPAPI_UTILITY_COMPLETION_CALLBACK_FACTORY_H_
|
|
|
| #include "ppapi/cpp/completion_callback.h"
|
| -#include "ppapi/utility/non_thread_safe_ref_count.h"
|
| +#include "ppapi/utility/completion_callback_factory_thread_traits.h"
|
|
|
| /// @file
|
| /// This file defines the API to create CompletionCallback objects that are
|
| @@ -43,8 +43,8 @@ template <typename T> struct TypeUnwrapper<const T&> {
|
| /// factory.
|
| ///
|
| /// <strong>Note: </strong><code>CompletionCallbackFactory<T></code> isn't
|
| -/// thread safe, but you can make it more thread-friendly by passing a
|
| -/// thread-safe refcounting class as the second template element. However, it
|
| +/// thread safe, but it is somewhat thread-friendly when used with a
|
| +/// thread-safe traits class as the second template element. However, it
|
| /// only guarantees safety for creating a callback from another thread, the
|
| /// callback itself needs to execute on the same thread as the thread that
|
| /// creates/destroys the factory. With this restriction, it is safe to create
|
| @@ -185,7 +185,7 @@ template <typename T> struct TypeUnwrapper<const T&> {
|
| /// is to accept your output argument as a non-const reference and to swap()
|
| /// the argument with a vector of your own to store it. This means you don't
|
| /// have to copy the buffer to consume it.
|
| -template <typename T, typename RefCount = NonThreadSafeRefCount>
|
| +template <typename T, typename ThreadTraits = ThreadSafeThreadTraits>
|
| class CompletionCallbackFactory {
|
| public:
|
|
|
| @@ -200,26 +200,35 @@ class CompletionCallbackFactory {
|
| /// parameter is <code>NULL</code>.
|
| explicit CompletionCallbackFactory(T* object = NULL)
|
| : object_(object) {
|
| + // Assume that we don't need to lock since construction should be complete
|
| + // before the pointer is used on another thread.
|
| InitBackPointer();
|
| }
|
|
|
| /// Destructor.
|
| ~CompletionCallbackFactory() {
|
| + // Assume that we don't need to lock since this object should not be used
|
| + // from multiple threads during destruction.
|
| ResetBackPointer();
|
| }
|
|
|
| /// CancelAll() cancels all <code>CompletionCallbacks</code> allocated from
|
| /// this factory.
|
| void CancelAll() {
|
| + ThreadTraits::AutoLock lock(lock_);
|
| +
|
| ResetBackPointer();
|
| InitBackPointer();
|
| }
|
| +
|
| /// Initialize() binds the <code>CallbackFactory</code> to a particular
|
| /// object. Use this when the object is not available at
|
| /// <code>CallbackFactory</code> creation, and the <code>NULL</code> default
|
| /// is passed to the constructor. The object may only be initialized once,
|
| /// either by the constructor, or by a call to Initialize().
|
| ///
|
| + /// This class may not be used on any thread until initialization is complete.
|
| + ///
|
| /// @param[in] object The object whose member functions are to be bound to
|
| /// the <code>CompletionCallback</code> created by this
|
| /// <code>CompletionCallbackFactory</code>.
|
| @@ -247,7 +256,6 @@ class CompletionCallbackFactory {
|
| /// @return A <code>CompletionCallback</code>.
|
| template <typename Method>
|
| CompletionCallback NewCallback(Method method) {
|
| - PP_DCHECK(object_);
|
| return NewCallbackHelper(new Dispatcher0<Method>(method));
|
| }
|
|
|
| @@ -302,7 +310,6 @@ class CompletionCallbackFactory {
|
| /// @return A <code>CompletionCallback</code>.
|
| template <typename Method, typename A>
|
| CompletionCallback NewCallback(Method method, const A& a) {
|
| - PP_DCHECK(object_);
|
| return NewCallbackHelper(new Dispatcher1<Method, A>(method, a));
|
| }
|
|
|
| @@ -369,7 +376,6 @@ class CompletionCallbackFactory {
|
| /// @return A <code>CompletionCallback</code>.
|
| template <typename Method, typename A, typename B>
|
| CompletionCallback NewCallback(Method method, const A& a, const B& b) {
|
| - PP_DCHECK(object_);
|
| return NewCallbackHelper(new Dispatcher2<Method, A, B>(method, a, b));
|
| }
|
|
|
| @@ -451,7 +457,6 @@ class CompletionCallbackFactory {
|
| template <typename Method, typename A, typename B, typename C>
|
| CompletionCallback NewCallback(Method method, const A& a, const B& b,
|
| const C& c) {
|
| - PP_DCHECK(object_);
|
| return NewCallbackHelper(new Dispatcher3<Method, A, B, C>(method, a, b, c));
|
| }
|
|
|
| @@ -522,7 +527,7 @@ class CompletionCallbackFactory {
|
| private:
|
| class BackPointer {
|
| public:
|
| - typedef CompletionCallbackFactory<T, RefCount> FactoryType;
|
| + typedef CompletionCallbackFactory<T, ThreadTraits> FactoryType;
|
|
|
| explicit BackPointer(FactoryType* factory)
|
| : factory_(factory) {
|
| @@ -546,7 +551,7 @@ class CompletionCallbackFactory {
|
| }
|
|
|
| private:
|
| - RefCount ref_;
|
| + typename ThreadTraits::RefCount ref_;
|
| FactoryType* factory_;
|
| };
|
|
|
| @@ -817,19 +822,26 @@ class CompletionCallbackFactory {
|
| typename Traits::StorageType output_;
|
| };
|
|
|
| + // Creates the back pointer object and takes a reference to it. This assumes
|
| + // either that the lock is held or that it is not needed.
|
| void InitBackPointer() {
|
| back_pointer_ = new BackPointer(this);
|
| back_pointer_->AddRef();
|
| }
|
|
|
| + // Releases our reference to the back pointer object and clears the pointer.
|
| + // This assumes either that the lock is held or that it is not needed.
|
| void ResetBackPointer() {
|
| back_pointer_->DropFactory();
|
| back_pointer_->Release();
|
| + back_pointer_ = NULL;
|
| }
|
|
|
| // Takes ownership of the dispatcher pointer, which should be heap allocated.
|
| template <typename Dispatcher>
|
| CompletionCallback NewCallbackHelper(Dispatcher* dispatcher) {
|
| + ThreadTraits::AutoLock lock(lock_);
|
| +
|
| PP_DCHECK(object_); // Expects a non-null object!
|
| return CompletionCallback(
|
| &CallbackData<Dispatcher>::Thunk,
|
| @@ -841,6 +853,8 @@ class CompletionCallbackFactory {
|
| typename internal::TypeUnwrapper<
|
| typename Dispatcher::OutputType>::StorageType>
|
| NewCallbackWithOutputHelper(Dispatcher* dispatcher) {
|
| + ThreadTraits::AutoLock lock(lock_);
|
| +
|
| PP_DCHECK(object_); // Expects a non-null object!
|
| CallbackData<Dispatcher>* data =
|
| new CallbackData<Dispatcher>(back_pointer_, dispatcher);
|
| @@ -855,7 +869,14 @@ class CompletionCallbackFactory {
|
| CompletionCallbackFactory(const CompletionCallbackFactory&);
|
| CompletionCallbackFactory& operator=(const CompletionCallbackFactory&);
|
|
|
| + // Never changed once initialized so does not need protection by the lock.
|
| T* object_;
|
| +
|
| + // Protects the back pointer.
|
| + typename ThreadTraits::Lock lock_;
|
| +
|
| + // Protected by the lock. This will get reset when you do CancelAll, for
|
| + // example.
|
| BackPointer* back_pointer_;
|
| };
|
|
|
|
|