Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: base/synchronized.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/synchronized.h ('k') | base/synchronized_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2004-2009 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 // Defines methods of classes used to encapsulate
17 // the synchronization primitives.
18
19 #include "omaha/base/synchronized.h"
20
21 #include "omaha/base/debug.h"
22 #include "omaha/base/error.h"
23 #include "omaha/base/logging.h"
24 #include "omaha/base/system.h"
25 #include "omaha/base/system_info.h"
26 #include "omaha/base/user_info.h"
27 #include "omaha/base/utils.h"
28
29 namespace omaha {
30
31 typedef HANDLE WINAPI CreateMutexExFunction(
32 LPSECURITY_ATTRIBUTES attributes,
33 const WCHAR* name,
34 DWORD flags,
35 DWORD desired_access
36 );
37
38 #define CREATE_EVENT_MANUAL_RESET 0x01
39 typedef HANDLE WINAPI CreateEventExFunction(
40 LPSECURITY_ATTRIBUTES attributes,
41 const WCHAR* name,
42 DWORD flags,
43 DWORD desired_access
44 );
45
46 CreateMutexExFunction* create_mutex_ex_function = NULL;
47 CreateEventExFunction* create_event_ex_function = NULL;
48
49 void EnsureCreateEx() {
50 if ((create_mutex_ex_function && create_event_ex_function) ||
51 !SystemInfo::IsRunningOnVistaOrLater()) {
52 return;
53 }
54
55 HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));
56 if (!kernel32_module) {
57 ASSERT(kernel32_module,
58 (_T("[GetModuleHandle error 0x%x]"), ::GetLastError()));
59 return;
60 }
61 GPA(kernel32_module, "CreateMutexExW", &create_mutex_ex_function);
62 ASSERT(create_mutex_ex_function,
63 (_T("[GPA error 0x%x]"), ::GetLastError()));
64
65 GPA(kernel32_module, "CreateEventExW", &create_event_ex_function);
66 ASSERT(create_event_ex_function,
67 (_T("[GPA error 0x%x]"), ::GetLastError()));
68 }
69
70 HANDLE CreateMutexWithSyncAccess(const TCHAR* name,
71 LPSECURITY_ATTRIBUTES lock_attributes) {
72 EnsureCreateEx();
73 if (create_mutex_ex_function) {
74 return create_mutex_ex_function(lock_attributes, name, 0,
75 SYNCHRONIZE |
76 MUTEX_MODIFY_STATE); // for ReleaseMutex
77 }
78 return ::CreateMutex(lock_attributes, false, name);
79 }
80
81 HANDLE CreateEventWithSyncAccess(const TCHAR* name,
82 LPSECURITY_ATTRIBUTES event_attributes) {
83 EnsureCreateEx();
84 if (create_event_ex_function) {
85 return create_event_ex_function(event_attributes, name,
86 CREATE_EVENT_MANUAL_RESET,
87 SYNCHRONIZE |
88 EVENT_MODIFY_STATE); // for Set/Reset, etc.
89 }
90 return ::CreateEvent(event_attributes, true, false, name);
91 }
92
93 // c-tor will take mutex.
94 AutoSync::AutoSync(const Lockable *pLock)
95 : lock_(pLock),
96 first_time_(true) {
97 ASSERT(lock_, (L""));
98 VERIFY(lock_->Lock(), (L"Failed to lock in constructor"));
99 }
100
101 // c-tor will take mutex.
102 AutoSync::AutoSync(const Lockable &rLock)
103 : lock_(&rLock),
104 first_time_(true) {
105 ASSERT(lock_, (L""));
106 VERIFY(lock_->Lock(), (L"Failed to lock in constructor"));
107 }
108
109 // d-tor will release mutex.
110 AutoSync::~AutoSync() {
111 ASSERT(lock_, (L""));
112 VERIFY(lock_->Unlock(), (L"Failed to unlock in denstructor"));
113 }
114
115 // Allows to write the for loop of __mutexBlock macro
116 bool AutoSync::FirstTime() {
117 if (first_time_) {
118 first_time_ = false;
119 return true;
120 }
121 return false;
122 }
123
124 // Constructor.
125 GLock::GLock() : mutex_(NULL) {
126 }
127
128 bool GLock::InitializeWithSecAttr(const TCHAR* name,
129 LPSECURITY_ATTRIBUTES lock_attributes) {
130 ASSERT(!mutex_, (L""));
131
132 #if defined(DEBUG) || defined(ASSERT_IN_RELEASE)
133 name_ = name;
134 #endif
135
136 mutex_ = CreateMutexWithSyncAccess(name, lock_attributes);
137 return mutex_ != NULL;
138 }
139
140 // Create mutex return the status of creation. Sets to default DACL.
141 bool GLock::Initialize(const TCHAR* name) {
142 return InitializeWithSecAttr(name, NULL);
143 }
144
145 // Clean up.
146 GLock::~GLock() {
147 if (mutex_) {
148 VERIFY(::CloseHandle(mutex_), (_T("")));
149 }
150 };
151
152 // Wait until signaled.
153 bool GLock::Lock() const {
154 return Lock(INFINITE);
155 }
156
157 bool GLock::Lock(DWORD dwMilliseconds) const {
158 ASSERT1(mutex_);
159
160 DWORD ret = ::WaitForSingleObject(mutex_, dwMilliseconds);
161 if (ret == WAIT_OBJECT_0) {
162 return true;
163 } else if (ret == WAIT_ABANDONED) {
164 UTIL_LOG(LE, (_T("[GLock::Lock - mutex was abandoned %s]"), name_));
165 return true;
166 }
167 return false;
168 }
169
170 // Release.
171 bool GLock::Unlock() const {
172 ASSERT1(mutex_);
173
174 bool ret = (false != ::ReleaseMutex(mutex_));
175 ASSERT(ret, (_T("ReleaseMutex failed. Err=%i"), ::GetLastError()));
176
177 return ret;
178 }
179
180 LLock::LLock() {
181 InitializeCriticalSection(&critical_section_);
182 }
183
184 LLock::~LLock() {
185 DeleteCriticalSection(&critical_section_);
186 }
187
188 bool LLock::Lock() const {
189 EnterCriticalSection(&critical_section_);
190 return true;
191 }
192
193 // not very precise funcion, but OK for our goals.
194 bool LLock::Lock(DWORD wait_ms) const {
195 if (::TryEnterCriticalSection(&critical_section_))
196 return true;
197 DWORD ticks_at_the_begin_of_wait = GetTickCount();
198 do {
199 ::Sleep(0);
200 if (::TryEnterCriticalSection(&critical_section_)) {
201 return true;
202 }
203 } while (::GetTickCount() - ticks_at_the_begin_of_wait < wait_ms);
204 return false;
205 }
206
207 bool LLock::Unlock() const {
208 LeaveCriticalSection(&critical_section_);
209 return true;
210 }
211
212 // LockCount is initialized to a value of -1; a value of 0 or greater indicates
213 // that the critical section is held or owned. When LockCount is not equal
214 // to -1, the OwningThread field contains the thread id that owns the section.
215 DWORD LLock::GetOwner() const {
216 return critical_section_.LockCount != -1 ?
217 reinterpret_cast<DWORD>(critical_section_.OwningThread) : 0;
218 }
219
220 // Use this c-tor for interprocess gates.
221 Gate::Gate(const TCHAR * event_name) : gate_(NULL) {
222 VERIFY(Initialize(event_name), (_T("")));
223 }
224
225 // Use this c-tor for in-process gates.
226 Gate::Gate() : gate_(NULL) {
227 VERIFY(Initialize(NULL), (_T("")));
228 }
229
230 // clean up.
231 Gate::~Gate() {
232 VERIFY(CloseHandle(gate_), (_T("")));
233 }
234
235 bool Gate::Initialize(const TCHAR * event_name) {
236 // event_name may be NULL
237 ASSERT1(gate_ == NULL);
238
239 // Create the event. The gate is initially closed.
240 // if this is in process gate we don't name event, otherwise we do.
241 // Created with default permissions.
242 gate_ = CreateEventWithSyncAccess(event_name, NULL);
243 return (NULL != gate_);
244 }
245
246 // Open the gate. Anyone can go through.
247 bool Gate::Open() {
248 return FALSE != SetEvent(gate_);
249 }
250
251 // Shut the gate closed.
252 bool Gate::Close() {
253 return FALSE != ResetEvent(gate_);
254 }
255
256 bool Gate::Wait(DWORD msec) {
257 return WAIT_OBJECT_0 == WaitForSingleObject(gate_, msec);
258 }
259
260 // Returns S_OK, and sets selected_gate to zero based index of the gate that
261 // was opened
262 // Returns E_FAIL if timeout occured or gate was abandoned.
263 HRESULT Gate::WaitAny(Gate const * const *gates,
264 int num_gates,
265 DWORD msec,
266 int *selected_gate) {
267 ASSERT1(selected_gate);
268 ASSERT1(gates);
269
270 return WaitMultipleHelper(gates, num_gates, msec, selected_gate, false);
271 }
272
273 // Returns S_OK if all gates were opened
274 // Returns E_FAIL if timeout occured or gate was abandoned.
275 HRESULT Gate::WaitAll(Gate const * const *gates, int num_gates, DWORD msec) {
276 ASSERT1(gates);
277
278 return WaitMultipleHelper(gates, num_gates, msec, NULL, true);
279 }
280
281 HRESULT Gate::WaitMultipleHelper(Gate const * const *gates,
282 int num_gates,
283 DWORD msec,
284 int *selected_gate,
285 bool wait_all) {
286 ASSERT1(gates);
287 ASSERT(num_gates > 0, (_T("There must be at least 1 gate")));
288
289 if ( num_gates <= 0 ) {
290 return E_FAIL;
291 }
292 HANDLE *gate_array = new HANDLE[ num_gates ];
293 ASSERT1(gate_array);
294 for ( int i = 0 ; i < num_gates ; ++i ) {
295 gate_array[ i ] = gates[ i ]->gate_;
296 }
297 DWORD res = WaitForMultipleObjects(num_gates,
298 gate_array,
299 wait_all ? TRUE : FALSE,
300 msec);
301 delete[] gate_array;
302
303 #pragma warning(disable : 4296)
304 // C4296: '>=' : expression is always true
305 if (WAIT_OBJECT_0 <= res && res < (WAIT_OBJECT_0 + num_gates)) {
306 if (selected_gate) {
307 *selected_gate = res - WAIT_OBJECT_0;
308 }
309 return S_OK;
310 }
311 #pragma warning(default : 4296)
312 return E_FAIL;
313 }
314
315 bool WaitAllowRepaint(const Gate& gate, DWORD msec) {
316 DWORD wait = 0;
317 HANDLE gate_handle = gate;
318 while ((wait = ::MsgWaitForMultipleObjects(1,
319 &gate_handle,
320 FALSE,
321 msec,
322 QS_PAINT)) == WAIT_OBJECT_0 + 1) {
323 MSG msg;
324 if (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
325 ::PeekMessage(&msg, NULL, WM_NCPAINT, WM_NCPAINT, PM_REMOVE)) {
326 ::TranslateMessage(&msg);
327 ::DispatchMessage(&msg);
328 }
329 }
330 return (wait == WAIT_OBJECT_0);
331 }
332
333 // SimpleLock
334 // TODO(omaha): Replace InterlockedCompareExchange with
335 // InterlockedCompareExchangeAcquire
336 // and InterlockedDecrement with InterlockedDecrementRelease for Windows 2003
337
338 bool SimpleLock::Lock() const {
339 while (1 == ::InterlockedCompareExchange(&lock_, 1, 0))
340 ::SleepEx(0, TRUE);
341 return true;
342 }
343
344 bool SimpleLock::Unlock() const {
345 ::InterlockedDecrement(&lock_);
346 return true;
347 }
348
349 // same with a delay in the loop to prevent CPU usage with significant
350 // contention
351
352 bool SimpleLockWithDelay::Lock() const {
353 while (1 == ::InterlockedCompareExchange(&lock_, 1, 0))
354 ::SleepEx(25, FALSE);
355 return true;
356 }
357
358 bool SimpleLockWithDelay::Unlock() const {
359 ::InterlockedDecrement(&lock_);
360 return true;
361 }
362
363
364 CriticalSection::CriticalSection()
365 : number_entries_(0) {
366 InitializeCriticalSection(&critical_section_);
367 }
368
369 // allow only one thread to hold a lock
370 CriticalSection::~CriticalSection() {
371 // we should not have to do anything in the destructor
372 ASSERT(!number_entries_, (_T("critical section destroyed while active")));
373 while (number_entries_) {
374 LeaveCriticalSection(&critical_section_);
375 number_entries_--;
376 }
377
378 DeleteCriticalSection(&critical_section_);
379 }
380
381 // enter the critical section
382 // entries may be nested
383 void CriticalSection::Enter() {
384 EnterCriticalSection(&critical_section_);
385 number_entries_++;
386 }
387
388 // exit the critical section
389 // number of exits must match number of entries
390 void CriticalSection::Exit() {
391 LeaveCriticalSection(&critical_section_);
392 number_entries_--;
393 }
394
395 // Take a CriticalSection and lock it
396 SingleLock::SingleLock(CriticalSection * cs) {
397 ASSERT(cs, (L""));
398 critical_section_ = cs;
399 critical_section_->Enter();
400 }
401
402 // If we haven't freed it yet, do so now since we fell out of scope
403 SingleLock::~SingleLock() {
404 if (critical_section_) {
405 critical_section_->Exit();
406 critical_section_ = NULL;
407 }
408 }
409
410 // Explicitly unlock
411 HRESULT SingleLock::Unlock() {
412 // If they did not
413 if (critical_section_ == NULL)
414 return S_FALSE;
415
416 critical_section_->Exit();
417 critical_section_ = NULL;
418 return S_OK;
419 }
420
421 // Encapsulation for kernel Event. Initializes and destroys with it's lifetime
422 void EventObj::Init(const TCHAR * event_name) {
423 ASSERT(event_name, (L""));
424
425 h_ = ::CreateEvent(NULL, false, false, event_name);
426 ASSERT1(h_);
427 }
428
429 EventObj::~EventObj() {
430 if (h_) {
431 VERIFY(CloseHandle(h_), (L""));
432 h_ = NULL;
433 }
434 }
435
436 BOOL EventObj::SetEvent() {
437 ASSERT(h_, (L""));
438 return ::SetEvent(h_);
439 }
440
441 // Is the given handle signaled?
442 //
443 // Typically used for events.
444 bool IsHandleSignaled(HANDLE h) {
445 ASSERT(h != NULL &&
446 h != INVALID_HANDLE_VALUE, (_T("")));
447
448 DWORD result = ::WaitForSingleObject(h, 0);
449 if (result == WAIT_OBJECT_0) {
450 return true;
451 }
452
453 ASSERT(result == WAIT_TIMEOUT,
454 (_T("unexpected result value: %u (hr=0x%x)"),
455 result, HRESULTFromLastError()));
456 return false;
457 }
458
459
460 // Create an id for the events/mutexes that can be used at the given scope.
461 // TODO(omaha): Error handling.
462 void CreateSyncId(const TCHAR* id, SyncScope scope, CString* sync_id) {
463 ASSERT1(id);
464 ASSERT1(sync_id);
465
466 CString postfix;
467 switch (scope) {
468 default:
469 ASSERT1(false);
470 break;
471
472 case SYNC_LOCAL:
473 sync_id->SetString(_T("Local\\"));
474 // no postfix for local ids
475 break;
476
477 case SYNC_USER:
478 case SYNC_GLOBAL:
479 sync_id->SetString(_T("Global\\"));
480
481 if (scope == SYNC_GLOBAL) {
482 // (MSDN insists that you can create objects with the same name with the
483 // prefixes "Global\" and "Local\" in a system "running Terminal
484 // Services". And it also assures that XP when running Fast User
485 // Switching uses Terminal Services. But when you try to create two
486 // objects with the same name but in the different namespaces on an
487 // XP Pro workstation NOT running Fast User Switching you can't - you
488 // get ERROR_ALREADY_EXISTS. And the reason is that in the Object table,
489 // Global and Local are both symlinks to the same object directory.
490 // Yet every technique that you can use to interrogate the system on
491 // whether or not the system is "running Terminal Services" says that
492 // the system is, in fact, running Terminal Services.
493 // Which is exactly what you'd expect, yet you can't create the
494 // two objects with the same name in different workspaces. So we change
495 // the name slightly.)
496 postfix.SetString(_T("_global"));
497 } else {
498 ASSERT1(scope == SYNC_USER);
499 // make the postfix the sid
500 VERIFY1(SUCCEEDED(omaha::user_info::GetProcessUser(NULL,
501 NULL,
502 &postfix)));
503 }
504 break;
505 }
506
507 sync_id->Append(id);
508 sync_id->Append(postfix);
509 }
510
511 } // namespace omaha
512
OLDNEW
« no previous file with comments | « base/synchronized.h ('k') | base/synchronized_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698