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