1 // gold-threads.cc -- thread support for gold 2 3 // Copyright (C) 2006-2016 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 #include "gold.h" 24 25 #include <cstring> 26 27 #ifdef ENABLE_THREADS 28 #include <pthread.h> 29 #endif 30 31 #include "options.h" 32 #include "parameters.h" 33 #include "gold-threads.h" 34 35 namespace gold 36 { 37 38 class Condvar_impl_nothreads; 39 40 // The non-threaded version of Lock_impl. 41 42 class Lock_impl_nothreads : public Lock_impl 43 { 44 public: 45 Lock_impl_nothreads() 46 : acquired_(false) 47 { } 48 49 ~Lock_impl_nothreads() 50 { gold_assert(!this->acquired_); } 51 52 void 53 acquire() 54 { 55 gold_assert(!this->acquired_); 56 this->acquired_ = true; 57 } 58 59 void 60 release() 61 { 62 gold_assert(this->acquired_); 63 this->acquired_ = false; 64 } 65 66 private: 67 friend class Condvar_impl_nothreads; 68 69 bool acquired_; 70 }; 71 72 #ifdef ENABLE_THREADS 73 74 class Condvar_impl_threads; 75 76 // The threaded version of Lock_impl. 77 78 class Lock_impl_threads : public Lock_impl 79 { 80 public: 81 Lock_impl_threads(); 82 ~Lock_impl_threads(); 83 84 void acquire(); 85 86 void release(); 87 88 private: 89 // This class can not be copied. 90 Lock_impl_threads(const Lock_impl_threads&); 91 Lock_impl_threads& operator=(const Lock_impl_threads&); 92 93 friend class Condvar_impl_threads; 94 95 pthread_mutex_t mutex_; 96 }; 97 98 Lock_impl_threads::Lock_impl_threads() 99 { 100 pthread_mutexattr_t attr; 101 int err = pthread_mutexattr_init(&attr); 102 if (err != 0) 103 gold_fatal(_("pthead_mutexattr_init failed: %s"), strerror(err)); 104 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP 105 err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); 106 if (err != 0) 107 gold_fatal(_("pthread_mutexattr_settype failed: %s"), strerror(err)); 108 #endif 109 110 err = pthread_mutex_init(&this->mutex_, &attr); 111 if (err != 0) 112 gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err)); 113 114 err = pthread_mutexattr_destroy(&attr); 115 if (err != 0) 116 gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(err)); 117 } 118 119 Lock_impl_threads::~Lock_impl_threads() 120 { 121 int err = pthread_mutex_destroy(&this->mutex_); 122 if (err != 0) 123 gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(err)); 124 } 125 126 void 127 Lock_impl_threads::acquire() 128 { 129 int err = pthread_mutex_lock(&this->mutex_); 130 if (err != 0) 131 gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); 132 } 133 134 void 135 Lock_impl_threads::release() 136 { 137 int err = pthread_mutex_unlock(&this->mutex_); 138 if (err != 0) 139 gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); 140 } 141 142 #endif // defined(ENABLE_THREADS) 143 144 // Class Lock. 145 146 Lock::Lock() 147 { 148 if (!parameters->options().threads()) 149 this->lock_ = new Lock_impl_nothreads; 150 else 151 { 152 #ifdef ENABLE_THREADS 153 this->lock_ = new Lock_impl_threads; 154 #else 155 gold_unreachable(); 156 #endif 157 } 158 } 159 160 Lock::~Lock() 161 { 162 delete this->lock_; 163 } 164 165 // The non-threaded version of Condvar_impl. 166 167 class Condvar_impl_nothreads : public Condvar_impl 168 { 169 public: 170 Condvar_impl_nothreads() 171 { } 172 173 ~Condvar_impl_nothreads() 174 { } 175 176 void 177 wait(Lock_impl* li) 178 { gold_assert(static_cast<Lock_impl_nothreads*>(li)->acquired_); } 179 180 void 181 signal() 182 { } 183 184 void 185 broadcast() 186 { } 187 }; 188 189 #ifdef ENABLE_THREADS 190 191 // The threaded version of Condvar_impl. 192 193 class Condvar_impl_threads : public Condvar_impl 194 { 195 public: 196 Condvar_impl_threads(); 197 ~Condvar_impl_threads(); 198 199 void 200 wait(Lock_impl*); 201 202 void 203 signal(); 204 205 void 206 broadcast(); 207 208 private: 209 // This class can not be copied. 210 Condvar_impl_threads(const Condvar_impl_threads&); 211 Condvar_impl_threads& operator=(const Condvar_impl_threads&); 212 213 pthread_cond_t cond_; 214 }; 215 216 Condvar_impl_threads::Condvar_impl_threads() 217 { 218 int err = pthread_cond_init(&this->cond_, NULL); 219 if (err != 0) 220 gold_fatal(_("pthread_cond_init failed: %s"), strerror(err)); 221 } 222 223 Condvar_impl_threads::~Condvar_impl_threads() 224 { 225 int err = pthread_cond_destroy(&this->cond_); 226 if (err != 0) 227 gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(err)); 228 } 229 230 void 231 Condvar_impl_threads::wait(Lock_impl* li) 232 { 233 Lock_impl_threads* lit = static_cast<Lock_impl_threads*>(li); 234 int err = pthread_cond_wait(&this->cond_, &lit->mutex_); 235 if (err != 0) 236 gold_fatal(_("pthread_cond_wait failed: %s"), strerror(err)); 237 } 238 239 void 240 Condvar_impl_threads::signal() 241 { 242 int err = pthread_cond_signal(&this->cond_); 243 if (err != 0) 244 gold_fatal(_("pthread_cond_signal failed: %s"), strerror(err)); 245 } 246 247 void 248 Condvar_impl_threads::broadcast() 249 { 250 int err = pthread_cond_broadcast(&this->cond_); 251 if (err != 0) 252 gold_fatal(_("pthread_cond_broadcast failed: %s"), strerror(err)); 253 } 254 255 #endif // defined(ENABLE_THREADS) 256 257 // Methods for Condvar class. 258 259 Condvar::Condvar(Lock& lock) 260 : lock_(lock) 261 { 262 if (!parameters->options().threads()) 263 this->condvar_ = new Condvar_impl_nothreads; 264 else 265 { 266 #ifdef ENABLE_THREADS 267 this->condvar_ = new Condvar_impl_threads; 268 #else 269 gold_unreachable(); 270 #endif 271 } 272 } 273 274 Condvar::~Condvar() 275 { 276 delete this->condvar_; 277 } 278 279 #ifdef ENABLE_THREADS 280 281 // Class Once_initialize. This exists to hold a pthread_once_t 282 // structure for Once. 283 284 class Once_initialize 285 { 286 public: 287 Once_initialize() 288 : once_(PTHREAD_ONCE_INIT) 289 { } 290 291 // Return a pointer to the pthread_once_t variable. 292 pthread_once_t* 293 once_control() 294 { return &this->once_; } 295 296 private: 297 pthread_once_t once_; 298 }; 299 300 #endif // defined(ENABLE_THREADS) 301 302 #ifdef ENABLE_THREADS 303 304 // A single lock which controls access to once_pointer. This is used 305 // because we can't pass parameters to functions passed to 306 // pthread_once. 307 308 static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER; 309 310 // A pointer to Once structure we want to run. Access to this is 311 // controlled by once_pointer_control. 312 313 static Once* once_pointer; 314 315 // The argument to pass to the Once structure. Access to this is 316 // controlled by once_pointer_control. 317 318 static void* once_arg; 319 320 // A routine passed to pthread_once which runs the Once pointer. 321 322 extern "C" 323 { 324 325 static void 326 c_run_once(void) 327 { 328 once_pointer->internal_run(once_arg); 329 } 330 331 } 332 333 #endif // defined(ENABLE_THREADS) 334 335 // Class Once. 336 337 Once::Once() 338 : was_run_(false) 339 #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) 340 , was_run_lock_(0) 341 #endif 342 { 343 #ifndef ENABLE_THREADS 344 this->once_ = NULL; 345 #else 346 this->once_ = new Once_initialize(); 347 #endif 348 } 349 350 // Run the function once. 351 352 void 353 Once::run_once(void* arg) 354 { 355 #ifndef ENABLE_THREADS 356 357 // If there is no threads support, we don't need to use pthread_once. 358 if (!this->was_run_) 359 this->internal_run(arg); 360 361 #else // defined(ENABLE_THREADS) 362 363 if (parameters->options_valid() && !parameters->options().threads()) 364 { 365 // If we are not using threads, we don't need to lock. 366 if (!this->was_run_) 367 this->internal_run(arg); 368 return; 369 } 370 371 // If we have the sync builtins, use them to skip the lock if the 372 // value has already been initialized. 373 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 374 while (true) 375 { 376 if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1)) 377 break; 378 } 379 bool was_run = this->was_run_; 380 while (true) 381 { 382 if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0)) 383 break; 384 } 385 if (was_run) 386 return; 387 #endif 388 389 // Since we can't pass parameters to routines called by 390 // pthread_once, we use a static variable: once_pointer. This in 391 // turns means that we need to use a mutex to control access to 392 // once_pointer. 393 394 int err = pthread_mutex_lock(&once_pointer_control); 395 if (err != 0) 396 gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); 397 398 once_pointer = this; 399 once_arg = arg; 400 401 err = pthread_once(this->once_->once_control(), c_run_once); 402 if (err != 0) 403 gold_fatal(_("pthread_once failed: %s"), strerror(err)); 404 405 once_pointer = NULL; 406 once_arg = NULL; 407 408 err = pthread_mutex_unlock(&once_pointer_control); 409 if (err != 0) 410 gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); 411 412 #endif // defined(ENABLE_THREADS) 413 } 414 415 // Actually run the function in the child class. This function will 416 // be run only once. 417 418 void 419 Once::internal_run(void* arg) 420 { 421 this->do_run_once(arg); 422 this->was_run_ = true; 423 } 424 425 // Class Initialize_lock. 426 427 // Initialize the lock. 428 429 bool 430 Initialize_lock::initialize() 431 { 432 // We can't initialize the lock until we have read the options. 433 if (!parameters->options_valid()) 434 return false; 435 else 436 { 437 this->run_once(NULL); 438 return true; 439 } 440 } 441 442 // Initialize the lock exactly once. 443 444 void 445 Initialize_lock::do_run_once(void*) 446 { 447 *this->pplock_ = new Lock(); 448 } 449 450 } // End namespace gold. 451