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

Side by Side Diff: base/condition_variable_unittest.cc

Issue 42402: Test was examining a variable without first acquiring a required Lock.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | base/lock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Multi-threaded tests of ConditionVariable class. 5 // Multi-threaded tests of ConditionVariable class.
6 6
7 #include <time.h> 7 #include <time.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 // Worker threads only call the following methods. 70 // Worker threads only call the following methods.
71 // They should use the lock to get exclusive access. 71 // They should use the lock to get exclusive access.
72 int GetThreadId(); // Get an ID assigned to a thread.. 72 int GetThreadId(); // Get an ID assigned to a thread..
73 bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out. 73 bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out.
74 TimeDelta GetAnAssignment(int thread_id); // Get a work task duration. 74 TimeDelta GetAnAssignment(int thread_id); // Get a work task duration.
75 void WorkIsCompleted(int thread_id); 75 void WorkIsCompleted(int thread_id);
76 76
77 int task_count() const; 77 int task_count() const;
78 bool allow_help_requests() const; // Workers can signal more workers. 78 bool allow_help_requests() const; // Workers can signal more workers.
79 bool shutdown() const; // Check if shutdown has been requested. 79 bool shutdown() const; // Check if shutdown has been requested.
80 int shutdown_task_count() const;
81 80
82 void thread_shutting_down(); 81 void thread_shutting_down();
83 82
83
84 //---------------------------------------------------------------------------- 84 //----------------------------------------------------------------------------
85 // Worker threads can call them but not needed to acquire a lock 85 // Worker threads can call them but not needed to acquire a lock.
86 Lock* lock(); 86 Lock* lock();
87 87
88 ConditionVariable* work_is_available(); 88 ConditionVariable* work_is_available();
89 ConditionVariable* all_threads_have_ids(); 89 ConditionVariable* all_threads_have_ids();
90 ConditionVariable* no_more_tasks(); 90 ConditionVariable* no_more_tasks();
91 91
92 //---------------------------------------------------------------------------- 92 //----------------------------------------------------------------------------
93 // The rest of the methods are for use by the controlling master thread (the 93 // The rest of the methods are for use by the controlling master thread (the
94 // test case code). 94 // test case code).
95 void ResetHistory(); 95 void ResetHistory();
96 int GetMinCompletionsByWorkerThread() const; 96 int GetMinCompletionsByWorkerThread() const;
97 int GetMaxCompletionsByWorkerThread() const; 97 int GetMaxCompletionsByWorkerThread() const;
98 int GetNumThreadsTakingAssignments() const; 98 int GetNumThreadsTakingAssignments() const;
99 int GetNumThreadsCompletingTasks() const; 99 int GetNumThreadsCompletingTasks() const;
100 int GetNumberOfCompletedTasks() const; 100 int GetNumberOfCompletedTasks() const;
101 101
102 void SetWorkTime(TimeDelta delay); 102 void SetWorkTime(TimeDelta delay);
103 void SetTaskCount(int count); 103 void SetTaskCount(int count);
104 void SetAllowHelp(bool allow); 104 void SetAllowHelp(bool allow);
105 105
106 // Caller must acquire lock before calling.
106 void SetShutdown(); 107 void SetShutdown();
107 108
109 // Compares the |shutdown_task_count_| to the |thread_count| and returns true
110 // if they are equal. This check will acquire the |lock_| so the caller
111 // should not hold the lock when calling this method.
112 bool ThreadSafeCheckShutdown(int thread_count);
113
108 private: 114 private:
109 // Both worker threads and controller use the following to synchronize. 115 // Both worker threads and controller use the following to synchronize.
110 Lock lock_; 116 Lock lock_;
111 ConditionVariable work_is_available_; // To tell threads there is work. 117 ConditionVariable work_is_available_; // To tell threads there is work.
112 118
113 // Conditions to notify the controlling process (if it is interested). 119 // Conditions to notify the controlling process (if it is interested).
114 ConditionVariable all_threads_have_ids_; // All threads are running. 120 ConditionVariable all_threads_have_ids_; // All threads are running.
115 ConditionVariable no_more_tasks_; // Task count is zero. 121 ConditionVariable no_more_tasks_; // Task count is zero.
116 122
117 const int thread_count_; 123 const int thread_count_;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 TimeDelta duration = TimeTicks::Now() - start; 175 TimeDelta duration = TimeTicks::Now() - start;
170 // We can't use EXPECT_GE here as the TimeDelta class does not support the 176 // We can't use EXPECT_GE here as the TimeDelta class does not support the
171 // required stream conversion. 177 // required stream conversion.
172 EXPECT_TRUE(duration >= WAIT_TIME); 178 EXPECT_TRUE(duration >= WAIT_TIME);
173 179
174 lock.Release(); 180 lock.Release();
175 } 181 }
176 182
177 // This test is flaky due to excessive timing sensitivity. 183 // This test is flaky due to excessive timing sensitivity.
178 // http://code.google.com/p/chromium/issues/detail?id=3599 184 // http://code.google.com/p/chromium/issues/detail?id=3599
185 // TODO(jar): A recent change to the WorkQueue fixed flakyness for the test
186 // LargeFastTaskTest. Specifically, the test was accessing the member variable
187 // WorkQueue::shutdown_task_count_ without a lock held. The MultiThreadConsumer
188 // test now ran successfully for 500 times on RalphL's machine. RalphL did not
189 // want to blindly re-enable this test if you know of other issues with it, but
190 // it appears that the flakyness is gone, but I'll leave that to you to verify.
179 TEST_F(ConditionVariableTest, DISABLED_MultiThreadConsumerTest) { 191 TEST_F(ConditionVariableTest, DISABLED_MultiThreadConsumerTest) {
180 const int kThreadCount = 10; 192 const int kThreadCount = 10;
181 WorkQueue queue(kThreadCount); // Start the threads. 193 WorkQueue queue(kThreadCount); // Start the threads.
182 194
183 Lock private_lock; // Used locally for master to wait. 195 Lock private_lock; // Used locally for master to wait.
184 AutoLock private_held_lock(private_lock); 196 AutoLock private_held_lock(private_lock);
185 ConditionVariable private_cv(&private_lock); 197 ConditionVariable private_cv(&private_lock);
186 198
187 { 199 {
188 AutoLock auto_lock(*queue.lock()); 200 AutoLock auto_lock(*queue.lock());
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 EXPECT_EQ(0, queue.task_count()); 341 EXPECT_EQ(0, queue.task_count());
330 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread()); 342 EXPECT_EQ(2, queue.GetMaxCompletionsByWorkerThread());
331 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread()); 343 EXPECT_EQ(2, queue.GetMinCompletionsByWorkerThread());
332 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks()); 344 EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
333 345
334 queue.SetShutdown(); 346 queue.SetShutdown();
335 } 347 }
336 queue.work_is_available()->Broadcast(); // Force check for shutdown. 348 queue.work_is_available()->Broadcast(); // Force check for shutdown.
337 349
338 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), 350 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
339 queue.shutdown_task_count() == kThreadCount); 351 queue.ThreadSafeCheckShutdown(kThreadCount));
340 PlatformThread::Sleep(10); // Be sure they're all shutdown. 352 PlatformThread::Sleep(10); // Be sure they're all shutdown.
341 } 353 }
342 354
343 TEST_F(ConditionVariableTest, LargeFastTaskTest) { 355 TEST_F(ConditionVariableTest, LargeFastTaskTest) {
344 const int kThreadCount = 200; 356 const int kThreadCount = 200;
345 WorkQueue queue(kThreadCount); // Start the threads. 357 WorkQueue queue(kThreadCount); // Start the threads.
346 358
347 Lock private_lock; // Used locally for master to wait. 359 Lock private_lock; // Used locally for master to wait.
348 AutoLock private_held_lock(private_lock); 360 AutoLock private_held_lock(private_lock);
349 ConditionVariable private_cv(&private_lock); 361 ConditionVariable private_cv(&private_lock);
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 EXPECT_EQ(0, queue.task_count()); 441 EXPECT_EQ(0, queue.task_count());
430 EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread()); 442 EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread());
431 EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks()); 443 EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks());
432 444
433 queue.SetShutdown(); 445 queue.SetShutdown();
434 } 446 }
435 queue.work_is_available()->Broadcast(); // Force check for shutdown. 447 queue.work_is_available()->Broadcast(); // Force check for shutdown.
436 448
437 // Wait for shutdowns to complete. 449 // Wait for shutdowns to complete.
438 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1), 450 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
439 queue.shutdown_task_count() == kThreadCount); 451 queue.ThreadSafeCheckShutdown(kThreadCount));
440 PlatformThread::Sleep(10); // Be sure they're all shutdown. 452 PlatformThread::Sleep(10); // Be sure they're all shutdown.
441 } 453 }
442 454
443 //------------------------------------------------------------------------------ 455 //------------------------------------------------------------------------------
444 // Finally we provide the implementation for the methods in the WorkQueue class. 456 // Finally we provide the implementation for the methods in the WorkQueue class.
445 //------------------------------------------------------------------------------ 457 //------------------------------------------------------------------------------
446 458
447 WorkQueue::WorkQueue(int thread_count) 459 WorkQueue::WorkQueue(int thread_count)
448 : lock_(), 460 : lock_(),
449 work_is_available_(&lock_), 461 work_is_available_(&lock_),
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); 524 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
513 return task_count_; 525 return task_count_;
514 } 526 }
515 527
516 bool WorkQueue::allow_help_requests() const { 528 bool WorkQueue::allow_help_requests() const {
517 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); 529 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
518 return allow_help_requests_; 530 return allow_help_requests_;
519 } 531 }
520 532
521 bool WorkQueue::shutdown() const { 533 bool WorkQueue::shutdown() const {
534 lock_.AssertAcquired();
522 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); 535 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
523 return shutdown_; 536 return shutdown_;
524 } 537 }
525 538
526 int WorkQueue::shutdown_task_count() const { 539 // Because this method is called from the test's main thread we need to actually
527 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); 540 // take the lock. Threads will call the thread_shutting_down() method with the
528 return shutdown_task_count_; 541 // lock already acquired.
542 bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) {
543 bool all_shutdown;
544 AutoLock auto_lock(lock_);
545 {
546 // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock.
547 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
548 all_shutdown = (shutdown_task_count_ == thread_count);
549 }
550 return all_shutdown;
529 } 551 }
530 552
531 void WorkQueue::thread_shutting_down() { 553 void WorkQueue::thread_shutting_down() {
554 lock_.AssertAcquired();
532 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_); 555 DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
533 shutdown_task_count_++; 556 shutdown_task_count_++;
534 } 557 }
535 558
536 Lock* WorkQueue::lock() { 559 Lock* WorkQueue::lock() {
537 return &lock_; 560 return &lock_;
538 } 561 }
539 562
540 ConditionVariable* WorkQueue::work_is_available() { 563 ConditionVariable* WorkQueue::work_is_available() {
541 return &work_is_available_; 564 return &work_is_available_;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 622
600 void WorkQueue::SetTaskCount(int count) { 623 void WorkQueue::SetTaskCount(int count) {
601 task_count_ = count; 624 task_count_ = count;
602 } 625 }
603 626
604 void WorkQueue::SetAllowHelp(bool allow) { 627 void WorkQueue::SetAllowHelp(bool allow) {
605 allow_help_requests_ = allow; 628 allow_help_requests_ = allow;
606 } 629 }
607 630
608 void WorkQueue::SetShutdown() { 631 void WorkQueue::SetShutdown() {
632 lock_.AssertAcquired();
609 shutdown_ = true; 633 shutdown_ = true;
610 } 634 }
611 635
612 //------------------------------------------------------------------------------ 636 //------------------------------------------------------------------------------
613 // Define the standard worker task. Several tests will spin out many of these 637 // Define the standard worker task. Several tests will spin out many of these
614 // threads. 638 // threads.
615 //------------------------------------------------------------------------------ 639 //------------------------------------------------------------------------------
616 640
617 // The multithread tests involve several threads with a task to perform as 641 // The multithread tests involve several threads with a task to perform as
618 // directed by an instance of the class WorkQueue. 642 // directed by an instance of the class WorkQueue.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 693
670 { 694 {
671 AutoLock auto_lock(lock_); 695 AutoLock auto_lock(lock_);
672 // Send notification that we completed our "work." 696 // Send notification that we completed our "work."
673 WorkIsCompleted(thread_id); 697 WorkIsCompleted(thread_id);
674 } 698 }
675 } 699 }
676 } 700 }
677 701
678 } // namespace 702 } // namespace
OLDNEW
« no previous file with comments | « no previous file | base/lock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698