123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- // workqueue.h -- the work queue for gold -*- C++ -*-
- // Copyright (C) 2006-2015 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)
|