Home | History | Annotate | Download | only in utility
      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_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_
      6 #define PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_
      7 
      8 #include "ppapi/cpp/logging.h"
      9 #include "ppapi/cpp/module.h"
     10 #include "ppapi/utility/threading/lock.h"
     11 
     12 /// @file
     13 /// Defines the traits structures for thread-safety of a completion callback
     14 /// factory. We provide thread-safe and non-thread-safe version. The thread-safe
     15 /// version is always correct (if you follow the thread usage rules of the
     16 /// callback factory), but if you know your object will only be used on one
     17 /// thread, you can uses the non-thread-safe version.
     18 ///
     19 /// The traits defines three nested classes to perform reference counting,
     20 /// locks, and scoped locking.
     21 
     22 namespace pp {
     23 
     24 /// The thread-safe version of thread traits. Using this class as the "traits"
     25 /// template argument to a completion callback factory will make it "somewhat
     26 /// thread-friendly." It will allow you to create completion callbacks from
     27 /// background threads and post them to another thread to run.
     28 ///
     29 /// Care still must be taken to ensure that the completion callbacks are
     30 /// executed on the same thread that the factory is destroyed on to avoid a
     31 /// race on destruction.
     32 ///
     33 /// Implementation note: this uses a lock instead of atomic add instructions.
     34 /// The number of platforms we need to support right now makes atomic
     35 /// operations unwieldy for this case that we don't actually use that often.
     36 /// As a further optimization, we can add support for this later.
     37 class ThreadSafeThreadTraits {
     38  public:
     39   class RefCount {
     40    public:
     41     /// Default constructor. In debug mode, this checks that the object is being
     42     /// created on the main thread.
     43     RefCount() : ref_(0) {
     44     }
     45 
     46     /// AddRef() increments the reference counter.
     47     ///
     48     /// @return An int32_t with the incremented reference counter.
     49     int32_t AddRef() {
     50       AutoLock lock(lock_);
     51       return ++ref_;
     52     }
     53 
     54     /// Release() decrements the reference counter.
     55     ///
     56     /// @return An int32_t with the decremeneted reference counter.
     57     int32_t Release() {
     58       AutoLock lock(lock_);
     59       PP_DCHECK(ref_ > 0);
     60       return --ref_;
     61     }
     62 
     63    private:
     64     Lock lock_;
     65     int32_t ref_;
     66   };
     67 
     68   typedef pp::Lock Lock;
     69   typedef pp::AutoLock AutoLock;
     70 };
     71 
     72 /// The non-thread-safe version of thread traits. Using this class as the
     73 /// "traits" template argument to a completion callback factory will make it
     74 /// not thread-safe but with potential extra performance.
     75 class NonThreadSafeThreadTraits {
     76  public:
     77   /// A simple reference counter that is not thread-safe.
     78   ///
     79   /// <strong>Note:</strong> in Debug mode, it checks that it is either called
     80   /// on the main thread, or always called on another thread.
     81   class RefCount {
     82    public:
     83     /// Default constructor. In debug mode, this checks that the object is being
     84     /// created on the main thread.
     85     RefCount() : ref_(0) {
     86 #ifndef NDEBUG
     87       is_main_thread_ = Module::Get()->core()->IsMainThread();
     88 #endif
     89     }
     90 
     91     /// Destructor.
     92     ~RefCount() {
     93       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread());
     94     }
     95 
     96     /// AddRef() increments the reference counter.
     97     ///
     98     /// @return An int32_t with the incremented reference counter.
     99     int32_t AddRef() {
    100       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread());
    101       return ++ref_;
    102     }
    103 
    104     /// Release() decrements the reference counter.
    105     ///
    106     /// @return An int32_t with the decremeneted reference counter.
    107     int32_t Release() {
    108       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread());
    109       return --ref_;
    110     }
    111 
    112    private:
    113     int32_t ref_;
    114 #ifndef NDEBUG
    115     bool is_main_thread_;
    116 #endif
    117   };
    118 
    119   /// A simple object that acts like a lock but does nothing.
    120   ///
    121   /// <strong>Note:</strong> in Debug mode, it checks that it is either
    122   /// called on the main thread, or always called on another thread. It also
    123   /// asserts that the caller does not recursively lock.
    124   class Lock {
    125    public:
    126     Lock() {
    127 #ifndef NDEBUG
    128       is_main_thread_ = Module::Get()->core()->IsMainThread();
    129       lock_held_ = false;
    130 #endif
    131     }
    132 
    133     ~Lock() {
    134       PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread());
    135     }
    136 
    137     /// Acquires the fake "lock". This does nothing except perform checks in
    138     /// debug mode.
    139     void Acquire() {
    140 #ifndef NDEBUG
    141       PP_DCHECK(!lock_held_);
    142       lock_held_ = true;
    143 #endif
    144     }
    145 
    146     /// Releases the fake "lock". This does nothing except perform checks in
    147     /// debug mode.
    148     void Release() {
    149 #ifndef NDEBUG
    150       PP_DCHECK(lock_held_);
    151       lock_held_ = false;
    152 #endif
    153     }
    154 
    155    private:
    156 #ifndef NDEBUG
    157     bool is_main_thread_;
    158     bool lock_held_;
    159 #endif
    160   };
    161 
    162   class AutoLock {
    163    public:
    164     explicit AutoLock(Lock& lock) : lock_(lock) {
    165       lock_.Acquire();
    166     }
    167     ~AutoLock() {
    168       lock_.Release();
    169     }
    170 
    171    private:
    172     Lock& lock_;
    173   };
    174 };
    175 
    176 }  // namespace pp
    177 
    178 #endif  // PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_
    179