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