You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
7.4 KiB
295 lines
7.4 KiB
// workqueue.h -- the work queue for gold -*- C++ -*- |
|
|
|
// Copyright (C) 2006-2014 Free Software Foundation, Inc. |
|
// Written by Ian Lance Taylor <iant@google.com>. |
|
|
|
// This file is part of gold. |
|
|
|
// This program is free software; you can redistribute it and/or modify |
|
// it under the terms of the GNU General Public License as published by |
|
// the Free Software Foundation; either version 3 of the License, or |
|
// (at your option) any later version. |
|
|
|
// This program is distributed in the hope that it will be useful, |
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
// GNU General Public License for more details. |
|
|
|
// You should have received a copy of the GNU General Public License |
|
// along with this program; if not, write to the Free Software |
|
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
|
// MA 02110-1301, USA. |
|
|
|
// After processing the command line, everything the linker does is |
|
// driven from a work queue. This permits us to parallelize the |
|
// linker where possible. |
|
|
|
#ifndef GOLD_WORKQUEUE_H |
|
#define GOLD_WORKQUEUE_H |
|
|
|
#include <string> |
|
|
|
#include "gold-threads.h" |
|
#include "token.h" |
|
|
|
namespace gold |
|
{ |
|
|
|
class General_options; |
|
class Workqueue; |
|
|
|
// The superclass for tasks to be placed on the workqueue. Each |
|
// specific task class will inherit from this one. |
|
|
|
class Task |
|
{ |
|
public: |
|
Task() |
|
: list_next_(NULL), name_(), should_run_soon_(false) |
|
{ } |
|
virtual ~Task() |
|
{ } |
|
|
|
// Check whether the Task can be run now. This method is only |
|
// called with the workqueue lock held. If the Task can run, this |
|
// returns NULL. Otherwise it returns a pointer to a token which |
|
// must be released before the Task can run. |
|
virtual Task_token* |
|
is_runnable() = 0; |
|
|
|
// Lock all the resources required by the Task, and store the locks |
|
// in a Task_locker. This method does not need to do anything if no |
|
// locks are required. This method is only called with the |
|
// workqueue lock held. |
|
virtual void |
|
locks(Task_locker*) = 0; |
|
|
|
// Run the task. |
|
virtual void |
|
run(Workqueue*) = 0; |
|
|
|
// Return whether this task should run soon. |
|
bool |
|
should_run_soon() const |
|
{ return this->should_run_soon_; } |
|
|
|
// Note that this task should run soon. |
|
void |
|
set_should_run_soon() |
|
{ this->should_run_soon_ = true; } |
|
|
|
// Get the next Task on the list of Tasks. Called by Task_list. |
|
Task* |
|
list_next() const |
|
{ return this->list_next_; } |
|
|
|
// Set the next Task on the list of Tasks. Called by Task_list. |
|
void |
|
set_list_next(Task* t) |
|
{ |
|
gold_assert(this->list_next_ == NULL); |
|
this->list_next_ = t; |
|
} |
|
|
|
// Clear the next Task on the list of Tasks. Called by Task_list. |
|
void |
|
clear_list_next() |
|
{ this->list_next_ = NULL; } |
|
|
|
// Return the name of the Task. This is only used for debugging |
|
// purposes. |
|
const std::string& |
|
name() |
|
{ |
|
if (this->name_.empty()) |
|
this->name_ = this->get_name(); |
|
return this->name_; |
|
} |
|
|
|
protected: |
|
// Get the name of the task. This must be implemented by the child |
|
// class. |
|
virtual std::string |
|
get_name() const = 0; |
|
|
|
private: |
|
// Tasks may not be copied. |
|
Task(const Task&); |
|
Task& operator=(const Task&); |
|
|
|
// If this Task is on a list, this is a pointer to the next Task on |
|
// the list. We use this simple list structure rather than building |
|
// a container, in order to avoid memory allocation while holding |
|
// the Workqueue lock. |
|
Task* list_next_; |
|
// Task name, for debugging purposes. |
|
std::string name_; |
|
// Whether this Task should be executed soon. This is used for |
|
// Tasks which can be run after some data is read. |
|
bool should_run_soon_; |
|
}; |
|
|
|
// An interface for Task_function. This is a convenience class to run |
|
// a single function. |
|
|
|
class Task_function_runner |
|
{ |
|
public: |
|
virtual ~Task_function_runner() |
|
{ } |
|
|
|
virtual void |
|
run(Workqueue*, const Task*) = 0; |
|
}; |
|
|
|
// A simple task which waits for a blocker and then runs a function. |
|
|
|
class Task_function : public Task |
|
{ |
|
public: |
|
// RUNNER and BLOCKER should be allocated using new, and will be |
|
// deleted after the task runs. |
|
Task_function(Task_function_runner* runner, Task_token* blocker, |
|
const char* name) |
|
: runner_(runner), blocker_(blocker), name_(name) |
|
{ gold_assert(blocker != NULL); } |
|
|
|
~Task_function() |
|
{ |
|
delete this->runner_; |
|
delete this->blocker_; |
|
} |
|
|
|
// The standard task methods. |
|
|
|
// Wait until the task is unblocked. |
|
Task_token* |
|
is_runnable() |
|
{ return this->blocker_->is_blocked() ? this->blocker_ : NULL; } |
|
|
|
// This type of task does not normally hold any locks. |
|
virtual void |
|
locks(Task_locker*) |
|
{ } |
|
|
|
// Run the action. |
|
void |
|
run(Workqueue* workqueue) |
|
{ this->runner_->run(workqueue, this); } |
|
|
|
// The debugging name. |
|
std::string |
|
get_name() const |
|
{ return this->name_; } |
|
|
|
private: |
|
Task_function(const Task_function&); |
|
Task_function& operator=(const Task_function&); |
|
|
|
Task_function_runner* runner_; |
|
Task_token* blocker_; |
|
const char* name_; |
|
}; |
|
|
|
// The workqueue itself. |
|
|
|
class Workqueue_threader; |
|
|
|
class Workqueue |
|
{ |
|
public: |
|
Workqueue(const General_options&); |
|
~Workqueue(); |
|
|
|
// Add a new task to the work queue. |
|
void |
|
queue(Task*); |
|
|
|
// Add a new task to the work queue which should run soon. If the |
|
// task is ready, it will be run before any tasks added using |
|
// queue(). |
|
void |
|
queue_soon(Task*); |
|
|
|
// Add a new task to the work queue which should run next if it is |
|
// ready. |
|
void |
|
queue_next(Task*); |
|
|
|
// Process all the tasks on the work queue. This function runs |
|
// until all tasks have completed. The argument is the thread |
|
// number, used only for debugging. |
|
void |
|
process(int); |
|
|
|
// Set the desired thread count--the number of threads we want to |
|
// have running. |
|
void |
|
set_thread_count(int); |
|
|
|
// Add a new blocker to an existing Task_token. This must be done |
|
// with the workqueue lock held. This should not be done routinely, |
|
// only in special circumstances. |
|
void |
|
add_blocker(Task_token*); |
|
|
|
private: |
|
// This class can not be copied. |
|
Workqueue(const Workqueue&); |
|
Workqueue& operator=(const Workqueue&); |
|
|
|
// Add a task to a queue. |
|
void |
|
add_to_queue(Task_list* queue, Task* t, bool front); |
|
|
|
// Find a runnable task, or wait for one. |
|
Task* |
|
find_runnable_or_wait(int thread_number); |
|
|
|
// Find a runnable task. |
|
Task* |
|
find_runnable(); |
|
|
|
// Find a runnable task in a list. |
|
Task* |
|
find_runnable_in_list(Task_list*); |
|
|
|
// Find an run a task. |
|
bool |
|
find_and_run_task(int); |
|
|
|
// Release the locks for a Task. Return the next Task to run. |
|
Task* |
|
release_locks(Task*, Task_locker*); |
|
|
|
// Store T into *PRET, or queue it as appropriate. |
|
bool |
|
return_or_queue(Task* t, bool is_blocker, Task** pret); |
|
|
|
// Return whether to cancel this thread. |
|
bool |
|
should_cancel_thread(int thread_number); |
|
|
|
// Master Workqueue lock. This controls access to the following |
|
// member variables. |
|
Lock lock_; |
|
// List of tasks to execute soon. |
|
Task_list first_tasks_; |
|
// List of tasks to execute after the ones in first_tasks_. |
|
Task_list tasks_; |
|
// Number of tasks currently running. |
|
int running_; |
|
// Number of tasks waiting for a lock to release. |
|
int waiting_; |
|
// Condition variable associated with lock_. This is signalled when |
|
// there may be a new Task to execute. |
|
Condvar condvar_; |
|
|
|
// The threading implementation. This is set at construction time |
|
// and not changed thereafter. |
|
Workqueue_threader* threader_; |
|
}; |
|
|
|
} // End namespace gold. |
|
|
|
#endif // !defined(GOLD_WORKQUEUE_H)
|
|
|