1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker // Multi-threaded tests of ConditionVariable class.
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/condition_variable.h"
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include <time.h>
10*635a8641SAndroid Build Coastguard Worker
11*635a8641SAndroid Build Coastguard Worker #include <algorithm>
12*635a8641SAndroid Build Coastguard Worker #include <memory>
13*635a8641SAndroid Build Coastguard Worker #include <vector>
14*635a8641SAndroid Build Coastguard Worker
15*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/location.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/single_thread_task_runner.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/spin_wait.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_collision_warner.h"
24*635a8641SAndroid Build Coastguard Worker #include "base/time/time.h"
25*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
26*635a8641SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
27*635a8641SAndroid Build Coastguard Worker #include "testing/platform_test.h"
28*635a8641SAndroid Build Coastguard Worker
29*635a8641SAndroid Build Coastguard Worker namespace base {
30*635a8641SAndroid Build Coastguard Worker
31*635a8641SAndroid Build Coastguard Worker namespace {
32*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
33*635a8641SAndroid Build Coastguard Worker // Define our test class, with several common variables.
34*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
35*635a8641SAndroid Build Coastguard Worker
36*635a8641SAndroid Build Coastguard Worker class ConditionVariableTest : public PlatformTest {
37*635a8641SAndroid Build Coastguard Worker public:
38*635a8641SAndroid Build Coastguard Worker const TimeDelta kZeroMs;
39*635a8641SAndroid Build Coastguard Worker const TimeDelta kTenMs;
40*635a8641SAndroid Build Coastguard Worker const TimeDelta kThirtyMs;
41*635a8641SAndroid Build Coastguard Worker const TimeDelta kFortyFiveMs;
42*635a8641SAndroid Build Coastguard Worker const TimeDelta kSixtyMs;
43*635a8641SAndroid Build Coastguard Worker const TimeDelta kOneHundredMs;
44*635a8641SAndroid Build Coastguard Worker
ConditionVariableTest()45*635a8641SAndroid Build Coastguard Worker ConditionVariableTest()
46*635a8641SAndroid Build Coastguard Worker : kZeroMs(TimeDelta::FromMilliseconds(0)),
47*635a8641SAndroid Build Coastguard Worker kTenMs(TimeDelta::FromMilliseconds(10)),
48*635a8641SAndroid Build Coastguard Worker kThirtyMs(TimeDelta::FromMilliseconds(30)),
49*635a8641SAndroid Build Coastguard Worker kFortyFiveMs(TimeDelta::FromMilliseconds(45)),
50*635a8641SAndroid Build Coastguard Worker kSixtyMs(TimeDelta::FromMilliseconds(60)),
51*635a8641SAndroid Build Coastguard Worker kOneHundredMs(TimeDelta::FromMilliseconds(100)) {
52*635a8641SAndroid Build Coastguard Worker }
53*635a8641SAndroid Build Coastguard Worker };
54*635a8641SAndroid Build Coastguard Worker
55*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
56*635a8641SAndroid Build Coastguard Worker // Define a class that will control activities an several multi-threaded tests.
57*635a8641SAndroid Build Coastguard Worker // The general structure of multi-threaded tests is that a test case will
58*635a8641SAndroid Build Coastguard Worker // construct an instance of a WorkQueue. The WorkQueue will spin up some
59*635a8641SAndroid Build Coastguard Worker // threads and control them throughout their lifetime, as well as maintaining
60*635a8641SAndroid Build Coastguard Worker // a central repository of the work thread's activity. Finally, the WorkQueue
61*635a8641SAndroid Build Coastguard Worker // will command the the worker threads to terminate. At that point, the test
62*635a8641SAndroid Build Coastguard Worker // cases will validate that the WorkQueue has records showing that the desired
63*635a8641SAndroid Build Coastguard Worker // activities were performed.
64*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
65*635a8641SAndroid Build Coastguard Worker
66*635a8641SAndroid Build Coastguard Worker // Callers are responsible for synchronizing access to the following class.
67*635a8641SAndroid Build Coastguard Worker // The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for
68*635a8641SAndroid Build Coastguard Worker // all synchronized access.
69*635a8641SAndroid Build Coastguard Worker class WorkQueue : public PlatformThread::Delegate {
70*635a8641SAndroid Build Coastguard Worker public:
71*635a8641SAndroid Build Coastguard Worker explicit WorkQueue(int thread_count);
72*635a8641SAndroid Build Coastguard Worker ~WorkQueue() override;
73*635a8641SAndroid Build Coastguard Worker
74*635a8641SAndroid Build Coastguard Worker // PlatformThread::Delegate interface.
75*635a8641SAndroid Build Coastguard Worker void ThreadMain() override;
76*635a8641SAndroid Build Coastguard Worker
77*635a8641SAndroid Build Coastguard Worker //----------------------------------------------------------------------------
78*635a8641SAndroid Build Coastguard Worker // Worker threads only call the following methods.
79*635a8641SAndroid Build Coastguard Worker // They should use the lock to get exclusive access.
80*635a8641SAndroid Build Coastguard Worker int GetThreadId(); // Get an ID assigned to a thread..
81*635a8641SAndroid Build Coastguard Worker bool EveryIdWasAllocated() const; // Indicates that all IDs were handed out.
82*635a8641SAndroid Build Coastguard Worker TimeDelta GetAnAssignment(int thread_id); // Get a work task duration.
83*635a8641SAndroid Build Coastguard Worker void WorkIsCompleted(int thread_id);
84*635a8641SAndroid Build Coastguard Worker
85*635a8641SAndroid Build Coastguard Worker int task_count() const;
86*635a8641SAndroid Build Coastguard Worker bool allow_help_requests() const; // Workers can signal more workers.
87*635a8641SAndroid Build Coastguard Worker bool shutdown() const; // Check if shutdown has been requested.
88*635a8641SAndroid Build Coastguard Worker
89*635a8641SAndroid Build Coastguard Worker void thread_shutting_down();
90*635a8641SAndroid Build Coastguard Worker
91*635a8641SAndroid Build Coastguard Worker
92*635a8641SAndroid Build Coastguard Worker //----------------------------------------------------------------------------
93*635a8641SAndroid Build Coastguard Worker // Worker threads can call them but not needed to acquire a lock.
94*635a8641SAndroid Build Coastguard Worker Lock* lock();
95*635a8641SAndroid Build Coastguard Worker
96*635a8641SAndroid Build Coastguard Worker ConditionVariable* work_is_available();
97*635a8641SAndroid Build Coastguard Worker ConditionVariable* all_threads_have_ids();
98*635a8641SAndroid Build Coastguard Worker ConditionVariable* no_more_tasks();
99*635a8641SAndroid Build Coastguard Worker
100*635a8641SAndroid Build Coastguard Worker //----------------------------------------------------------------------------
101*635a8641SAndroid Build Coastguard Worker // The rest of the methods are for use by the controlling master thread (the
102*635a8641SAndroid Build Coastguard Worker // test case code).
103*635a8641SAndroid Build Coastguard Worker void ResetHistory();
104*635a8641SAndroid Build Coastguard Worker int GetMinCompletionsByWorkerThread() const;
105*635a8641SAndroid Build Coastguard Worker int GetMaxCompletionsByWorkerThread() const;
106*635a8641SAndroid Build Coastguard Worker int GetNumThreadsTakingAssignments() const;
107*635a8641SAndroid Build Coastguard Worker int GetNumThreadsCompletingTasks() const;
108*635a8641SAndroid Build Coastguard Worker int GetNumberOfCompletedTasks() const;
109*635a8641SAndroid Build Coastguard Worker
110*635a8641SAndroid Build Coastguard Worker void SetWorkTime(TimeDelta delay);
111*635a8641SAndroid Build Coastguard Worker void SetTaskCount(int count);
112*635a8641SAndroid Build Coastguard Worker void SetAllowHelp(bool allow);
113*635a8641SAndroid Build Coastguard Worker
114*635a8641SAndroid Build Coastguard Worker // The following must be called without locking, and will spin wait until the
115*635a8641SAndroid Build Coastguard Worker // threads are all in a wait state.
116*635a8641SAndroid Build Coastguard Worker void SpinUntilAllThreadsAreWaiting();
117*635a8641SAndroid Build Coastguard Worker void SpinUntilTaskCountLessThan(int task_count);
118*635a8641SAndroid Build Coastguard Worker
119*635a8641SAndroid Build Coastguard Worker // Caller must acquire lock before calling.
120*635a8641SAndroid Build Coastguard Worker void SetShutdown();
121*635a8641SAndroid Build Coastguard Worker
122*635a8641SAndroid Build Coastguard Worker // Compares the |shutdown_task_count_| to the |thread_count| and returns true
123*635a8641SAndroid Build Coastguard Worker // if they are equal. This check will acquire the |lock_| so the caller
124*635a8641SAndroid Build Coastguard Worker // should not hold the lock when calling this method.
125*635a8641SAndroid Build Coastguard Worker bool ThreadSafeCheckShutdown(int thread_count);
126*635a8641SAndroid Build Coastguard Worker
127*635a8641SAndroid Build Coastguard Worker private:
128*635a8641SAndroid Build Coastguard Worker // Both worker threads and controller use the following to synchronize.
129*635a8641SAndroid Build Coastguard Worker Lock lock_;
130*635a8641SAndroid Build Coastguard Worker ConditionVariable work_is_available_; // To tell threads there is work.
131*635a8641SAndroid Build Coastguard Worker
132*635a8641SAndroid Build Coastguard Worker // Conditions to notify the controlling process (if it is interested).
133*635a8641SAndroid Build Coastguard Worker ConditionVariable all_threads_have_ids_; // All threads are running.
134*635a8641SAndroid Build Coastguard Worker ConditionVariable no_more_tasks_; // Task count is zero.
135*635a8641SAndroid Build Coastguard Worker
136*635a8641SAndroid Build Coastguard Worker const int thread_count_;
137*635a8641SAndroid Build Coastguard Worker int waiting_thread_count_;
138*635a8641SAndroid Build Coastguard Worker std::unique_ptr<PlatformThreadHandle[]> thread_handles_;
139*635a8641SAndroid Build Coastguard Worker std::vector<int> assignment_history_; // Number of assignment per worker.
140*635a8641SAndroid Build Coastguard Worker std::vector<int> completion_history_; // Number of completions per worker.
141*635a8641SAndroid Build Coastguard Worker int thread_started_counter_; // Used to issue unique id to workers.
142*635a8641SAndroid Build Coastguard Worker int shutdown_task_count_; // Number of tasks told to shutdown
143*635a8641SAndroid Build Coastguard Worker int task_count_; // Number of assignment tasks waiting to be processed.
144*635a8641SAndroid Build Coastguard Worker TimeDelta worker_delay_; // Time each task takes to complete.
145*635a8641SAndroid Build Coastguard Worker bool allow_help_requests_; // Workers can signal more workers.
146*635a8641SAndroid Build Coastguard Worker bool shutdown_; // Set when threads need to terminate.
147*635a8641SAndroid Build Coastguard Worker
148*635a8641SAndroid Build Coastguard Worker DFAKE_MUTEX(locked_methods_);
149*635a8641SAndroid Build Coastguard Worker };
150*635a8641SAndroid Build Coastguard Worker
151*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
152*635a8641SAndroid Build Coastguard Worker // The next section contains the actual tests.
153*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
154*635a8641SAndroid Build Coastguard Worker
TEST_F(ConditionVariableTest,StartupShutdownTest)155*635a8641SAndroid Build Coastguard Worker TEST_F(ConditionVariableTest, StartupShutdownTest) {
156*635a8641SAndroid Build Coastguard Worker Lock lock;
157*635a8641SAndroid Build Coastguard Worker
158*635a8641SAndroid Build Coastguard Worker // First try trivial startup/shutdown.
159*635a8641SAndroid Build Coastguard Worker {
160*635a8641SAndroid Build Coastguard Worker ConditionVariable cv1(&lock);
161*635a8641SAndroid Build Coastguard Worker } // Call for cv1 destruction.
162*635a8641SAndroid Build Coastguard Worker
163*635a8641SAndroid Build Coastguard Worker // Exercise with at least a few waits.
164*635a8641SAndroid Build Coastguard Worker ConditionVariable cv(&lock);
165*635a8641SAndroid Build Coastguard Worker
166*635a8641SAndroid Build Coastguard Worker lock.Acquire();
167*635a8641SAndroid Build Coastguard Worker cv.TimedWait(kTenMs); // Wait for 10 ms.
168*635a8641SAndroid Build Coastguard Worker cv.TimedWait(kTenMs); // Wait for 10 ms.
169*635a8641SAndroid Build Coastguard Worker lock.Release();
170*635a8641SAndroid Build Coastguard Worker
171*635a8641SAndroid Build Coastguard Worker lock.Acquire();
172*635a8641SAndroid Build Coastguard Worker cv.TimedWait(kTenMs); // Wait for 10 ms.
173*635a8641SAndroid Build Coastguard Worker cv.TimedWait(kTenMs); // Wait for 10 ms.
174*635a8641SAndroid Build Coastguard Worker cv.TimedWait(kTenMs); // Wait for 10 ms.
175*635a8641SAndroid Build Coastguard Worker lock.Release();
176*635a8641SAndroid Build Coastguard Worker } // Call for cv destruction.
177*635a8641SAndroid Build Coastguard Worker
TEST_F(ConditionVariableTest,TimeoutTest)178*635a8641SAndroid Build Coastguard Worker TEST_F(ConditionVariableTest, TimeoutTest) {
179*635a8641SAndroid Build Coastguard Worker Lock lock;
180*635a8641SAndroid Build Coastguard Worker ConditionVariable cv(&lock);
181*635a8641SAndroid Build Coastguard Worker lock.Acquire();
182*635a8641SAndroid Build Coastguard Worker
183*635a8641SAndroid Build Coastguard Worker TimeTicks start = TimeTicks::Now();
184*635a8641SAndroid Build Coastguard Worker const TimeDelta WAIT_TIME = TimeDelta::FromMilliseconds(300);
185*635a8641SAndroid Build Coastguard Worker // Allow for clocking rate granularity.
186*635a8641SAndroid Build Coastguard Worker const TimeDelta FUDGE_TIME = TimeDelta::FromMilliseconds(50);
187*635a8641SAndroid Build Coastguard Worker
188*635a8641SAndroid Build Coastguard Worker cv.TimedWait(WAIT_TIME + FUDGE_TIME);
189*635a8641SAndroid Build Coastguard Worker TimeDelta duration = TimeTicks::Now() - start;
190*635a8641SAndroid Build Coastguard Worker // We can't use EXPECT_GE here as the TimeDelta class does not support the
191*635a8641SAndroid Build Coastguard Worker // required stream conversion.
192*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(duration >= WAIT_TIME);
193*635a8641SAndroid Build Coastguard Worker
194*635a8641SAndroid Build Coastguard Worker lock.Release();
195*635a8641SAndroid Build Coastguard Worker }
196*635a8641SAndroid Build Coastguard Worker
197*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX)
198*635a8641SAndroid Build Coastguard Worker const int kDiscontinuitySeconds = 2;
199*635a8641SAndroid Build Coastguard Worker
BackInTime(Lock * lock)200*635a8641SAndroid Build Coastguard Worker void BackInTime(Lock* lock) {
201*635a8641SAndroid Build Coastguard Worker AutoLock auto_lock(*lock);
202*635a8641SAndroid Build Coastguard Worker
203*635a8641SAndroid Build Coastguard Worker timeval tv;
204*635a8641SAndroid Build Coastguard Worker gettimeofday(&tv, nullptr);
205*635a8641SAndroid Build Coastguard Worker tv.tv_sec -= kDiscontinuitySeconds;
206*635a8641SAndroid Build Coastguard Worker settimeofday(&tv, nullptr);
207*635a8641SAndroid Build Coastguard Worker }
208*635a8641SAndroid Build Coastguard Worker
209*635a8641SAndroid Build Coastguard Worker // Tests that TimedWait ignores changes to the system clock.
210*635a8641SAndroid Build Coastguard Worker // Test is disabled by default, because it needs to run as root to muck with the
211*635a8641SAndroid Build Coastguard Worker // system clock.
212*635a8641SAndroid Build Coastguard Worker // http://crbug.com/293736
TEST_F(ConditionVariableTest,DISABLED_TimeoutAcrossSetTimeOfDay)213*635a8641SAndroid Build Coastguard Worker TEST_F(ConditionVariableTest, DISABLED_TimeoutAcrossSetTimeOfDay) {
214*635a8641SAndroid Build Coastguard Worker timeval tv;
215*635a8641SAndroid Build Coastguard Worker gettimeofday(&tv, nullptr);
216*635a8641SAndroid Build Coastguard Worker tv.tv_sec += kDiscontinuitySeconds;
217*635a8641SAndroid Build Coastguard Worker if (settimeofday(&tv, nullptr) < 0) {
218*635a8641SAndroid Build Coastguard Worker PLOG(ERROR) << "Could not set time of day. Run as root?";
219*635a8641SAndroid Build Coastguard Worker return;
220*635a8641SAndroid Build Coastguard Worker }
221*635a8641SAndroid Build Coastguard Worker
222*635a8641SAndroid Build Coastguard Worker Lock lock;
223*635a8641SAndroid Build Coastguard Worker ConditionVariable cv(&lock);
224*635a8641SAndroid Build Coastguard Worker lock.Acquire();
225*635a8641SAndroid Build Coastguard Worker
226*635a8641SAndroid Build Coastguard Worker Thread thread("Helper");
227*635a8641SAndroid Build Coastguard Worker thread.Start();
228*635a8641SAndroid Build Coastguard Worker thread.task_runner()->PostTask(FROM_HERE, base::BindOnce(&BackInTime, &lock));
229*635a8641SAndroid Build Coastguard Worker
230*635a8641SAndroid Build Coastguard Worker TimeTicks start = TimeTicks::Now();
231*635a8641SAndroid Build Coastguard Worker const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300);
232*635a8641SAndroid Build Coastguard Worker // Allow for clocking rate granularity.
233*635a8641SAndroid Build Coastguard Worker const TimeDelta kFudgeTime = TimeDelta::FromMilliseconds(50);
234*635a8641SAndroid Build Coastguard Worker
235*635a8641SAndroid Build Coastguard Worker cv.TimedWait(kWaitTime + kFudgeTime);
236*635a8641SAndroid Build Coastguard Worker TimeDelta duration = TimeTicks::Now() - start;
237*635a8641SAndroid Build Coastguard Worker
238*635a8641SAndroid Build Coastguard Worker thread.Stop();
239*635a8641SAndroid Build Coastguard Worker // We can't use EXPECT_GE here as the TimeDelta class does not support the
240*635a8641SAndroid Build Coastguard Worker // required stream conversion.
241*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(duration >= kWaitTime);
242*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(duration <= TimeDelta::FromSeconds(kDiscontinuitySeconds));
243*635a8641SAndroid Build Coastguard Worker
244*635a8641SAndroid Build Coastguard Worker lock.Release();
245*635a8641SAndroid Build Coastguard Worker }
246*635a8641SAndroid Build Coastguard Worker #endif
247*635a8641SAndroid Build Coastguard Worker
248*635a8641SAndroid Build Coastguard Worker // Suddenly got flaky on Win, see http://crbug.com/10607 (starting at
249*635a8641SAndroid Build Coastguard Worker // comment #15).
250*635a8641SAndroid Build Coastguard Worker // This is also flaky on Fuchsia, see http://crbug.com/738275.
251*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN) || defined(OS_FUCHSIA)
252*635a8641SAndroid Build Coastguard Worker #define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest
253*635a8641SAndroid Build Coastguard Worker #else
254*635a8641SAndroid Build Coastguard Worker #define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest
255*635a8641SAndroid Build Coastguard Worker #endif
256*635a8641SAndroid Build Coastguard Worker // Test serial task servicing, as well as two parallel task servicing methods.
TEST_F(ConditionVariableTest,MAYBE_MultiThreadConsumerTest)257*635a8641SAndroid Build Coastguard Worker TEST_F(ConditionVariableTest, MAYBE_MultiThreadConsumerTest) {
258*635a8641SAndroid Build Coastguard Worker const int kThreadCount = 10;
259*635a8641SAndroid Build Coastguard Worker WorkQueue queue(kThreadCount); // Start the threads.
260*635a8641SAndroid Build Coastguard Worker
261*635a8641SAndroid Build Coastguard Worker const int kTaskCount = 10; // Number of tasks in each mini-test here.
262*635a8641SAndroid Build Coastguard Worker
263*635a8641SAndroid Build Coastguard Worker Time start_time; // Used to time task processing.
264*635a8641SAndroid Build Coastguard Worker
265*635a8641SAndroid Build Coastguard Worker {
266*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
267*635a8641SAndroid Build Coastguard Worker while (!queue.EveryIdWasAllocated())
268*635a8641SAndroid Build Coastguard Worker queue.all_threads_have_ids()->Wait();
269*635a8641SAndroid Build Coastguard Worker }
270*635a8641SAndroid Build Coastguard Worker
271*635a8641SAndroid Build Coastguard Worker // If threads aren't in a wait state, they may start to gobble up tasks in
272*635a8641SAndroid Build Coastguard Worker // parallel, short-circuiting (breaking) this test.
273*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
274*635a8641SAndroid Build Coastguard Worker
275*635a8641SAndroid Build Coastguard Worker {
276*635a8641SAndroid Build Coastguard Worker // Since we have no tasks yet, all threads should be waiting by now.
277*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
278*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
279*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
280*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
281*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
282*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
283*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
284*635a8641SAndroid Build Coastguard Worker
285*635a8641SAndroid Build Coastguard Worker // Set up to make each task include getting help from another worker, so
286*635a8641SAndroid Build Coastguard Worker // so that the work gets done in paralell.
287*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
288*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(kTaskCount);
289*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kThirtyMs);
290*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(true);
291*635a8641SAndroid Build Coastguard Worker
292*635a8641SAndroid Build Coastguard Worker start_time = Time::Now();
293*635a8641SAndroid Build Coastguard Worker }
294*635a8641SAndroid Build Coastguard Worker
295*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Signal(); // But each worker can signal another.
296*635a8641SAndroid Build Coastguard Worker // Wait till we at least start to handle tasks (and we're not all waiting).
297*635a8641SAndroid Build Coastguard Worker queue.SpinUntilTaskCountLessThan(kTaskCount);
298*635a8641SAndroid Build Coastguard Worker // Wait to allow the all workers to get done.
299*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
300*635a8641SAndroid Build Coastguard Worker
301*635a8641SAndroid Build Coastguard Worker {
302*635a8641SAndroid Build Coastguard Worker // Wait until all work tasks have at least been assigned.
303*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
304*635a8641SAndroid Build Coastguard Worker while (queue.task_count())
305*635a8641SAndroid Build Coastguard Worker queue.no_more_tasks()->Wait();
306*635a8641SAndroid Build Coastguard Worker
307*635a8641SAndroid Build Coastguard Worker // To avoid racy assumptions, we'll just assert that at least 2 threads
308*635a8641SAndroid Build Coastguard Worker // did work. We know that the first worker should have gone to sleep, and
309*635a8641SAndroid Build Coastguard Worker // hence a second worker should have gotten an assignment.
310*635a8641SAndroid Build Coastguard Worker EXPECT_LE(2, queue.GetNumThreadsTakingAssignments());
311*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
312*635a8641SAndroid Build Coastguard Worker
313*635a8641SAndroid Build Coastguard Worker // Try to ask all workers to help, and only a few will do the work.
314*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
315*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(3);
316*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kThirtyMs);
317*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(false);
318*635a8641SAndroid Build Coastguard Worker }
319*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Broadcast(); // Make them all try.
320*635a8641SAndroid Build Coastguard Worker // Wait till we at least start to handle tasks (and we're not all waiting).
321*635a8641SAndroid Build Coastguard Worker queue.SpinUntilTaskCountLessThan(3);
322*635a8641SAndroid Build Coastguard Worker // Wait to allow the 3 workers to get done.
323*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
324*635a8641SAndroid Build Coastguard Worker
325*635a8641SAndroid Build Coastguard Worker {
326*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
327*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
328*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
329*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
330*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
331*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
332*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
333*635a8641SAndroid Build Coastguard Worker
334*635a8641SAndroid Build Coastguard Worker // Set up to make each task get help from another worker.
335*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
336*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(3);
337*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kThirtyMs);
338*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(true); // Allow (unnecessary) help requests.
339*635a8641SAndroid Build Coastguard Worker }
340*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Broadcast(); // Signal all threads.
341*635a8641SAndroid Build Coastguard Worker // Wait till we at least start to handle tasks (and we're not all waiting).
342*635a8641SAndroid Build Coastguard Worker queue.SpinUntilTaskCountLessThan(3);
343*635a8641SAndroid Build Coastguard Worker // Wait to allow the 3 workers to get done.
344*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
345*635a8641SAndroid Build Coastguard Worker
346*635a8641SAndroid Build Coastguard Worker {
347*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
348*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
349*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
350*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
351*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
352*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
353*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
354*635a8641SAndroid Build Coastguard Worker
355*635a8641SAndroid Build Coastguard Worker // Set up to make each task get help from another worker.
356*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
357*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(20); // 2 tasks per thread.
358*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kThirtyMs);
359*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(true);
360*635a8641SAndroid Build Coastguard Worker }
361*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Signal(); // But each worker can signal another.
362*635a8641SAndroid Build Coastguard Worker // Wait till we at least start to handle tasks (and we're not all waiting).
363*635a8641SAndroid Build Coastguard Worker queue.SpinUntilTaskCountLessThan(20);
364*635a8641SAndroid Build Coastguard Worker // Wait to allow the 10 workers to get done.
365*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms.
366*635a8641SAndroid Build Coastguard Worker
367*635a8641SAndroid Build Coastguard Worker {
368*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
369*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
370*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
371*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
372*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
373*635a8641SAndroid Build Coastguard Worker
374*635a8641SAndroid Build Coastguard Worker // Same as last test, but with Broadcast().
375*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
376*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(20); // 2 tasks per thread.
377*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kThirtyMs);
378*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(true);
379*635a8641SAndroid Build Coastguard Worker }
380*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Broadcast();
381*635a8641SAndroid Build Coastguard Worker // Wait till we at least start to handle tasks (and we're not all waiting).
382*635a8641SAndroid Build Coastguard Worker queue.SpinUntilTaskCountLessThan(20);
383*635a8641SAndroid Build Coastguard Worker // Wait to allow the 10 workers to get done.
384*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting(); // Should take about 60 ms.
385*635a8641SAndroid Build Coastguard Worker
386*635a8641SAndroid Build Coastguard Worker {
387*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
388*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
389*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
390*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
391*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
392*635a8641SAndroid Build Coastguard Worker
393*635a8641SAndroid Build Coastguard Worker queue.SetShutdown();
394*635a8641SAndroid Build Coastguard Worker }
395*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Broadcast(); // Force check for shutdown.
396*635a8641SAndroid Build Coastguard Worker
397*635a8641SAndroid Build Coastguard Worker SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
398*635a8641SAndroid Build Coastguard Worker queue.ThreadSafeCheckShutdown(kThreadCount));
399*635a8641SAndroid Build Coastguard Worker }
400*635a8641SAndroid Build Coastguard Worker
401*635a8641SAndroid Build Coastguard Worker #if defined(OS_FUCHSIA)
402*635a8641SAndroid Build Coastguard Worker // TODO(crbug.com/751894): This flakily times out on Fuchsia.
403*635a8641SAndroid Build Coastguard Worker #define MAYBE_LargeFastTaskTest DISABLED_LargeFastTaskTest
404*635a8641SAndroid Build Coastguard Worker #else
405*635a8641SAndroid Build Coastguard Worker #define MAYBE_LargeFastTaskTest LargeFastTaskTest
406*635a8641SAndroid Build Coastguard Worker #endif
TEST_F(ConditionVariableTest,MAYBE_LargeFastTaskTest)407*635a8641SAndroid Build Coastguard Worker TEST_F(ConditionVariableTest, MAYBE_LargeFastTaskTest) {
408*635a8641SAndroid Build Coastguard Worker const int kThreadCount = 200;
409*635a8641SAndroid Build Coastguard Worker WorkQueue queue(kThreadCount); // Start the threads.
410*635a8641SAndroid Build Coastguard Worker
411*635a8641SAndroid Build Coastguard Worker Lock private_lock; // Used locally for master to wait.
412*635a8641SAndroid Build Coastguard Worker base::AutoLock private_held_lock(private_lock);
413*635a8641SAndroid Build Coastguard Worker ConditionVariable private_cv(&private_lock);
414*635a8641SAndroid Build Coastguard Worker
415*635a8641SAndroid Build Coastguard Worker {
416*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
417*635a8641SAndroid Build Coastguard Worker while (!queue.EveryIdWasAllocated())
418*635a8641SAndroid Build Coastguard Worker queue.all_threads_have_ids()->Wait();
419*635a8641SAndroid Build Coastguard Worker }
420*635a8641SAndroid Build Coastguard Worker
421*635a8641SAndroid Build Coastguard Worker // Wait a bit more to allow threads to reach their wait state.
422*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
423*635a8641SAndroid Build Coastguard Worker
424*635a8641SAndroid Build Coastguard Worker {
425*635a8641SAndroid Build Coastguard Worker // Since we have no tasks, all threads should be waiting by now.
426*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
427*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
428*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
429*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
430*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
431*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
432*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
433*635a8641SAndroid Build Coastguard Worker
434*635a8641SAndroid Build Coastguard Worker // Set up to make all workers do (an average of) 20 tasks.
435*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
436*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(20 * kThreadCount);
437*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kFortyFiveMs);
438*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(false);
439*635a8641SAndroid Build Coastguard Worker }
440*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Broadcast(); // Start up all threads.
441*635a8641SAndroid Build Coastguard Worker // Wait until we've handed out all tasks.
442*635a8641SAndroid Build Coastguard Worker {
443*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
444*635a8641SAndroid Build Coastguard Worker while (queue.task_count() != 0)
445*635a8641SAndroid Build Coastguard Worker queue.no_more_tasks()->Wait();
446*635a8641SAndroid Build Coastguard Worker }
447*635a8641SAndroid Build Coastguard Worker
448*635a8641SAndroid Build Coastguard Worker // Wait till the last of the tasks complete.
449*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
450*635a8641SAndroid Build Coastguard Worker
451*635a8641SAndroid Build Coastguard Worker {
452*635a8641SAndroid Build Coastguard Worker // With Broadcast(), every thread should have participated.
453*635a8641SAndroid Build Coastguard Worker // but with racing.. they may not all have done equal numbers of tasks.
454*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
455*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
456*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
457*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
458*635a8641SAndroid Build Coastguard Worker EXPECT_LE(20, queue.GetMaxCompletionsByWorkerThread());
459*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(20 * kThreadCount, queue.GetNumberOfCompletedTasks());
460*635a8641SAndroid Build Coastguard Worker
461*635a8641SAndroid Build Coastguard Worker // Set up to make all workers do (an average of) 4 tasks.
462*635a8641SAndroid Build Coastguard Worker queue.ResetHistory();
463*635a8641SAndroid Build Coastguard Worker queue.SetTaskCount(kThreadCount * 4);
464*635a8641SAndroid Build Coastguard Worker queue.SetWorkTime(kFortyFiveMs);
465*635a8641SAndroid Build Coastguard Worker queue.SetAllowHelp(true); // Might outperform Broadcast().
466*635a8641SAndroid Build Coastguard Worker }
467*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Signal(); // Start up one thread.
468*635a8641SAndroid Build Coastguard Worker
469*635a8641SAndroid Build Coastguard Worker // Wait until we've handed out all tasks
470*635a8641SAndroid Build Coastguard Worker {
471*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
472*635a8641SAndroid Build Coastguard Worker while (queue.task_count() != 0)
473*635a8641SAndroid Build Coastguard Worker queue.no_more_tasks()->Wait();
474*635a8641SAndroid Build Coastguard Worker }
475*635a8641SAndroid Build Coastguard Worker
476*635a8641SAndroid Build Coastguard Worker // Wait till the last of the tasks complete.
477*635a8641SAndroid Build Coastguard Worker queue.SpinUntilAllThreadsAreWaiting();
478*635a8641SAndroid Build Coastguard Worker
479*635a8641SAndroid Build Coastguard Worker {
480*635a8641SAndroid Build Coastguard Worker // With Signal(), every thread should have participated.
481*635a8641SAndroid Build Coastguard Worker // but with racing.. they may not all have done four tasks.
482*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(*queue.lock());
483*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
484*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
485*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, queue.task_count());
486*635a8641SAndroid Build Coastguard Worker EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread());
487*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks());
488*635a8641SAndroid Build Coastguard Worker
489*635a8641SAndroid Build Coastguard Worker queue.SetShutdown();
490*635a8641SAndroid Build Coastguard Worker }
491*635a8641SAndroid Build Coastguard Worker queue.work_is_available()->Broadcast(); // Force check for shutdown.
492*635a8641SAndroid Build Coastguard Worker
493*635a8641SAndroid Build Coastguard Worker // Wait for shutdowns to complete.
494*635a8641SAndroid Build Coastguard Worker SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
495*635a8641SAndroid Build Coastguard Worker queue.ThreadSafeCheckShutdown(kThreadCount));
496*635a8641SAndroid Build Coastguard Worker }
497*635a8641SAndroid Build Coastguard Worker
498*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
499*635a8641SAndroid Build Coastguard Worker // Finally we provide the implementation for the methods in the WorkQueue class.
500*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
501*635a8641SAndroid Build Coastguard Worker
WorkQueue(int thread_count)502*635a8641SAndroid Build Coastguard Worker WorkQueue::WorkQueue(int thread_count)
503*635a8641SAndroid Build Coastguard Worker : lock_(),
504*635a8641SAndroid Build Coastguard Worker work_is_available_(&lock_),
505*635a8641SAndroid Build Coastguard Worker all_threads_have_ids_(&lock_),
506*635a8641SAndroid Build Coastguard Worker no_more_tasks_(&lock_),
507*635a8641SAndroid Build Coastguard Worker thread_count_(thread_count),
508*635a8641SAndroid Build Coastguard Worker waiting_thread_count_(0),
509*635a8641SAndroid Build Coastguard Worker thread_handles_(new PlatformThreadHandle[thread_count]),
510*635a8641SAndroid Build Coastguard Worker assignment_history_(thread_count),
511*635a8641SAndroid Build Coastguard Worker completion_history_(thread_count),
512*635a8641SAndroid Build Coastguard Worker thread_started_counter_(0),
513*635a8641SAndroid Build Coastguard Worker shutdown_task_count_(0),
514*635a8641SAndroid Build Coastguard Worker task_count_(0),
515*635a8641SAndroid Build Coastguard Worker allow_help_requests_(false),
516*635a8641SAndroid Build Coastguard Worker shutdown_(false) {
517*635a8641SAndroid Build Coastguard Worker EXPECT_GE(thread_count_, 1);
518*635a8641SAndroid Build Coastguard Worker ResetHistory();
519*635a8641SAndroid Build Coastguard Worker SetTaskCount(0);
520*635a8641SAndroid Build Coastguard Worker SetWorkTime(TimeDelta::FromMilliseconds(30));
521*635a8641SAndroid Build Coastguard Worker
522*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i) {
523*635a8641SAndroid Build Coastguard Worker PlatformThreadHandle pth;
524*635a8641SAndroid Build Coastguard Worker EXPECT_TRUE(PlatformThread::Create(0, this, &pth));
525*635a8641SAndroid Build Coastguard Worker thread_handles_[i] = pth;
526*635a8641SAndroid Build Coastguard Worker }
527*635a8641SAndroid Build Coastguard Worker }
528*635a8641SAndroid Build Coastguard Worker
~WorkQueue()529*635a8641SAndroid Build Coastguard Worker WorkQueue::~WorkQueue() {
530*635a8641SAndroid Build Coastguard Worker {
531*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
532*635a8641SAndroid Build Coastguard Worker SetShutdown();
533*635a8641SAndroid Build Coastguard Worker }
534*635a8641SAndroid Build Coastguard Worker work_is_available_.Broadcast(); // Tell them all to terminate.
535*635a8641SAndroid Build Coastguard Worker
536*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i) {
537*635a8641SAndroid Build Coastguard Worker PlatformThread::Join(thread_handles_[i]);
538*635a8641SAndroid Build Coastguard Worker }
539*635a8641SAndroid Build Coastguard Worker EXPECT_EQ(0, waiting_thread_count_);
540*635a8641SAndroid Build Coastguard Worker }
541*635a8641SAndroid Build Coastguard Worker
GetThreadId()542*635a8641SAndroid Build Coastguard Worker int WorkQueue::GetThreadId() {
543*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
544*635a8641SAndroid Build Coastguard Worker DCHECK(!EveryIdWasAllocated());
545*635a8641SAndroid Build Coastguard Worker return thread_started_counter_++; // Give out Unique IDs.
546*635a8641SAndroid Build Coastguard Worker }
547*635a8641SAndroid Build Coastguard Worker
EveryIdWasAllocated() const548*635a8641SAndroid Build Coastguard Worker bool WorkQueue::EveryIdWasAllocated() const {
549*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
550*635a8641SAndroid Build Coastguard Worker return thread_count_ == thread_started_counter_;
551*635a8641SAndroid Build Coastguard Worker }
552*635a8641SAndroid Build Coastguard Worker
GetAnAssignment(int thread_id)553*635a8641SAndroid Build Coastguard Worker TimeDelta WorkQueue::GetAnAssignment(int thread_id) {
554*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
555*635a8641SAndroid Build Coastguard Worker DCHECK_LT(0, task_count_);
556*635a8641SAndroid Build Coastguard Worker assignment_history_[thread_id]++;
557*635a8641SAndroid Build Coastguard Worker if (0 == --task_count_) {
558*635a8641SAndroid Build Coastguard Worker no_more_tasks_.Signal();
559*635a8641SAndroid Build Coastguard Worker }
560*635a8641SAndroid Build Coastguard Worker return worker_delay_;
561*635a8641SAndroid Build Coastguard Worker }
562*635a8641SAndroid Build Coastguard Worker
WorkIsCompleted(int thread_id)563*635a8641SAndroid Build Coastguard Worker void WorkQueue::WorkIsCompleted(int thread_id) {
564*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
565*635a8641SAndroid Build Coastguard Worker completion_history_[thread_id]++;
566*635a8641SAndroid Build Coastguard Worker }
567*635a8641SAndroid Build Coastguard Worker
task_count() const568*635a8641SAndroid Build Coastguard Worker int WorkQueue::task_count() const {
569*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
570*635a8641SAndroid Build Coastguard Worker return task_count_;
571*635a8641SAndroid Build Coastguard Worker }
572*635a8641SAndroid Build Coastguard Worker
allow_help_requests() const573*635a8641SAndroid Build Coastguard Worker bool WorkQueue::allow_help_requests() const {
574*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
575*635a8641SAndroid Build Coastguard Worker return allow_help_requests_;
576*635a8641SAndroid Build Coastguard Worker }
577*635a8641SAndroid Build Coastguard Worker
shutdown() const578*635a8641SAndroid Build Coastguard Worker bool WorkQueue::shutdown() const {
579*635a8641SAndroid Build Coastguard Worker lock_.AssertAcquired();
580*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
581*635a8641SAndroid Build Coastguard Worker return shutdown_;
582*635a8641SAndroid Build Coastguard Worker }
583*635a8641SAndroid Build Coastguard Worker
584*635a8641SAndroid Build Coastguard Worker // Because this method is called from the test's main thread we need to actually
585*635a8641SAndroid Build Coastguard Worker // take the lock. Threads will call the thread_shutting_down() method with the
586*635a8641SAndroid Build Coastguard Worker // lock already acquired.
ThreadSafeCheckShutdown(int thread_count)587*635a8641SAndroid Build Coastguard Worker bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) {
588*635a8641SAndroid Build Coastguard Worker bool all_shutdown;
589*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
590*635a8641SAndroid Build Coastguard Worker {
591*635a8641SAndroid Build Coastguard Worker // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock.
592*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
593*635a8641SAndroid Build Coastguard Worker all_shutdown = (shutdown_task_count_ == thread_count);
594*635a8641SAndroid Build Coastguard Worker }
595*635a8641SAndroid Build Coastguard Worker return all_shutdown;
596*635a8641SAndroid Build Coastguard Worker }
597*635a8641SAndroid Build Coastguard Worker
thread_shutting_down()598*635a8641SAndroid Build Coastguard Worker void WorkQueue::thread_shutting_down() {
599*635a8641SAndroid Build Coastguard Worker lock_.AssertAcquired();
600*635a8641SAndroid Build Coastguard Worker DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
601*635a8641SAndroid Build Coastguard Worker shutdown_task_count_++;
602*635a8641SAndroid Build Coastguard Worker }
603*635a8641SAndroid Build Coastguard Worker
lock()604*635a8641SAndroid Build Coastguard Worker Lock* WorkQueue::lock() {
605*635a8641SAndroid Build Coastguard Worker return &lock_;
606*635a8641SAndroid Build Coastguard Worker }
607*635a8641SAndroid Build Coastguard Worker
work_is_available()608*635a8641SAndroid Build Coastguard Worker ConditionVariable* WorkQueue::work_is_available() {
609*635a8641SAndroid Build Coastguard Worker return &work_is_available_;
610*635a8641SAndroid Build Coastguard Worker }
611*635a8641SAndroid Build Coastguard Worker
all_threads_have_ids()612*635a8641SAndroid Build Coastguard Worker ConditionVariable* WorkQueue::all_threads_have_ids() {
613*635a8641SAndroid Build Coastguard Worker return &all_threads_have_ids_;
614*635a8641SAndroid Build Coastguard Worker }
615*635a8641SAndroid Build Coastguard Worker
no_more_tasks()616*635a8641SAndroid Build Coastguard Worker ConditionVariable* WorkQueue::no_more_tasks() {
617*635a8641SAndroid Build Coastguard Worker return &no_more_tasks_;
618*635a8641SAndroid Build Coastguard Worker }
619*635a8641SAndroid Build Coastguard Worker
ResetHistory()620*635a8641SAndroid Build Coastguard Worker void WorkQueue::ResetHistory() {
621*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i) {
622*635a8641SAndroid Build Coastguard Worker assignment_history_[i] = 0;
623*635a8641SAndroid Build Coastguard Worker completion_history_[i] = 0;
624*635a8641SAndroid Build Coastguard Worker }
625*635a8641SAndroid Build Coastguard Worker }
626*635a8641SAndroid Build Coastguard Worker
GetMinCompletionsByWorkerThread() const627*635a8641SAndroid Build Coastguard Worker int WorkQueue::GetMinCompletionsByWorkerThread() const {
628*635a8641SAndroid Build Coastguard Worker int minumum = completion_history_[0];
629*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i)
630*635a8641SAndroid Build Coastguard Worker minumum = std::min(minumum, completion_history_[i]);
631*635a8641SAndroid Build Coastguard Worker return minumum;
632*635a8641SAndroid Build Coastguard Worker }
633*635a8641SAndroid Build Coastguard Worker
GetMaxCompletionsByWorkerThread() const634*635a8641SAndroid Build Coastguard Worker int WorkQueue::GetMaxCompletionsByWorkerThread() const {
635*635a8641SAndroid Build Coastguard Worker int maximum = completion_history_[0];
636*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i)
637*635a8641SAndroid Build Coastguard Worker maximum = std::max(maximum, completion_history_[i]);
638*635a8641SAndroid Build Coastguard Worker return maximum;
639*635a8641SAndroid Build Coastguard Worker }
640*635a8641SAndroid Build Coastguard Worker
GetNumThreadsTakingAssignments() const641*635a8641SAndroid Build Coastguard Worker int WorkQueue::GetNumThreadsTakingAssignments() const {
642*635a8641SAndroid Build Coastguard Worker int count = 0;
643*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i)
644*635a8641SAndroid Build Coastguard Worker if (assignment_history_[i])
645*635a8641SAndroid Build Coastguard Worker count++;
646*635a8641SAndroid Build Coastguard Worker return count;
647*635a8641SAndroid Build Coastguard Worker }
648*635a8641SAndroid Build Coastguard Worker
GetNumThreadsCompletingTasks() const649*635a8641SAndroid Build Coastguard Worker int WorkQueue::GetNumThreadsCompletingTasks() const {
650*635a8641SAndroid Build Coastguard Worker int count = 0;
651*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i)
652*635a8641SAndroid Build Coastguard Worker if (completion_history_[i])
653*635a8641SAndroid Build Coastguard Worker count++;
654*635a8641SAndroid Build Coastguard Worker return count;
655*635a8641SAndroid Build Coastguard Worker }
656*635a8641SAndroid Build Coastguard Worker
GetNumberOfCompletedTasks() const657*635a8641SAndroid Build Coastguard Worker int WorkQueue::GetNumberOfCompletedTasks() const {
658*635a8641SAndroid Build Coastguard Worker int total = 0;
659*635a8641SAndroid Build Coastguard Worker for (int i = 0; i < thread_count_; ++i)
660*635a8641SAndroid Build Coastguard Worker total += completion_history_[i];
661*635a8641SAndroid Build Coastguard Worker return total;
662*635a8641SAndroid Build Coastguard Worker }
663*635a8641SAndroid Build Coastguard Worker
SetWorkTime(TimeDelta delay)664*635a8641SAndroid Build Coastguard Worker void WorkQueue::SetWorkTime(TimeDelta delay) {
665*635a8641SAndroid Build Coastguard Worker worker_delay_ = delay;
666*635a8641SAndroid Build Coastguard Worker }
667*635a8641SAndroid Build Coastguard Worker
SetTaskCount(int count)668*635a8641SAndroid Build Coastguard Worker void WorkQueue::SetTaskCount(int count) {
669*635a8641SAndroid Build Coastguard Worker task_count_ = count;
670*635a8641SAndroid Build Coastguard Worker }
671*635a8641SAndroid Build Coastguard Worker
SetAllowHelp(bool allow)672*635a8641SAndroid Build Coastguard Worker void WorkQueue::SetAllowHelp(bool allow) {
673*635a8641SAndroid Build Coastguard Worker allow_help_requests_ = allow;
674*635a8641SAndroid Build Coastguard Worker }
675*635a8641SAndroid Build Coastguard Worker
SetShutdown()676*635a8641SAndroid Build Coastguard Worker void WorkQueue::SetShutdown() {
677*635a8641SAndroid Build Coastguard Worker lock_.AssertAcquired();
678*635a8641SAndroid Build Coastguard Worker shutdown_ = true;
679*635a8641SAndroid Build Coastguard Worker }
680*635a8641SAndroid Build Coastguard Worker
SpinUntilAllThreadsAreWaiting()681*635a8641SAndroid Build Coastguard Worker void WorkQueue::SpinUntilAllThreadsAreWaiting() {
682*635a8641SAndroid Build Coastguard Worker while (true) {
683*635a8641SAndroid Build Coastguard Worker {
684*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
685*635a8641SAndroid Build Coastguard Worker if (waiting_thread_count_ == thread_count_)
686*635a8641SAndroid Build Coastguard Worker break;
687*635a8641SAndroid Build Coastguard Worker }
688*635a8641SAndroid Build Coastguard Worker PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
689*635a8641SAndroid Build Coastguard Worker }
690*635a8641SAndroid Build Coastguard Worker }
691*635a8641SAndroid Build Coastguard Worker
SpinUntilTaskCountLessThan(int task_count)692*635a8641SAndroid Build Coastguard Worker void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
693*635a8641SAndroid Build Coastguard Worker while (true) {
694*635a8641SAndroid Build Coastguard Worker {
695*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
696*635a8641SAndroid Build Coastguard Worker if (task_count_ < task_count)
697*635a8641SAndroid Build Coastguard Worker break;
698*635a8641SAndroid Build Coastguard Worker }
699*635a8641SAndroid Build Coastguard Worker PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
700*635a8641SAndroid Build Coastguard Worker }
701*635a8641SAndroid Build Coastguard Worker }
702*635a8641SAndroid Build Coastguard Worker
703*635a8641SAndroid Build Coastguard Worker
704*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
705*635a8641SAndroid Build Coastguard Worker // Define the standard worker task. Several tests will spin out many of these
706*635a8641SAndroid Build Coastguard Worker // threads.
707*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
708*635a8641SAndroid Build Coastguard Worker
709*635a8641SAndroid Build Coastguard Worker // The multithread tests involve several threads with a task to perform as
710*635a8641SAndroid Build Coastguard Worker // directed by an instance of the class WorkQueue.
711*635a8641SAndroid Build Coastguard Worker // The task is to:
712*635a8641SAndroid Build Coastguard Worker // a) Check to see if there are more tasks (there is a task counter).
713*635a8641SAndroid Build Coastguard Worker // a1) Wait on condition variable if there are no tasks currently.
714*635a8641SAndroid Build Coastguard Worker // b) Call a function to see what should be done.
715*635a8641SAndroid Build Coastguard Worker // c) Do some computation based on the number of milliseconds returned in (b).
716*635a8641SAndroid Build Coastguard Worker // d) go back to (a).
717*635a8641SAndroid Build Coastguard Worker
718*635a8641SAndroid Build Coastguard Worker // WorkQueue::ThreadMain() implements the above task for all threads.
719*635a8641SAndroid Build Coastguard Worker // It calls the controlling object to tell the creator about progress, and to
720*635a8641SAndroid Build Coastguard Worker // ask about tasks.
721*635a8641SAndroid Build Coastguard Worker
ThreadMain()722*635a8641SAndroid Build Coastguard Worker void WorkQueue::ThreadMain() {
723*635a8641SAndroid Build Coastguard Worker int thread_id;
724*635a8641SAndroid Build Coastguard Worker {
725*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
726*635a8641SAndroid Build Coastguard Worker thread_id = GetThreadId();
727*635a8641SAndroid Build Coastguard Worker if (EveryIdWasAllocated())
728*635a8641SAndroid Build Coastguard Worker all_threads_have_ids()->Signal(); // Tell creator we're ready.
729*635a8641SAndroid Build Coastguard Worker }
730*635a8641SAndroid Build Coastguard Worker
731*635a8641SAndroid Build Coastguard Worker Lock private_lock; // Used to waste time on "our work".
732*635a8641SAndroid Build Coastguard Worker while (1) { // This is the main consumer loop.
733*635a8641SAndroid Build Coastguard Worker TimeDelta work_time;
734*635a8641SAndroid Build Coastguard Worker bool could_use_help;
735*635a8641SAndroid Build Coastguard Worker {
736*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
737*635a8641SAndroid Build Coastguard Worker while (0 == task_count() && !shutdown()) {
738*635a8641SAndroid Build Coastguard Worker ++waiting_thread_count_;
739*635a8641SAndroid Build Coastguard Worker work_is_available()->Wait();
740*635a8641SAndroid Build Coastguard Worker --waiting_thread_count_;
741*635a8641SAndroid Build Coastguard Worker }
742*635a8641SAndroid Build Coastguard Worker if (shutdown()) {
743*635a8641SAndroid Build Coastguard Worker // Ack the notification of a shutdown message back to the controller.
744*635a8641SAndroid Build Coastguard Worker thread_shutting_down();
745*635a8641SAndroid Build Coastguard Worker return; // Terminate.
746*635a8641SAndroid Build Coastguard Worker }
747*635a8641SAndroid Build Coastguard Worker // Get our task duration from the queue.
748*635a8641SAndroid Build Coastguard Worker work_time = GetAnAssignment(thread_id);
749*635a8641SAndroid Build Coastguard Worker could_use_help = (task_count() > 0) && allow_help_requests();
750*635a8641SAndroid Build Coastguard Worker } // Release lock
751*635a8641SAndroid Build Coastguard Worker
752*635a8641SAndroid Build Coastguard Worker // Do work (outside of locked region.
753*635a8641SAndroid Build Coastguard Worker if (could_use_help)
754*635a8641SAndroid Build Coastguard Worker work_is_available()->Signal(); // Get help from other threads.
755*635a8641SAndroid Build Coastguard Worker
756*635a8641SAndroid Build Coastguard Worker if (work_time > TimeDelta::FromMilliseconds(0)) {
757*635a8641SAndroid Build Coastguard Worker // We could just sleep(), but we'll instead further exercise the
758*635a8641SAndroid Build Coastguard Worker // condition variable class, and do a timed wait.
759*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(private_lock);
760*635a8641SAndroid Build Coastguard Worker ConditionVariable private_cv(&private_lock);
761*635a8641SAndroid Build Coastguard Worker private_cv.TimedWait(work_time); // Unsynchronized waiting.
762*635a8641SAndroid Build Coastguard Worker }
763*635a8641SAndroid Build Coastguard Worker
764*635a8641SAndroid Build Coastguard Worker {
765*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
766*635a8641SAndroid Build Coastguard Worker // Send notification that we completed our "work."
767*635a8641SAndroid Build Coastguard Worker WorkIsCompleted(thread_id);
768*635a8641SAndroid Build Coastguard Worker }
769*635a8641SAndroid Build Coastguard Worker }
770*635a8641SAndroid Build Coastguard Worker }
771*635a8641SAndroid Build Coastguard Worker
772*635a8641SAndroid Build Coastguard Worker } // namespace
773*635a8641SAndroid Build Coastguard Worker
774*635a8641SAndroid Build Coastguard Worker } // namespace base
775