| Index: base/tracked_objects.cc
|
| ===================================================================
|
| --- base/tracked_objects.cc (revision 110643)
|
| +++ base/tracked_objects.cc (working copy)
|
| @@ -11,6 +11,7 @@
|
| #include "base/stringprintf.h"
|
| #include "base/threading/thread_restrictions.h"
|
| #include "build/build_config.h"
|
| +#include "base/port.h"
|
|
|
| using base::TimeDelta;
|
|
|
| @@ -147,22 +148,18 @@
|
| ThreadData::ThreadData(const std::string& suggested_name)
|
| : incarnation_count_for_pool_(-1),
|
| next_(NULL),
|
| - is_a_worker_thread_(false) {
|
| + worker_thread_number_(0) {
|
| DCHECK_GE(suggested_name.size(), 0u);
|
| thread_name_ = suggested_name;
|
| PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
|
| }
|
|
|
| -ThreadData::ThreadData()
|
| +ThreadData::ThreadData(size_t thread_number)
|
| : incarnation_count_for_pool_(-1),
|
| next_(NULL),
|
| - is_a_worker_thread_(true) {
|
| - int thread_number;
|
| - {
|
| - base::AutoLock lock(*list_lock_.Pointer());
|
| - thread_number = ++thread_number_counter_;
|
| - }
|
| - base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
|
| + worker_thread_number_(thread_number) {
|
| + CHECK_NE(thread_number, 0u);
|
| + base::StringAppendF(&thread_name_, "WorkerThread-%"PRIuS, thread_number);
|
| PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
|
| }
|
|
|
| @@ -198,19 +195,25 @@
|
|
|
| // We must be a worker thread, since we didn't pre-register.
|
| ThreadData* worker_thread_data = NULL;
|
| + size_t thread_number = 0;
|
| {
|
| base::AutoLock lock(*list_lock_.Pointer());
|
| - if (unregistered_thread_data_pool_ &&
|
| - !unregistered_thread_data_pool_->empty()) {
|
| + if (!unregistered_thread_data_pool_)
|
| + unregistered_thread_data_pool_ = new ThreadDataPool;
|
| + if (!unregistered_thread_data_pool_->empty()) {
|
| worker_thread_data =
|
| const_cast<ThreadData*>(unregistered_thread_data_pool_->top());
|
| unregistered_thread_data_pool_->pop();
|
| + } else {
|
| + thread_number = ++thread_number_counter_;
|
| + unregistered_thread_data_pool_->reserve(thread_number);
|
| }
|
| }
|
|
|
| // If we can't find a previously used instance, then we have to create one.
|
| if (!worker_thread_data)
|
| - worker_thread_data = new ThreadData();
|
| + worker_thread_data = new ThreadData(thread_number);
|
| + DCHECK_GT(worker_thread_data->worker_thread_number_, 0u);
|
|
|
| tls_index_.Set(worker_thread_data);
|
| return worker_thread_data;
|
| @@ -226,18 +229,12 @@
|
| }
|
|
|
| void ThreadData::OnThreadTerminationCleanup() const {
|
| - if (!is_a_worker_thread_)
|
| + if (!worker_thread_number_)
|
| return;
|
| base::AutoLock lock(*list_lock_.Pointer());
|
| if (incarnation_counter_ != incarnation_count_for_pool_)
|
| return; // ThreadData was constructed in an earlier unit test.
|
| -
|
| - // Handle case where we are in unit tests, and have become UNINITIALIZED.
|
| - // In that case, the pool might be NULL. We really should detect this via the
|
| - // incarnation_counter_, but this call is rarely made, so we can afford to
|
| - // code defensively.
|
| - if (!unregistered_thread_data_pool_)
|
| - unregistered_thread_data_pool_ = new ThreadDataPool;
|
| + // The following will never have to do an allocation.
|
| unregistered_thread_data_pool_->push(this);
|
| }
|
|
|
| @@ -562,6 +559,49 @@
|
| }
|
|
|
| //------------------------------------------------------------------------------
|
| +// Small partial implementation of a stack that never has to allocate during a
|
| +// push() operation, because it is always prepared to accept the maximum number
|
| +// of ThreadData instances (all the worker thread related instances).
|
| +
|
| +ThreadData::ThreadDataPool::ThreadDataPool() : empty_slot_(0) {};
|
| +ThreadData::ThreadDataPool::~ThreadDataPool() {};
|
| +
|
| +bool ThreadData::ThreadDataPool::empty() const { return empty_slot_ == 0; }
|
| +
|
| +void ThreadData::ThreadDataPool::reserve(size_t largest_worker_pool_number) {
|
| + // Worker pool numbers start at 1, and exclude 0, so the number is exactly
|
| + // the least size needed.
|
| + // Due to asynchronous construction of worker-pool numbers (and associated
|
| + // ThreadData), we might not hear about the numbers sequentially.
|
| + if (largest_worker_pool_number > stack_.size())
|
| + stack_.resize(largest_worker_pool_number);
|
| +}
|
| +
|
| +const ThreadData* ThreadData::ThreadDataPool::top() const {
|
| + if (empty_slot_ > 0)
|
| + return stack_[empty_slot_ - 1];
|
| + NOTREACHED();
|
| + return NULL;
|
| +}
|
| +
|
| +void ThreadData::ThreadDataPool::push(const ThreadData* thread_data) {
|
| + if (empty_slot_ < stack_.size()) {
|
| + stack_[empty_slot_] = thread_data;
|
| + ++empty_slot_;
|
| + return;
|
| + }
|
| + NOTREACHED();
|
| +}
|
| +
|
| +void ThreadData::ThreadDataPool::pop() {
|
| + if (empty_slot_ > 0) {
|
| + --empty_slot_;
|
| + return;
|
| + }
|
| + NOTREACHED();
|
| +}
|
| +
|
| +//------------------------------------------------------------------------------
|
| // Individual 3-tuple of birth (place and thread) along with death thread, and
|
| // the accumulated stats for instances (DeathData).
|
|
|
|
|