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