* elf32-xtensa.c (relax_section): Check for a reference to a discarded
[deliverable/binutils-gdb.git] / gold / workqueue.cc
CommitLineData
bae7f79e
ILT
1// workqueue.cc -- the workqueue for gold
2
6cb15b7f
ILT
3// Copyright 2006, 2007 Free Software Foundation, Inc.
4// Written by Ian Lance Taylor <iant@google.com>.
5
6// This file is part of gold.
7
8// This program is free software; you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by
10// the Free Software Foundation; either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21// MA 02110-1301, USA.
22
bae7f79e 23#include "gold.h"
c33feb2b 24
bae7f79e
ILT
25#include "workqueue.h"
26
27namespace gold
28{
29
30// Task_token methods.
31
32Task_token::Task_token()
33 : is_blocker_(false), readers_(0), writer_(NULL)
34{
35}
36
37Task_token::~Task_token()
38{
a3ad94ed 39 gold_assert(this->readers_ == 0 && this->writer_ == NULL);
bae7f79e
ILT
40}
41
42bool
43Task_token::is_readable() const
44{
a3ad94ed 45 gold_assert(!this->is_blocker_);
bae7f79e
ILT
46 return this->writer_ == NULL;
47}
48
49void
50Task_token::add_reader()
51{
a3ad94ed
ILT
52 gold_assert(!this->is_blocker_);
53 gold_assert(this->is_readable());
bae7f79e
ILT
54 ++this->readers_;
55}
56
57void
58Task_token::remove_reader()
59{
a3ad94ed
ILT
60 gold_assert(!this->is_blocker_);
61 gold_assert(this->readers_ > 0);
bae7f79e
ILT
62 --this->readers_;
63}
64
65bool
66Task_token::is_writable() const
67{
a3ad94ed 68 gold_assert(!this->is_blocker_);
bae7f79e
ILT
69 return this->writer_ == NULL && this->readers_ == 0;
70}
71
72void
73Task_token::add_writer(const Task* t)
74{
a3ad94ed
ILT
75 gold_assert(!this->is_blocker_);
76 gold_assert(this->is_writable());
bae7f79e
ILT
77 this->writer_ = t;
78}
79
80void
81Task_token::remove_writer(const Task* t)
82{
a3ad94ed
ILT
83 gold_assert(!this->is_blocker_);
84 gold_assert(this->writer_ == t);
bae7f79e
ILT
85 this->writer_ = NULL;
86}
87
88bool
89Task_token::has_write_lock(const Task* t)
90{
a3ad94ed 91 gold_assert(!this->is_blocker_);
bae7f79e
ILT
92 return this->writer_ == t;
93}
94
95// For blockers, we just use the readers_ field.
96
97void
98Task_token::add_blocker()
99{
100 if (this->readers_ == 0 && this->writer_ == NULL)
101 this->is_blocker_ = true;
102 else
a3ad94ed 103 gold_assert(this->is_blocker_);
bae7f79e
ILT
104 ++this->readers_;
105}
106
107bool
108Task_token::remove_blocker()
109{
a3ad94ed 110 gold_assert(this->is_blocker_ && this->readers_ > 0);
bae7f79e
ILT
111 --this->readers_;
112 return this->readers_ == 0;
113}
114
115bool
116Task_token::is_blocked() const
117{
a3ad94ed
ILT
118 gold_assert(this->is_blocker_
119 || (this->readers_ == 0 && this->writer_ == NULL));
bae7f79e
ILT
120 return this->readers_ > 0;
121}
122
123// The Task_block_token class.
124
125Task_block_token::Task_block_token(Task_token& token, Workqueue* workqueue)
126 : token_(token), workqueue_(workqueue)
127{
128 // We must increment the block count when the task is created and
129 // put on the queue. This object is created when the task is run,
130 // so we don't increment the block count here.
a3ad94ed 131 gold_assert(this->token_.is_blocked());
bae7f79e
ILT
132}
133
134Task_block_token::~Task_block_token()
135{
136 if (this->token_.remove_blocker())
137 {
138 // Tell the workqueue that a blocker was cleared. This is
139 // always called in the main thread, so no locking is required.
140 this->workqueue_->cleared_blocker();
141 }
142}
143
144// The Workqueue_runner abstract class.
145
146class Workqueue_runner
147{
148 public:
149 Workqueue_runner(Workqueue* workqueue)
150 : workqueue_(workqueue)
151 { }
152 virtual ~Workqueue_runner()
153 { }
154
155 // Run a task. This is always called in the main thread.
156 virtual void run(Task*, Task_locker*) = 0;
157
158 protected:
159 // This is called by an implementation when a task is completed.
160 void completed(Task* t, Task_locker* tl)
161 { this->workqueue_->completed(t, tl); }
162
163 Workqueue* get_workqueue() const
164 { return this->workqueue_; }
165
166 private:
167 Workqueue* workqueue_;
168};
169
170// The simple single-threaded implementation of Workqueue_runner.
171
172class Workqueue_runner_single : public Workqueue_runner
173{
174 public:
175 Workqueue_runner_single(Workqueue* workqueue)
176 : Workqueue_runner(workqueue)
177 { }
178 ~Workqueue_runner_single()
179 { }
180
181 void run(Task*, Task_locker*);
182};
183
184void
185Workqueue_runner_single::run(Task* t, Task_locker* tl)
186{
187 t->run(this->get_workqueue());
188 this->completed(t, tl);
189}
190
191// Workqueue methods.
192
193Workqueue::Workqueue(const General_options&)
194 : tasks_lock_(),
195 tasks_(),
196 completed_lock_(),
197 completed_(),
198 running_(0),
199 completed_condvar_(this->completed_lock_),
200 cleared_blockers_(0)
201{
202 // At some point we will select the specific implementation of
203 // Workqueue_runner to use based on the command line options.
204 this->runner_ = new Workqueue_runner_single(this);
205}
206
207Workqueue::~Workqueue()
208{
a3ad94ed
ILT
209 gold_assert(this->tasks_.empty());
210 gold_assert(this->completed_.empty());
211 gold_assert(this->running_ == 0);
bae7f79e
ILT
212}
213
92e059d8
ILT
214// Add a task to the queue.
215
bae7f79e
ILT
216void
217Workqueue::queue(Task* t)
218{
219 Hold_lock hl(this->tasks_lock_);
220 this->tasks_.push_back(t);
221}
222
92e059d8
ILT
223// Add a task to the front of the queue.
224
225void
226Workqueue::queue_front(Task* t)
227{
228 Hold_lock hl(this->tasks_lock_);
229 this->tasks_.push_front(t);
230}
231
bae7f79e
ILT
232// Clear the list of completed tasks. Return whether we cleared
233// anything. The completed_lock_ must be held when this is called.
234
235bool
236Workqueue::clear_completed()
237{
238 if (this->completed_.empty())
239 return false;
240 do
241 {
242 delete this->completed_.front();
243 this->completed_.pop_front();
244 }
245 while (!this->completed_.empty());
246 return true;
247}
248
249// Find a runnable task in TASKS, which is non-empty. Return NULL if
250// none could be found. The tasks_lock_ must be held when this is
251// called. Sets ALL_BLOCKED if all non-runnable tasks are waiting on
252// a blocker.
253
254Task*
255Workqueue::find_runnable(Task_list& tasks, bool* all_blocked)
256{
257 Task* tlast = tasks.back();
258 *all_blocked = true;
259 while (true)
260 {
261 Task* t = tasks.front();
262 tasks.pop_front();
263
264 Task::Is_runnable_type is_runnable = t->is_runnable(this);
265 if (is_runnable == Task::IS_RUNNABLE)
266 return t;
267
268 if (is_runnable != Task::IS_BLOCKED)
269 *all_blocked = false;
270
271 tasks.push_back(t);
272
273 if (t == tlast)
274 {
275 // We couldn't find any runnable task. If there are any
276 // completed tasks, free their locks and try again.
277
278 {
279 Hold_lock hl2(this->completed_lock_);
280
281 if (!this->clear_completed())
282 {
283 // There had better be some tasks running, or we will
284 // never find a runnable task.
a3ad94ed 285 gold_assert(this->running_ > 0);
bae7f79e
ILT
286
287 // We couldn't find any runnable tasks, and we
288 // couldn't release any locks.
289 return NULL;
290 }
291 }
292
293 // We're going around again, so recompute ALL_BLOCKED.
294 *all_blocked = true;
295 }
296 }
297}
298
299// Process all the tasks on the workqueue. This is the main loop in
300// the linker. Note that as we process tasks, new tasks will be
301// added.
302
303void
304Workqueue::process()
305{
306 while (true)
307 {
308 Task* t;
309 bool empty;
310 bool all_blocked;
311
312 {
313 Hold_lock hl(this->tasks_lock_);
314
315 if (this->tasks_.empty())
316 {
317 t = NULL;
318 empty = true;
319 all_blocked = false;
320 }
321 else
322 {
323 t = this->find_runnable(this->tasks_, &all_blocked);
324 empty = false;
325 }
326 }
327
328 // If T != NULL, it is a task we can run.
329 // If T == NULL && empty, then there are no tasks waiting to
330 // be run at this level.
331 // If T == NULL && !empty, then there tasks waiting to be
332 // run at this level, but they are waiting for something to
333 // unlock.
334
335 if (t != NULL)
336 this->run(t);
337 else if (!empty)
338 {
339 {
340 Hold_lock hl(this->completed_lock_);
341
342 // There must be something for us to wait for, or we won't
343 // be able to make progress.
a3ad94ed 344 gold_assert(this->running_ > 0 || !this->completed_.empty());
bae7f79e
ILT
345
346 if (all_blocked)
347 {
348 this->cleared_blockers_ = 0;
349 this->clear_completed();
350 while (this->cleared_blockers_ == 0)
351 {
a3ad94ed 352 gold_assert(this->running_ > 0);
bae7f79e
ILT
353 this->completed_condvar_.wait();
354 this->clear_completed();
355 }
356 }
357 else
358 {
359 if (this->running_ > 0)
360 {
361 // Wait for a task to finish.
362 this->completed_condvar_.wait();
363 }
364 this->clear_completed();
365 }
366 }
367 }
368 else
369 {
370 {
371 Hold_lock hl(this->completed_lock_);
372
373 // If there are no running tasks, then we are done.
374 if (this->running_ == 0)
375 {
376 this->clear_completed();
377 return;
378 }
379
380 // Wait for a task to finish. Then we have to loop around
381 // again in case it added any new tasks before finishing.
382 this->completed_condvar_.wait();
383 this->clear_completed();
384 }
385 }
386 }
387}
388
389// Run a task. This is always called in the main thread.
390
391void
392Workqueue::run(Task* t)
393{
394 ++this->running_;
395 this->runner_->run(t, t->locks(this));
396}
397
398// This is called when a task is completed to put the locks on the
399// list to be released. We use a list because we only want the locks
400// to be released in the main thread.
401
402void
403Workqueue::completed(Task* t, Task_locker* tl)
404{
405 {
406 Hold_lock hl(this->completed_lock_);
a3ad94ed 407 gold_assert(this->running_ > 0);
bae7f79e
ILT
408 --this->running_;
409 this->completed_.push_back(tl);
410 this->completed_condvar_.signal();
411 }
412 delete t;
413}
414
415// This is called when the last task for a blocker has completed.
416// This is always called in the main thread.
417
418void
419Workqueue::cleared_blocker()
420{
421 ++this->cleared_blockers_;
422}
423
424} // End namespace gold.
This page took 0.074326 seconds and 4 git commands to generate.