1 // workqueue-threads.cc -- the threaded workqueue for gold 2 3 // Copyright (C) 2007-2014 Free Software Foundation, Inc. 4 // Written by Ian Lance Taylor <iant (at) 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 38 namespace gold 39 { 40 41 // Class Workqueue_thread represents a single thread. Creating an 42 // instance of this spawns a new thread. 43 44 class 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 75 Workqueue_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 96 Workqueue_thread::~Workqueue_thread() 97 { 98 } 99 100 // Check for an error. 101 102 void 103 Workqueue_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 111 extern "C" 112 void* 113 Workqueue_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 129 Workqueue_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 141 Workqueue_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 149 void 150 Workqueue_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 176 bool 177 Workqueue_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