1 // gold-threads.cc -- thread support for gold 2 3 // Copyright (C) 2006-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 #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_mutextattr_init failed: %s"), strerror(err)); 104 #ifdef PTHREAD_MUTEX_ADAPTIVE_NP 105 err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); 106 if (err != 0) 107 gold_fatal(_("pthread_mutextattr_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 #if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) 289 : once_(PTHREAD_ONCE_INIT) 290 { } 291 #else 292 // In Drawin PTHREAD_ONCE_INIT is {0x30B1BCBA, {0}} and the GCC < 4.4 doesn't support 293 // extended initializer list as above */ 294 { 295 pthread_once_t once_2 = PTHREAD_ONCE_INIT; 296 once_ = once_2; 297 } 298 #endif 299 300 // Return a pointer to the pthread_once_t variable. 301 pthread_once_t* 302 once_control() 303 { return &this->once_; } 304 305 private: 306 pthread_once_t once_; 307 }; 308 309 #endif // defined(ENABLE_THREADS) 310 311 #ifdef ENABLE_THREADS 312 313 // A single lock which controls access to once_pointer. This is used 314 // because we can't pass parameters to functions passed to 315 // pthread_once. 316 317 static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER; 318 319 // A pointer to Once structure we want to run. Access to this is 320 // controlled by once_pointer_control. 321 322 static Once* once_pointer; 323 324 // The argument to pass to the Once structure. Access to this is 325 // controlled by once_pointer_control. 326 327 static void* once_arg; 328 329 // A routine passed to pthread_once which runs the Once pointer. 330 331 extern "C" 332 { 333 334 static void 335 c_run_once(void) 336 { 337 once_pointer->internal_run(once_arg); 338 } 339 340 } 341 342 #endif // defined(ENABLE_THREADS) 343 344 // Class Once. 345 346 Once::Once() 347 : was_run_(false) 348 #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) 349 , was_run_lock_(0) 350 #endif 351 { 352 #ifndef ENABLE_THREADS 353 this->once_ = NULL; 354 #else 355 this->once_ = new Once_initialize(); 356 #endif 357 } 358 359 // Run the function once. 360 361 void 362 Once::run_once(void* arg) 363 { 364 #ifndef ENABLE_THREADS 365 366 // If there is no threads support, we don't need to use pthread_once. 367 if (!this->was_run_) 368 this->internal_run(arg); 369 370 #else // defined(ENABLE_THREADS) 371 372 if (parameters->options_valid() && !parameters->options().threads()) 373 { 374 // If we are not using threads, we don't need to lock. 375 if (!this->was_run_) 376 this->internal_run(arg); 377 return; 378 } 379 380 // If we have the sync builtins, use them to skip the lock if the 381 // value has already been initialized. 382 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 383 while (true) 384 { 385 if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1)) 386 break; 387 } 388 bool was_run = this->was_run_; 389 while (true) 390 { 391 if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0)) 392 break; 393 } 394 if (was_run) 395 return; 396 #endif 397 398 // Since we can't pass parameters to routines called by 399 // pthread_once, we use a static variable: once_pointer. This in 400 // turns means that we need to use a mutex to control access to 401 // once_pointer. 402 403 int err = pthread_mutex_lock(&once_pointer_control); 404 if (err != 0) 405 gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); 406 407 once_pointer = this; 408 once_arg = arg; 409 410 err = pthread_once(this->once_->once_control(), c_run_once); 411 if (err != 0) 412 gold_fatal(_("pthread_once failed: %s"), strerror(err)); 413 414 once_pointer = NULL; 415 once_arg = NULL; 416 417 err = pthread_mutex_unlock(&once_pointer_control); 418 if (err != 0) 419 gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); 420 421 #endif // defined(ENABLE_THREADS) 422 } 423 424 // Actually run the function in the child class. This function will 425 // be run only once. 426 427 void 428 Once::internal_run(void* arg) 429 { 430 this->do_run_once(arg); 431 this->was_run_ = true; 432 } 433 434 // Class Initialize_lock. 435 436 // Initialize the lock. 437 438 bool 439 Initialize_lock::initialize() 440 { 441 // We can't initialize the lock until we have read the options. 442 if (!parameters->options_valid()) 443 return false; 444 else 445 { 446 this->run_once(NULL); 447 return true; 448 } 449 } 450 451 // Initialize the lock exactly once. 452 453 void 454 Initialize_lock::do_run_once(void*) 455 { 456 *this->pplock_ = new Lock(); 457 } 458 459 } // End namespace gold. 460