1 // workqueue.cc -- the workqueue for gold
12 // Task_token methods.
14 Task_token::Task_token()
15 : is_blocker_(false), readers_(0), writer_(NULL
)
19 Task_token::~Task_token()
21 assert(this->readers_
== 0 && this->writer_
== NULL
);
25 Task_token::is_readable() const
27 assert(!this->is_blocker_
);
28 return this->writer_
== NULL
;
32 Task_token::add_reader()
34 assert(!this->is_blocker_
);
35 assert(this->is_readable());
40 Task_token::remove_reader()
42 assert(!this->is_blocker_
);
43 assert(this->readers_
> 0);
48 Task_token::is_writable() const
50 assert(!this->is_blocker_
);
51 return this->writer_
== NULL
&& this->readers_
== 0;
55 Task_token::add_writer(const Task
* t
)
57 assert(!this->is_blocker_
);
58 assert(this->is_writable());
63 Task_token::remove_writer(const Task
* t
)
65 assert(!this->is_blocker_
);
66 assert(this->writer_
== t
);
71 Task_token::has_write_lock(const Task
* t
)
73 assert(!this->is_blocker_
);
74 return this->writer_
== t
;
77 // For blockers, we just use the readers_ field.
80 Task_token::add_blocker()
82 if (this->readers_
== 0 && this->writer_
== NULL
)
83 this->is_blocker_
= true;
85 assert(this->is_blocker_
);
90 Task_token::remove_blocker()
92 assert(this->is_blocker_
&& this->readers_
> 0);
94 return this->readers_
== 0;
98 Task_token::is_blocked() const
100 assert(this->is_blocker_
|| (this->readers_
== 0 && this->writer_
== NULL
));
101 return this->readers_
> 0;
104 // The Task_block_token class.
106 Task_block_token::Task_block_token(Task_token
& token
, Workqueue
* workqueue
)
107 : token_(token
), workqueue_(workqueue
)
109 // We must increment the block count when the task is created and
110 // put on the queue. This object is created when the task is run,
111 // so we don't increment the block count here.
112 assert(this->token_
.is_blocked());
115 Task_block_token::~Task_block_token()
117 if (this->token_
.remove_blocker())
119 // Tell the workqueue that a blocker was cleared. This is
120 // always called in the main thread, so no locking is required.
121 this->workqueue_
->cleared_blocker();
125 // The Workqueue_runner abstract class.
127 class Workqueue_runner
130 Workqueue_runner(Workqueue
* workqueue
)
131 : workqueue_(workqueue
)
133 virtual ~Workqueue_runner()
136 // Run a task. This is always called in the main thread.
137 virtual void run(Task
*, Task_locker
*) = 0;
140 // This is called by an implementation when a task is completed.
141 void completed(Task
* t
, Task_locker
* tl
)
142 { this->workqueue_
->completed(t
, tl
); }
144 Workqueue
* get_workqueue() const
145 { return this->workqueue_
; }
148 Workqueue
* workqueue_
;
151 // The simple single-threaded implementation of Workqueue_runner.
153 class Workqueue_runner_single
: public Workqueue_runner
156 Workqueue_runner_single(Workqueue
* workqueue
)
157 : Workqueue_runner(workqueue
)
159 ~Workqueue_runner_single()
162 void run(Task
*, Task_locker
*);
166 Workqueue_runner_single::run(Task
* t
, Task_locker
* tl
)
168 t
->run(this->get_workqueue());
169 this->completed(t
, tl
);
172 // Workqueue methods.
174 Workqueue::Workqueue(const General_options
&)
180 completed_condvar_(this->completed_lock_
),
183 // At some point we will select the specific implementation of
184 // Workqueue_runner to use based on the command line options.
185 this->runner_
= new Workqueue_runner_single(this);
188 Workqueue::~Workqueue()
190 assert(this->tasks_
.empty());
191 assert(this->completed_
.empty());
192 assert(this->running_
== 0);
195 // Add a task to the queue.
198 Workqueue::queue(Task
* t
)
200 Hold_lock
hl(this->tasks_lock_
);
201 this->tasks_
.push_back(t
);
204 // Add a task to the front of the queue.
207 Workqueue::queue_front(Task
* t
)
209 Hold_lock
hl(this->tasks_lock_
);
210 this->tasks_
.push_front(t
);
213 // Clear the list of completed tasks. Return whether we cleared
214 // anything. The completed_lock_ must be held when this is called.
217 Workqueue::clear_completed()
219 if (this->completed_
.empty())
223 delete this->completed_
.front();
224 this->completed_
.pop_front();
226 while (!this->completed_
.empty());
230 // Find a runnable task in TASKS, which is non-empty. Return NULL if
231 // none could be found. The tasks_lock_ must be held when this is
232 // called. Sets ALL_BLOCKED if all non-runnable tasks are waiting on
236 Workqueue::find_runnable(Task_list
& tasks
, bool* all_blocked
)
238 Task
* tlast
= tasks
.back();
242 Task
* t
= tasks
.front();
245 Task::Is_runnable_type is_runnable
= t
->is_runnable(this);
246 if (is_runnable
== Task::IS_RUNNABLE
)
249 if (is_runnable
!= Task::IS_BLOCKED
)
250 *all_blocked
= false;
256 // We couldn't find any runnable task. If there are any
257 // completed tasks, free their locks and try again.
260 Hold_lock
hl2(this->completed_lock_
);
262 if (!this->clear_completed())
264 // There had better be some tasks running, or we will
265 // never find a runnable task.
266 assert(this->running_
> 0);
268 // We couldn't find any runnable tasks, and we
269 // couldn't release any locks.
274 // We're going around again, so recompute ALL_BLOCKED.
280 // Process all the tasks on the workqueue. This is the main loop in
281 // the linker. Note that as we process tasks, new tasks will be
294 Hold_lock
hl(this->tasks_lock_
);
296 if (this->tasks_
.empty())
304 t
= this->find_runnable(this->tasks_
, &all_blocked
);
309 // If T != NULL, it is a task we can run.
310 // If T == NULL && empty, then there are no tasks waiting to
311 // be run at this level.
312 // If T == NULL && !empty, then there tasks waiting to be
313 // run at this level, but they are waiting for something to
321 Hold_lock
hl(this->completed_lock_
);
323 // There must be something for us to wait for, or we won't
324 // be able to make progress.
325 assert(this->running_
> 0 || !this->completed_
.empty());
329 this->cleared_blockers_
= 0;
330 this->clear_completed();
331 while (this->cleared_blockers_
== 0)
333 assert(this->running_
> 0);
334 this->completed_condvar_
.wait();
335 this->clear_completed();
340 if (this->running_
> 0)
342 // Wait for a task to finish.
343 this->completed_condvar_
.wait();
345 this->clear_completed();
352 Hold_lock
hl(this->completed_lock_
);
354 // If there are no running tasks, then we are done.
355 if (this->running_
== 0)
357 this->clear_completed();
361 // Wait for a task to finish. Then we have to loop around
362 // again in case it added any new tasks before finishing.
363 this->completed_condvar_
.wait();
364 this->clear_completed();
370 // Run a task. This is always called in the main thread.
373 Workqueue::run(Task
* t
)
376 this->runner_
->run(t
, t
->locks(this));
379 // This is called when a task is completed to put the locks on the
380 // list to be released. We use a list because we only want the locks
381 // to be released in the main thread.
384 Workqueue::completed(Task
* t
, Task_locker
* tl
)
387 Hold_lock
hl(this->completed_lock_
);
388 assert(this->running_
> 0);
390 this->completed_
.push_back(tl
);
391 this->completed_condvar_
.signal();
396 // This is called when the last task for a blocker has completed.
397 // This is always called in the main thread.
400 Workqueue::cleared_blocker()
402 ++this->cleared_blockers_
;
405 } // End namespace gold.