Commit | Line | Data |
---|---|---|
bae7f79e ILT |
1 | // gold-threads.cc -- thread support for gold |
2 | ||
219d1afa | 3 | // Copyright (C) 2006-2018 Free Software Foundation, Inc. |
6cb15b7f ILT |
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 | ||
bae7f79e ILT |
23 | #include "gold.h" |
24 | ||
fe9a4c12 ILT |
25 | #include <cstring> |
26 | ||
bae7f79e ILT |
27 | #ifdef ENABLE_THREADS |
28 | #include <pthread.h> | |
29 | #endif | |
30 | ||
8851ecca | 31 | #include "options.h" |
c7912668 | 32 | #include "parameters.h" |
bae7f79e ILT |
33 | #include "gold-threads.h" |
34 | ||
35 | namespace gold | |
36 | { | |
37 | ||
c7912668 | 38 | class Condvar_impl_nothreads; |
bae7f79e | 39 | |
c7912668 ILT |
40 | // The non-threaded version of Lock_impl. |
41 | ||
42 | class Lock_impl_nothreads : public Lock_impl | |
bae7f79e ILT |
43 | { |
44 | public: | |
c7912668 ILT |
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(); | |
bae7f79e ILT |
83 | |
84 | void acquire(); | |
85 | ||
86 | void release(); | |
87 | ||
88 | private: | |
89 | // This class can not be copied. | |
c7912668 ILT |
90 | Lock_impl_threads(const Lock_impl_threads&); |
91 | Lock_impl_threads& operator=(const Lock_impl_threads&); | |
bae7f79e | 92 | |
c7912668 | 93 | friend class Condvar_impl_threads; |
bae7f79e | 94 | |
bae7f79e | 95 | pthread_mutex_t mutex_; |
bae7f79e ILT |
96 | }; |
97 | ||
c7912668 | 98 | Lock_impl_threads::Lock_impl_threads() |
bae7f79e ILT |
99 | { |
100 | pthread_mutexattr_t attr; | |
c7912668 ILT |
101 | int err = pthread_mutexattr_init(&attr); |
102 | if (err != 0) | |
2ec060b7 | 103 | gold_fatal(_("pthead_mutexattr_init failed: %s"), strerror(err)); |
0f32ea4c | 104 | #ifdef PTHREAD_MUTEX_ADAPTIVE_NP |
2ec060b7 | 105 | err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); |
c7912668 | 106 | if (err != 0) |
2ec060b7 | 107 | gold_fatal(_("pthread_mutexattr_settype failed: %s"), strerror(err)); |
bae7f79e ILT |
108 | #endif |
109 | ||
ca09d69a | 110 | err = pthread_mutex_init(&this->mutex_, &attr); |
c7912668 ILT |
111 | if (err != 0) |
112 | gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err)); | |
bae7f79e | 113 | |
c7912668 ILT |
114 | err = pthread_mutexattr_destroy(&attr); |
115 | if (err != 0) | |
116 | gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(err)); | |
bae7f79e ILT |
117 | } |
118 | ||
c7912668 | 119 | Lock_impl_threads::~Lock_impl_threads() |
bae7f79e | 120 | { |
c7912668 ILT |
121 | int err = pthread_mutex_destroy(&this->mutex_); |
122 | if (err != 0) | |
123 | gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(err)); | |
bae7f79e ILT |
124 | } |
125 | ||
126 | void | |
c7912668 | 127 | Lock_impl_threads::acquire() |
bae7f79e | 128 | { |
c7912668 ILT |
129 | int err = pthread_mutex_lock(&this->mutex_); |
130 | if (err != 0) | |
131 | gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); | |
bae7f79e ILT |
132 | } |
133 | ||
134 | void | |
c7912668 | 135 | Lock_impl_threads::release() |
bae7f79e | 136 | { |
c7912668 ILT |
137 | int err = pthread_mutex_unlock(&this->mutex_); |
138 | if (err != 0) | |
139 | gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); | |
bae7f79e ILT |
140 | } |
141 | ||
c7912668 | 142 | #endif // defined(ENABLE_THREADS) |
bae7f79e | 143 | |
c7912668 | 144 | // Class Lock. |
bae7f79e | 145 | |
c7912668 | 146 | Lock::Lock() |
bae7f79e | 147 | { |
8851ecca | 148 | if (!parameters->options().threads()) |
c7912668 ILT |
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 | } | |
bae7f79e ILT |
158 | } |
159 | ||
c7912668 | 160 | Lock::~Lock() |
bae7f79e | 161 | { |
c7912668 | 162 | delete this->lock_; |
bae7f79e ILT |
163 | } |
164 | ||
c7912668 ILT |
165 | // The non-threaded version of Condvar_impl. |
166 | ||
167 | class Condvar_impl_nothreads : public Condvar_impl | |
bae7f79e | 168 | { |
c7912668 ILT |
169 | public: |
170 | Condvar_impl_nothreads() | |
171 | { } | |
bae7f79e | 172 | |
c7912668 ILT |
173 | ~Condvar_impl_nothreads() |
174 | { } | |
bae7f79e | 175 | |
c7912668 ILT |
176 | void |
177 | wait(Lock_impl* li) | |
178 | { gold_assert(static_cast<Lock_impl_nothreads*>(li)->acquired_); } | |
bae7f79e | 179 | |
c7912668 ILT |
180 | void |
181 | signal() | |
182 | { } | |
bae7f79e | 183 | |
c7912668 ILT |
184 | void |
185 | broadcast() | |
186 | { } | |
187 | }; | |
bae7f79e | 188 | |
c7912668 | 189 | #ifdef ENABLE_THREADS |
bae7f79e | 190 | |
c7912668 | 191 | // The threaded version of Condvar_impl. |
bae7f79e | 192 | |
c7912668 | 193 | class Condvar_impl_threads : public Condvar_impl |
bae7f79e ILT |
194 | { |
195 | public: | |
c7912668 ILT |
196 | Condvar_impl_threads(); |
197 | ~Condvar_impl_threads(); | |
bae7f79e | 198 | |
c7912668 ILT |
199 | void |
200 | wait(Lock_impl*); | |
201 | ||
202 | void | |
203 | signal(); | |
204 | ||
205 | void | |
206 | broadcast(); | |
bae7f79e ILT |
207 | |
208 | private: | |
209 | // This class can not be copied. | |
c7912668 ILT |
210 | Condvar_impl_threads(const Condvar_impl_threads&); |
211 | Condvar_impl_threads& operator=(const Condvar_impl_threads&); | |
bae7f79e | 212 | |
bae7f79e | 213 | pthread_cond_t cond_; |
bae7f79e ILT |
214 | }; |
215 | ||
c7912668 | 216 | Condvar_impl_threads::Condvar_impl_threads() |
bae7f79e | 217 | { |
c7912668 ILT |
218 | int err = pthread_cond_init(&this->cond_, NULL); |
219 | if (err != 0) | |
220 | gold_fatal(_("pthread_cond_init failed: %s"), strerror(err)); | |
bae7f79e ILT |
221 | } |
222 | ||
c7912668 | 223 | Condvar_impl_threads::~Condvar_impl_threads() |
bae7f79e | 224 | { |
c7912668 ILT |
225 | int err = pthread_cond_destroy(&this->cond_); |
226 | if (err != 0) | |
227 | gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(err)); | |
bae7f79e ILT |
228 | } |
229 | ||
230 | void | |
c7912668 | 231 | Condvar_impl_threads::wait(Lock_impl* li) |
bae7f79e | 232 | { |
c7912668 ILT |
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)); | |
bae7f79e ILT |
237 | } |
238 | ||
239 | void | |
c7912668 | 240 | Condvar_impl_threads::signal() |
bae7f79e | 241 | { |
c7912668 ILT |
242 | int err = pthread_cond_signal(&this->cond_); |
243 | if (err != 0) | |
244 | gold_fatal(_("pthread_cond_signal failed: %s"), strerror(err)); | |
bae7f79e ILT |
245 | } |
246 | ||
247 | void | |
c7912668 | 248 | Condvar_impl_threads::broadcast() |
bae7f79e | 249 | { |
c7912668 ILT |
250 | int err = pthread_cond_broadcast(&this->cond_); |
251 | if (err != 0) | |
252 | gold_fatal(_("pthread_cond_broadcast failed: %s"), strerror(err)); | |
bae7f79e ILT |
253 | } |
254 | ||
c7912668 | 255 | #endif // defined(ENABLE_THREADS) |
bae7f79e ILT |
256 | |
257 | // Methods for Condvar class. | |
258 | ||
259 | Condvar::Condvar(Lock& lock) | |
260 | : lock_(lock) | |
261 | { | |
8851ecca | 262 | if (!parameters->options().threads()) |
c7912668 ILT |
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 | } | |
bae7f79e ILT |
272 | } |
273 | ||
274 | Condvar::~Condvar() | |
275 | { | |
276 | delete this->condvar_; | |
277 | } | |
278 | ||
7f055c20 ILT |
279 | #ifdef ENABLE_THREADS |
280 | ||
114dfbe1 ILT |
281 | // Class Once_initialize. This exists to hold a pthread_once_t |
282 | // structure for Once. | |
7f055c20 | 283 | |
114dfbe1 | 284 | class Once_initialize |
7f055c20 ILT |
285 | { |
286 | public: | |
114dfbe1 | 287 | Once_initialize() |
7f055c20 ILT |
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 | ||
114dfbe1 | 300 | #endif // defined(ENABLE_THREADS) |
7f055c20 ILT |
301 | |
302 | #ifdef ENABLE_THREADS | |
303 | ||
114dfbe1 ILT |
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; | |
7f055c20 | 309 | |
114dfbe1 ILT |
310 | // A pointer to Once structure we want to run. Access to this is |
311 | // controlled by once_pointer_control. | |
7f055c20 | 312 | |
114dfbe1 | 313 | static Once* once_pointer; |
7f055c20 | 314 | |
114dfbe1 ILT |
315 | // The argument to pass to the Once structure. Access to this is |
316 | // controlled by once_pointer_control. | |
7f055c20 | 317 | |
114dfbe1 ILT |
318 | static void* once_arg; |
319 | ||
320 | // A routine passed to pthread_once which runs the Once pointer. | |
7f055c20 ILT |
321 | |
322 | extern "C" | |
323 | { | |
324 | ||
325 | static void | |
114dfbe1 | 326 | c_run_once(void) |
7f055c20 | 327 | { |
114dfbe1 | 328 | once_pointer->internal_run(once_arg); |
7f055c20 ILT |
329 | } |
330 | ||
331 | } | |
332 | ||
114dfbe1 | 333 | #endif // defined(ENABLE_THREADS) |
7f055c20 | 334 | |
114dfbe1 | 335 | // Class Once. |
7f055c20 | 336 | |
114dfbe1 | 337 | Once::Once() |
39d9ead7 RM |
338 | : was_run_(false) |
339 | #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |
340 | , was_run_lock_(0) | |
341 | #endif | |
7f055c20 ILT |
342 | { |
343 | #ifndef ENABLE_THREADS | |
344 | this->once_ = NULL; | |
345 | #else | |
114dfbe1 | 346 | this->once_ = new Once_initialize(); |
7f055c20 ILT |
347 | #endif |
348 | } | |
349 | ||
114dfbe1 | 350 | // Run the function once. |
7f055c20 | 351 | |
114dfbe1 ILT |
352 | void |
353 | Once::run_once(void* arg) | |
7f055c20 | 354 | { |
114dfbe1 | 355 | #ifndef ENABLE_THREADS |
7f055c20 | 356 | |
114dfbe1 ILT |
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); | |
7f055c20 | 360 | |
114dfbe1 ILT |
361 | #else // defined(ENABLE_THREADS) |
362 | ||
363 | if (parameters->options_valid() && !parameters->options().threads()) | |
7f055c20 | 364 | { |
114dfbe1 ILT |
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; | |
7f055c20 ILT |
369 | } |
370 | ||
114dfbe1 ILT |
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 | |
7f055c20 ILT |
388 | |
389 | // Since we can't pass parameters to routines called by | |
114dfbe1 ILT |
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. | |
7f055c20 | 393 | |
114dfbe1 | 394 | int err = pthread_mutex_lock(&once_pointer_control); |
7f055c20 ILT |
395 | if (err != 0) |
396 | gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); | |
397 | ||
114dfbe1 ILT |
398 | once_pointer = this; |
399 | once_arg = arg; | |
7f055c20 | 400 | |
114dfbe1 | 401 | err = pthread_once(this->once_->once_control(), c_run_once); |
7f055c20 ILT |
402 | if (err != 0) |
403 | gold_fatal(_("pthread_once failed: %s"), strerror(err)); | |
404 | ||
114dfbe1 ILT |
405 | once_pointer = NULL; |
406 | once_arg = NULL; | |
7f055c20 | 407 | |
114dfbe1 | 408 | err = pthread_mutex_unlock(&once_pointer_control); |
7f055c20 | 409 | if (err != 0) |
9b547ce6 | 410 | gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); |
7f055c20 | 411 | |
114dfbe1 ILT |
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 | } | |
7f055c20 | 441 | |
114dfbe1 | 442 | // Initialize the lock exactly once. |
7f055c20 | 443 | |
114dfbe1 ILT |
444 | void |
445 | Initialize_lock::do_run_once(void*) | |
446 | { | |
447 | *this->pplock_ = new Lock(); | |
7f055c20 ILT |
448 | } |
449 | ||
bae7f79e | 450 | } // End namespace gold. |