X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=gold%2Fworkqueue-threads.cc;fp=gold%2Fworkqueue-threads.cc;h=60d4adcbb3a579b4d74628686d6b63cd42c7b5d1;hp=0000000000000000000000000000000000000000;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/gold/workqueue-threads.cc b/gold/workqueue-threads.cc new file mode 100644 index 0000000..60d4adc --- /dev/null +++ b/gold/workqueue-threads.cc @@ -0,0 +1,198 @@ +// workqueue-threads.cc -- the threaded workqueue for gold + +// Copyright 2007, 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// This file holds the workqueue implementation which may be used when +// using threads. + +#include "gold.h" + +#ifdef ENABLE_THREADS + +#include +#include + +#include "debug.h" +#include "gold-threads.h" +#include "workqueue.h" +#include "workqueue-internal.h" + +namespace gold +{ + +// Class Workqueue_thread represents a single thread. Creating an +// instance of this spawns a new thread. + +class Workqueue_thread +{ + public: + Workqueue_thread(Workqueue_threader_threadpool*, int thread_number); + + ~Workqueue_thread(); + + private: + // This class can not be copied. + Workqueue_thread(const Workqueue_thread&); + Workqueue_thread& operator=(const Workqueue_thread&); + + // Check for error from a pthread function. + void + check(const char* function, int err) const; + + // A function to pass to pthread_create. This is called with a + // pointer to an instance of this object. + static void* + thread_body(void*); + + // A pointer to the threadpool that this thread is part of. + 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_threader_threadpool* threadpool, + int thread_number) + : threadpool_(threadpool), thread_number_(thread_number) +{ + pthread_attr_t attr; + int err = pthread_attr_init(&attr); + this->check("pthread_attr_init", err); + + err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + this->check("pthread_attr_setdetachstate", err); + + err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body, + reinterpret_cast(this)); + this->check("pthread_create", err); + + err = pthread_attr_destroy(&attr); + this->check("pthread_attr_destroy", err); +} + +// The destructor will be called when the thread is exiting. + +Workqueue_thread::~Workqueue_thread() +{ +} + +// Check for an error. + +void +Workqueue_thread::check(const char* function, int err) const +{ + if (err != 0) + gold_fatal(_("%s failed: %s"), function, strerror(err)); +} + +// Passed to pthread_create. + +extern "C" +void* +Workqueue_thread::thread_body(void* arg) +{ + Workqueue_thread* pwt = reinterpret_cast(arg); + + pwt->threadpool_->process(pwt->thread_number_); + + // Delete the thread object as we exit. + delete pwt; + + return NULL; +} + +// Class Workqueue_threader_threadpool. + +// Constructor. + +Workqueue_threader_threadpool::Workqueue_threader_threadpool( + Workqueue* workqueue) + : Workqueue_threader(workqueue), + check_thread_count_(0), + lock_(), + desired_thread_count_(1), + threads_(1) +{ +} + +// Destructor. + +Workqueue_threader_threadpool::~Workqueue_threader_threadpool() +{ + // Tell the threads to exit. + this->get_workqueue()->set_thread_count(0); +} + +// Set the thread count. + +void +Workqueue_threader_threadpool::set_thread_count(int thread_count) +{ + int create; + { + Hold_lock hl(this->lock_); + + this->desired_thread_count_ = thread_count; + create = this->desired_thread_count_ - this->threads_; + if (create < 0) + this->check_thread_count_ = 1; + } + + if (create > 0) + { + 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_; + } + } +} + +// Return whether the current thread should be cancelled. + +bool +Workqueue_threader_threadpool::should_cancel_thread() +{ + // Fast exit without taking a lock. + if (!this->check_thread_count_) + return false; + + { + Hold_lock hl(this->lock_); + if (this->threads_ > this->desired_thread_count_) + { + --this->threads_; + return true; + } + this->check_thread_count_ = 0; + } + + return false; +} + +} // End namespace gold. + +#endif // defined(ENABLE_THREADS)