1*a9fa9459Szrj // workqueue-threads.cc -- the threaded workqueue for gold 2*a9fa9459Szrj 3*a9fa9459Szrj // Copyright (C) 2007-2016 Free Software Foundation, Inc. 4*a9fa9459Szrj // Written by Ian Lance Taylor <iant@google.com>. 5*a9fa9459Szrj 6*a9fa9459Szrj // This file is part of gold. 7*a9fa9459Szrj 8*a9fa9459Szrj // This program is free software; you can redistribute it and/or modify 9*a9fa9459Szrj // it under the terms of the GNU General Public License as published by 10*a9fa9459Szrj // the Free Software Foundation; either version 3 of the License, or 11*a9fa9459Szrj // (at your option) any later version. 12*a9fa9459Szrj 13*a9fa9459Szrj // This program is distributed in the hope that it will be useful, 14*a9fa9459Szrj // but WITHOUT ANY WARRANTY; without even the implied warranty of 15*a9fa9459Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*a9fa9459Szrj // GNU General Public License for more details. 17*a9fa9459Szrj 18*a9fa9459Szrj // You should have received a copy of the GNU General Public License 19*a9fa9459Szrj // along with this program; if not, write to the Free Software 20*a9fa9459Szrj // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21*a9fa9459Szrj // MA 02110-1301, USA. 22*a9fa9459Szrj 23*a9fa9459Szrj // This file holds the workqueue implementation which may be used when 24*a9fa9459Szrj // using threads. 25*a9fa9459Szrj 26*a9fa9459Szrj #include "gold.h" 27*a9fa9459Szrj 28*a9fa9459Szrj #ifdef ENABLE_THREADS 29*a9fa9459Szrj 30*a9fa9459Szrj #include <cstring> 31*a9fa9459Szrj #include <pthread.h> 32*a9fa9459Szrj 33*a9fa9459Szrj #include "debug.h" 34*a9fa9459Szrj #include "gold-threads.h" 35*a9fa9459Szrj #include "workqueue.h" 36*a9fa9459Szrj #include "workqueue-internal.h" 37*a9fa9459Szrj 38*a9fa9459Szrj namespace gold 39*a9fa9459Szrj { 40*a9fa9459Szrj 41*a9fa9459Szrj // Class Workqueue_thread represents a single thread. Creating an 42*a9fa9459Szrj // instance of this spawns a new thread. 43*a9fa9459Szrj 44*a9fa9459Szrj class Workqueue_thread 45*a9fa9459Szrj { 46*a9fa9459Szrj public: 47*a9fa9459Szrj Workqueue_thread(Workqueue_threader_threadpool*, int thread_number); 48*a9fa9459Szrj 49*a9fa9459Szrj ~Workqueue_thread(); 50*a9fa9459Szrj 51*a9fa9459Szrj private: 52*a9fa9459Szrj // This class can not be copied. 53*a9fa9459Szrj Workqueue_thread(const Workqueue_thread&); 54*a9fa9459Szrj Workqueue_thread& operator=(const Workqueue_thread&); 55*a9fa9459Szrj 56*a9fa9459Szrj // Check for error from a pthread function. 57*a9fa9459Szrj void 58*a9fa9459Szrj check(const char* function, int err) const; 59*a9fa9459Szrj 60*a9fa9459Szrj // A function to pass to pthread_create. This is called with a 61*a9fa9459Szrj // pointer to an instance of this object. 62*a9fa9459Szrj static void* 63*a9fa9459Szrj thread_body(void*); 64*a9fa9459Szrj 65*a9fa9459Szrj // A pointer to the threadpool that this thread is part of. 66*a9fa9459Szrj Workqueue_threader_threadpool* threadpool_; 67*a9fa9459Szrj // The thread number. 68*a9fa9459Szrj int thread_number_; 69*a9fa9459Szrj // The thread ID. 70*a9fa9459Szrj pthread_t tid_; 71*a9fa9459Szrj }; 72*a9fa9459Szrj 73*a9fa9459Szrj // Create the thread in the constructor. 74*a9fa9459Szrj 75*a9fa9459Szrj Workqueue_thread::Workqueue_thread(Workqueue_threader_threadpool* threadpool, 76*a9fa9459Szrj int thread_number) 77*a9fa9459Szrj : threadpool_(threadpool), thread_number_(thread_number) 78*a9fa9459Szrj { 79*a9fa9459Szrj pthread_attr_t attr; 80*a9fa9459Szrj int err = pthread_attr_init(&attr); 81*a9fa9459Szrj this->check("pthread_attr_init", err); 82*a9fa9459Szrj 83*a9fa9459Szrj err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 84*a9fa9459Szrj this->check("pthread_attr_setdetachstate", err); 85*a9fa9459Szrj 86*a9fa9459Szrj err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body, 87*a9fa9459Szrj reinterpret_cast<void*>(this)); 88*a9fa9459Szrj this->check("pthread_create", err); 89*a9fa9459Szrj 90*a9fa9459Szrj err = pthread_attr_destroy(&attr); 91*a9fa9459Szrj this->check("pthread_attr_destroy", err); 92*a9fa9459Szrj } 93*a9fa9459Szrj 94*a9fa9459Szrj // The destructor will be called when the thread is exiting. 95*a9fa9459Szrj 96*a9fa9459Szrj Workqueue_thread::~Workqueue_thread() 97*a9fa9459Szrj { 98*a9fa9459Szrj } 99*a9fa9459Szrj 100*a9fa9459Szrj // Check for an error. 101*a9fa9459Szrj 102*a9fa9459Szrj void 103*a9fa9459Szrj Workqueue_thread::check(const char* function, int err) const 104*a9fa9459Szrj { 105*a9fa9459Szrj if (err != 0) 106*a9fa9459Szrj gold_fatal(_("%s failed: %s"), function, strerror(err)); 107*a9fa9459Szrj } 108*a9fa9459Szrj 109*a9fa9459Szrj // Passed to pthread_create. 110*a9fa9459Szrj 111*a9fa9459Szrj extern "C" 112*a9fa9459Szrj void* 113*a9fa9459Szrj Workqueue_thread::thread_body(void* arg) 114*a9fa9459Szrj { 115*a9fa9459Szrj Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg); 116*a9fa9459Szrj 117*a9fa9459Szrj pwt->threadpool_->process(pwt->thread_number_); 118*a9fa9459Szrj 119*a9fa9459Szrj // Delete the thread object as we exit. 120*a9fa9459Szrj delete pwt; 121*a9fa9459Szrj 122*a9fa9459Szrj return NULL; 123*a9fa9459Szrj } 124*a9fa9459Szrj 125*a9fa9459Szrj // Class Workqueue_threader_threadpool. 126*a9fa9459Szrj 127*a9fa9459Szrj // Constructor. 128*a9fa9459Szrj 129*a9fa9459Szrj Workqueue_threader_threadpool::Workqueue_threader_threadpool( 130*a9fa9459Szrj Workqueue* workqueue) 131*a9fa9459Szrj : Workqueue_threader(workqueue), 132*a9fa9459Szrj check_thread_count_(0), 133*a9fa9459Szrj lock_(), 134*a9fa9459Szrj desired_thread_count_(1), 135*a9fa9459Szrj threads_(1) 136*a9fa9459Szrj { 137*a9fa9459Szrj } 138*a9fa9459Szrj 139*a9fa9459Szrj // Destructor. 140*a9fa9459Szrj 141*a9fa9459Szrj Workqueue_threader_threadpool::~Workqueue_threader_threadpool() 142*a9fa9459Szrj { 143*a9fa9459Szrj // Tell the threads to exit. 144*a9fa9459Szrj this->get_workqueue()->set_thread_count(0); 145*a9fa9459Szrj } 146*a9fa9459Szrj 147*a9fa9459Szrj // Set the thread count. 148*a9fa9459Szrj 149*a9fa9459Szrj void 150*a9fa9459Szrj Workqueue_threader_threadpool::set_thread_count(int thread_count) 151*a9fa9459Szrj { 152*a9fa9459Szrj int create; 153*a9fa9459Szrj { 154*a9fa9459Szrj Hold_lock hl(this->lock_); 155*a9fa9459Szrj 156*a9fa9459Szrj this->desired_thread_count_ = thread_count; 157*a9fa9459Szrj create = this->desired_thread_count_ - this->threads_; 158*a9fa9459Szrj if (create < 0) 159*a9fa9459Szrj this->check_thread_count_ = 1; 160*a9fa9459Szrj } 161*a9fa9459Szrj 162*a9fa9459Szrj if (create > 0) 163*a9fa9459Szrj { 164*a9fa9459Szrj for (int i = 0; i < create; ++i) 165*a9fa9459Szrj { 166*a9fa9459Szrj // Note that threads delete themselves when they exit, so we 167*a9fa9459Szrj // don't keep pointers to them. 168*a9fa9459Szrj new Workqueue_thread(this, this->threads_); 169*a9fa9459Szrj ++this->threads_; 170*a9fa9459Szrj } 171*a9fa9459Szrj } 172*a9fa9459Szrj } 173*a9fa9459Szrj 174*a9fa9459Szrj // Return whether the current thread should be cancelled. 175*a9fa9459Szrj 176*a9fa9459Szrj bool 177*a9fa9459Szrj Workqueue_threader_threadpool::should_cancel_thread(int thread_number) 178*a9fa9459Szrj { 179*a9fa9459Szrj // Fast exit without taking a lock. 180*a9fa9459Szrj if (!this->check_thread_count_) 181*a9fa9459Szrj return false; 182*a9fa9459Szrj 183*a9fa9459Szrj { 184*a9fa9459Szrj Hold_lock hl(this->lock_); 185*a9fa9459Szrj if (thread_number > this->desired_thread_count_) 186*a9fa9459Szrj { 187*a9fa9459Szrj --this->threads_; 188*a9fa9459Szrj if (this->threads_ <= this->desired_thread_count_) 189*a9fa9459Szrj this->check_thread_count_ = 0; 190*a9fa9459Szrj return true; 191*a9fa9459Szrj } 192*a9fa9459Szrj } 193*a9fa9459Szrj 194*a9fa9459Szrj return false; 195*a9fa9459Szrj } 196*a9fa9459Szrj 197*a9fa9459Szrj } // End namespace gold. 198*a9fa9459Szrj 199*a9fa9459Szrj #endif // defined(ENABLE_THREADS) 200