Home | History | Annotate | Download | only in child
      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
      3 // found in the LICENSE file.
      4 
      5 #include "base/callback.h"
      6 #include "base/lazy_instance.h"
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/observer_list.h"
     10 #include "webkit/child/worker_task_runner.h"
     11 
     12 using WebKit::WebWorkerRunLoop;
     13 
     14 namespace {
     15 
     16 class RunClosureTask : public WebWorkerRunLoop::Task {
     17  public:
     18   RunClosureTask(const base::Closure& task) : task_(task) {}
     19   virtual ~RunClosureTask() {}
     20   virtual void Run() {
     21     task_.Run();
     22   }
     23  private:
     24   base::Closure task_;
     25 };
     26 
     27 } // unnamed namespace
     28 
     29 namespace webkit_glue {
     30 
     31 struct WorkerTaskRunner::ThreadLocalState {
     32   ThreadLocalState(int id, const WebWorkerRunLoop& loop)
     33       : id_(id), run_loop_(loop) {
     34   }
     35   int id_;
     36   WebWorkerRunLoop run_loop_;
     37   ObserverList<WorkerTaskRunner::Observer> stop_observers_;
     38 };
     39 
     40 WorkerTaskRunner::WorkerTaskRunner() {
     41   // Start worker ids at 1, 0 is reserved for the main thread.
     42   int id = id_sequence_.GetNext();
     43   DCHECK(!id);
     44 }
     45 
     46 bool WorkerTaskRunner::PostTask(
     47     int id, const base::Closure& closure) {
     48   DCHECK(id > 0);
     49   base::AutoLock locker(loop_map_lock_);
     50   IDToLoopMap::iterator found = loop_map_.find(id);
     51   if (found == loop_map_.end())
     52     return false;
     53   return found->second.postTask(new RunClosureTask(closure));
     54 }
     55 
     56 int WorkerTaskRunner::PostTaskToAllThreads(const base::Closure& closure) {
     57   base::AutoLock locker(loop_map_lock_);
     58   IDToLoopMap::iterator it;
     59   for (it = loop_map_.begin(); it != loop_map_.end(); ++it)
     60     it->second.postTask(new RunClosureTask(closure));
     61   return static_cast<int>(loop_map_.size());
     62 }
     63 
     64 int WorkerTaskRunner::CurrentWorkerId() {
     65   if (!current_tls_.Get())
     66     return 0;
     67   return current_tls_.Get()->id_;
     68 }
     69 
     70 WorkerTaskRunner* WorkerTaskRunner::Instance() {
     71   static base::LazyInstance<WorkerTaskRunner>::Leaky
     72       worker_task_runner = LAZY_INSTANCE_INITIALIZER;
     73   return worker_task_runner.Pointer();
     74 }
     75 
     76 void WorkerTaskRunner::AddStopObserver(Observer* obs) {
     77   DCHECK(CurrentWorkerId() > 0);
     78   current_tls_.Get()->stop_observers_.AddObserver(obs);
     79 }
     80 
     81 void WorkerTaskRunner::RemoveStopObserver(Observer* obs) {
     82   DCHECK(CurrentWorkerId() > 0);
     83   current_tls_.Get()->stop_observers_.RemoveObserver(obs);
     84 }
     85 
     86 WorkerTaskRunner::~WorkerTaskRunner() {
     87 }
     88 
     89 void WorkerTaskRunner::OnWorkerRunLoopStarted(const WebWorkerRunLoop& loop) {
     90   DCHECK(!current_tls_.Get());
     91   int id = id_sequence_.GetNext();
     92   current_tls_.Set(new ThreadLocalState(id, loop));
     93 
     94   base::AutoLock locker_(loop_map_lock_);
     95   loop_map_[id] = loop;
     96 }
     97 
     98 void WorkerTaskRunner::OnWorkerRunLoopStopped(const WebWorkerRunLoop& loop) {
     99   DCHECK(current_tls_.Get());
    100   FOR_EACH_OBSERVER(Observer, current_tls_.Get()->stop_observers_,
    101                     OnWorkerRunLoopStopped());
    102   {
    103     base::AutoLock locker(loop_map_lock_);
    104     DCHECK(loop_map_[CurrentWorkerId()] == loop);
    105     loop_map_.erase(CurrentWorkerId());
    106   }
    107   delete current_tls_.Get();
    108   current_tls_.Set(NULL);
    109 }
    110 
    111 }  // namespace webkit_glue
    112