Chromium Code Reviews| Index: base/threading/sequenced_worker_pool.cc |
| diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc |
| index f98b23d5d6168a818178fe0c2e0a777edd618bd5..22883a8a49aa09f9a8a8b3152e718732bd5dd7d6 100644 |
| --- a/base/threading/sequenced_worker_pool.cc |
| +++ b/base/threading/sequenced_worker_pool.cc |
| @@ -15,16 +15,17 @@ |
| #include "base/compiler_specific.h" |
| #include "base/critical_closure.h" |
| #include "base/debug/trace_event.h" |
| +#include "base/lazy_instance.h" |
| #include "base/logging.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/message_loop/message_loop_proxy.h" |
| -#include "base/metrics/histogram.h" |
| #include "base/stl_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/synchronization/condition_variable.h" |
| #include "base/synchronization/lock.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/threading/simple_thread.h" |
| +#include "base/threading/thread_local.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/time/time.h" |
| #include "base/tracked_objects.h" |
| @@ -33,10 +34,17 @@ |
| #include "base/mac/scoped_nsautorelease_pool.h" |
| #endif |
| +#if !defined(OS_NACL) |
| +#include "base/metrics/histogram.h" |
| +#endif |
| + |
| namespace base { |
| namespace { |
| +base::LazyInstance<base::ThreadLocalPointer<SequencedWorkerPool> > |
| + lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER; |
| + |
| struct SequencedTask : public TrackingInfo { |
| SequencedTask() |
| : sequence_token_id(0), |
| @@ -267,6 +275,8 @@ class SequencedWorkerPool::Inner { |
| SequenceToken GetNamedSequenceToken(const std::string& name); |
| + bool GetCurrentThreadSequenceToken(SequenceToken* result_token) const; |
| + |
| // This function accepts a name and an ID. If the name is null, the |
| // token ID is used. This allows us to implement the optional name lookup |
| // from a single function without having to enter the lock a separate time. |
| @@ -479,6 +489,9 @@ SequencedWorkerPool::Worker::~Worker() { |
| } |
| void SequencedWorkerPool::Worker::Run() { |
| + // Store the SequencedWorkerPool associated with this worker thread. |
| + lazy_tls_ptr.Get().Set(worker_pool_.get()); |
| + |
| // Just jump back to the Inner object to run the thread, since it has all the |
| // tracking information and queues. It might be more natural to implement |
| // using DelegateSimpleThread and have Inner implement the Delegate to avoid |
| @@ -543,6 +556,17 @@ SequencedWorkerPool::Inner::GetNamedSequenceToken(const std::string& name) { |
| return SequenceToken(LockedGetNamedTokenID(name)); |
| } |
| +bool SequencedWorkerPool::Inner::GetCurrentThreadSequenceToken( |
| + SequenceToken* result_token) const { |
| + DCHECK(result_token); |
| + AutoLock lock(lock_); |
| + ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId()); |
|
darin (slow to review)
2013/07/02 13:54:23
Why do we need TLS to find the owner and this map
tommycli
2013/07/02 17:22:58
Sequence tokens are assigned from positive integer
|
| + if (found == threads_.end()) |
| + return false; |
| + *result_token = found->second->running_sequence(); |
| + return true; |
| +} |
| + |
| bool SequencedWorkerPool::Inner::PostTask( |
| const std::string* optional_token_name, |
| SequenceToken sequence_token, |
| @@ -611,11 +635,10 @@ bool SequencedWorkerPool::Inner::RunsTasksOnCurrentThread() const { |
| bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread( |
| SequenceToken sequence_token) const { |
| - AutoLock lock(lock_); |
| - ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId()); |
| - if (found == threads_.end()) |
| + SequenceToken current_thread_token; |
| + if (!GetCurrentThreadSequenceToken(¤t_thread_token)) |
| return false; |
| - return found->second->running_sequence().Equals(sequence_token); |
| + return current_thread_token.Equals(sequence_token); |
| } |
| // See https://code.google.com/p/chromium/issues/detail?id=168415 |
| @@ -674,8 +697,10 @@ void SequencedWorkerPool::Inner::Shutdown( |
| while (!CanShutdown()) |
| can_shutdown_cv_.Wait(); |
| } |
| +#if !defined(OS_NACL) |
| UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime", |
| TimeTicks::Now() - shutdown_wait_begin); |
| +#endif |
| } |
| void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| @@ -872,8 +897,10 @@ SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork( |
| std::vector<Closure>* delete_these_outside_lock) { |
| lock_.AssertAcquired(); |
| +#if !defined(OS_NACL) |
| UMA_HISTOGRAM_COUNTS_100("SequencedWorkerPool.TaskCount", |
| static_cast<int>(pending_tasks_.size())); |
| +#endif |
| // Find the next task with a sequence token that's not currently in use. |
| // If the token is in use, that means another thread is running something |
| @@ -958,8 +985,10 @@ SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork( |
| // Track the number of tasks we had to skip over to see if we should be |
| // making this more efficient. If this number ever becomes large or is |
| // frequently "some", we should consider the optimization above. |
| +#if !defined(OS_NACL) |
| UMA_HISTOGRAM_COUNTS_100("SequencedWorkerPool.UnrunnableTaskCount", |
| unrunnable_tasks); |
| +#endif |
| return status; |
| } |
| @@ -1127,6 +1156,11 @@ SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken( |
| return inner_->GetNamedSequenceToken(name); |
| } |
| +bool SequencedWorkerPool::GetCurrentThreadSequenceToken( |
| + SequenceToken* result_token) const { |
| + return inner_->GetCurrentThreadSequenceToken(result_token); |
| +} |
| + |
| scoped_refptr<SequencedTaskRunner> SequencedWorkerPool::GetSequencedTaskRunner( |
| SequenceToken token) { |
| return GetSequencedTaskRunnerWithShutdownBehavior(token, BLOCK_SHUTDOWN); |
| @@ -1236,4 +1270,9 @@ void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) { |
| inner_->Shutdown(max_new_blocking_tasks_after_shutdown); |
| } |
| +// static |
| +SequencedWorkerPool* SequencedWorkerPool::Owner() { |
| + return lazy_tls_ptr.Get().Get(); |
| +} |
| + |
| } // namespace base |