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.
5 #include "tools/gn/scheduler.h"
8 #include "base/command_line.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "tools/gn/standard_out.h"
11 #include "tools/gn/switches.h"
13 Scheduler
* g_scheduler
= nullptr;
17 int GetThreadCount() {
18 std::string thread_count
=
19 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
23 if (thread_count
.empty() || !base::StringToInt(thread_count
, &result
))
30 Scheduler::Scheduler()
31 : pool_(new base::SequencedWorkerPool(GetThreadCount(), "worker_")),
32 input_file_manager_(new InputFileManager
),
33 verbose_logging_(false),
36 has_been_shutdown_(false) {
40 Scheduler::~Scheduler() {
41 if (!has_been_shutdown_
)
43 g_scheduler
= nullptr;
46 bool Scheduler::Run() {
50 base::AutoLock
lock(lock_
);
51 local_is_failed
= is_failed();
52 has_been_shutdown_
= true;
54 // Don't do this inside the lock since it will block on the workers, which
55 // may be in turn waiting on the lock.
57 return !local_is_failed
;
60 void Scheduler::Log(const std::string
& verb
, const std::string
& msg
) {
61 if (base::MessageLoop::current() == &main_loop_
) {
62 LogOnMainThread(verb
, msg
);
64 // The run loop always joins on the sub threads, so the lifetime of this
65 // object outlives the invocations of this function, hence "unretained".
66 main_loop_
.PostTask(FROM_HERE
,
67 base::Bind(&Scheduler::LogOnMainThread
,
68 base::Unretained(this), verb
, msg
));
72 void Scheduler::FailWithError(const Err
& err
) {
73 DCHECK(err
.has_error());
75 base::AutoLock
lock(lock_
);
77 if (is_failed_
|| has_been_shutdown_
)
78 return; // Ignore errors once we see one.
82 if (base::MessageLoop::current() == &main_loop_
) {
83 FailWithErrorOnMainThread(err
);
85 // The run loop always joins on the sub threads, so the lifetime of this
86 // object outlives the invocations of this function, hence "unretained".
87 main_loop_
.PostTask(FROM_HERE
,
88 base::Bind(&Scheduler::FailWithErrorOnMainThread
,
89 base::Unretained(this), err
));
93 void Scheduler::ScheduleWork(const base::Closure
& work
) {
95 pool_
->PostWorkerTaskWithShutdownBehavior(
96 FROM_HERE
, base::Bind(&Scheduler::DoWork
,
97 base::Unretained(this), work
),
98 base::SequencedWorkerPool::BLOCK_SHUTDOWN
);
101 void Scheduler::AddGenDependency(const base::FilePath
& file
) {
102 base::AutoLock
lock(lock_
);
103 gen_dependencies_
.push_back(file
);
106 std::vector
<base::FilePath
> Scheduler::GetGenDependencies() const {
107 base::AutoLock
lock(lock_
);
108 return gen_dependencies_
;
111 void Scheduler::AddWrittenFile(const SourceFile
& file
) {
112 base::AutoLock
lock(lock_
);
113 written_files_
.push_back(file
);
116 std::vector
<SourceFile
> Scheduler::GetWrittenFiles() const {
117 base::AutoLock
lock(lock_
);
118 return written_files_
;
121 void Scheduler::AddUnknownGeneratedInput(const Target
* target
,
122 const SourceFile
& file
) {
123 base::AutoLock
lock(lock_
);
124 unknown_generated_inputs_
.insert(std::make_pair(file
, target
));
127 std::multimap
<SourceFile
, const Target
*>
128 Scheduler::GetUnknownGeneratedInputs() const {
129 base::AutoLock
lock(lock_
);
131 // Remove all unknown inputs that were written files. These are OK as inputs
132 // to build steps since they were written as a side-effect of running GN.
134 // It's assumed that this function is called once during cleanup to check for
135 // errors, so performing this work in the lock doesn't matter.
136 std::multimap
<SourceFile
, const Target
*> filtered
= unknown_generated_inputs_
;
137 for (const SourceFile
& file
: written_files_
)
138 filtered
.erase(file
);
143 void Scheduler::ClearUnknownGeneratedInputsAndWrittenFiles() {
144 base::AutoLock
lock(lock_
);
145 unknown_generated_inputs_
.clear();
146 written_files_
.clear();
149 void Scheduler::IncrementWorkCount() {
150 base::AtomicRefCountInc(&work_count_
);
153 void Scheduler::DecrementWorkCount() {
154 if (!base::AtomicRefCountDec(&work_count_
)) {
155 if (base::MessageLoop::current() == &main_loop_
) {
158 main_loop_
.PostTask(FROM_HERE
,
159 base::Bind(&Scheduler::OnComplete
,
160 base::Unretained(this)));
165 void Scheduler::LogOnMainThread(const std::string
& verb
,
166 const std::string
& msg
) {
167 OutputString(verb
, DECORATION_YELLOW
);
168 OutputString(" " + msg
+ "\n");
171 void Scheduler::FailWithErrorOnMainThread(const Err
& err
) {
176 void Scheduler::DoWork(const base::Closure
& closure
) {
178 DecrementWorkCount();
181 void Scheduler::OnComplete() {
182 // Should be called on the main thread.
183 DCHECK(base::MessageLoop::current() == main_loop());