1 // workqueue-threads.cc -- the threaded workqueue for gold
3 // Copyright 2007 Free Software Foundation, Inc.
4 // Written by Ian Lance Taylor <iant@google.com>.
6 // This file is part of gold.
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.
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.
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.
23 // This file holds the workqueue implementation which may be used when
34 #include "gold-threads.h"
35 #include "workqueue.h"
36 #include "workqueue-internal.h"
41 // Class Workqueue_thread represents a single thread. Creating an
42 // instance of this spawns a new thread.
44 class Workqueue_thread
47 Workqueue_thread(Workqueue_runner_threadpool
*);
52 // This class can not be copied.
53 Workqueue_thread(const Workqueue_thread
&);
54 Workqueue_thread
& operator=(const Workqueue_thread
&);
56 // Check for error from a pthread function.
58 check(const char* function
, int err
) const;
60 // A function to pass to pthread_create. This is called with a
61 // pointer to an instance of this object.
65 // The main loop of the thread.
69 // A pointer to the threadpool that this thread is part of.
70 Workqueue_runner_threadpool
* threadpool_
;
75 // Create the thread in the constructor.
77 Workqueue_thread::Workqueue_thread(Workqueue_runner_threadpool
* threadpool
)
78 : threadpool_(threadpool
)
81 int err
= pthread_attr_init(&attr
);
82 this->check("pthread_attr_init", err
);
84 err
= pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
85 this->check("pthread_attr_setdetachstate", err
);
87 err
= pthread_create(&this->tid_
, &attr
, &Workqueue_thread::thread_body
,
88 reinterpret_cast<void*>(this));
89 this->check("pthread_create", err
);
91 err
= pthread_attr_destroy(&attr
);
92 this->check("pthread_attr_destroy", err
);
95 // The destructor will be called when the thread is exiting.
97 Workqueue_thread::~Workqueue_thread()
101 // Check for an error.
104 Workqueue_thread::check(const char* function
, int err
) const
107 gold_fatal(_("%s failed: %s"), function
, strerror(err
));
110 // Passed to pthread_create.
114 Workqueue_thread::thread_body(void* arg
)
116 Workqueue_thread
* pwt
= reinterpret_cast<Workqueue_thread
*>(arg
);
119 // Delete the thread object as we exit.
125 // This is the main loop of a worker thread. It picks up a new Task
129 Workqueue_thread::run()
131 Workqueue_runner_threadpool
* threadpool
= this->threadpool_
;
132 Workqueue
* workqueue
= threadpool
->get_workqueue();
138 if (!threadpool
->get_next(&t
, &tl
))
141 gold_debug(DEBUG_TASK
, "running task %s", t
->name().c_str());
144 threadpool
->thread_completed(t
, tl
);
148 // Class Workqueue_runner_threadpool.
152 Workqueue_runner_threadpool::Workqueue_runner_threadpool(Workqueue
* workqueue
)
153 : Workqueue_runner(workqueue
),
154 desired_thread_count_(0),
156 actual_thread_count_(0),
157 running_thread_count_(0),
159 task_queue_condvar_(this->lock_
)
165 Workqueue_runner_threadpool::~Workqueue_runner_threadpool()
167 // Tell the threads to exit.
168 Hold_lock
hl(this->lock_
);
169 this->desired_thread_count_
= 0;
170 this->task_queue_condvar_
.broadcast();
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.
177 Workqueue_runner_threadpool::run(Task
* t
, Task_locker
* tl
)
179 Hold_lock
hl(this->lock_
);
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_
)
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_
;
194 this->task_queue_
.push(std::make_pair(t
, tl
));
195 this->task_queue_condvar_
.signal();
198 // Set the thread count. This is only called in the main thread, and
199 // is only called when there are no threads running.
202 Workqueue_runner_threadpool::set_thread_count(int thread_count
)
204 gold_assert(this->running_thread_count_
<= 1);
205 gold_assert(thread_count
> 0);
206 this->desired_thread_count_
= thread_count
;
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.
214 Workqueue_runner_threadpool::get_next(Task
** pt
, Task_locker
** ptl
)
216 Hold_lock
hl(this->lock_
);
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_
)
222 --this->actual_thread_count_
;
226 while (this->task_queue_
.empty() && this->desired_thread_count_
> 0)
228 // Wait for a new task to become available.
229 this->task_queue_condvar_
.wait();
232 // Check whether we are exiting.
233 if (this->desired_thread_count_
== 0)
235 gold_assert(this->actual_thread_count_
> 0);
236 --this->actual_thread_count_
;
240 *pt
= this->task_queue_
.front().first
;
241 *ptl
= this->task_queue_
.front().second
;
242 this->task_queue_
.pop();
244 ++this->running_thread_count_
;
249 // This is called when a thread completes its task.
252 Workqueue_runner_threadpool::thread_completed(Task
* t
, Task_locker
* tl
)
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_
;
261 this->completed(t
, tl
);
264 } // End namespace gold.
266 #endif // defined(ENABLE_THREADS)