Commit | Line | Data |
---|---|---|
c7912668 ILT |
1 | // workqueue-threads.cc -- the threaded workqueue for gold |
2 | ||
ebdbb458 | 3 | // Copyright 2007, 2008 Free Software Foundation, Inc. |
c7912668 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 | ||
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: | |
17a1d0a9 | 47 | Workqueue_thread(Workqueue_threader_threadpool*, int thread_number); |
c7912668 ILT |
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 | ||
c7912668 | 65 | // A pointer to the threadpool that this thread is part of. |
17a1d0a9 ILT |
66 | Workqueue_threader_threadpool* threadpool_; |
67 | // The thread number. | |
68 | int thread_number_; | |
c7912668 ILT |
69 | // The thread ID. |
70 | pthread_t tid_; | |
71 | }; | |
72 | ||
73 | // Create the thread in the constructor. | |
74 | ||
17a1d0a9 ILT |
75 | Workqueue_thread::Workqueue_thread(Workqueue_threader_threadpool* threadpool, |
76 | int thread_number) | |
77 | : threadpool_(threadpool), thread_number_(thread_number) | |
c7912668 ILT |
78 | { |
79 | pthread_attr_t attr; | |
80 | int err = pthread_attr_init(&attr); | |
81 | this->check("pthread_attr_init", err); | |
82 | ||
83 | err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | |
84 | this->check("pthread_attr_setdetachstate", err); | |
85 | ||
86 | err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body, | |
87 | reinterpret_cast<void*>(this)); | |
88 | this->check("pthread_create", err); | |
89 | ||
90 | err = pthread_attr_destroy(&attr); | |
91 | this->check("pthread_attr_destroy", err); | |
92 | } | |
93 | ||
94 | // The destructor will be called when the thread is exiting. | |
95 | ||
96 | Workqueue_thread::~Workqueue_thread() | |
97 | { | |
98 | } | |
99 | ||
100 | // Check for an error. | |
101 | ||
102 | void | |
103 | Workqueue_thread::check(const char* function, int err) const | |
104 | { | |
105 | if (err != 0) | |
106 | gold_fatal(_("%s failed: %s"), function, strerror(err)); | |
107 | } | |
108 | ||
109 | // Passed to pthread_create. | |
110 | ||
111 | extern "C" | |
112 | void* | |
113 | Workqueue_thread::thread_body(void* arg) | |
114 | { | |
115 | Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg); | |
17a1d0a9 ILT |
116 | |
117 | pwt->threadpool_->process(pwt->thread_number_); | |
c7912668 ILT |
118 | |
119 | // Delete the thread object as we exit. | |
120 | delete pwt; | |
121 | ||
122 | return NULL; | |
123 | } | |
124 | ||
17a1d0a9 | 125 | // Class Workqueue_threader_threadpool. |
c7912668 ILT |
126 | |
127 | // Constructor. | |
128 | ||
17a1d0a9 ILT |
129 | Workqueue_threader_threadpool::Workqueue_threader_threadpool( |
130 | Workqueue* workqueue) | |
131 | : Workqueue_threader(workqueue), | |
132 | check_thread_count_(0), | |
c7912668 | 133 | lock_(), |
17a1d0a9 ILT |
134 | desired_thread_count_(1), |
135 | threads_(1) | |
c7912668 ILT |
136 | { |
137 | } | |
138 | ||
139 | // Destructor. | |
140 | ||
17a1d0a9 | 141 | Workqueue_threader_threadpool::~Workqueue_threader_threadpool() |
c7912668 ILT |
142 | { |
143 | // Tell the threads to exit. | |
17a1d0a9 | 144 | this->get_workqueue()->set_thread_count(0); |
c7912668 ILT |
145 | } |
146 | ||
17a1d0a9 | 147 | // Set the thread count. |
c7912668 ILT |
148 | |
149 | void | |
17a1d0a9 | 150 | Workqueue_threader_threadpool::set_thread_count(int thread_count) |
c7912668 | 151 | { |
17a1d0a9 ILT |
152 | int create; |
153 | { | |
154 | Hold_lock hl(this->lock_); | |
c7912668 | 155 | |
17a1d0a9 ILT |
156 | this->desired_thread_count_ = thread_count; |
157 | create = this->desired_thread_count_ - this->threads_; | |
158 | if (create < 0) | |
159 | this->check_thread_count_ = 1; | |
160 | } | |
c7912668 | 161 | |
17a1d0a9 | 162 | if (create > 0) |
c7912668 | 163 | { |
17a1d0a9 ILT |
164 | for (int i = 0; i < create; ++i) |
165 | { | |
166 | // Note that threads delete themselves when they exit, so we | |
167 | // don't keep pointers to them. | |
168 | new Workqueue_thread(this, this->threads_); | |
169 | ++this->threads_; | |
170 | } | |
c7912668 | 171 | } |
c7912668 ILT |
172 | } |
173 | ||
17a1d0a9 | 174 | // Return whether the current thread should be cancelled. |
c7912668 | 175 | |
17a1d0a9 | 176 | bool |
dcd8d12e | 177 | Workqueue_threader_threadpool::should_cancel_thread(int thread_number) |
c7912668 | 178 | { |
17a1d0a9 ILT |
179 | // Fast exit without taking a lock. |
180 | if (!this->check_thread_count_) | |
181 | return false; | |
182 | ||
c7912668 ILT |
183 | { |
184 | Hold_lock hl(this->lock_); | |
dcd8d12e | 185 | if (thread_number > this->desired_thread_count_) |
17a1d0a9 ILT |
186 | { |
187 | --this->threads_; | |
dcd8d12e CC |
188 | if (this->threads_ <= this->desired_thread_count_) |
189 | this->check_thread_count_ = 0; | |
17a1d0a9 ILT |
190 | return true; |
191 | } | |
c7912668 ILT |
192 | } |
193 | ||
17a1d0a9 | 194 | return false; |
c7912668 ILT |
195 | } |
196 | ||
197 | } // End namespace gold. | |
198 | ||
199 | #endif // defined(ENABLE_THREADS) |