gold-threads.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. // gold-threads.cc -- thread support for gold
  2. // Copyright (C) 2006-2022 Free Software Foundation, Inc.
  3. // Written by Ian Lance Taylor <iant@google.com>.
  4. // This file is part of gold.
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. // MA 02110-1301, USA.
  17. #include "gold.h"
  18. #include <cstring>
  19. #ifdef ENABLE_THREADS
  20. #include <pthread.h>
  21. #endif
  22. #include "options.h"
  23. #include "parameters.h"
  24. #include "gold-threads.h"
  25. namespace gold
  26. {
  27. class Condvar_impl_nothreads;
  28. // The non-threaded version of Lock_impl.
  29. class Lock_impl_nothreads : public Lock_impl
  30. {
  31. public:
  32. Lock_impl_nothreads()
  33. : acquired_(false)
  34. { }
  35. ~Lock_impl_nothreads()
  36. { gold_assert(!this->acquired_); }
  37. void
  38. acquire()
  39. {
  40. gold_assert(!this->acquired_);
  41. this->acquired_ = true;
  42. }
  43. void
  44. release()
  45. {
  46. gold_assert(this->acquired_);
  47. this->acquired_ = false;
  48. }
  49. private:
  50. friend class Condvar_impl_nothreads;
  51. bool acquired_;
  52. };
  53. #ifdef ENABLE_THREADS
  54. class Condvar_impl_threads;
  55. // The threaded version of Lock_impl.
  56. class Lock_impl_threads : public Lock_impl
  57. {
  58. public:
  59. Lock_impl_threads();
  60. ~Lock_impl_threads();
  61. void acquire();
  62. void release();
  63. private:
  64. // This class can not be copied.
  65. Lock_impl_threads(const Lock_impl_threads&);
  66. Lock_impl_threads& operator=(const Lock_impl_threads&);
  67. friend class Condvar_impl_threads;
  68. pthread_mutex_t mutex_;
  69. };
  70. Lock_impl_threads::Lock_impl_threads()
  71. {
  72. pthread_mutexattr_t attr;
  73. int err = pthread_mutexattr_init(&attr);
  74. if (err != 0)
  75. gold_fatal(_("pthead_mutexattr_init failed: %s"), strerror(err));
  76. #ifdef PTHREAD_MUTEX_ADAPTIVE_NP
  77. err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
  78. if (err != 0)
  79. gold_fatal(_("pthread_mutexattr_settype failed: %s"), strerror(err));
  80. #endif
  81. err = pthread_mutex_init(&this->mutex_, &attr);
  82. if (err != 0)
  83. gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err));
  84. err = pthread_mutexattr_destroy(&attr);
  85. if (err != 0)
  86. gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(err));
  87. }
  88. Lock_impl_threads::~Lock_impl_threads()
  89. {
  90. int err = pthread_mutex_destroy(&this->mutex_);
  91. if (err != 0)
  92. gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(err));
  93. }
  94. void
  95. Lock_impl_threads::acquire()
  96. {
  97. int err = pthread_mutex_lock(&this->mutex_);
  98. if (err != 0)
  99. gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err));
  100. }
  101. void
  102. Lock_impl_threads::release()
  103. {
  104. int err = pthread_mutex_unlock(&this->mutex_);
  105. if (err != 0)
  106. gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err));
  107. }
  108. #endif // defined(ENABLE_THREADS)
  109. // Class Lock.
  110. Lock::Lock()
  111. {
  112. if (!parameters->options().threads())
  113. this->lock_ = new Lock_impl_nothreads;
  114. else
  115. {
  116. #ifdef ENABLE_THREADS
  117. this->lock_ = new Lock_impl_threads;
  118. #else
  119. gold_unreachable();
  120. #endif
  121. }
  122. }
  123. Lock::~Lock()
  124. {
  125. delete this->lock_;
  126. }
  127. // The non-threaded version of Condvar_impl.
  128. class Condvar_impl_nothreads : public Condvar_impl
  129. {
  130. public:
  131. Condvar_impl_nothreads()
  132. { }
  133. ~Condvar_impl_nothreads()
  134. { }
  135. void
  136. wait(Lock_impl* li)
  137. { gold_assert(static_cast<Lock_impl_nothreads*>(li)->acquired_); }
  138. void
  139. signal()
  140. { }
  141. void
  142. broadcast()
  143. { }
  144. };
  145. #ifdef ENABLE_THREADS
  146. // The threaded version of Condvar_impl.
  147. class Condvar_impl_threads : public Condvar_impl
  148. {
  149. public:
  150. Condvar_impl_threads();
  151. ~Condvar_impl_threads();
  152. void
  153. wait(Lock_impl*);
  154. void
  155. signal();
  156. void
  157. broadcast();
  158. private:
  159. // This class can not be copied.
  160. Condvar_impl_threads(const Condvar_impl_threads&);
  161. Condvar_impl_threads& operator=(const Condvar_impl_threads&);
  162. pthread_cond_t cond_;
  163. };
  164. Condvar_impl_threads::Condvar_impl_threads()
  165. {
  166. int err = pthread_cond_init(&this->cond_, NULL);
  167. if (err != 0)
  168. gold_fatal(_("pthread_cond_init failed: %s"), strerror(err));
  169. }
  170. Condvar_impl_threads::~Condvar_impl_threads()
  171. {
  172. int err = pthread_cond_destroy(&this->cond_);
  173. if (err != 0)
  174. gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(err));
  175. }
  176. void
  177. Condvar_impl_threads::wait(Lock_impl* li)
  178. {
  179. Lock_impl_threads* lit = static_cast<Lock_impl_threads*>(li);
  180. int err = pthread_cond_wait(&this->cond_, &lit->mutex_);
  181. if (err != 0)
  182. gold_fatal(_("pthread_cond_wait failed: %s"), strerror(err));
  183. }
  184. void
  185. Condvar_impl_threads::signal()
  186. {
  187. int err = pthread_cond_signal(&this->cond_);
  188. if (err != 0)
  189. gold_fatal(_("pthread_cond_signal failed: %s"), strerror(err));
  190. }
  191. void
  192. Condvar_impl_threads::broadcast()
  193. {
  194. int err = pthread_cond_broadcast(&this->cond_);
  195. if (err != 0)
  196. gold_fatal(_("pthread_cond_broadcast failed: %s"), strerror(err));
  197. }
  198. #endif // defined(ENABLE_THREADS)
  199. // Methods for Condvar class.
  200. Condvar::Condvar(Lock& lock)
  201. : lock_(lock)
  202. {
  203. if (!parameters->options().threads())
  204. this->condvar_ = new Condvar_impl_nothreads;
  205. else
  206. {
  207. #ifdef ENABLE_THREADS
  208. this->condvar_ = new Condvar_impl_threads;
  209. #else
  210. gold_unreachable();
  211. #endif
  212. }
  213. }
  214. Condvar::~Condvar()
  215. {
  216. delete this->condvar_;
  217. }
  218. #ifdef ENABLE_THREADS
  219. // Class Once_initialize. This exists to hold a pthread_once_t
  220. // structure for Once.
  221. class Once_initialize
  222. {
  223. public:
  224. Once_initialize()
  225. : once_(PTHREAD_ONCE_INIT)
  226. { }
  227. // Return a pointer to the pthread_once_t variable.
  228. pthread_once_t*
  229. once_control()
  230. { return &this->once_; }
  231. private:
  232. pthread_once_t once_;
  233. };
  234. #endif // defined(ENABLE_THREADS)
  235. #ifdef ENABLE_THREADS
  236. // A single lock which controls access to once_pointer. This is used
  237. // because we can't pass parameters to functions passed to
  238. // pthread_once.
  239. static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER;
  240. // A pointer to Once structure we want to run. Access to this is
  241. // controlled by once_pointer_control.
  242. static Once* once_pointer;
  243. // The argument to pass to the Once structure. Access to this is
  244. // controlled by once_pointer_control.
  245. static void* once_arg;
  246. // A routine passed to pthread_once which runs the Once pointer.
  247. extern "C"
  248. {
  249. static void
  250. c_run_once(void)
  251. {
  252. once_pointer->internal_run(once_arg);
  253. }
  254. }
  255. #endif // defined(ENABLE_THREADS)
  256. // Class Once.
  257. Once::Once()
  258. : was_run_(false)
  259. #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
  260. , was_run_lock_(0)
  261. #endif
  262. {
  263. #ifndef ENABLE_THREADS
  264. this->once_ = NULL;
  265. #else
  266. this->once_ = new Once_initialize();
  267. #endif
  268. }
  269. // Run the function once.
  270. void
  271. Once::run_once(void* arg)
  272. {
  273. #ifndef ENABLE_THREADS
  274. // If there is no threads support, we don't need to use pthread_once.
  275. if (!this->was_run_)
  276. this->internal_run(arg);
  277. #else // defined(ENABLE_THREADS)
  278. if (parameters->options_valid() && !parameters->options().threads())
  279. {
  280. // If we are not using threads, we don't need to lock.
  281. if (!this->was_run_)
  282. this->internal_run(arg);
  283. return;
  284. }
  285. // If we have the sync builtins, use them to skip the lock if the
  286. // value has already been initialized.
  287. #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
  288. while (true)
  289. {
  290. if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1))
  291. break;
  292. }
  293. bool was_run = this->was_run_;
  294. while (true)
  295. {
  296. if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0))
  297. break;
  298. }
  299. if (was_run)
  300. return;
  301. #endif
  302. // Since we can't pass parameters to routines called by
  303. // pthread_once, we use a static variable: once_pointer. This in
  304. // turns means that we need to use a mutex to control access to
  305. // once_pointer.
  306. int err = pthread_mutex_lock(&once_pointer_control);
  307. if (err != 0)
  308. gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err));
  309. once_pointer = this;
  310. once_arg = arg;
  311. err = pthread_once(this->once_->once_control(), c_run_once);
  312. if (err != 0)
  313. gold_fatal(_("pthread_once failed: %s"), strerror(err));
  314. once_pointer = NULL;
  315. once_arg = NULL;
  316. err = pthread_mutex_unlock(&once_pointer_control);
  317. if (err != 0)
  318. gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err));
  319. #endif // defined(ENABLE_THREADS)
  320. }
  321. // Actually run the function in the child class. This function will
  322. // be run only once.
  323. void
  324. Once::internal_run(void* arg)
  325. {
  326. this->do_run_once(arg);
  327. this->was_run_ = true;
  328. }
  329. // Class Initialize_lock.
  330. // Initialize the lock.
  331. bool
  332. Initialize_lock::initialize()
  333. {
  334. // We can't initialize the lock until we have read the options.
  335. if (!parameters->options_valid())
  336. return false;
  337. else
  338. {
  339. this->run_once(NULL);
  340. return true;
  341. }
  342. }
  343. // Initialize the lock exactly once.
  344. void
  345. Initialize_lock::do_run_once(void*)
  346. {
  347. *this->pplock_ = new Lock();
  348. }
  349. } // End namespace gold.