| 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> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/atomicops.h" | 13 #include "base/atomicops.h" |
| 14 #include "base/callback.h" | 14 #include "base/callback.h" |
| 15 #include "base/compiler_specific.h" | 15 #include "base/compiler_specific.h" |
| 16 #include "base/critical_closure.h" | 16 #include "base/critical_closure.h" |
| 17 #include "base/debug/trace_event.h" |
| 17 #include "base/logging.h" | 18 #include "base/logging.h" |
| 18 #include "base/memory/linked_ptr.h" | 19 #include "base/memory/linked_ptr.h" |
| 19 #include "base/message_loop_proxy.h" | 20 #include "base/message_loop_proxy.h" |
| 20 #include "base/metrics/histogram.h" | 21 #include "base/metrics/histogram.h" |
| 21 #include "base/stl_util.h" | 22 #include "base/stl_util.h" |
| 22 #include "base/stringprintf.h" | 23 #include "base/stringprintf.h" |
| 23 #include "base/synchronization/condition_variable.h" | 24 #include "base/synchronization/condition_variable.h" |
| 24 #include "base/synchronization/lock.h" | 25 #include "base/synchronization/lock.h" |
| 25 #include "base/threading/platform_thread.h" | 26 #include "base/threading/platform_thread.h" |
| 26 #include "base/threading/simple_thread.h" | 27 #include "base/threading/simple_thread.h" |
| 27 #include "base/threading/thread_restrictions.h" | 28 #include "base/threading/thread_restrictions.h" |
| 28 #include "base/time.h" | 29 #include "base/time.h" |
| 29 #include "base/tracked_objects.h" | 30 #include "base/tracked_objects.h" |
| 30 | 31 |
| 31 #if defined(OS_MACOSX) | 32 #if defined(OS_MACOSX) |
| 32 #include "base/mac/scoped_nsautorelease_pool.h" | 33 #include "base/mac/scoped_nsautorelease_pool.h" |
| 33 #endif | 34 #endif |
| 34 | 35 |
| 35 namespace base { | 36 namespace base { |
| 36 | 37 |
| 37 namespace { | 38 namespace { |
| 38 | 39 |
| 39 struct SequencedTask : public TrackingInfo { | 40 struct SequencedTask : public TrackingInfo { |
| 40 SequencedTask() | 41 SequencedTask() |
| 41 : sequence_token_id(0), | 42 : sequence_token_id(0), |
| 43 trace_id(0), |
| 42 shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {} | 44 shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {} |
| 43 | 45 |
| 44 explicit SequencedTask(const tracked_objects::Location& from_here) | 46 explicit SequencedTask(const tracked_objects::Location& from_here) |
| 45 : base::TrackingInfo(from_here, TimeTicks()), | 47 : base::TrackingInfo(from_here, TimeTicks()), |
| 46 sequence_token_id(0), | 48 sequence_token_id(0), |
| 49 trace_id(0), |
| 47 shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {} | 50 shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {} |
| 48 | 51 |
| 49 ~SequencedTask() {} | 52 ~SequencedTask() {} |
| 50 | 53 |
| 51 int sequence_token_id; | 54 int sequence_token_id; |
| 55 int trace_id; |
| 52 SequencedWorkerPool::WorkerShutdown shutdown_behavior; | 56 SequencedWorkerPool::WorkerShutdown shutdown_behavior; |
| 53 tracked_objects::Location posted_from; | 57 tracked_objects::Location posted_from; |
| 54 Closure task; | 58 Closure task; |
| 55 }; | 59 }; |
| 56 | 60 |
| 57 // SequencedWorkerPoolTaskRunner --------------------------------------------- | 61 // SequencedWorkerPoolTaskRunner --------------------------------------------- |
| 58 // A TaskRunner which posts tasks to a SequencedWorkerPool with a | 62 // A TaskRunner which posts tasks to a SequencedWorkerPool with a |
| 59 // fixed ShutdownBehavior. | 63 // fixed ShutdownBehavior. |
| 60 // | 64 // |
| 61 // Note that this class is RefCountedThreadSafe (inherited from TaskRunner). | 65 // Note that this class is RefCountedThreadSafe (inherited from TaskRunner). |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 TimeDelta delay) { | 205 TimeDelta delay) { |
| 202 // TODO(francoisk777@gmail.com): Change the following two statements once | 206 // TODO(francoisk777@gmail.com): Change the following two statements once |
| 203 // SequencedWorkerPool supports non-zero delays. | 207 // SequencedWorkerPool supports non-zero delays. |
| 204 DCHECK_EQ(delay.InMillisecondsRoundedUp(), 0) | 208 DCHECK_EQ(delay.InMillisecondsRoundedUp(), 0) |
| 205 << "SequencedWorkerPoolSequencedTaskRunner does not yet support non-zero" | 209 << "SequencedWorkerPoolSequencedTaskRunner does not yet support non-zero" |
| 206 " delays"; | 210 " delays"; |
| 207 return pool_->PostSequencedWorkerTaskWithShutdownBehavior( | 211 return pool_->PostSequencedWorkerTaskWithShutdownBehavior( |
| 208 token_, from_here, task, shutdown_behavior_); | 212 token_, from_here, task, shutdown_behavior_); |
| 209 } | 213 } |
| 210 | 214 |
| 215 // Create a process-wide unique ID to represent this task in trace events. This |
| 216 // will be mangled with a Process ID hash to reduce the likelyhood of colliding |
| 217 // with MessageLoop pointers on other processes. |
| 218 uint64 GetTaskTraceID(const SequencedTask& task, |
| 219 void* pool) { |
| 220 return (static_cast<uint64>(task.trace_id) << 32) | |
| 221 static_cast<uint64>(reinterpret_cast<intptr_t>(pool)); |
| 222 } |
| 223 |
| 211 } // namespace | 224 } // namespace |
| 212 | 225 |
| 213 // Worker --------------------------------------------------------------------- | 226 // Worker --------------------------------------------------------------------- |
| 214 | 227 |
| 215 class SequencedWorkerPool::Worker : public SimpleThread { | 228 class SequencedWorkerPool::Worker : public SimpleThread { |
| 216 public: | 229 public: |
| 217 // Hold a (cyclic) ref to |worker_pool|, since we want to keep it | 230 // Hold a (cyclic) ref to |worker_pool|, since we want to keep it |
| 218 // around as long as we are running. | 231 // around as long as we are running. |
| 219 Worker(const scoped_refptr<SequencedWorkerPool>& worker_pool, | 232 Worker(const scoped_refptr<SequencedWorkerPool>& worker_pool, |
| 220 int thread_number, | 233 int thread_number, |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 std::list<SequencedTask> pending_tasks_; | 402 std::list<SequencedTask> pending_tasks_; |
| 390 size_t pending_task_count_; | 403 size_t pending_task_count_; |
| 391 | 404 |
| 392 // Number of tasks in the pending_tasks_ list that are marked as blocking | 405 // Number of tasks in the pending_tasks_ list that are marked as blocking |
| 393 // shutdown. | 406 // shutdown. |
| 394 size_t blocking_shutdown_pending_task_count_; | 407 size_t blocking_shutdown_pending_task_count_; |
| 395 | 408 |
| 396 // Lists all sequence tokens currently executing. | 409 // Lists all sequence tokens currently executing. |
| 397 std::set<int> current_sequences_; | 410 std::set<int> current_sequences_; |
| 398 | 411 |
| 412 // An ID for each posted task to distinguish the task from others in traces. |
| 413 int trace_id_; |
| 414 |
| 399 // Set when Shutdown is called and no further tasks should be | 415 // Set when Shutdown is called and no further tasks should be |
| 400 // allowed, though we may still be running existing tasks. | 416 // allowed, though we may still be running existing tasks. |
| 401 bool shutdown_called_; | 417 bool shutdown_called_; |
| 402 | 418 |
| 403 TestingObserver* const testing_observer_; | 419 TestingObserver* const testing_observer_; |
| 404 | 420 |
| 405 DISALLOW_COPY_AND_ASSIGN(Inner); | 421 DISALLOW_COPY_AND_ASSIGN(Inner); |
| 406 }; | 422 }; |
| 407 | 423 |
| 408 // Worker definitions --------------------------------------------------------- | 424 // Worker definitions --------------------------------------------------------- |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 has_work_cv_(&lock_), | 460 has_work_cv_(&lock_), |
| 445 is_idle_cv_(&lock_), | 461 is_idle_cv_(&lock_), |
| 446 can_shutdown_cv_(&lock_), | 462 can_shutdown_cv_(&lock_), |
| 447 max_threads_(max_threads), | 463 max_threads_(max_threads), |
| 448 thread_name_prefix_(thread_name_prefix), | 464 thread_name_prefix_(thread_name_prefix), |
| 449 thread_being_created_(false), | 465 thread_being_created_(false), |
| 450 waiting_thread_count_(0), | 466 waiting_thread_count_(0), |
| 451 blocking_shutdown_thread_count_(0), | 467 blocking_shutdown_thread_count_(0), |
| 452 pending_task_count_(0), | 468 pending_task_count_(0), |
| 453 blocking_shutdown_pending_task_count_(0), | 469 blocking_shutdown_pending_task_count_(0), |
| 470 trace_id_(0), |
| 454 shutdown_called_(false), | 471 shutdown_called_(false), |
| 455 testing_observer_(observer) {} | 472 testing_observer_(observer) {} |
| 456 | 473 |
| 457 SequencedWorkerPool::Inner::~Inner() { | 474 SequencedWorkerPool::Inner::~Inner() { |
| 458 // You must call Shutdown() before destroying the pool. | 475 // You must call Shutdown() before destroying the pool. |
| 459 DCHECK(shutdown_called_); | 476 DCHECK(shutdown_called_); |
| 460 | 477 |
| 461 // Need to explicitly join with the threads before they're destroyed or else | 478 // Need to explicitly join with the threads before they're destroyed or else |
| 462 // they will be running when our object is half torn down. | 479 // they will be running when our object is half torn down. |
| 463 for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it) | 480 for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it) |
| (...skipping 30 matching lines...) Expand all Loading... |
| 494 sequenced.task = | 511 sequenced.task = |
| 495 shutdown_behavior == BLOCK_SHUTDOWN ? | 512 shutdown_behavior == BLOCK_SHUTDOWN ? |
| 496 base::MakeCriticalClosure(task) : task; | 513 base::MakeCriticalClosure(task) : task; |
| 497 | 514 |
| 498 int create_thread_id = 0; | 515 int create_thread_id = 0; |
| 499 { | 516 { |
| 500 AutoLock lock(lock_); | 517 AutoLock lock(lock_); |
| 501 if (shutdown_called_) | 518 if (shutdown_called_) |
| 502 return false; | 519 return false; |
| 503 | 520 |
| 521 // The trace_id is used for identifying the task in about:tracing. |
| 522 sequenced.trace_id = trace_id_++; |
| 523 |
| 524 TRACE_EVENT_FLOW_BEGIN0("task", "SequencedWorkerPool::PostTask", |
| 525 TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this)))); |
| 526 |
| 504 // Now that we have the lock, apply the named token rules. | 527 // Now that we have the lock, apply the named token rules. |
| 505 if (optional_token_name) | 528 if (optional_token_name) |
| 506 sequenced.sequence_token_id = LockedGetNamedTokenID(*optional_token_name); | 529 sequenced.sequence_token_id = LockedGetNamedTokenID(*optional_token_name); |
| 507 | 530 |
| 508 pending_tasks_.push_back(sequenced); | 531 pending_tasks_.push_back(sequenced); |
| 509 pending_task_count_++; | 532 pending_task_count_++; |
| 510 if (shutdown_behavior == BLOCK_SHUTDOWN) | 533 if (shutdown_behavior == BLOCK_SHUTDOWN) |
| 511 blocking_shutdown_pending_task_count_++; | 534 blocking_shutdown_pending_task_count_++; |
| 512 | 535 |
| 513 create_thread_id = PrepareToStartAdditionalThreadIfHelpful(); | 536 create_thread_id = PrepareToStartAdditionalThreadIfHelpful(); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 | 621 |
| 599 while (true) { | 622 while (true) { |
| 600 #if defined(OS_MACOSX) | 623 #if defined(OS_MACOSX) |
| 601 base::mac::ScopedNSAutoreleasePool autorelease_pool; | 624 base::mac::ScopedNSAutoreleasePool autorelease_pool; |
| 602 #endif | 625 #endif |
| 603 | 626 |
| 604 // See GetWork for what delete_these_outside_lock is doing. | 627 // See GetWork for what delete_these_outside_lock is doing. |
| 605 SequencedTask task; | 628 SequencedTask task; |
| 606 std::vector<Closure> delete_these_outside_lock; | 629 std::vector<Closure> delete_these_outside_lock; |
| 607 if (GetWork(&task, &delete_these_outside_lock)) { | 630 if (GetWork(&task, &delete_these_outside_lock)) { |
| 631 TRACE_EVENT_FLOW_END0("task", "SequencedWorkerPool::PostTask", |
| 632 TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this)))); |
| 633 TRACE_EVENT2("task", "SequencedWorkerPool::ThreadLoop", |
| 634 "src_file", task.posted_from.file_name(), |
| 635 "src_func", task.posted_from.function_name()); |
| 608 int new_thread_id = WillRunWorkerTask(task); | 636 int new_thread_id = WillRunWorkerTask(task); |
| 609 { | 637 { |
| 610 AutoUnlock unlock(lock_); | 638 AutoUnlock unlock(lock_); |
| 611 // There may be more work available, so wake up another | 639 // There may be more work available, so wake up another |
| 612 // worker thread. (Technically not required, since we | 640 // worker thread. (Technically not required, since we |
| 613 // already get a signal for each new task, but it doesn't | 641 // already get a signal for each new task, but it doesn't |
| 614 // hurt.) | 642 // hurt.) |
| 615 SignalHasWork(); | 643 SignalHasWork(); |
| 616 delete_these_outside_lock.clear(); | 644 delete_these_outside_lock.clear(); |
| 617 | 645 |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1015 void SequencedWorkerPool::SignalHasWorkForTesting() { | 1043 void SequencedWorkerPool::SignalHasWorkForTesting() { |
| 1016 inner_->SignalHasWorkForTesting(); | 1044 inner_->SignalHasWorkForTesting(); |
| 1017 } | 1045 } |
| 1018 | 1046 |
| 1019 void SequencedWorkerPool::Shutdown() { | 1047 void SequencedWorkerPool::Shutdown() { |
| 1020 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); | 1048 DCHECK(constructor_message_loop_->BelongsToCurrentThread()); |
| 1021 inner_->Shutdown(); | 1049 inner_->Shutdown(); |
| 1022 } | 1050 } |
| 1023 | 1051 |
| 1024 } // namespace base | 1052 } // namespace base |
| OLD | NEW |