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 | |
viettrungluu
2012/07/10 22:47:58
You should probably include ppapi/cpp/logging.h.
| |
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" | |
viettrungluu
2012/07/10 22:47:58
s/threadsafe/thread-safe/
| |
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. | |
viettrungluu
2012/07/10 22:47:58
s/unweildy/unwieldy/
| |
35 /// As a further optimization, we can add support for this. | |
viettrungluu
2012/07/10 22:47:58
s/\.$/ later./ ?
| |
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_; | |
viettrungluu
2012/07/10 22:47:58
Maybe it's worth having a PP_DCHECK(ref > 0)?
| |
59 } | |
60 | |
61 private: | |
62 Lock lock_; | |
63 int32_t ref_; | |
64 }; | |
viettrungluu
2012/07/10 22:47:58
Maybe you should disallow copy/assign?
| |
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_; | |
viettrungluu
2012/07/10 22:47:58
I'm not entirely convinced that we should even let
| |
114 #endif | |
115 }; | |
viettrungluu
2012/07/10 22:47:58
"
| |
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. | |
viettrungluu
2012/07/10 22:47:58
s/called/caller/ ?
| |
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_); | |
viettrungluu
2012/07/10 22:47:58
I don't think it's documented anywhere that locks
| |
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 { | |
viettrungluu
2012/07/10 22:47:58
It feels kind of dumb that you have to repeat the
| |
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 |