• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/command_line.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "tools/gn/standard_out.h"
11 
12 Scheduler* g_scheduler = NULL;
13 
14 namespace {
15 
GetThreadCount()16 int GetThreadCount() {
17   std::string thread_count =
18       CommandLine::ForCurrentProcess()->GetSwitchValueASCII("threads");
19 
20   int result;
21   if (thread_count.empty() || !base::StringToInt(thread_count, &result))
22     return 32;
23   return result;
24 }
25 
26 }  // namespace
27 
Scheduler()28 Scheduler::Scheduler()
29     : pool_(new base::SequencedWorkerPool(GetThreadCount(), "worker_")),
30       input_file_manager_(new InputFileManager),
31       verbose_logging_(false),
32       work_count_(0),
33       is_failed_(false),
34       has_been_shutdown_(false) {
35   g_scheduler = this;
36 }
37 
~Scheduler()38 Scheduler::~Scheduler() {
39   if (!has_been_shutdown_)
40     pool_->Shutdown();
41   g_scheduler = NULL;
42 }
43 
Run()44 bool Scheduler::Run() {
45   runner_.Run();
46   bool local_is_failed;
47   {
48     base::AutoLock lock(lock_);
49     local_is_failed = is_failed();
50     has_been_shutdown_ = true;
51   }
52   // Don't do this inside the lock since it will block on the workers, which
53   // may be in turn waiting on the lock.
54   pool_->Shutdown();
55   return !local_is_failed;
56 }
57 
Log(const std::string & verb,const std::string & msg)58 void Scheduler::Log(const std::string& verb, const std::string& msg) {
59   if (base::MessageLoop::current() == &main_loop_) {
60     LogOnMainThread(verb, msg);
61   } else {
62     // The run loop always joins on the sub threads, so the lifetime of this
63     // object outlives the invocations of this function, hence "unretained".
64     main_loop_.PostTask(FROM_HERE,
65                         base::Bind(&Scheduler::LogOnMainThread,
66                                    base::Unretained(this), verb, msg));
67   }
68 }
69 
FailWithError(const Err & err)70 void Scheduler::FailWithError(const Err& err) {
71   DCHECK(err.has_error());
72   {
73     base::AutoLock lock(lock_);
74 
75     if (is_failed_ || has_been_shutdown_)
76       return;  // Ignore errors once we see one.
77     is_failed_ = true;
78   }
79 
80   if (base::MessageLoop::current() == &main_loop_) {
81     FailWithErrorOnMainThread(err);
82   } else {
83     // The run loop always joins on the sub threads, so the lifetime of this
84     // object outlives the invocations of this function, hence "unretained".
85     main_loop_.PostTask(FROM_HERE,
86                         base::Bind(&Scheduler::FailWithErrorOnMainThread,
87                                    base::Unretained(this), err));
88   }
89 }
90 
ScheduleWork(const base::Closure & work)91 void Scheduler::ScheduleWork(const base::Closure& work) {
92   IncrementWorkCount();
93   pool_->PostWorkerTaskWithShutdownBehavior(
94       FROM_HERE, base::Bind(&Scheduler::DoWork,
95                             base::Unretained(this), work),
96       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
97 }
98 
AddGenDependency(const base::FilePath & file)99 void Scheduler::AddGenDependency(const base::FilePath& file) {
100   base::AutoLock lock(lock_);
101   gen_dependencies_.push_back(file);
102 }
103 
GetGenDependencies() const104 std::vector<base::FilePath> Scheduler::GetGenDependencies() const {
105   base::AutoLock lock(lock_);
106   return gen_dependencies_;
107 }
108 
IncrementWorkCount()109 void Scheduler::IncrementWorkCount() {
110   base::AtomicRefCountInc(&work_count_);
111 }
112 
DecrementWorkCount()113 void Scheduler::DecrementWorkCount() {
114   if (!base::AtomicRefCountDec(&work_count_)) {
115     if (base::MessageLoop::current() == &main_loop_) {
116       OnComplete();
117     } else {
118       main_loop_.PostTask(FROM_HERE,
119                           base::Bind(&Scheduler::OnComplete,
120                                      base::Unretained(this)));
121     }
122   }
123 }
124 
LogOnMainThread(const std::string & verb,const std::string & msg)125 void Scheduler::LogOnMainThread(const std::string& verb,
126                                 const std::string& msg) {
127   OutputString(verb, DECORATION_YELLOW);
128   OutputString(" " + msg + "\n");
129 }
130 
FailWithErrorOnMainThread(const Err & err)131 void Scheduler::FailWithErrorOnMainThread(const Err& err) {
132   err.PrintToStdout();
133   runner_.Quit();
134 }
135 
DoWork(const base::Closure & closure)136 void Scheduler::DoWork(const base::Closure& closure) {
137   closure.Run();
138   DecrementWorkCount();
139 }
140 
OnComplete()141 void Scheduler::OnComplete() {
142   // Should be called on the main thread.
143   DCHECK(base::MessageLoop::current() == main_loop());
144   runner_.Quit();
145 }
146