a4f347de5dee4ae79ef1c630e37dbec1c7ace6c6
[external/binutils.git] / gold / workqueue-threads.cc
1 // workqueue-threads.cc -- the threaded workqueue for gold
2
3 // Copyright 2007 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 // This file holds the workqueue implementation which may be used when
24 // using threads.
25
26 #include "gold.h"
27
28 #ifdef ENABLE_THREADS
29
30 #include <cstring>
31 #include <pthread.h>
32
33 #include "debug.h"
34 #include "gold-threads.h"
35 #include "workqueue.h"
36 #include "workqueue-internal.h"
37
38 namespace gold
39 {
40
41 // Class Workqueue_thread represents a single thread.  Creating an
42 // instance of this spawns a new thread.
43
44 class Workqueue_thread
45 {
46  public:
47   Workqueue_thread(Workqueue_runner_threadpool*);
48
49   ~Workqueue_thread();
50
51  private:
52   // This class can not be copied.
53   Workqueue_thread(const Workqueue_thread&);
54   Workqueue_thread& operator=(const Workqueue_thread&);
55
56   // Check for error from a pthread function.
57   void
58   check(const char* function, int err) const;
59
60   // A function to pass to pthread_create.  This is called with a
61   // pointer to an instance of this object.
62   static void*
63   thread_body(void*);
64
65   // The main loop of the thread.
66   void
67   run();
68
69   // A pointer to the threadpool that this thread is part of.
70   Workqueue_runner_threadpool* threadpool_;
71   // The thread ID.
72   pthread_t tid_;
73 };
74
75 // Create the thread in the constructor.
76
77 Workqueue_thread::Workqueue_thread(Workqueue_runner_threadpool* threadpool)
78   : threadpool_(threadpool)
79 {
80   pthread_attr_t attr;
81   int err = pthread_attr_init(&attr);
82   this->check("pthread_attr_init", err);
83
84   err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
85   this->check("pthread_attr_setdetachstate", err);
86
87   err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body,
88                        reinterpret_cast<void*>(this));
89   this->check("pthread_create", err);
90
91   err = pthread_attr_destroy(&attr);
92   this->check("pthread_attr_destroy", err);
93 }
94
95 // The destructor will be called when the thread is exiting.
96
97 Workqueue_thread::~Workqueue_thread()
98 {
99 }
100
101 // Check for an error.
102
103 void
104 Workqueue_thread::check(const char* function, int err) const
105 {
106   if (err != 0)
107     gold_fatal(_("%s failed: %s"), function, strerror(err));
108 }
109
110 // Passed to pthread_create.
111
112 extern "C"
113 void*
114 Workqueue_thread::thread_body(void* arg)
115 {
116   Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg);
117   pwt->run();
118
119   // Delete the thread object as we exit.
120   delete pwt;
121
122   return NULL;
123 }
124
125 // This is the main loop of a worker thread.  It picks up a new Task
126 // and runs it.
127
128 void
129 Workqueue_thread::run()
130 {
131   Workqueue_runner_threadpool* threadpool = this->threadpool_;
132   Workqueue* workqueue = threadpool->get_workqueue();
133
134   while (true)
135     {
136       Task* t;
137       Task_locker* tl;
138       if (!threadpool->get_next(&t, &tl))
139         return;
140
141       gold_debug(DEBUG_TASK, "running   task %s", t->name().c_str());
142
143       t->run(workqueue);
144       threadpool->thread_completed(t, tl);
145     }
146 }
147
148 // Class Workqueue_runner_threadpool.
149
150 // Constructor.
151
152 Workqueue_runner_threadpool::Workqueue_runner_threadpool(Workqueue* workqueue)
153   : Workqueue_runner(workqueue),
154     desired_thread_count_(0),
155     lock_(),
156     actual_thread_count_(0),
157     running_thread_count_(0),
158     task_queue_(),
159     task_queue_condvar_(this->lock_)
160 {
161 }
162
163 // Destructor.
164
165 Workqueue_runner_threadpool::~Workqueue_runner_threadpool()
166 {
167   // Tell the threads to exit.
168   Hold_lock hl(this->lock_);
169   this->desired_thread_count_ = 0;
170   this->task_queue_condvar_.broadcast();
171 }
172
173 // Run a task.  This doesn't actually run the task: it pushes on the
174 // queue of tasks to run.  This is always called in the main thread.
175
176 void
177 Workqueue_runner_threadpool::run(Task* t, Task_locker* tl)
178 {
179   Hold_lock hl(this->lock_);
180
181   // This is where we create threads as needed, subject to the limit
182   // of the desired thread count.
183   gold_assert(this->desired_thread_count_ > 0);
184   gold_assert(this->actual_thread_count_ >= this->running_thread_count_);
185   if (this->actual_thread_count_ == this->running_thread_count_
186       && this->actual_thread_count_ < this->desired_thread_count_)
187     {
188       // Note that threads delete themselves when they exit, so we
189       // don't keep pointers to them.
190       new Workqueue_thread(this);
191       ++this->actual_thread_count_;
192     }
193
194   this->task_queue_.push(std::make_pair(t, tl));
195   this->task_queue_condvar_.signal();
196 }
197
198 // Set the thread count.  This is only called in the main thread, and
199 // is only called when there are no threads running.
200
201 void
202 Workqueue_runner_threadpool::set_thread_count(int thread_count)
203 {
204   gold_assert(this->running_thread_count_ <= 1);
205   gold_assert(thread_count > 0);
206   this->desired_thread_count_ = thread_count;
207 }
208
209 // Get the next task to run.  This is always called by an instance of
210 // Workqueue_thread, and is never called in the main thread.  It
211 // returns false if the calling thread should exit.
212
213 bool
214 Workqueue_runner_threadpool::get_next(Task** pt, Task_locker** ptl)
215 {
216   Hold_lock hl(this->lock_);
217
218   // This is where we destroy threads, by telling them to exit.
219   gold_assert(this->actual_thread_count_ > this->running_thread_count_);
220   if (this->actual_thread_count_ > this->desired_thread_count_)
221     {
222       --this->actual_thread_count_;
223       return false;
224     }
225
226   while (this->task_queue_.empty() && this->desired_thread_count_ > 0)
227     {
228       // Wait for a new task to become available.
229       this->task_queue_condvar_.wait();
230     }
231
232   // Check whether we are exiting.
233   if (this->desired_thread_count_ == 0)
234     {
235       gold_assert(this->actual_thread_count_ > 0);
236       --this->actual_thread_count_;
237       return false;
238     }
239
240   *pt = this->task_queue_.front().first;
241   *ptl = this->task_queue_.front().second;
242   this->task_queue_.pop();
243
244   ++this->running_thread_count_;
245
246   return true;
247 }
248
249 // This is called when a thread completes its task.
250
251 void
252 Workqueue_runner_threadpool::thread_completed(Task* t, Task_locker* tl)
253 {
254   {
255     Hold_lock hl(this->lock_);
256     gold_assert(this->actual_thread_count_ > 0);
257     gold_assert(this->running_thread_count_ > 0);
258     --this->running_thread_count_;
259   }
260
261   this->completed(t, tl);
262 }
263
264 } // End namespace gold.
265
266 #endif // defined(ENABLE_THREADS)