| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ | 
 | #define PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include "ppapi/cpp/logging.h" | 
 | #include "ppapi/cpp/module.h" | 
 | #include "ppapi/utility/threading/lock.h" | 
 |  | 
 | /// @file | 
 | /// Defines the traits structures for thread-safety of a completion callback | 
 | /// factory. We provide thread-safe and non-thread-safe version. The thread-safe | 
 | /// version is always correct (if you follow the thread usage rules of the | 
 | /// callback factory), but if you know your object will only be used on one | 
 | /// thread, you can uses the non-thread-safe version. | 
 | /// | 
 | /// The traits defines three nested classes to perform reference counting, | 
 | /// locks, and scoped locking. | 
 |  | 
 | namespace pp { | 
 |  | 
 | /// The thread-safe version of thread traits. Using this class as the "traits" | 
 | /// template argument to a completion callback factory will make it "somewhat | 
 | /// thread-friendly." It will allow you to create completion callbacks from | 
 | /// background threads and post them to another thread to run. | 
 | /// | 
 | /// Care still must be taken to ensure that the completion callbacks are | 
 | /// executed on the same thread that the factory is destroyed on to avoid a | 
 | /// race on destruction. | 
 | /// | 
 | /// Implementation note: this uses a lock instead of atomic add instructions. | 
 | /// The number of platforms we need to support right now makes atomic | 
 | /// operations unwieldy for this case that we don't actually use that often. | 
 | /// As a further optimization, we can add support for this later. | 
 | class ThreadSafeThreadTraits { | 
 |  public: | 
 |   class RefCount { | 
 |    public: | 
 |     /// Default constructor. In debug mode, this checks that the object is being | 
 |     /// created on the main thread. | 
 |     RefCount() : ref_(0) { | 
 |     } | 
 |  | 
 |     /// AddRef() increments the reference counter. | 
 |     /// | 
 |     /// @return An int32_t with the incremented reference counter. | 
 |     int32_t AddRef() { | 
 |       AutoLock lock(lock_); | 
 |       return ++ref_; | 
 |     } | 
 |  | 
 |     /// Release() decrements the reference counter. | 
 |     /// | 
 |     /// @return An int32_t with the decremeneted reference counter. | 
 |     int32_t Release() { | 
 |       AutoLock lock(lock_); | 
 |       PP_DCHECK(ref_ > 0); | 
 |       return --ref_; | 
 |     } | 
 |  | 
 |    private: | 
 |     Lock lock_; | 
 |     int32_t ref_; | 
 |   }; | 
 |  | 
 |   typedef pp::Lock Lock; | 
 |   typedef pp::AutoLock AutoLock; | 
 | }; | 
 |  | 
 | /// The non-thread-safe version of thread traits. Using this class as the | 
 | /// "traits" template argument to a completion callback factory will make it | 
 | /// not thread-safe but with potential extra performance. | 
 | class NonThreadSafeThreadTraits { | 
 |  public: | 
 |   /// A simple reference counter that is not thread-safe. | 
 |   /// | 
 |   /// <strong>Note:</strong> in Debug mode, it checks that it is either called | 
 |   /// on the main thread, or always called on another thread. | 
 |   class RefCount { | 
 |    public: | 
 |     /// Default constructor. In debug mode, this checks that the object is being | 
 |     /// created on the main thread. | 
 |     RefCount() : ref_(0) { | 
 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | 
 |       is_main_thread_ = Module::Get()->core()->IsMainThread(); | 
 | #endif | 
 |     } | 
 |  | 
 |     /// Destructor. | 
 |     ~RefCount() { | 
 |       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); | 
 |     } | 
 |  | 
 |     /// AddRef() increments the reference counter. | 
 |     /// | 
 |     /// @return An int32_t with the incremented reference counter. | 
 |     int32_t AddRef() { | 
 |       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); | 
 |       return ++ref_; | 
 |     } | 
 |  | 
 |     /// Release() decrements the reference counter. | 
 |     /// | 
 |     /// @return An int32_t with the decremeneted reference counter. | 
 |     int32_t Release() { | 
 |       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); | 
 |       return --ref_; | 
 |     } | 
 |  | 
 |    private: | 
 |     int32_t ref_; | 
 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | 
 |     bool is_main_thread_; | 
 | #endif | 
 |   }; | 
 |  | 
 |   /// A simple object that acts like a lock but does nothing. | 
 |   /// | 
 |   /// <strong>Note:</strong> in Debug mode, it checks that it is either | 
 |   /// called on the main thread, or always called on another thread. It also | 
 |   /// asserts that the caller does not recursively lock. | 
 |   class Lock { | 
 |    public: | 
 |     Lock() { | 
 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | 
 |       is_main_thread_ = Module::Get()->core()->IsMainThread(); | 
 |       lock_held_ = false; | 
 | #endif | 
 |     } | 
 |  | 
 |     ~Lock() { | 
 |       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); | 
 |     } | 
 |  | 
 |     /// Acquires the fake "lock". This does nothing except perform checks in | 
 |     /// debug mode. | 
 |     void Acquire() { | 
 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | 
 |       PP_DCHECK(!lock_held_); | 
 |       lock_held_ = true; | 
 | #endif | 
 |     } | 
 |  | 
 |     /// Releases the fake "lock". This does nothing except perform checks in | 
 |     /// debug mode. | 
 |     void Release() { | 
 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | 
 |       PP_DCHECK(lock_held_); | 
 |       lock_held_ = false; | 
 | #endif | 
 |     } | 
 |  | 
 |    private: | 
 | #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | 
 |     bool is_main_thread_; | 
 |     bool lock_held_; | 
 | #endif | 
 |   }; | 
 |  | 
 |   class AutoLock { | 
 |    public: | 
 |     explicit AutoLock(Lock& lock) : lock_(lock) { | 
 |       lock_.Acquire(); | 
 |     } | 
 |     ~AutoLock() { | 
 |       lock_.Release(); | 
 |     } | 
 |  | 
 |    private: | 
 |     Lock& lock_; | 
 |   }; | 
 | }; | 
 |  | 
 | }  // namespace pp | 
 |  | 
 | #endif  // PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ |