]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - gold/workqueue.h
Imported binutils-2.20
[msp430-binutils.git] / gold / workqueue.h
diff --git a/gold/workqueue.h b/gold/workqueue.h
new file mode 100644 (file)
index 0000000..7545224
--- /dev/null
@@ -0,0 +1,295 @@
+// workqueue.h -- the work queue for gold   -*- C++ -*-
+
+// Copyright 2006, 2007, 2008 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)
+  { }
+
+  ~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();
+
+  // 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)