Commit | Line | Data |
---|---|---|
bae7f79e ILT |
1 | // gold-threads.cc -- thread support for gold |
2 | ||
ebdbb458 | 3 | // Copyright 2006, 2007, 2008 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) | |
103 | gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(err)); | |
bae7f79e | 104 | #ifdef PTHREAD_MUTEXT_ADAPTIVE_NP |
c7912668 ILT |
105 | err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); |
106 | if (err != 0) | |
107 | gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(err)); | |
bae7f79e ILT |
108 | #endif |
109 | ||
c7912668 ILT |
110 | err = pthread_mutex_init (&this->mutex_, &attr); |
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 | ||
281 | // Class Initialize_lock_once. This exists to hold a pthread_once_t | |
282 | // structure for Initialize_lock. | |
283 | ||
284 | class Initialize_lock_once | |
285 | { | |
286 | public: | |
287 | Initialize_lock_once() | |
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 initialize_lock_pointer. | |
305 | // This is used because we can't pass parameters to functions passed | |
306 | // to pthread_once. | |
307 | ||
308 | static pthread_mutex_t initialize_lock_control = PTHREAD_MUTEX_INITIALIZER; | |
309 | ||
310 | // A pointer to a pointer to the lock which we need to initialize | |
22fd9730 | 311 | // once. Access to this is controlled by initialize_lock_control. |
7f055c20 ILT |
312 | |
313 | static Lock** initialize_lock_pointer; | |
314 | ||
315 | // A routine passed to pthread_once which initializes the lock which | |
316 | // initialize_lock_pointer points to. | |
317 | ||
318 | extern "C" | |
319 | { | |
320 | ||
321 | static void | |
322 | initialize_lock_once() | |
323 | { | |
324 | *initialize_lock_pointer = new Lock(); | |
325 | } | |
326 | ||
327 | } | |
328 | ||
329 | #endif // !defined(ENABLE_THREADS) | |
330 | ||
331 | // Class Initialize_lock. | |
332 | ||
333 | Initialize_lock::Initialize_lock(Lock** pplock) | |
334 | : pplock_(pplock) | |
335 | { | |
336 | #ifndef ENABLE_THREADS | |
337 | this->once_ = NULL; | |
338 | #else | |
339 | this->once_ = new Initialize_lock_once(); | |
340 | #endif | |
341 | } | |
342 | ||
343 | // Initialize the lock. | |
344 | ||
345 | bool | |
346 | Initialize_lock::initialize() | |
347 | { | |
348 | // If the lock has already been initialized, we don't need to do | |
349 | // anything. Note that this assumes that the pointer value will be | |
350 | // set completely or not at all. I hope this is always safe. We | |
351 | // want to do this for efficiency. | |
352 | if (*this->pplock_ != NULL) | |
353 | return true; | |
354 | ||
355 | // We can't initialize the lock until we have read the options. | |
356 | if (!parameters->options_valid()) | |
357 | return false; | |
358 | ||
359 | // If the user did not use --threads, then we can initialize | |
360 | // directly. | |
361 | if (!parameters->options().threads()) | |
362 | { | |
363 | *this->pplock_ = new Lock(); | |
364 | return true; | |
365 | } | |
366 | ||
367 | #ifndef ENABLE_THREADS | |
368 | ||
369 | // If there is no threads support, we don't need to use | |
370 | // pthread_once. | |
371 | *this->pplock_ = new Lock(); | |
372 | ||
373 | #else // !defined(ENABLE_THREADS) | |
374 | ||
375 | // Since we can't pass parameters to routines called by | |
376 | // pthread_once, we use a static variable: initialize_lock_pointer. | |
377 | // That in turns means that we need to use a mutex to control access | |
378 | // to initialize_lock_pointer. | |
379 | ||
380 | int err = pthread_mutex_lock(&initialize_lock_control); | |
381 | if (err != 0) | |
382 | gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); | |
383 | ||
384 | initialize_lock_pointer = this->pplock_; | |
385 | ||
386 | err = pthread_once(this->once_->once_control(), initialize_lock_once); | |
387 | if (err != 0) | |
388 | gold_fatal(_("pthread_once failed: %s"), strerror(err)); | |
389 | ||
390 | initialize_lock_pointer = NULL; | |
391 | ||
392 | err = pthread_mutex_unlock(&initialize_lock_control); | |
393 | if (err != 0) | |
394 | gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); | |
395 | ||
396 | gold_assert(*this->pplock_ != NULL); | |
397 | ||
398 | #endif // !defined(ENABLE_THREADS) | |
399 | ||
400 | return true; | |
401 | } | |
402 | ||
bae7f79e | 403 | } // End namespace gold. |