Home | History | Annotate | Download | only in gn
      1 // Copyright (c) 2013 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 "tools/gn/scheduler.h"
      6 
      7 #include "base/bind.h"
      8 #include "tools/gn/ninja_target_writer.h"
      9 #include "tools/gn/standard_out.h"
     10 
     11 Scheduler* g_scheduler = NULL;
     12 
     13 Scheduler::Scheduler()
     14     : pool_(new base::SequencedWorkerPool(32, "worker_")),
     15       input_file_manager_(new InputFileManager),
     16       verbose_logging_(false),
     17       work_count_(0),
     18       is_failed_(false) {
     19   g_scheduler = this;
     20 }
     21 
     22 Scheduler::~Scheduler() {
     23   g_scheduler = NULL;
     24 }
     25 
     26 bool Scheduler::Run() {
     27   runner_.Run();
     28   pool_->Shutdown();
     29   return !is_failed();
     30 }
     31 
     32 void Scheduler::Log(const std::string& verb, const std::string& msg) {
     33   if (base::MessageLoop::current() == &main_loop_) {
     34     LogOnMainThread(verb, msg);
     35   } else {
     36     // The run loop always joins on the sub threads, so the lifetime of this
     37     // object outlives the invocations of this function, hence "unretained".
     38     main_loop_.PostTask(FROM_HERE,
     39                         base::Bind(&Scheduler::LogOnMainThread,
     40                                    base::Unretained(this), verb, msg));
     41   }
     42 }
     43 
     44 void Scheduler::FailWithError(const Err& err) {
     45   DCHECK(err.has_error());
     46   {
     47     base::AutoLock lock(lock_);
     48 
     49     if (is_failed_)
     50       return;  // Ignore errors once we see one.
     51     is_failed_ = true;
     52   }
     53 
     54   if (base::MessageLoop::current() == &main_loop_) {
     55     FailWithErrorOnMainThread(err);
     56   } else {
     57     // The run loop always joins on the sub threads, so the lifetime of this
     58     // object outlives the invocations of this function, hence "unretained".
     59     main_loop_.PostTask(FROM_HERE,
     60                         base::Bind(&Scheduler::FailWithErrorOnMainThread,
     61                                    base::Unretained(this), err));
     62   }
     63 }
     64 
     65 void Scheduler::ScheduleWork(const base::Closure& work) {
     66   IncrementWorkCount();
     67   pool_->PostWorkerTaskWithShutdownBehavior(
     68       FROM_HERE, base::Bind(&Scheduler::DoWork,
     69                             base::Unretained(this), work),
     70       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
     71 }
     72 
     73 void Scheduler::ScheduleTargetFileWrite(const Target* target) {
     74   pool_->PostWorkerTaskWithShutdownBehavior(
     75       FROM_HERE, base::Bind(&Scheduler::DoTargetFileWrite,
     76                             base::Unretained(this), target),
     77       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
     78 }
     79 
     80 void Scheduler::AddGenDependency(const SourceFile& source_file) {
     81   base::AutoLock lock(lock_);
     82   gen_dependencies_.push_back(source_file);
     83 }
     84 
     85 std::vector<SourceFile> Scheduler::GetGenDependencies() const {
     86   base::AutoLock lock(lock_);
     87   return gen_dependencies_;
     88 }
     89 
     90 void Scheduler::IncrementWorkCount() {
     91   base::AtomicRefCountInc(&work_count_);
     92 }
     93 
     94 void Scheduler::DecrementWorkCount() {
     95   if (!base::AtomicRefCountDec(&work_count_)) {
     96     if (base::MessageLoop::current() == &main_loop_) {
     97       OnComplete();
     98     } else {
     99       main_loop_.PostTask(FROM_HERE,
    100                           base::Bind(&Scheduler::OnComplete,
    101                                      base::Unretained(this)));
    102     }
    103   }
    104 }
    105 
    106 void Scheduler::LogOnMainThread(const std::string& verb,
    107                                 const std::string& msg) {
    108   OutputString(verb, DECORATION_YELLOW);
    109   OutputString(" " + msg + "\n");
    110 }
    111 
    112 void Scheduler::FailWithErrorOnMainThread(const Err& err) {
    113   err.PrintToStdout();
    114   runner_.Quit();
    115 }
    116 
    117 void Scheduler::DoTargetFileWrite(const Target* target) {
    118   NinjaTargetWriter::RunAndWriteFile(target);
    119 }
    120 
    121 void Scheduler::DoWork(const base::Closure& closure) {
    122   closure.Run();
    123   DecrementWorkCount();
    124 }
    125 
    126 void Scheduler::OnComplete() {
    127   // Should be called on the main thread.
    128   DCHECK(base::MessageLoop::current() == main_loop());
    129   runner_.Quit();
    130 }
    131