13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Multi-threaded tests of ConditionVariable class.
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <time.h>
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm>
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <vector>
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/spin_wait.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/condition_variable.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/synchronization/lock.h"
163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h"
173f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread_collision_warner.h"
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/time.h"
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/platform_test.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
223f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base {
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace {
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Define our test class, with several common variables.
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass ConditionVariableTest : public PlatformTest {
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta kZeroMs;
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta kTenMs;
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta kThirtyMs;
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta kFortyFiveMs;
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta kSixtyMs;
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta kOneHundredMs;
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  explicit ConditionVariableTest()
393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      : kZeroMs(TimeDelta::FromMilliseconds(0)),
403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        kTenMs(TimeDelta::FromMilliseconds(10)),
413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        kThirtyMs(TimeDelta::FromMilliseconds(30)),
423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        kFortyFiveMs(TimeDelta::FromMilliseconds(45)),
433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        kSixtyMs(TimeDelta::FromMilliseconds(60)),
443f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen        kOneHundredMs(TimeDelta::FromMilliseconds(100)) {
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Define a class that will control activities an several multi-threaded tests.
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The general structure of multi-threaded tests is that a test case will
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// construct an instance of a WorkQueue.  The WorkQueue will spin up some
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// threads and control them throughout their lifetime, as well as maintaining
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a central repository of the work thread's activity.  Finally, the WorkQueue
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// will command the the worker threads to terminate.  At that point, the test
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// cases will validate that the WorkQueue has records showing that the desired
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// activities were performed.
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Callers are responsible for synchronizing access to the following class.
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// all synchronized access.
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass WorkQueue : public PlatformThread::Delegate {
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  explicit WorkQueue(int thread_count);
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ~WorkQueue();
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // PlatformThread::Delegate interface.
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void ThreadMain();
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //----------------------------------------------------------------------------
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Worker threads only call the following methods.
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // They should use the lock to get exclusive access.
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int GetThreadId();  // Get an ID assigned to a thread..
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool EveryIdWasAllocated() const;  // Indicates that all IDs were handed out.
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TimeDelta GetAnAssignment(int thread_id);  // Get a work task duration.
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void WorkIsCompleted(int thread_id);
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int task_count() const;
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool allow_help_requests() const;  // Workers can signal more workers.
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool shutdown() const;  // Check if shutdown has been requested.
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void thread_shutting_down();
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //----------------------------------------------------------------------------
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Worker threads can call them but not needed to acquire a lock.
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock* lock();
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable* work_is_available();
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable* all_threads_have_ids();
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable* no_more_tasks();
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  //----------------------------------------------------------------------------
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // The rest of the methods are for use by the controlling master thread (the
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // test case code).
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void ResetHistory();
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int GetMinCompletionsByWorkerThread() const;
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int GetMaxCompletionsByWorkerThread() const;
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int GetNumThreadsTakingAssignments() const;
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int GetNumThreadsCompletingTasks() const;
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int GetNumberOfCompletedTasks() const;
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TimeDelta GetWorkTime() const;
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void SetWorkTime(TimeDelta delay);
105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void SetTaskCount(int count);
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void SetAllowHelp(bool allow);
107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The following must be called without locking, and will spin wait until the
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // threads are all in a wait state.
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void SpinUntilAllThreadsAreWaiting();
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void SpinUntilTaskCountLessThan(int task_count);
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Caller must acquire lock before calling.
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void SetShutdown();
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Compares the |shutdown_task_count_| to the |thread_count| and returns true
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // if they are equal.  This check will acquire the |lock_| so the caller
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // should not hold the lock when calling this method.
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool ThreadSafeCheckShutdown(int thread_count);
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Both worker threads and controller use the following to synchronize.
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock lock_;
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable work_is_available_;  // To tell threads there is work.
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Conditions to notify the controlling process (if it is interested).
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable all_threads_have_ids_;  // All threads are running.
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable no_more_tasks_;  // Task count is zero.
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const int thread_count_;
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int waiting_thread_count_;
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_array<PlatformThreadHandle> thread_handles_;
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::vector<int> assignment_history_;  // Number of assignment per worker.
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::vector<int> completion_history_;  // Number of completions per worker.
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int thread_started_counter_;  // Used to issue unique id to workers.
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int shutdown_task_count_;  // Number of tasks told to shutdown
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int task_count_;  // Number of assignment tasks waiting to be processed.
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TimeDelta worker_delay_;  // Time each task takes to complete.
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool allow_help_requests_;  // Workers can signal more workers.
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool shutdown_;  // Set when threads need to terminate.
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_MUTEX(locked_methods_);
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The next section contains the actual tests.
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(ConditionVariableTest, StartupShutdownTest) {
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock lock;
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // First try trivial startup/shutdown.
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ConditionVariable cv1(&lock);
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }  // Call for cv1 destruction.
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Exercise with at least a few waits.
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable cv(&lock);
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock.Acquire();
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cv.TimedWait(kTenMs);  // Wait for 10 ms.
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cv.TimedWait(kTenMs);  // Wait for 10 ms.
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock.Release();
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock.Acquire();
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cv.TimedWait(kTenMs);  // Wait for 10 ms.
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cv.TimedWait(kTenMs);  // Wait for 10 ms.
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cv.TimedWait(kTenMs);  // Wait for 10 ms.
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock.Release();
170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // Call for cv destruction.
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(ConditionVariableTest, TimeoutTest) {
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock lock;
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable cv(&lock);
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock.Acquire();
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TimeTicks start = TimeTicks::Now();
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta WAIT_TIME = TimeDelta::FromMilliseconds(300);
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Allow for clocking rate granularity.
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const TimeDelta FUDGE_TIME = TimeDelta::FromMilliseconds(50);
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  cv.TimedWait(WAIT_TIME + FUDGE_TIME);
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  TimeDelta duration = TimeTicks::Now() - start;
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We can't use EXPECT_GE here as the TimeDelta class does not support the
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // required stream conversion.
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_TRUE(duration >= WAIT_TIME);
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock.Release();
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Test serial task servicing, as well as two parallel task servicing methods.
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTEST_F(ConditionVariableTest, MultiThreadConsumerTest) {
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const int kThreadCount = 10;
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WorkQueue queue(kThreadCount);  // Start the threads.
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const int kTaskCount = 10;  // Number of tasks in each mini-test here.
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1983f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  Time start_time;  // Used to time task processing.
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (!queue.EveryIdWasAllocated())
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      queue.all_threads_have_ids()->Wait();
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If threads aren't in a wait state, they may start to gobble up tasks in
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // parallel, short-circuiting (breaking) this test.
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Since we have no tasks yet, all threads should be waiting by now.
21272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Set up to make one worker do 30ms tasks sequentially.
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetTaskCount(kTaskCount);
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kThirtyMs);
224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(false);
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    start_time = Time::Now();
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Signal();  // Start up one thread.
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Wait till we at least start to handle tasks (and we're not all waiting).
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilTaskCountLessThan(kTaskCount);
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Wait until all 10 work tasks have at least been assigned.
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (queue.task_count())
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      queue.no_more_tasks()->Wait();
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The last of the tasks *might* still be running, but... all but one should
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // be done by now, since tasks are being done serially.
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_LE(queue.GetWorkTime().InMilliseconds() * (kTaskCount - 1),
2413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen              (Time::Now() - start_time).InMilliseconds());
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments());
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks());
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_LE(kTaskCount - 1, queue.GetMaxCompletionsByWorkerThread());
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_LE(kTaskCount - 1, queue.GetNumberOfCompletedTasks());
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait to be sure all tasks are done.
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Check that all work was done by one thread id.
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(1, queue.GetNumThreadsTakingAssignments());
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(1, queue.GetNumThreadsCompletingTasks());
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kTaskCount, queue.GetMaxCompletionsByWorkerThread());
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Set up to make each task include getting help from another worker, so
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // so that the work gets done in paralell.
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetTaskCount(kTaskCount);
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kThirtyMs);
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(true);
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    start_time = Time::Now();
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Signal();  // But each worker can signal another.
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Wait till we at least start to handle tasks (and we're not all waiting).
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilTaskCountLessThan(kTaskCount);
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait to allow the all workers to get done.
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Wait until all work tasks have at least been assigned.
28172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (queue.task_count())
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      queue.no_more_tasks()->Wait();
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // To avoid racy assumptions, we'll just assert that at least 2 threads
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // did work.  We know that the first worker should have gone to sleep, and
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // hence a second worker should have gotten an assignment.
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_LE(2, queue.GetNumThreadsTakingAssignments());
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Try to ask all workers to help, and only a few will do the work.
292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetTaskCount(3);
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kThirtyMs);
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(false);
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Broadcast();  // Make them all try.
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Wait till we at least start to handle tasks (and we're not all waiting).
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilTaskCountLessThan(3);
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait to allow the 3 workers to get done.
3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
30472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Set up to make each task get help from another worker.
313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetTaskCount(3);
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kThirtyMs);
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(true);  // Allow (unnecessary) help requests.
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.work_is_available()->Broadcast();  // Signal all threads.
3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Wait till we at least start to handle tasks (and we're not all waiting).
3203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilTaskCountLessThan(3);
321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait to allow the 3 workers to get done.
3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
32572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Set up to make each task get help from another worker.
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    queue.SetTaskCount(20);  // 2 tasks per thread.
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kThirtyMs);
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(true);
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Signal();  // But each worker can signal another.
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Wait till we at least start to handle tasks (and we're not all waiting).
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilTaskCountLessThan(20);
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait to allow the 10 workers to get done.
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();  // Should take about 60 ms.
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Same as last test, but with Broadcast().
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    queue.SetTaskCount(20);  // 2 tasks per thread.
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kThirtyMs);
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(true);
357c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Broadcast();
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Wait till we at least start to handle tasks (and we're not all waiting).
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilTaskCountLessThan(20);
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait to allow the 10 workers to get done.
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();  // Should take about 60 ms.
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
36572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetShutdown();
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Broadcast();  // Force check for shutdown.
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   queue.ThreadSafeCheckShutdown(kThreadCount));
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(ConditionVariableTest, LargeFastTaskTest) {
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const int kThreadCount = 200;
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  WorkQueue queue(kThreadCount);  // Start the threads.
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock private_lock;  // Used locally for master to wait.
38472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock private_held_lock(private_lock);
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ConditionVariable private_cv(&private_lock);
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
38872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (!queue.EveryIdWasAllocated())
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      queue.all_threads_have_ids()->Wait();
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait a bit more to allow threads to reach their wait state.
3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Since we have no tasks, all threads should be waiting by now.
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Set up to make all workers do (an average of) 20 tasks.
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetTaskCount(20 * kThreadCount);
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kFortyFiveMs);
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(false);
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Broadcast();  // Start up all threads.
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait until we've handed out all tasks.
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (queue.task_count() != 0)
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      queue.no_more_tasks()->Wait();
418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait till the last of the tasks complete.
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // With Broadcast(), every thread should have participated.
425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // but with racing.. they may not all have done equal numbers of tasks.
42672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_LE(20, queue.GetMaxCompletionsByWorkerThread());
431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(20 * kThreadCount, queue.GetNumberOfCompletedTasks());
432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Set up to make all workers do (an average of) 4 tasks.
434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.ResetHistory();
435c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetTaskCount(kThreadCount * 4);
436c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetWorkTime(kFortyFiveMs);
437c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetAllowHelp(true);  // Might outperform Broadcast().
438c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
439c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Signal();  // Start up one thread.
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait until we've handed out all tasks
442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
44372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    while (queue.task_count() != 0)
445c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      queue.no_more_tasks()->Wait();
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait till the last of the tasks complete.
4493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  queue.SpinUntilAllThreadsAreWaiting();
450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // With Signal(), every thread should have participated.
453c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // but with racing.. they may not all have done four tasks.
45472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(*queue.lock());
455c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(0, queue.task_count());
458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread());
459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks());
460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    queue.SetShutdown();
462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  queue.work_is_available()->Broadcast();  // Force check for shutdown.
464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Wait for shutdowns to complete.
466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                   queue.ThreadSafeCheckShutdown(kThreadCount));
468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Finally we provide the implementation for the methods in the WorkQueue class.
472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWorkQueue::WorkQueue(int thread_count)
475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  : lock_(),
476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    work_is_available_(&lock_),
477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    all_threads_have_ids_(&lock_),
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    no_more_tasks_(&lock_),
479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_count_(thread_count),
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    waiting_thread_count_(0),
481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_handles_(new PlatformThreadHandle[thread_count]),
482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    assignment_history_(thread_count),
483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    completion_history_(thread_count),
484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_started_counter_(0),
485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    shutdown_task_count_(0),
486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    task_count_(0),
487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    allow_help_requests_(false),
488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    shutdown_(false) {
489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  EXPECT_GE(thread_count_, 1);
490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ResetHistory();
491c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetTaskCount(0);
492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  SetWorkTime(TimeDelta::FromMilliseconds(30));
493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i) {
495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PlatformThreadHandle pth;
496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    EXPECT_TRUE(PlatformThread::Create(0, this, &pth));
497c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_handles_[i] = pth;
498c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
499c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
500c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
501c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWorkQueue::~WorkQueue() {
502c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
50372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(lock_);
504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    SetShutdown();
505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  work_is_available_.Broadcast();  // Tell them all to terminate.
507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i) {
509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PlatformThread::Join(thread_handles_[i]);
510c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
5113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(0, waiting_thread_count_);
512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::GetThreadId() {
515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!EveryIdWasAllocated());
517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return thread_started_counter_++;  // Give out Unique IDs.
518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
519c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool WorkQueue::EveryIdWasAllocated() const {
521c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return thread_count_ == thread_started_counter_;
523c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTimeDelta WorkQueue::GetAnAssignment(int thread_id) {
526c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_LT(0, task_count_);
528c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  assignment_history_[thread_id]++;
529c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (0 == --task_count_) {
530c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    no_more_tasks_.Signal();
531c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return worker_delay_;
533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
535c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::WorkIsCompleted(int thread_id) {
536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
537c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  completion_history_[thread_id]++;
538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
539c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
540c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::task_count() const {
541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return task_count_;
543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
544c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
545c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool WorkQueue::allow_help_requests() const {
546c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
547c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return allow_help_requests_;
548c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
549c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
550c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool WorkQueue::shutdown() const {
551c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock_.AssertAcquired();
552c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
553c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return shutdown_;
554c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
555c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
556c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Because this method is called from the test's main thread we need to actually
557c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// take the lock.  Threads will call the thread_shutting_down() method with the
558c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// lock already acquired.
559c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool WorkQueue::ThreadSafeCheckShutdown(int thread_count) {
560c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool all_shutdown;
56172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock auto_lock(lock_);
562c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
563c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock.
564c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
565c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    all_shutdown = (shutdown_task_count_ == thread_count);
566c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
567c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return all_shutdown;
568c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
569c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
570c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::thread_shutting_down() {
571c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock_.AssertAcquired();
572c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
573c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  shutdown_task_count_++;
574c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
575c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
576c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottLock* WorkQueue::lock() {
577c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return &lock_;
578c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
579c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
580c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottConditionVariable* WorkQueue::work_is_available() {
581c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return &work_is_available_;
582c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
583c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
584c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottConditionVariable* WorkQueue::all_threads_have_ids() {
585c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return &all_threads_have_ids_;
586c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
587c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
588c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottConditionVariable* WorkQueue::no_more_tasks() {
589c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return &no_more_tasks_;
590c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
591c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
592c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::ResetHistory() {
593c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i) {
594c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    assignment_history_[i] = 0;
595c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    completion_history_[i] = 0;
596c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
597c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
598c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
599c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::GetMinCompletionsByWorkerThread() const {
600c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int minumum = completion_history_[0];
601c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i)
602c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    minumum = std::min(minumum, completion_history_[i]);
603c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return minumum;
604c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
605c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
606c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::GetMaxCompletionsByWorkerThread() const {
607c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int maximum = completion_history_[0];
608c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i)
609c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    maximum = std::max(maximum, completion_history_[i]);
610c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return maximum;
611c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
612c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
613c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::GetNumThreadsTakingAssignments() const {
614c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int count = 0;
615c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i)
616c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (assignment_history_[i])
617c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      count++;
618c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return count;
619c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
620c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
621c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::GetNumThreadsCompletingTasks() const {
622c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int count = 0;
623c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i)
624c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (completion_history_[i])
625c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      count++;
626c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return count;
627c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
628c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
629c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint WorkQueue::GetNumberOfCompletedTasks() const {
630c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int total = 0;
631c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  for (int i = 0; i < thread_count_; ++i)
632c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    total += completion_history_[i];
633c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return total;
634c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
635c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
636c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTimeDelta WorkQueue::GetWorkTime() const {
637c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return worker_delay_;
638c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
639c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
640c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::SetWorkTime(TimeDelta delay) {
641c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  worker_delay_ = delay;
642c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
643c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
644c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::SetTaskCount(int count) {
645c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  task_count_ = count;
646c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
647c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
648c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::SetAllowHelp(bool allow) {
649c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  allow_help_requests_ = allow;
650c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
651c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
652c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::SetShutdown() {
653c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  lock_.AssertAcquired();
654c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  shutdown_ = true;
655c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
656c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
6573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WorkQueue::SpinUntilAllThreadsAreWaiting() {
6583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  while (true) {
6593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    {
66072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock auto_lock(lock_);
6613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (waiting_thread_count_ == thread_count_)
6623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
6633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
6643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThread::Sleep(30);
6653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
6693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  while (true) {
6703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    {
67172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock auto_lock(lock_);
6723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (task_count_ < task_count)
6733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        break;
6743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
6753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    PlatformThread::Sleep(30);
6763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
6773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
6783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
6793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
680c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
681c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Define the standard worker task. Several tests will spin out many of these
682c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// threads.
683c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------
684c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
685c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The multithread tests involve several threads with a task to perform as
686c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// directed by an instance of the class WorkQueue.
687c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The task is to:
688c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a) Check to see if there are more tasks (there is a task counter).
689c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//    a1) Wait on condition variable if there are no tasks currently.
690c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// b) Call a function to see what should be done.
691c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// c) Do some computation based on the number of milliseconds returned in (b).
692c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// d) go back to (a).
693c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
694c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// WorkQueue::ThreadMain() implements the above task for all threads.
695c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// It calls the controlling object to tell the creator about progress, and to
696c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// ask about tasks.
697c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
698c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WorkQueue::ThreadMain() {
699c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int thread_id;
700c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
70172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock auto_lock(lock_);
702c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    thread_id = GetThreadId();
703c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (EveryIdWasAllocated())
704c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      all_threads_have_ids()->Signal();  // Tell creator we're ready.
705c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
706c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
707c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Lock private_lock;  // Used to waste time on "our work".
708c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  while (1) {  // This is the main consumer loop.
709c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    TimeDelta work_time;
710c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bool could_use_help;
711c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    {
71272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock auto_lock(lock_);
713c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      while (0 == task_count() && !shutdown()) {
7143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        ++waiting_thread_count_;
715c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        work_is_available()->Wait();
7163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        --waiting_thread_count_;
717c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
718c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (shutdown()) {
719c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // Ack the notification of a shutdown message back to the controller.
720c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        thread_shutting_down();
721c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return;  // Terminate.
722c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
723c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Get our task duration from the queue.
724c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      work_time = GetAnAssignment(thread_id);
725c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      could_use_help = (task_count() > 0) && allow_help_requests();
726c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }  // Release lock
727c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
728c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Do work (outside of locked region.
729c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (could_use_help)
730c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      work_is_available()->Signal();  // Get help from other threads.
731c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
732c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (work_time > TimeDelta::FromMilliseconds(0)) {
733c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // We could just sleep(), but we'll instead further exercise the
734c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // condition variable class, and do a timed wait.
73572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock auto_lock(private_lock);
736c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ConditionVariable private_cv(&private_lock);
737c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      private_cv.TimedWait(work_time);  // Unsynchronized waiting.
738c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
739c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
740c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    {
74172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::AutoLock auto_lock(lock_);
742c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Send notification that we completed our "work."
743c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      WorkIsCompleted(thread_id);
744c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
745c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
746c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
747c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
748c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace
7493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
7503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace base
751