X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fworkqueue-threads.cc;h=f4fa370208c0f6300aa17e8975253099393255cf;hb=4162bb66c684478bfd0f6f0e121c25b6830d8191;hp=a4f347de5dee4ae79ef1c630e37dbec1c7ace6c6;hpb=c79126688f8211ab17a893c5e80b09811d424fc1;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/workqueue-threads.cc b/gold/workqueue-threads.cc index a4f347de5d..f4fa370208 100644 --- a/gold/workqueue-threads.cc +++ b/gold/workqueue-threads.cc @@ -1,6 +1,6 @@ // workqueue-threads.cc -- the threaded workqueue for gold -// Copyright 2007 Free Software Foundation, Inc. +// Copyright (C) 2007-2017 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -44,7 +44,7 @@ namespace gold class Workqueue_thread { public: - Workqueue_thread(Workqueue_runner_threadpool*); + Workqueue_thread(Workqueue_threader_threadpool*, int thread_number); ~Workqueue_thread(); @@ -62,20 +62,19 @@ class Workqueue_thread static void* thread_body(void*); - // The main loop of the thread. - void - run(); - // A pointer to the threadpool that this thread is part of. - Workqueue_runner_threadpool* threadpool_; + Workqueue_threader_threadpool* threadpool_; + // The thread number. + int thread_number_; // The thread ID. pthread_t tid_; }; // Create the thread in the constructor. -Workqueue_thread::Workqueue_thread(Workqueue_runner_threadpool* threadpool) - : threadpool_(threadpool) +Workqueue_thread::Workqueue_thread(Workqueue_threader_threadpool* threadpool, + int thread_number) + : threadpool_(threadpool), thread_number_(thread_number) { pthread_attr_t attr; int err = pthread_attr_init(&attr); @@ -114,7 +113,8 @@ void* Workqueue_thread::thread_body(void* arg) { Workqueue_thread* pwt = reinterpret_cast(arg); - pwt->run(); + + pwt->threadpool_->process(pwt->thread_number_); // Delete the thread object as we exit. delete pwt; @@ -122,143 +122,76 @@ Workqueue_thread::thread_body(void* arg) return NULL; } -// This is the main loop of a worker thread. It picks up a new Task -// and runs it. - -void -Workqueue_thread::run() -{ - Workqueue_runner_threadpool* threadpool = this->threadpool_; - Workqueue* workqueue = threadpool->get_workqueue(); - - while (true) - { - Task* t; - Task_locker* tl; - if (!threadpool->get_next(&t, &tl)) - return; - - gold_debug(DEBUG_TASK, "running task %s", t->name().c_str()); - - t->run(workqueue); - threadpool->thread_completed(t, tl); - } -} - -// Class Workqueue_runner_threadpool. +// Class Workqueue_threader_threadpool. // Constructor. -Workqueue_runner_threadpool::Workqueue_runner_threadpool(Workqueue* workqueue) - : Workqueue_runner(workqueue), - desired_thread_count_(0), +Workqueue_threader_threadpool::Workqueue_threader_threadpool( + Workqueue* workqueue) + : Workqueue_threader(workqueue), + check_thread_count_(0), lock_(), - actual_thread_count_(0), - running_thread_count_(0), - task_queue_(), - task_queue_condvar_(this->lock_) + desired_thread_count_(1), + threads_(1) { } // Destructor. -Workqueue_runner_threadpool::~Workqueue_runner_threadpool() +Workqueue_threader_threadpool::~Workqueue_threader_threadpool() { // Tell the threads to exit. - Hold_lock hl(this->lock_); - this->desired_thread_count_ = 0; - this->task_queue_condvar_.broadcast(); -} - -// Run a task. This doesn't actually run the task: it pushes on the -// queue of tasks to run. This is always called in the main thread. - -void -Workqueue_runner_threadpool::run(Task* t, Task_locker* tl) -{ - Hold_lock hl(this->lock_); - - // This is where we create threads as needed, subject to the limit - // of the desired thread count. - gold_assert(this->desired_thread_count_ > 0); - gold_assert(this->actual_thread_count_ >= this->running_thread_count_); - if (this->actual_thread_count_ == this->running_thread_count_ - && this->actual_thread_count_ < this->desired_thread_count_) - { - // Note that threads delete themselves when they exit, so we - // don't keep pointers to them. - new Workqueue_thread(this); - ++this->actual_thread_count_; - } - - this->task_queue_.push(std::make_pair(t, tl)); - this->task_queue_condvar_.signal(); + this->get_workqueue()->set_thread_count(0); } -// Set the thread count. This is only called in the main thread, and -// is only called when there are no threads running. +// Set the thread count. void -Workqueue_runner_threadpool::set_thread_count(int thread_count) -{ - gold_assert(this->running_thread_count_ <= 1); - gold_assert(thread_count > 0); - this->desired_thread_count_ = thread_count; -} - -// Get the next task to run. This is always called by an instance of -// Workqueue_thread, and is never called in the main thread. It -// returns false if the calling thread should exit. - -bool -Workqueue_runner_threadpool::get_next(Task** pt, Task_locker** ptl) +Workqueue_threader_threadpool::set_thread_count(int thread_count) { - Hold_lock hl(this->lock_); - - // This is where we destroy threads, by telling them to exit. - gold_assert(this->actual_thread_count_ > this->running_thread_count_); - if (this->actual_thread_count_ > this->desired_thread_count_) - { - --this->actual_thread_count_; - return false; - } + int create; + { + Hold_lock hl(this->lock_); - while (this->task_queue_.empty() && this->desired_thread_count_ > 0) - { - // Wait for a new task to become available. - this->task_queue_condvar_.wait(); - } + this->desired_thread_count_ = thread_count; + create = this->desired_thread_count_ - this->threads_; + if (create < 0) + this->check_thread_count_ = 1; + } - // Check whether we are exiting. - if (this->desired_thread_count_ == 0) + if (create > 0) { - gold_assert(this->actual_thread_count_ > 0); - --this->actual_thread_count_; - return false; + for (int i = 0; i < create; ++i) + { + // Note that threads delete themselves when they exit, so we + // don't keep pointers to them. + new Workqueue_thread(this, this->threads_); + ++this->threads_; + } } - - *pt = this->task_queue_.front().first; - *ptl = this->task_queue_.front().second; - this->task_queue_.pop(); - - ++this->running_thread_count_; - - return true; } -// This is called when a thread completes its task. +// Return whether the current thread should be cancelled. -void -Workqueue_runner_threadpool::thread_completed(Task* t, Task_locker* tl) +bool +Workqueue_threader_threadpool::should_cancel_thread(int thread_number) { + // Fast exit without taking a lock. + if (!this->check_thread_count_) + return false; + { Hold_lock hl(this->lock_); - gold_assert(this->actual_thread_count_ > 0); - gold_assert(this->running_thread_count_ > 0); - --this->running_thread_count_; + if (thread_number > this->desired_thread_count_) + { + --this->threads_; + if (this->threads_ <= this->desired_thread_count_) + this->check_thread_count_ = 0; + return true; + } } - this->completed(t, tl); + return false; } } // End namespace gold.