OLD | NEW |
| (Empty) |
1 // Copyright 2004-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 // | |
16 // Declares some classes and macros to encapsulate | |
17 // the synchronization primitives. | |
18 | |
19 // TODO(omaha): remove dependency on atlstr | |
20 | |
21 #ifndef OMAHA_BASE_SYNCHRONIZED_H_ | |
22 #define OMAHA_BASE_SYNCHRONIZED_H_ | |
23 | |
24 #include <windows.h> | |
25 #include <atlstr.h> | |
26 #include "base/basictypes.h" | |
27 | |
28 namespace omaha { | |
29 | |
30 // This macros are used to create a unique name | |
31 // We need to go through two steps of expansion. | |
32 // Macro kMakeName1 will expand to string + number | |
33 // and macro kMakeName1 will put them together to create | |
34 // the unique name. | |
35 #define MAKE_NAME2(x, y) x##y | |
36 #define MAKE_NAME1(x, y) MAKE_NAME2(x, y) | |
37 #define MAKE_NAME(x) MAKE_NAME1(x, __COUNTER__) | |
38 | |
39 // Declare the interface in implement mutual | |
40 // exclusion. For in process mutual exclusion | |
41 // simple critical sections can be used. For | |
42 // interprocess mutual exclusion some named | |
43 // kernel mode object will have to be used. | |
44 struct Lockable { | |
45 virtual ~Lockable() {} | |
46 virtual bool Lock() const = 0; | |
47 virtual bool Unlock() const = 0; | |
48 }; | |
49 | |
50 // Scope based mutual exclusion. Locks | |
51 // the object on construction and unlocks | |
52 // during destruction. Very convinient to use | |
53 // with the macros __mutexScope and __mutexBlock | |
54 class AutoSync { | |
55 bool first_time_; | |
56 public: | |
57 explicit AutoSync(const Lockable *pLock); | |
58 explicit AutoSync(const Lockable &rLock); | |
59 ~AutoSync(); | |
60 // this function is only needed to use with | |
61 // the macro __mutexBlock | |
62 bool FirstTime(); | |
63 private: | |
64 const Lockable * lock_; | |
65 DISALLOW_EVIL_CONSTRUCTORS(AutoSync); | |
66 }; | |
67 | |
68 // the usaage: | |
69 // class A : public Lockable { | |
70 // | |
71 // | |
72 // | |
73 // void foo(){ | |
74 // __mutexScope(this); | |
75 // ...... | |
76 // ....... | |
77 // everything is synchronized till the end of the | |
78 // function or the time it returns (from any place) | |
79 // } // end foo. | |
80 // | |
81 // void bar() { | |
82 // ...... | |
83 // ...... do something here. | |
84 // ...... | |
85 // __mutexBlock(this){ | |
86 // .... do some other stuff | |
87 // .... | |
88 // .... | |
89 // } everything is synchronized till here | |
90 // | |
91 // }; // end class A | |
92 | |
93 // | |
94 #define __mutexScope(lock) AutoSync MAKE_NAME(hiddenLock)(lock) | |
95 #define __mutexBlock(lock) \ | |
96 for (AutoSync hiddenLock(lock); hiddenLock.FirstTime(); ) | |
97 | |
98 // GLock stands for global lock. | |
99 // Implementaion of Lockable to allow mutual exclusion | |
100 // between different processes. | |
101 // For in-process mutual exclusion use LLock - local lock | |
102 class GLock : public Lockable { | |
103 public: | |
104 GLock(); | |
105 virtual ~GLock(); | |
106 | |
107 // Create mutex returns the status of creation. Use ::GetLastError for | |
108 // error information. | |
109 bool InitializeWithSecAttr(const TCHAR* name, | |
110 LPSECURITY_ATTRIBUTES lock_attributes); | |
111 | |
112 // Create mutex return the status of creation. Sets to default DACL. | |
113 bool Initialize(const TCHAR* name); | |
114 | |
115 virtual bool Lock() const; | |
116 virtual bool Lock(DWORD dwMilliseconds) const; | |
117 virtual bool Unlock() const; | |
118 | |
119 private: | |
120 #if defined(DEBUG) || defined(ASSERT_IN_RELEASE) | |
121 CString name_; | |
122 #endif | |
123 mutable HANDLE mutex_; | |
124 DISALLOW_EVIL_CONSTRUCTORS(GLock); | |
125 }; | |
126 | |
127 // FakeGLock looks like a GLock, but none of its methods do anything. | |
128 // Only used with SharedMemoryPtr, in cases where locking is not required or | |
129 // desired. | |
130 class FakeGLock : public Lockable { | |
131 public: | |
132 FakeGLock() {} | |
133 virtual ~FakeGLock() {} | |
134 bool InitializeWithSecAttr(const TCHAR*, LPSECURITY_ATTRIBUTES) { | |
135 return true; | |
136 } | |
137 bool Initialize(const TCHAR*) { return true; } | |
138 virtual bool Lock() const { return true; } | |
139 virtual bool Lock(DWORD) const { return true; } | |
140 virtual bool Unlock() const { return true; } | |
141 | |
142 private: | |
143 DISALLOW_EVIL_CONSTRUCTORS(FakeGLock); | |
144 }; | |
145 | |
146 // LLock stands for local lock. | |
147 // means works only inside the process. | |
148 // use GLock - global lock for inter-process | |
149 // guarded access to data. | |
150 class LLock : public Lockable { | |
151 public: | |
152 LLock(); | |
153 virtual ~LLock(); | |
154 virtual bool Lock() const; | |
155 virtual bool Lock(DWORD wait_ms) const; | |
156 virtual bool Unlock() const; | |
157 | |
158 // Returns the thread id of the owner or 0 if the lock is not owned. | |
159 DWORD GetOwner() const; | |
160 private: | |
161 mutable CRITICAL_SECTION critical_section_; | |
162 DISALLOW_EVIL_CONSTRUCTORS(LLock); | |
163 }; | |
164 | |
165 // A gate is a synchronization object used to either stop all | |
166 // threads from proceeding through a point or to allow them all to proceed. | |
167 class Gate { | |
168 public: | |
169 // In process gate. | |
170 Gate(); | |
171 | |
172 // Interprocess gate. | |
173 explicit Gate(const TCHAR * event_name); | |
174 | |
175 ~Gate(); | |
176 | |
177 // Open the gate. | |
178 bool Open(); | |
179 | |
180 // Close the gate. | |
181 bool Close(); | |
182 | |
183 // Wait to enter the gate. | |
184 bool Wait(DWORD msec); | |
185 | |
186 // Conversion from the object to a HANDLE. | |
187 operator HANDLE() const {return gate_;} | |
188 | |
189 // Returns S_OK, and sets selected_gate to zero based index of the gate that | |
190 // was opened. | |
191 // Returns E_FAIL if timeout occured or gate was abandoned. | |
192 static HRESULT WaitAny(Gate const * const *gates, | |
193 int num_gates, | |
194 DWORD msec, | |
195 int *selected_gate); | |
196 | |
197 // Returns S_OK if all gates were opened | |
198 // Returns E_FAIL if timeout occured or gate was abandoned. | |
199 static HRESULT WaitAll(Gate const * const *gates, int num_gates, DWORD msec); | |
200 | |
201 private: | |
202 bool Initialize(const TCHAR * event_name); | |
203 static HRESULT WaitMultipleHelper(Gate const * const *gates, | |
204 int num_gates, | |
205 DWORD msec, | |
206 int *selected_gate, | |
207 bool wait_all); | |
208 HANDLE gate_; | |
209 DISALLOW_EVIL_CONSTRUCTORS(Gate); | |
210 }; | |
211 | |
212 bool WaitAllowRepaint(const Gate& gate, DWORD msec); | |
213 | |
214 class AutoGateKeeper { | |
215 public: | |
216 explicit AutoGateKeeper(Gate *gate) : gate_(gate) { | |
217 gate_->Open(); | |
218 } | |
219 ~AutoGateKeeper() { | |
220 gate_->Close(); | |
221 } | |
222 private: | |
223 Gate *gate_; | |
224 DISALLOW_EVIL_CONSTRUCTORS(AutoGateKeeper); | |
225 }; | |
226 | |
227 // A very simple rather fast lock - if uncontested. USE ONLY AS A GLOBAL OBJECT | |
228 // (i.e., DECLARED AT FILE SCOPE or as a STATIC CLASS MEMBER) - this is not | |
229 // enforced. Uses interlocked instructions on an int to get a fast user-mode | |
230 // lock. (Locks the bus and does a couple of memory references so it isn't | |
231 // free.) Spin-waits to get the lock. Has the advantage that it needs no | |
232 // initialization - thus has no order-of-evaluation problems with respect to | |
233 // other global objects. Does not work (causes deadlock) if locked twice by | |
234 // the same thread. (Has no constructor so is initialized to 0 by C++. | |
235 // This is why it must be a global or static class member: it doesn't initialize | |
236 // itself to 0. This is also why it doesn't inherit from Lockable, which would | |
237 // make it need to initialize a virtual table.) | |
238 struct SimpleLock { | |
239 bool Lock() const; | |
240 bool Unlock() const; | |
241 private: | |
242 mutable volatile long lock_; | |
243 }; | |
244 | |
245 struct SimpleLockWithDelay { | |
246 bool Lock() const; | |
247 bool Unlock() const; | |
248 private: | |
249 mutable volatile long lock_; | |
250 }; | |
251 | |
252 class AutoSimpleLock { | |
253 public: | |
254 explicit AutoSimpleLock(const SimpleLock& lock) | |
255 : lock_(lock) { lock_.Lock(); } | |
256 ~AutoSimpleLock() { lock_.Unlock(); } | |
257 private: | |
258 const SimpleLock& lock_; | |
259 DISALLOW_EVIL_CONSTRUCTORS(AutoSimpleLock); | |
260 }; | |
261 | |
262 class AutoSimpleLockWithDelay { | |
263 public: | |
264 explicit AutoSimpleLockWithDelay(const SimpleLockWithDelay& lock) | |
265 : lock_(lock) { lock_.Lock(); } | |
266 ~AutoSimpleLockWithDelay() { lock_.Unlock(); } | |
267 private: | |
268 const SimpleLockWithDelay& lock_; | |
269 DISALLOW_EVIL_CONSTRUCTORS(AutoSimpleLockWithDelay); | |
270 }; | |
271 | |
272 | |
273 // allow only one thread to hold a lock | |
274 class CriticalSection { | |
275 public: | |
276 CriticalSection(); | |
277 ~CriticalSection(); | |
278 | |
279 void Enter(); | |
280 void Exit(); | |
281 | |
282 private: | |
283 CRITICAL_SECTION critical_section_; | |
284 uint32 number_entries_; | |
285 | |
286 DISALLOW_EVIL_CONSTRUCTORS(CriticalSection); | |
287 }; | |
288 | |
289 // A class that manages a CriticalSection with its lifetime, you pass | |
290 // it one in the constructor and then it will either be freed in the | |
291 // destructor or implicitly [but only once] | |
292 class SingleLock { | |
293 public: | |
294 // TODO(omaha): Not sure if immediately locking is a good idea; | |
295 // the API is asymmetrical (there's an Unlock but no Lock). | |
296 | |
297 // Lock a critical section immediately | |
298 explicit SingleLock(CriticalSection * cs); | |
299 | |
300 // If we have not explicitly unlocked it, this destructor will | |
301 ~SingleLock(); | |
302 | |
303 // Release the lock explicitly [should be called only once, after that | |
304 // does nothing. If we do not do so, the destructor will] | |
305 HRESULT Unlock(); | |
306 | |
307 private: | |
308 CriticalSection * critical_section_; | |
309 | |
310 DISALLOW_EVIL_CONSTRUCTORS(SingleLock); | |
311 }; | |
312 | |
313 // Encapsulation for kernel Event. Initializes and destroys with it's lifetime | |
314 class EventObj { | |
315 public: | |
316 explicit EventObj(const TCHAR * event_name) { | |
317 Init(event_name); | |
318 } | |
319 ~EventObj(); | |
320 void Init(const TCHAR * event_name); | |
321 BOOL SetEvent(); | |
322 HANDLE GetHandle() { return h_; } | |
323 | |
324 private: | |
325 HANDLE h_; | |
326 | |
327 DISALLOW_EVIL_CONSTRUCTORS(EventObj); | |
328 }; | |
329 | |
330 // Is the given handle signaled? | |
331 // | |
332 // Typically used for events. | |
333 bool IsHandleSignaled(HANDLE h); | |
334 | |
335 | |
336 enum SyncScope { | |
337 // local to a session | |
338 SYNC_LOCAL, | |
339 | |
340 // global scope but the name is decorated to make it unique for the user | |
341 SYNC_USER, | |
342 | |
343 // a globally scoped name | |
344 SYNC_GLOBAL, | |
345 }; | |
346 | |
347 // Create an id for the events/mutexes that can be used at the given scope | |
348 void CreateSyncId(const TCHAR* id, SyncScope scope, CString* sync_id); | |
349 | |
350 // If any place needs to create a mutex that multiple | |
351 // processes need to access, use this. | |
352 HANDLE CreateMutexWithSyncAccess(const TCHAR* name, | |
353 LPSECURITY_ATTRIBUTES lock_attributes); | |
354 | |
355 } // namespace omaha | |
356 | |
357 #endif // OMAHA_BASE_SYNCHRONIZED_H_ | |
358 | |
OLD | NEW |