// workqueue.cc -- the workqueue for gold
+// Copyright 2006, 2007 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.
+
#include "gold.h"
+
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+#endif
+
#include "workqueue.h"
namespace gold
Task_token::~Task_token()
{
- assert(this->readers_ == 0 && this->writer_ == NULL);
+ gold_assert(this->readers_ == 0 && this->writer_ == NULL);
}
bool
Task_token::is_readable() const
{
- assert(!this->is_blocker_);
+ gold_assert(!this->is_blocker_);
return this->writer_ == NULL;
}
void
Task_token::add_reader()
{
- assert(!this->is_blocker_);
- assert(this->is_readable());
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->is_readable());
++this->readers_;
}
void
Task_token::remove_reader()
{
- assert(!this->is_blocker_);
- assert(this->readers_ > 0);
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->readers_ > 0);
--this->readers_;
}
bool
Task_token::is_writable() const
{
- assert(!this->is_blocker_);
+ gold_assert(!this->is_blocker_);
return this->writer_ == NULL && this->readers_ == 0;
}
void
Task_token::add_writer(const Task* t)
{
- assert(!this->is_blocker_);
- assert(this->is_writable());
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->is_writable());
this->writer_ = t;
}
void
Task_token::remove_writer(const Task* t)
{
- assert(!this->is_blocker_);
- assert(this->writer_ == t);
+ gold_assert(!this->is_blocker_);
+ gold_assert(this->writer_ == t);
this->writer_ = NULL;
}
bool
Task_token::has_write_lock(const Task* t)
{
- assert(!this->is_blocker_);
+ gold_assert(!this->is_blocker_);
return this->writer_ == t;
}
if (this->readers_ == 0 && this->writer_ == NULL)
this->is_blocker_ = true;
else
- assert(this->is_blocker_);
+ gold_assert(this->is_blocker_);
++this->readers_;
}
bool
Task_token::remove_blocker()
{
- assert(this->is_blocker_ && this->readers_ > 0);
+ gold_assert(this->is_blocker_ && this->readers_ > 0);
--this->readers_;
return this->readers_ == 0;
}
bool
Task_token::is_blocked() const
{
- assert(this->is_blocker_ || (this->readers_ == 0 && this->writer_ == NULL));
+ gold_assert(this->is_blocker_
+ || (this->readers_ == 0 && this->writer_ == NULL));
return this->readers_ > 0;
}
// We must increment the block count when the task is created and
// put on the queue. This object is created when the task is run,
// so we don't increment the block count here.
- assert(this->token_.is_blocked());
+ gold_assert(this->token_.is_blocked());
}
Task_block_token::~Task_block_token()
{ }
// Run a task. This is always called in the main thread.
- virtual void run(Task*, Task_locker*) = 0;
+ virtual void
+ run(Task*, Task_locker*) = 0;
+
+ // Set the number of threads to use. This is ignored when not using
+ // threads.
+ virtual void
+ set_thread_count(int) = 0;
protected:
// This is called by an implementation when a task is completed.
~Workqueue_runner_single()
{ }
- void run(Task*, Task_locker*);
+ void
+ run(Task*, Task_locker*);
+
+ void
+ set_thread_count(int);
};
void
this->completed(t, tl);
}
+void
+Workqueue_runner_single::set_thread_count(int thread_count)
+{
+ gold_assert(thread_count > 0);
+}
+
// Workqueue methods.
-Workqueue::Workqueue(const General_options&)
+Workqueue::Workqueue(const General_options& options)
: tasks_lock_(),
tasks_(),
completed_lock_(),
completed_condvar_(this->completed_lock_),
cleared_blockers_(0)
{
- // At some point we will select the specific implementation of
- // Workqueue_runner to use based on the command line options.
- this->runner_ = new Workqueue_runner_single(this);
+ bool threads = options.threads();
+#ifndef ENABLE_THREADS
+ threads = false;
+#endif
+ if (!threads)
+ this->runner_ = new Workqueue_runner_single(this);
+ else
+ gold_unreachable();
}
Workqueue::~Workqueue()
{
- assert(this->tasks_.empty());
- assert(this->completed_.empty());
- assert(this->running_ == 0);
+ gold_assert(this->tasks_.empty());
+ gold_assert(this->completed_.empty());
+ gold_assert(this->running_ == 0);
}
+// Add a task to the queue.
+
void
Workqueue::queue(Task* t)
{
this->tasks_.push_back(t);
}
+// Add a task to the front of the queue.
+
+void
+Workqueue::queue_front(Task* t)
+{
+ Hold_lock hl(this->tasks_lock_);
+ this->tasks_.push_front(t);
+}
+
// Clear the list of completed tasks. Return whether we cleared
// anything. The completed_lock_ must be held when this is called.
{
// There had better be some tasks running, or we will
// never find a runnable task.
- assert(this->running_ > 0);
+ gold_assert(this->running_ > 0);
// We couldn't find any runnable tasks, and we
// couldn't release any locks.
// There must be something for us to wait for, or we won't
// be able to make progress.
- assert(this->running_ > 0 || !this->completed_.empty());
+ gold_assert(this->running_ > 0 || !this->completed_.empty());
if (all_blocked)
{
this->clear_completed();
while (this->cleared_blockers_ == 0)
{
- assert(this->running_ > 0);
+ gold_assert(this->running_ > 0);
this->completed_condvar_.wait();
this->clear_completed();
}
{
{
Hold_lock hl(this->completed_lock_);
- assert(this->running_ > 0);
+ gold_assert(this->running_ > 0);
--this->running_;
this->completed_.push_back(tl);
this->completed_condvar_.signal();
++this->cleared_blockers_;
}
+// Set the number of threads to use for the workqueue, if we are using
+// threads.
+
+void
+Workqueue::set_thread_count(int threads)
+{
+ this->runner_->set_thread_count(threads);
+}
+
} // End namespace gold.