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/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 /// MStrong>Note:</strong> in Debug mode, it checks that it is either | |
kmixter1
2012/07/30 21:08:59
typo
| |
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_ | |
OLD | NEW |