OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/task_scheduler/scheduler_worker.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <memory> | |
10 #include <vector> | |
11 | |
12 #include "base/bind.h" | |
13 #include "base/bind_helpers.h" | |
14 #include "base/macros.h" | |
15 #include "base/memory/ptr_util.h" | |
16 #include "base/synchronization/condition_variable.h" | |
17 #include "base/synchronization/waitable_event.h" | |
18 #include "base/task_scheduler/scheduler_lock.h" | |
19 #include "base/task_scheduler/sequence.h" | |
20 #include "base/task_scheduler/task.h" | |
21 #include "base/task_scheduler/task_tracker.h" | |
22 #include "base/threading/platform_thread.h" | |
23 #include "base/time/time.h" | |
24 #include "build/build_config.h" | |
25 #include "testing/gmock/include/gmock/gmock.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 | |
28 using testing::_; | |
29 using testing::Mock; | |
30 using testing::Ne; | |
31 using testing::StrictMock; | |
32 | |
33 namespace base { | |
34 namespace internal { | |
35 namespace { | |
36 | |
37 const size_t kNumSequencesPerTest = 150; | |
38 | |
39 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { | |
40 public: | |
41 SchedulerWorkerDefaultDelegate() = default; | |
42 | |
43 // SchedulerWorker::Delegate: | |
44 void OnMainEntry(SchedulerWorker* worker, const TimeDelta& detach_duration) ov
erride {} | |
45 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { return nul
lptr; } | |
46 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | |
47 ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; | |
48 } | |
49 TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } | |
50 bool CanDetach(SchedulerWorker* worker) override { return false; } | |
51 | |
52 private: | |
53 DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); | |
54 }; | |
55 | |
56 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | |
57 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { | |
58 protected: | |
59 TaskSchedulerWorkerTest() | |
60 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, | |
61 WaitableEvent::InitialState::NOT_SIGNALED), | |
62 num_get_work_cv_(lock_.CreateConditionVariable()), | |
63 worker_set_(WaitableEvent::ResetPolicy::MANUAL, | |
64 WaitableEvent::InitialState::NOT_SIGNALED) {} | |
65 | |
66 void SetUp() override { | |
67 worker_ = SchedulerWorker::Create( | |
68 ThreadPriority::NORMAL, | |
69 WrapUnique(new TestSchedulerWorkerDelegate(this)), | |
70 &task_tracker_, | |
71 SchedulerWorker::InitialState::ALIVE); | |
72 ASSERT_TRUE(worker_); | |
73 worker_set_.Signal(); | |
74 main_entry_called_.Wait(); | |
75 } | |
76 | |
77 void TearDown() override { | |
78 worker_->JoinForTesting(); | |
79 } | |
80 | |
81 size_t TasksPerSequence() const { return GetParam(); } | |
82 | |
83 // Wait until GetWork() has been called |num_get_work| times. | |
84 void WaitForNumGetWork(size_t num_get_work) { | |
85 AutoSchedulerLock auto_lock(lock_); | |
86 while (num_get_work_ < num_get_work) | |
87 num_get_work_cv_->Wait(); | |
88 } | |
89 | |
90 void SetMaxGetWork(size_t max_get_work) { | |
91 AutoSchedulerLock auto_lock(lock_); | |
92 max_get_work_ = max_get_work; | |
93 } | |
94 | |
95 void SetNumSequencesToCreate(size_t num_sequences_to_create) { | |
96 AutoSchedulerLock auto_lock(lock_); | |
97 EXPECT_EQ(0U, num_sequences_to_create_); | |
98 num_sequences_to_create_ = num_sequences_to_create; | |
99 } | |
100 | |
101 size_t NumRunTasks() { | |
102 AutoSchedulerLock auto_lock(lock_); | |
103 return num_run_tasks_; | |
104 } | |
105 | |
106 std::vector<scoped_refptr<Sequence>> CreatedSequences() { | |
107 AutoSchedulerLock auto_lock(lock_); | |
108 return created_sequences_; | |
109 } | |
110 | |
111 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { | |
112 AutoSchedulerLock auto_lock(lock_); | |
113 return re_enqueued_sequences_; | |
114 } | |
115 | |
116 std::unique_ptr<SchedulerWorker> worker_; | |
117 | |
118 private: | |
119 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { | |
120 public: | |
121 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) | |
122 : outer_(outer) {} | |
123 | |
124 // SchedulerWorker::Delegate: | |
125 void OnMainEntry(SchedulerWorker* worker, | |
126 const TimeDelta& detach_duration) override { | |
127 outer_->worker_set_.Wait(); | |
128 EXPECT_EQ(outer_->worker_.get(), worker); | |
129 | |
130 // Without synchronization, OnMainEntry() could be called twice without | |
131 // generating an error. | |
132 AutoSchedulerLock auto_lock(outer_->lock_); | |
133 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); | |
134 outer_->main_entry_called_.Signal(); | |
135 } | |
136 | |
137 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | |
138 EXPECT_EQ(outer_->worker_.get(), worker); | |
139 | |
140 { | |
141 AutoSchedulerLock auto_lock(outer_->lock_); | |
142 | |
143 // Increment the number of times that this method has been called. | |
144 ++outer_->num_get_work_; | |
145 outer_->num_get_work_cv_->Signal(); | |
146 | |
147 // Verify that this method isn't called more times than expected. | |
148 EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_); | |
149 | |
150 // Check if a Sequence should be returned. | |
151 if (outer_->num_sequences_to_create_ == 0) | |
152 return nullptr; | |
153 --outer_->num_sequences_to_create_; | |
154 } | |
155 | |
156 // Create a Sequence with TasksPerSequence() Tasks. | |
157 scoped_refptr<Sequence> sequence(new Sequence); | |
158 for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) { | |
159 std::unique_ptr<Task> task(new Task( | |
160 FROM_HERE, Bind(&TaskSchedulerWorkerTest::RunTaskCallback, | |
161 Unretained(outer_)), | |
162 TaskTraits(), TimeDelta())); | |
163 EXPECT_TRUE(outer_->task_tracker_.WillPostTask(task.get())); | |
164 sequence->PushTask(std::move(task)); | |
165 } | |
166 | |
167 { | |
168 // Add the Sequence to the vector of created Sequences. | |
169 AutoSchedulerLock auto_lock(outer_->lock_); | |
170 outer_->created_sequences_.push_back(sequence); | |
171 } | |
172 | |
173 return sequence; | |
174 } | |
175 | |
176 // This override verifies that |sequence| contains the expected number of | |
177 // Tasks and adds it to |enqueued_sequences_|. Unlike a normal | |
178 // EnqueueSequence implementation, it doesn't reinsert |sequence| into a | |
179 // queue for further execution. | |
180 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | |
181 EXPECT_GT(outer_->TasksPerSequence(), 1U); | |
182 | |
183 // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. | |
184 for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) { | |
185 EXPECT_TRUE(sequence->PeekTask()); | |
186 sequence->PopTask(); | |
187 } | |
188 EXPECT_FALSE(sequence->PeekTask()); | |
189 | |
190 // Add |sequence| to |re_enqueued_sequences_|. | |
191 AutoSchedulerLock auto_lock(outer_->lock_); | |
192 outer_->re_enqueued_sequences_.push_back(std::move(sequence)); | |
193 EXPECT_LE(outer_->re_enqueued_sequences_.size(), | |
194 outer_->created_sequences_.size()); | |
195 } | |
196 | |
197 private: | |
198 TaskSchedulerWorkerTest* outer_; | |
199 }; | |
200 | |
201 void RunTaskCallback() { | |
202 AutoSchedulerLock auto_lock(lock_); | |
203 ++num_run_tasks_; | |
204 EXPECT_LE(num_run_tasks_, created_sequences_.size()); | |
205 } | |
206 | |
207 TaskTracker task_tracker_; | |
208 | |
209 // Synchronizes access to all members below. | |
210 mutable SchedulerLock lock_; | |
211 | |
212 // Signaled once OnMainEntry() has been called. | |
213 WaitableEvent main_entry_called_; | |
214 | |
215 // Number of Sequences that should be created by GetWork(). When this | |
216 // is 0, GetWork() returns nullptr. | |
217 size_t num_sequences_to_create_ = 0; | |
218 | |
219 // Number of times that GetWork() has been called. | |
220 size_t num_get_work_ = 0; | |
221 | |
222 // Maximum number of times that GetWork() can be called. | |
223 size_t max_get_work_ = 0; | |
224 | |
225 // Condition variable signaled when |num_get_work_| is incremented. | |
226 std::unique_ptr<ConditionVariable> num_get_work_cv_; | |
227 | |
228 // Sequences created by GetWork(). | |
229 std::vector<scoped_refptr<Sequence>> created_sequences_; | |
230 | |
231 // Sequences passed to EnqueueSequence(). | |
232 std::vector<scoped_refptr<Sequence>> re_enqueued_sequences_; | |
233 | |
234 // Number of times that RunTaskCallback() has been called. | |
235 size_t num_run_tasks_ = 0; | |
236 | |
237 // Signaled after |worker_| is set. | |
238 WaitableEvent worker_set_; | |
239 | |
240 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerTest); | |
241 }; | |
242 | |
243 // Verify that when GetWork() continuously returns Sequences, all Tasks in these | |
244 // Sequences run successfully. The test wakes up the SchedulerWorker once. | |
245 TEST_P(TaskSchedulerWorkerTest, ContinuousWork) { | |
246 // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to | |
247 // return nullptr. | |
248 SetNumSequencesToCreate(kNumSequencesPerTest); | |
249 | |
250 // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a | |
251 // Sequence and one call in which its returns nullptr. | |
252 const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; | |
253 SetMaxGetWork(kExpectedNumGetWork); | |
254 | |
255 // Wake up |worker_| and wait until GetWork() has been invoked the | |
256 // expected amount of times. | |
257 worker_->WakeUp(); | |
258 WaitForNumGetWork(kExpectedNumGetWork); | |
259 | |
260 // All tasks should have run. | |
261 EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); | |
262 | |
263 // If Sequences returned by GetWork() contain more than one Task, they aren't | |
264 // empty after the worker pops Tasks from them and thus should be returned to | |
265 // EnqueueSequence(). | |
266 if (TasksPerSequence() > 1) | |
267 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | |
268 else | |
269 EXPECT_TRUE(EnqueuedSequences().empty()); | |
270 } | |
271 | |
272 // Verify that when GetWork() alternates between returning a Sequence and | |
273 // returning nullptr, all Tasks in the returned Sequences run successfully. The | |
274 // test wakes up the SchedulerWorker once for each Sequence. | |
275 TEST_P(TaskSchedulerWorkerTest, IntermittentWork) { | |
276 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { | |
277 // Set GetWork() to return 1 Sequence before starting to return | |
278 // nullptr. | |
279 SetNumSequencesToCreate(1); | |
280 | |
281 // Expect |i + 1| calls to GetWork() in which it returns a Sequence and | |
282 // |i + 1| calls in which it returns nullptr. | |
283 const size_t expected_num_get_work = 2 * (i + 1); | |
284 SetMaxGetWork(expected_num_get_work); | |
285 | |
286 // Wake up |worker_| and wait until GetWork() has been invoked | |
287 // the expected amount of times. | |
288 worker_->WakeUp(); | |
289 WaitForNumGetWork(expected_num_get_work); | |
290 | |
291 // The Task should have run | |
292 EXPECT_EQ(i + 1, NumRunTasks()); | |
293 | |
294 // If Sequences returned by GetWork() contain more than one Task, they | |
295 // aren't empty after the worker pops Tasks from them and thus should be | |
296 // returned to EnqueueSequence(). | |
297 if (TasksPerSequence() > 1) | |
298 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | |
299 else | |
300 EXPECT_TRUE(EnqueuedSequences().empty()); | |
301 } | |
302 } | |
303 | |
304 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, | |
305 TaskSchedulerWorkerTest, | |
306 ::testing::Values(1)); | |
307 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | |
308 TaskSchedulerWorkerTest, | |
309 ::testing::Values(2)); | |
310 | |
311 namespace { | |
312 | |
313 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { | |
314 public: | |
315 ControllableDetachDelegate() | |
316 : work_processed_(WaitableEvent::ResetPolicy::MANUAL, | |
317 WaitableEvent::InitialState::NOT_SIGNALED), | |
318 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | |
319 WaitableEvent::InitialState::NOT_SIGNALED) {} | |
320 | |
321 ~ControllableDetachDelegate() override = default; | |
322 | |
323 // SchedulerWorker::Delegate: | |
324 MOCK_METHOD2(OnMainEntry, | |
325 void(SchedulerWorker* worker, const TimeDelta& detach_duration)); | |
326 | |
327 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) | |
328 override { | |
329 // Sends one item of work to signal |work_processed_|. On subsequent calls, | |
330 // sends nullptr to indicate there's no more work to be done. | |
331 if (work_requested_) | |
332 return nullptr; | |
333 | |
334 work_requested_ = true; | |
335 scoped_refptr<Sequence> sequence(new Sequence); | |
336 std::unique_ptr<Task> task(new Task( | |
337 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), | |
338 TaskTraits(), TimeDelta())); | |
339 sequence->PushTask(std::move(task)); | |
340 return sequence; | |
341 } | |
342 | |
343 bool CanDetach(SchedulerWorker* worker) override { | |
344 detach_requested_.Signal(); | |
345 return can_detach_; | |
346 } | |
347 | |
348 void WaitForWorkToRun() { | |
349 work_processed_.Wait(); | |
350 } | |
351 | |
352 void WaitForDetachRequest() { | |
353 detach_requested_.Wait(); | |
354 } | |
355 | |
356 void ResetState() { | |
357 work_requested_ = false; | |
358 work_processed_.Reset(); | |
359 detach_requested_.Reset(); | |
360 } | |
361 | |
362 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | |
363 | |
364 private: | |
365 bool work_requested_ = false; | |
366 bool can_detach_ = false; | |
367 WaitableEvent work_processed_; | |
368 WaitableEvent detach_requested_; | |
369 | |
370 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); | |
371 }; | |
372 | |
373 } // namespace | |
374 | |
375 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { | |
376 TaskTracker task_tracker; | |
377 // Will be owned by SchedulerWorker. | |
378 ControllableDetachDelegate* delegate = | |
379 new StrictMock<ControllableDetachDelegate>; | |
380 delegate->set_can_detach(true); | |
381 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | |
382 std::unique_ptr<SchedulerWorker> worker = | |
383 SchedulerWorker::Create( | |
384 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | |
385 SchedulerWorker::InitialState::ALIVE); | |
386 worker->WakeUp(); | |
387 delegate->WaitForWorkToRun(); | |
388 Mock::VerifyAndClear(delegate); | |
389 delegate->WaitForDetachRequest(); | |
390 // Sleep to give a chance for the detach to happen. A yield is too short. | |
391 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
392 ASSERT_FALSE(worker->ThreadAliveForTesting()); | |
393 } | |
394 | |
395 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | |
396 TaskTracker task_tracker; | |
397 // Will be owned by SchedulerWorker. | |
398 ControllableDetachDelegate* delegate = | |
399 new StrictMock<ControllableDetachDelegate>; | |
400 delegate->set_can_detach(true); | |
401 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | |
402 std::unique_ptr<SchedulerWorker> worker = | |
403 SchedulerWorker::Create( | |
404 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | |
405 SchedulerWorker::InitialState::ALIVE); | |
406 worker->WakeUp(); | |
407 delegate->WaitForWorkToRun(); | |
408 Mock::VerifyAndClear(delegate); | |
409 delegate->WaitForDetachRequest(); | |
410 // Sleep to give a chance for the detach to happen. A yield is too short. | |
411 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
412 ASSERT_FALSE(worker->ThreadAliveForTesting()); | |
413 | |
414 delegate->ResetState(); | |
415 delegate->set_can_detach(false); | |
416 // When SchedulerWorker recreates its thread, expect OnMainEntry() to be | |
417 // called with a detach duration which is not TimeDelta::Max(). | |
418 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), Ne(TimeDelta::Max()))); | |
419 worker->WakeUp(); | |
420 delegate->WaitForWorkToRun(); | |
421 Mock::VerifyAndClear(delegate); | |
422 delegate->WaitForDetachRequest(); | |
423 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
424 ASSERT_TRUE(worker->ThreadAliveForTesting()); | |
425 worker->JoinForTesting(); | |
426 } | |
427 | |
428 TEST(TaskSchedulerWorkerTest, CreateDetached) { | |
429 TaskTracker task_tracker; | |
430 // Will be owned by SchedulerWorker. | |
431 ControllableDetachDelegate* delegate = | |
432 new StrictMock<ControllableDetachDelegate>; | |
433 std::unique_ptr<SchedulerWorker> worker = | |
434 SchedulerWorker::Create( | |
435 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | |
436 SchedulerWorker::InitialState::DETACHED); | |
437 ASSERT_FALSE(worker->ThreadAliveForTesting()); | |
438 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), TimeDelta::Max())); | |
439 worker->WakeUp(); | |
440 delegate->WaitForWorkToRun(); | |
441 Mock::VerifyAndClear(delegate); | |
442 delegate->WaitForDetachRequest(); | |
443 ASSERT_TRUE(worker->ThreadAliveForTesting()); | |
444 worker->JoinForTesting(); | |
445 } | |
446 | |
447 namespace { | |
448 | |
449 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { | |
450 public: | |
451 ExpectThreadPriorityDelegate() | |
452 : priority_verified_in_get_work_event_( | |
453 WaitableEvent::ResetPolicy::AUTOMATIC, | |
454 WaitableEvent::InitialState::NOT_SIGNALED), | |
455 expected_thread_priority_(ThreadPriority::BACKGROUND) {} | |
456 | |
457 void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { | |
458 expected_thread_priority_ = expected_thread_priority; | |
459 } | |
460 | |
461 void WaitForPriorityVerifiedInGetWork() { | |
462 priority_verified_in_get_work_event_.Wait(); | |
463 } | |
464 | |
465 // SchedulerWorker::Delegate: | |
466 void OnMainEntry(SchedulerWorker* worker, | |
467 const TimeDelta& detach_duration) override { | |
468 VerifyThreadPriority(); | |
469 } | |
470 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | |
471 VerifyThreadPriority(); | |
472 priority_verified_in_get_work_event_.Signal(); | |
473 return nullptr; | |
474 } | |
475 | |
476 private: | |
477 void VerifyThreadPriority() { | |
478 AutoSchedulerLock auto_lock(expected_thread_priority_lock_); | |
479 EXPECT_EQ(expected_thread_priority_, | |
480 PlatformThread::GetCurrentThreadPriority()); | |
481 } | |
482 | |
483 // Signaled after GetWork() has verified the priority of the worker thread. | |
484 WaitableEvent priority_verified_in_get_work_event_; | |
485 | |
486 // Synchronizes access to |expected_thread_priority_|. | |
487 SchedulerLock expected_thread_priority_lock_; | |
488 | |
489 // Expected thread priority for the next call to OnMainEntry() or GetWork(). | |
490 ThreadPriority expected_thread_priority_; | |
491 | |
492 DISALLOW_COPY_AND_ASSIGN(ExpectThreadPriorityDelegate); | |
493 }; | |
494 | |
495 } // namespace | |
496 | |
497 TEST(TaskSchedulerWorkerTest, BumpPriorityOfAliveThreadDuringShutdown) { | |
498 TaskTracker task_tracker; | |
499 | |
500 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( | |
501 new ExpectThreadPriorityDelegate); | |
502 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); | |
503 delegate_raw->SetExpectedThreadPriority( | |
504 PlatformThread::CanIncreaseCurrentThreadPriority() | |
505 ? ThreadPriority::BACKGROUND | |
506 : ThreadPriority::NORMAL); | |
507 | |
508 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
509 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, | |
510 SchedulerWorker::InitialState::ALIVE); | |
511 | |
512 // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread | |
513 // priority can't be increased). | |
514 worker->WakeUp(); | |
515 delegate_raw->WaitForPriorityVerifiedInGetWork(); | |
516 | |
517 // Verify that the thread priority is bumped to NORMAL during shutdown. | |
518 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); | |
519 task_tracker.SetHasShutdownStartedForTesting(); | |
520 worker->WakeUp(); | |
521 delegate_raw->WaitForPriorityVerifiedInGetWork(); | |
522 | |
523 worker->JoinForTesting(); | |
524 } | |
525 | |
526 TEST(TaskSchedulerWorkerTest, BumpPriorityOfDetachedThreadDuringShutdown) { | |
527 TaskTracker task_tracker; | |
528 | |
529 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( | |
530 new ExpectThreadPriorityDelegate); | |
531 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); | |
532 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); | |
533 | |
534 // Create a DETACHED thread. | |
535 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
536 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, | |
537 SchedulerWorker::InitialState::DETACHED); | |
538 | |
539 // Pretend that shutdown has started. | |
540 task_tracker.SetHasShutdownStartedForTesting(); | |
541 | |
542 // Wake up the thread and verify that its priority is NORMAL when | |
543 // OnMainEntry() and GetWork() are called. | |
544 worker->WakeUp(); | |
545 delegate_raw->WaitForPriorityVerifiedInGetWork(); | |
546 | |
547 worker->JoinForTesting(); | |
548 } | |
549 | |
550 } // namespace | |
551 } // namespace internal | |
552 } // namespace base | |
OLD | NEW |