Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/threading/sequenced_worker_pool.h" | 5 #include "base/threading/sequenced_worker_pool.h" |
| 6 | 6 |
| 7 #include <list> | 7 #include <list> |
| 8 #include <map> | 8 #include <map> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 bool PostTask(const std::string* optional_token_name, | 86 bool PostTask(const std::string* optional_token_name, |
| 87 SequenceToken sequence_token, | 87 SequenceToken sequence_token, |
| 88 WorkerShutdown shutdown_behavior, | 88 WorkerShutdown shutdown_behavior, |
| 89 const tracked_objects::Location& from_here, | 89 const tracked_objects::Location& from_here, |
| 90 const Closure& task); | 90 const Closure& task); |
| 91 | 91 |
| 92 bool RunsTasksOnCurrentThread() const; | 92 bool RunsTasksOnCurrentThread() const; |
| 93 | 93 |
| 94 void FlushForTesting(); | 94 void FlushForTesting(); |
| 95 | 95 |
| 96 void TriggerSpuriousWorkSignalForTesting(); | |
| 97 | |
| 98 int GetWorkSignalCountForTesting() const; | |
| 99 | |
| 96 void Shutdown(); | 100 void Shutdown(); |
| 97 | 101 |
| 98 void SetTestingObserver(TestingObserver* observer); | 102 void SetTestingObserver(TestingObserver* observer); |
| 99 | 103 |
| 100 // Runs the worker loop on the background thread. | 104 // Runs the worker loop on the background thread. |
| 101 void ThreadLoop(Worker* this_worker); | 105 void ThreadLoop(Worker* this_worker); |
| 102 | 106 |
| 103 private: | 107 private: |
| 108 // Returns whether there are no more pending tasks and all threads | |
| 109 // are idle. Must be called under lock. | |
| 110 bool IsIdle() const; | |
| 111 | |
| 104 // Called from within the lock, this converts the given token name into a | 112 // Called from within the lock, this converts the given token name into a |
| 105 // token ID, creating a new one if necessary. | 113 // token ID, creating a new one if necessary. |
| 106 int LockedGetNamedTokenID(const std::string& name); | 114 int LockedGetNamedTokenID(const std::string& name); |
| 107 | 115 |
| 108 // The calling code should clear the given delete_these_oustide_lock | 116 // The calling code should clear the given delete_these_oustide_lock |
| 109 // vector the next time the lock is released. See the implementation for | 117 // vector the next time the lock is released. See the implementation for |
| 110 // a more detailed description. | 118 // a more detailed description. |
| 111 bool GetWork(SequencedTask* task, | 119 bool GetWork(SequencedTask* task, |
| 112 std::vector<Closure>* delete_these_outside_lock); | 120 std::vector<Closure>* delete_these_outside_lock); |
| 113 | 121 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 135 // | 143 // |
| 136 // See the implementedion for more. | 144 // See the implementedion for more. |
| 137 int PrepareToStartAdditionalThreadIfHelpful(); | 145 int PrepareToStartAdditionalThreadIfHelpful(); |
| 138 | 146 |
| 139 // The second part of thread creation after | 147 // The second part of thread creation after |
| 140 // PrepareToStartAdditionalThreadIfHelpful with the thread number it | 148 // PrepareToStartAdditionalThreadIfHelpful with the thread number it |
| 141 // generated. This actually creates the thread and should be called outside | 149 // generated. This actually creates the thread and should be called outside |
| 142 // the lock to avoid blocking important work starting a thread in the lock. | 150 // the lock to avoid blocking important work starting a thread in the lock. |
| 143 void FinishStartingAdditionalThread(int thread_number); | 151 void FinishStartingAdditionalThread(int thread_number); |
| 144 | 152 |
| 153 // Signal |has_work_| and increment |has_work_signal_count_|. | |
| 154 void SignalHasWork(); | |
| 155 | |
| 145 // Checks whether there is work left that's blocking shutdown. Must be | 156 // Checks whether there is work left that's blocking shutdown. Must be |
| 146 // called inside the lock. | 157 // called inside the lock. |
| 147 bool CanShutdown() const; | 158 bool CanShutdown() const; |
| 148 | 159 |
| 149 SequencedWorkerPool* const worker_pool_; | 160 SequencedWorkerPool* const worker_pool_; |
| 150 | 161 |
| 151 // The last sequence number used. Managed by GetSequenceToken, since this | 162 // The last sequence number used. Managed by GetSequenceToken, since this |
| 152 // only does threadsafe increment operations, you do not need to hold the | 163 // only does threadsafe increment operations, you do not need to hold the |
| 153 // lock. | 164 // lock. |
| 154 volatile subtle::Atomic32 last_sequence_number_; | 165 volatile subtle::Atomic32 last_sequence_number_; |
| 155 | 166 |
| 156 // This lock protects |everything in this class|. Do not read or modify | 167 // This lock protects |everything in this class|. Do not read or modify |
| 157 // anything without holding this lock. Do not block while holding this | 168 // anything without holding this lock. Do not block while holding this |
| 158 // lock. | 169 // lock. |
| 159 mutable Lock lock_; | 170 mutable Lock lock_; |
| 160 | 171 |
| 161 // Condition variable used to wake up worker threads when a task is runnable. | 172 // Condition variable that is signalled whenever a new task is |
| 162 ConditionVariable cond_var_; | 173 // posted or when Shutdown() is called. |
| 174 ConditionVariable has_work_cv_; | |
| 175 | |
| 176 // Number of times |has_work_| has been signalled. Used for testing. | |
| 177 int has_work_signal_count_; | |
| 178 | |
| 179 // Condition variable that is signalled whenever IsIdle() goes to | |
| 180 // true. | |
| 181 ConditionVariable is_idle_cv_; | |
| 182 | |
| 183 // Condition variable that is signalled whwnever CanShutdown() goes | |
| 184 // to true. | |
| 185 ConditionVariable can_shutdown_cv_; | |
| 163 | 186 |
| 164 // The maximum number of worker threads we'll create. | 187 // The maximum number of worker threads we'll create. |
| 165 const size_t max_threads_; | 188 const size_t max_threads_; |
| 166 | 189 |
| 167 const std::string thread_name_prefix_; | 190 const std::string thread_name_prefix_; |
| 168 | 191 |
| 169 // Associates all known sequence token names with their IDs. | 192 // Associates all known sequence token names with their IDs. |
| 170 std::map<std::string, int> named_sequence_tokens_; | 193 std::map<std::string, int> named_sequence_tokens_; |
| 171 | 194 |
| 172 // Owning pointers to all threads we've created so far, indexed by | 195 // Owning pointers to all threads we've created so far, indexed by |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 | 261 |
| 239 // Inner definitions --------------------------------------------------------- | 262 // Inner definitions --------------------------------------------------------- |
| 240 | 263 |
| 241 SequencedWorkerPool::Inner::Inner( | 264 SequencedWorkerPool::Inner::Inner( |
| 242 SequencedWorkerPool* worker_pool, | 265 SequencedWorkerPool* worker_pool, |
| 243 size_t max_threads, | 266 size_t max_threads, |
| 244 const std::string& thread_name_prefix) | 267 const std::string& thread_name_prefix) |
| 245 : worker_pool_(worker_pool), | 268 : worker_pool_(worker_pool), |
| 246 last_sequence_number_(0), | 269 last_sequence_number_(0), |
| 247 lock_(), | 270 lock_(), |
| 248 cond_var_(&lock_), | 271 has_work_cv_(&lock_), |
| 272 has_work_signal_count_(0), | |
| 273 is_idle_cv_(&lock_), | |
| 274 can_shutdown_cv_(&lock_), | |
| 249 max_threads_(max_threads), | 275 max_threads_(max_threads), |
| 250 thread_name_prefix_(thread_name_prefix), | 276 thread_name_prefix_(thread_name_prefix), |
| 251 thread_being_created_(false), | 277 thread_being_created_(false), |
| 252 waiting_thread_count_(0), | 278 waiting_thread_count_(0), |
| 253 blocking_shutdown_thread_count_(0), | 279 blocking_shutdown_thread_count_(0), |
| 254 pending_task_count_(0), | 280 pending_task_count_(0), |
| 255 blocking_shutdown_pending_task_count_(0), | 281 blocking_shutdown_pending_task_count_(0), |
| 256 shutdown_called_(false), | 282 shutdown_called_(false), |
| 257 testing_observer_(NULL) {} | 283 testing_observer_(NULL) {} |
| 258 | 284 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 311 blocking_shutdown_pending_task_count_++; | 337 blocking_shutdown_pending_task_count_++; |
| 312 | 338 |
| 313 create_thread_id = PrepareToStartAdditionalThreadIfHelpful(); | 339 create_thread_id = PrepareToStartAdditionalThreadIfHelpful(); |
| 314 } | 340 } |
| 315 | 341 |
| 316 // Actually start the additional thread or signal an existing one now that | 342 // Actually start the additional thread or signal an existing one now that |
| 317 // we're outside the lock. | 343 // we're outside the lock. |
| 318 if (create_thread_id) | 344 if (create_thread_id) |
| 319 FinishStartingAdditionalThread(create_thread_id); | 345 FinishStartingAdditionalThread(create_thread_id); |
| 320 else | 346 else |
| 321 cond_var_.Signal(); | 347 SignalHasWork(); |
| 322 | 348 |
| 323 return true; | 349 return true; |
| 324 } | 350 } |
| 325 | 351 |
| 326 bool SequencedWorkerPool::Inner::RunsTasksOnCurrentThread() const { | 352 bool SequencedWorkerPool::Inner::RunsTasksOnCurrentThread() const { |
| 327 AutoLock lock(lock_); | 353 AutoLock lock(lock_); |
| 328 return ContainsKey(threads_, PlatformThread::CurrentId()); | 354 return ContainsKey(threads_, PlatformThread::CurrentId()); |
| 329 } | 355 } |
| 330 | 356 |
| 331 void SequencedWorkerPool::Inner::FlushForTesting() { | 357 void SequencedWorkerPool::Inner::FlushForTesting() { |
| 332 { | 358 AutoLock lock(lock_); |
| 333 AutoLock lock(lock_); | 359 while (!IsIdle()) |
| 334 while (pending_task_count_ > 0 || waiting_thread_count_ < threads_.size()) | 360 is_idle_cv_.Wait(); |
| 335 cond_var_.Wait(); | 361 } |
| 336 } | 362 |
| 337 cond_var_.Signal(); | 363 void SequencedWorkerPool::Inner::TriggerSpuriousWorkSignalForTesting() { |
| 364 SignalHasWork(); | |
| 365 } | |
| 366 | |
| 367 int SequencedWorkerPool::Inner::GetWorkSignalCountForTesting() const { | |
|
jar (doing other things)
2012/03/12 19:42:36
nit: It bugs me a little that we've added this mus
akalin
2012/03/12 20:42:16
I think I can remove this variable and instead add
| |
| 368 AutoLock lock(lock_); | |
| 369 return has_work_signal_count_; | |
| 338 } | 370 } |
| 339 | 371 |
| 340 void SequencedWorkerPool::Inner::Shutdown() { | 372 void SequencedWorkerPool::Inner::Shutdown() { |
| 341 // Mark us as terminated and go through and drop all tasks that aren't | 373 // Mark us as terminated and go through and drop all tasks that aren't |
| 342 // required to run on shutdown. Since no new tasks will get posted once the | 374 // required to run on shutdown. Since no new tasks will get posted once the |
| 343 // terminated flag is set, this ensures that all remaining tasks are required | 375 // terminated flag is set, this ensures that all remaining tasks are required |
| 344 // for shutdown whenever the termianted_ flag is set. | 376 // for shutdown whenever the termianted_ flag is set. |
| 345 { | 377 { |
| 346 AutoLock lock(lock_); | 378 AutoLock lock(lock_); |
| 347 | 379 |
| 348 if (shutdown_called_) | 380 if (shutdown_called_) |
| 349 return; | 381 return; |
| 350 shutdown_called_ = true; | 382 shutdown_called_ = true; |
| 351 | 383 |
| 352 // Tickle the threads. This will wake up a waiting one so it will know that | 384 // Tickle the threads. This will wake up a waiting one so it will know that |
| 353 // it can exit, which in turn will wake up any other waiting ones. | 385 // it can exit, which in turn will wake up any other waiting ones. |
| 354 cond_var_.Signal(); | 386 has_work_cv_.Signal(); |
| 355 | 387 |
| 356 // There are no pending or running tasks blocking shutdown, we're done. | 388 // There are no pending or running tasks blocking shutdown, we're done. |
| 357 if (CanShutdown()) | 389 if (CanShutdown()) |
| 358 return; | 390 return; |
| 359 } | 391 } |
| 360 | 392 |
| 361 // If we get here, we know we're either waiting on a blocking task that's | 393 // If we're here, then something is blocking shutdown. So wait for |
| 362 // currently running, waiting on a blocking task that hasn't been scheduled | 394 // CanShutdown() to go to true. |
| 363 // yet, or both. Block on the "queue empty" event to know when all tasks are | 395 |
| 364 // complete. This must be done outside the lock. | |
| 365 if (testing_observer_) | 396 if (testing_observer_) |
| 366 testing_observer_->WillWaitForShutdown(); | 397 testing_observer_->WillWaitForShutdown(); |
| 367 | 398 |
| 368 TimeTicks shutdown_wait_begin = TimeTicks::Now(); | 399 TimeTicks shutdown_wait_begin = TimeTicks::Now(); |
| 369 | 400 |
| 370 // Wait for no more tasks. | |
| 371 { | 401 { |
| 372 AutoLock lock(lock_); | 402 AutoLock lock(lock_); |
| 373 while (!CanShutdown()) | 403 while (!CanShutdown()) |
| 374 cond_var_.Wait(); | 404 can_shutdown_cv_.Wait(); |
| 375 } | 405 } |
| 376 UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime", | 406 UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime", |
| 377 TimeTicks::Now() - shutdown_wait_begin); | 407 TimeTicks::Now() - shutdown_wait_begin); |
| 378 } | 408 } |
| 379 | 409 |
| 380 void SequencedWorkerPool::Inner::SetTestingObserver( | 410 void SequencedWorkerPool::Inner::SetTestingObserver( |
| 381 TestingObserver* observer) { | 411 TestingObserver* observer) { |
| 382 AutoLock lock(lock_); | 412 AutoLock lock(lock_); |
| 383 testing_observer_ = observer; | 413 testing_observer_ = observer; |
| 384 } | 414 } |
| 385 | 415 |
| 386 void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { | 416 void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| 387 { | 417 { |
| 388 AutoLock lock(lock_); | 418 AutoLock lock(lock_); |
| 389 DCHECK(thread_being_created_); | 419 DCHECK(thread_being_created_); |
| 390 thread_being_created_ = false; | 420 thread_being_created_ = false; |
| 391 std::pair<ThreadMap::iterator, bool> result = | 421 std::pair<ThreadMap::iterator, bool> result = |
| 392 threads_.insert( | 422 threads_.insert( |
| 393 std::make_pair(this_worker->tid(), make_linked_ptr(this_worker))); | 423 std::make_pair(this_worker->tid(), make_linked_ptr(this_worker))); |
| 394 DCHECK(result.second); | 424 DCHECK(result.second); |
| 395 | 425 |
| 396 while (true) { | 426 while (true) { |
| 397 // See GetWork for what delete_these_outside_lock is doing. | 427 // See GetWork for what delete_these_outside_lock is doing. |
| 398 SequencedTask task; | 428 SequencedTask task; |
| 399 std::vector<Closure> delete_these_outside_lock; | 429 std::vector<Closure> delete_these_outside_lock; |
| 400 if (GetWork(&task, &delete_these_outside_lock)) { | 430 if (GetWork(&task, &delete_these_outside_lock)) { |
| 401 int new_thread_id = WillRunWorkerTask(task); | 431 int new_thread_id = WillRunWorkerTask(task); |
| 402 { | 432 { |
| 403 AutoUnlock unlock(lock_); | 433 AutoUnlock unlock(lock_); |
| 404 cond_var_.Signal(); | 434 // There may be more work available, so wake up another |
| 435 // worker thread. | |
| 436 has_work_cv_.Signal(); | |
| 405 delete_these_outside_lock.clear(); | 437 delete_these_outside_lock.clear(); |
| 406 | 438 |
| 407 // Complete thread creation outside the lock if necessary. | 439 // Complete thread creation outside the lock if necessary. |
| 408 if (new_thread_id) | 440 if (new_thread_id) |
| 409 FinishStartingAdditionalThread(new_thread_id); | 441 FinishStartingAdditionalThread(new_thread_id); |
| 410 | 442 |
| 411 task.task.Run(); | 443 task.task.Run(); |
| 412 | 444 |
| 413 // Make sure our task is erased outside the lock for the same reason | 445 // Make sure our task is erased outside the lock for the same reason |
| 414 // we do this with delete_these_oustide_lock. | 446 // we do this with delete_these_oustide_lock. |
| 415 task.task = Closure(); | 447 task.task = Closure(); |
| 416 } | 448 } |
| 417 DidRunWorkerTask(task); // Must be done inside the lock. | 449 DidRunWorkerTask(task); // Must be done inside the lock. |
| 418 } else { | 450 } else { |
| 419 // When we're terminating and there's no more work, we can | 451 // When we're terminating and there's no more work, we can |
| 420 // shut down. You can't get more tasks posted once | 452 // shut down. You can't get more tasks posted once |
| 421 // shutdown_called_ is set. There may be some tasks stuck | 453 // shutdown_called_ is set. There may be some tasks stuck |
| 422 // behind running ones with the same sequence token, but | 454 // behind running ones with the same sequence token, but |
| 423 // additional threads won't help this case. | 455 // additional threads won't help this case. |
| 424 if (shutdown_called_) | 456 if (shutdown_called_) |
| 425 break; | 457 break; |
| 426 waiting_thread_count_++; | 458 waiting_thread_count_++; |
| 427 cond_var_.Signal(); // For Flush() that may be waiting on the | 459 // This is the only time that IsIdle() can go to true. |
| 428 // waiting thread count to go up. | 460 if (IsIdle()) |
| 429 cond_var_.Wait(); | 461 is_idle_cv_.Signal(); |
| 462 has_work_cv_.Wait(); | |
| 430 waiting_thread_count_--; | 463 waiting_thread_count_--; |
| 431 } | 464 } |
| 432 } | 465 } |
| 466 | |
| 467 // Unblock shutdown if possible. | |
| 468 if (CanShutdown()) | |
| 469 can_shutdown_cv_.Signal(); | |
|
jar (doing other things)
2012/03/12 19:42:36
Placing this here is probably more optimal than I
akalin
2012/03/12 20:42:16
Yeah, I think that's simpler. I moved it out.
| |
| 433 } | 470 } |
|
jar (doing other things)
2012/03/12 19:42:36
nit: Add comment: // Release lock_.
akalin
2012/03/12 20:42:16
Done.
| |
| 434 | 471 |
| 435 // We noticed we should exit. Wake up the next worker so it knows it should | 472 // We noticed we should exit. Wake up the next worker so it knows it should |
| 436 // exit as well (because the Shutdown() code only signals once). | 473 // exit as well (because the Shutdown() code only signals once). |
| 437 cond_var_.Signal(); | 474 has_work_cv_.Signal(); |
| 475 } | |
| 476 | |
| 477 bool SequencedWorkerPool::Inner::IsIdle() const { | |
| 478 lock_.AssertAcquired(); | |
| 479 return pending_task_count_ == 0 && waiting_thread_count_ == threads_.size(); | |
| 438 } | 480 } |
| 439 | 481 |
| 440 int SequencedWorkerPool::Inner::LockedGetNamedTokenID( | 482 int SequencedWorkerPool::Inner::LockedGetNamedTokenID( |
| 441 const std::string& name) { | 483 const std::string& name) { |
| 442 lock_.AssertAcquired(); | 484 lock_.AssertAcquired(); |
| 443 DCHECK(!name.empty()); | 485 DCHECK(!name.empty()); |
| 444 | 486 |
| 445 std::map<std::string, int>::const_iterator found = | 487 std::map<std::string, int>::const_iterator found = |
| 446 named_sequence_tokens_.find(name); | 488 named_sequence_tokens_.find(name); |
| 447 if (found != named_sequence_tokens_.end()) | 489 if (found != named_sequence_tokens_.end()) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 511 // vector they passed to us once the lock is exited to make this | 553 // vector they passed to us once the lock is exited to make this |
| 512 // happen. | 554 // happen. |
| 513 delete_these_outside_lock->push_back(i->task); | 555 delete_these_outside_lock->push_back(i->task); |
| 514 i = pending_tasks_.erase(i); | 556 i = pending_tasks_.erase(i); |
| 515 pending_task_count_--; | 557 pending_task_count_--; |
| 516 } else { | 558 } else { |
| 517 // Found a runnable task. | 559 // Found a runnable task. |
| 518 *task = *i; | 560 *task = *i; |
| 519 i = pending_tasks_.erase(i); | 561 i = pending_tasks_.erase(i); |
| 520 pending_task_count_--; | 562 pending_task_count_--; |
| 521 if (task->shutdown_behavior == BLOCK_SHUTDOWN) | 563 if (task->shutdown_behavior == BLOCK_SHUTDOWN) { |
| 522 blocking_shutdown_pending_task_count_--; | 564 blocking_shutdown_pending_task_count_--; |
| 565 } | |
| 523 | 566 |
| 524 found_task = true; | 567 found_task = true; |
| 525 break; | 568 break; |
| 526 } | 569 } |
| 527 } | 570 } |
| 528 | 571 |
| 529 // Track the number of tasks we had to skip over to see if we should be | 572 // Track the number of tasks we had to skip over to see if we should be |
| 530 // making this more efficient. If this number ever becomes large or is | 573 // making this more efficient. If this number ever becomes large or is |
| 531 // frequently "some", we should consider the optimization above. | 574 // frequently "some", we should consider the optimization above. |
| 532 UMA_HISTOGRAM_COUNTS_100("SequencedWorkerPool.UnrunnableTaskCount", | 575 UMA_HISTOGRAM_COUNTS_100("SequencedWorkerPool.UnrunnableTaskCount", |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 633 void SequencedWorkerPool::Inner::FinishStartingAdditionalThread( | 676 void SequencedWorkerPool::Inner::FinishStartingAdditionalThread( |
| 634 int thread_number) { | 677 int thread_number) { |
| 635 // Called outside of the lock. | 678 // Called outside of the lock. |
| 636 DCHECK(thread_number > 0); | 679 DCHECK(thread_number > 0); |
| 637 | 680 |
| 638 // The worker is assigned to the list when the thread actually starts, which | 681 // The worker is assigned to the list when the thread actually starts, which |
| 639 // will manage the memory of the pointer. | 682 // will manage the memory of the pointer. |
| 640 new Worker(worker_pool_, thread_number, thread_name_prefix_); | 683 new Worker(worker_pool_, thread_number, thread_name_prefix_); |
| 641 } | 684 } |
| 642 | 685 |
| 686 void SequencedWorkerPool::Inner::SignalHasWork() { | |
| 687 has_work_cv_.Signal(); | |
| 688 { | |
| 689 AutoLock lock(lock_); | |
| 690 ++has_work_signal_count_; | |
| 691 } | |
| 692 } | |
| 693 | |
| 643 bool SequencedWorkerPool::Inner::CanShutdown() const { | 694 bool SequencedWorkerPool::Inner::CanShutdown() const { |
| 644 lock_.AssertAcquired(); | 695 lock_.AssertAcquired(); |
| 645 // See PrepareToStartAdditionalThreadIfHelpful for how thread creation works. | 696 // See PrepareToStartAdditionalThreadIfHelpful for how thread creation works. |
| 646 return !thread_being_created_ && | 697 return !thread_being_created_ && |
| 647 blocking_shutdown_thread_count_ == 0 && | 698 blocking_shutdown_thread_count_ == 0 && |
| 648 blocking_shutdown_pending_task_count_ == 0; | 699 blocking_shutdown_pending_task_count_ == 0; |
| 649 } | 700 } |
| 650 | 701 |
| 651 // SequencedWorkerPool -------------------------------------------------------- | 702 // SequencedWorkerPool -------------------------------------------------------- |
| 652 | 703 |
| 653 SequencedWorkerPool::SequencedWorkerPool( | 704 SequencedWorkerPool::SequencedWorkerPool( |
| 654 size_t max_threads, | 705 size_t max_threads, |
| 655 const std::string& thread_name_prefix) | 706 const std::string& thread_name_prefix) |
| 656 : constructor_message_loop_(MessageLoopProxy::current()), | 707 : constructor_message_loop_(MessageLoopProxy::current()), |
| 657 inner_(new Inner(ALLOW_THIS_IN_INITIALIZER_LIST(this), | 708 inner_(new Inner(ALLOW_THIS_IN_INITIALIZER_LIST(this), |
| 658 max_threads, thread_name_prefix)) { | 709 max_threads, thread_name_prefix)) { |
| 659 DCHECK(constructor_message_loop_.get()); | 710 DCHECK(constructor_message_loop_.get()); |
| 660 } | 711 } |
| 661 | 712 |
| 662 SequencedWorkerPool::~SequencedWorkerPool() {} | 713 SequencedWorkerPool::~SequencedWorkerPool() {} |
| 663 | 714 |
| 664 void SequencedWorkerPool::OnDestruct() const { | 715 void SequencedWorkerPool::OnDestruct() const { |
| 665 // TODO(akalin): Once we can easily check if we're on a worker | 716 // TODO(akalin): Once we can easily check if we're on a worker |
| 666 // thread or not, use that instead of restricting destruction to | 717 // thread or not, use that instead of restricting destruction to |
| 667 // only the constructor message loop. | 718 // only the constructor message loop. |
| 668 if (constructor_message_loop_->BelongsToCurrentThread()) { | 719 if (constructor_message_loop_->BelongsToCurrentThread()) |
| 669 delete this; | 720 delete this; |
| 670 } else { | 721 else |
| 671 constructor_message_loop_->DeleteSoon(FROM_HERE, this); | 722 constructor_message_loop_->DeleteSoon(FROM_HERE, this); |
| 672 } | |
| 673 } | 723 } |
| 674 | 724 |
| 675 SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() { | 725 SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() { |
| 676 return inner_->GetSequenceToken(); | 726 return inner_->GetSequenceToken(); |
| 677 } | 727 } |
| 678 | 728 |
| 679 SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken( | 729 SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken( |
| 680 const std::string& name) { | 730 const std::string& name) { |
| 681 return inner_->GetNamedSequenceToken(name); | 731 return inner_->GetNamedSequenceToken(name); |
| 682 } | 732 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 741 } | 791 } |
| 742 | 792 |
| 743 bool SequencedWorkerPool::RunsTasksOnCurrentThread() const { | 793 bool SequencedWorkerPool::RunsTasksOnCurrentThread() const { |
| 744 return inner_->RunsTasksOnCurrentThread(); | 794 return inner_->RunsTasksOnCurrentThread(); |
| 745 } | 795 } |
| 746 | 796 |
| 747 void SequencedWorkerPool::FlushForTesting() { | 797 void SequencedWorkerPool::FlushForTesting() { |
| 748 inner_->FlushForTesting(); | 798 inner_->FlushForTesting(); |
| 749 } | 799 } |
| 750 | 800 |
| 801 void SequencedWorkerPool::TriggerSpuriousWorkSignalForTesting() { | |
| 802 inner_->TriggerSpuriousWorkSignalForTesting(); | |
| 803 } | |
| 804 | |
| 805 int SequencedWorkerPool::GetWorkSignalCountForTesting() const { | |
| 806 return inner_->GetWorkSignalCountForTesting(); | |
| 807 } | |
| 808 | |
| 751 void SequencedWorkerPool::Shutdown() { | 809 void SequencedWorkerPool::Shutdown() { |
| 810 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); | |
| 752 inner_->Shutdown(); | 811 inner_->Shutdown(); |
| 753 } | 812 } |
| 754 | 813 |
| 755 void SequencedWorkerPool::SetTestingObserver(TestingObserver* observer) { | 814 void SequencedWorkerPool::SetTestingObserver(TestingObserver* observer) { |
| 756 inner_->SetTestingObserver(observer); | 815 inner_->SetTestingObserver(observer); |
| 757 } | 816 } |
| 758 | 817 |
| 759 } // namespace base | 818 } // namespace base |
| OLD | NEW |