1*fae548d3Szrj // workqueue-threads.cc -- the threaded workqueue for gold
2*fae548d3Szrj
3*fae548d3Szrj // Copyright (C) 2007-2020 Free Software Foundation, Inc.
4*fae548d3Szrj // Written by Ian Lance Taylor <iant@google.com>.
5*fae548d3Szrj
6*fae548d3Szrj // This file is part of gold.
7*fae548d3Szrj
8*fae548d3Szrj // This program is free software; you can redistribute it and/or modify
9*fae548d3Szrj // it under the terms of the GNU General Public License as published by
10*fae548d3Szrj // the Free Software Foundation; either version 3 of the License, or
11*fae548d3Szrj // (at your option) any later version.
12*fae548d3Szrj
13*fae548d3Szrj // This program is distributed in the hope that it will be useful,
14*fae548d3Szrj // but WITHOUT ANY WARRANTY; without even the implied warranty of
15*fae548d3Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*fae548d3Szrj // GNU General Public License for more details.
17*fae548d3Szrj
18*fae548d3Szrj // You should have received a copy of the GNU General Public License
19*fae548d3Szrj // along with this program; if not, write to the Free Software
20*fae548d3Szrj // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21*fae548d3Szrj // MA 02110-1301, USA.
22*fae548d3Szrj
23*fae548d3Szrj // This file holds the workqueue implementation which may be used when
24*fae548d3Szrj // using threads.
25*fae548d3Szrj
26*fae548d3Szrj #include "gold.h"
27*fae548d3Szrj
28*fae548d3Szrj #ifdef ENABLE_THREADS
29*fae548d3Szrj
30*fae548d3Szrj #include <cstring>
31*fae548d3Szrj #include <pthread.h>
32*fae548d3Szrj
33*fae548d3Szrj #include "debug.h"
34*fae548d3Szrj #include "gold-threads.h"
35*fae548d3Szrj #include "workqueue.h"
36*fae548d3Szrj #include "workqueue-internal.h"
37*fae548d3Szrj
38*fae548d3Szrj namespace gold
39*fae548d3Szrj {
40*fae548d3Szrj
41*fae548d3Szrj // Class Workqueue_thread represents a single thread. Creating an
42*fae548d3Szrj // instance of this spawns a new thread.
43*fae548d3Szrj
44*fae548d3Szrj class Workqueue_thread
45*fae548d3Szrj {
46*fae548d3Szrj public:
47*fae548d3Szrj Workqueue_thread(Workqueue_threader_threadpool*, int thread_number);
48*fae548d3Szrj
49*fae548d3Szrj ~Workqueue_thread();
50*fae548d3Szrj
51*fae548d3Szrj private:
52*fae548d3Szrj // This class can not be copied.
53*fae548d3Szrj Workqueue_thread(const Workqueue_thread&);
54*fae548d3Szrj Workqueue_thread& operator=(const Workqueue_thread&);
55*fae548d3Szrj
56*fae548d3Szrj // Check for error from a pthread function.
57*fae548d3Szrj void
58*fae548d3Szrj check(const char* function, int err) const;
59*fae548d3Szrj
60*fae548d3Szrj // A function to pass to pthread_create. This is called with a
61*fae548d3Szrj // pointer to an instance of this object.
62*fae548d3Szrj static void*
63*fae548d3Szrj thread_body(void*);
64*fae548d3Szrj
65*fae548d3Szrj // A pointer to the threadpool that this thread is part of.
66*fae548d3Szrj Workqueue_threader_threadpool* threadpool_;
67*fae548d3Szrj // The thread number.
68*fae548d3Szrj int thread_number_;
69*fae548d3Szrj // The thread ID.
70*fae548d3Szrj pthread_t tid_;
71*fae548d3Szrj };
72*fae548d3Szrj
73*fae548d3Szrj // Create the thread in the constructor.
74*fae548d3Szrj
Workqueue_thread(Workqueue_threader_threadpool * threadpool,int thread_number)75*fae548d3Szrj Workqueue_thread::Workqueue_thread(Workqueue_threader_threadpool* threadpool,
76*fae548d3Szrj int thread_number)
77*fae548d3Szrj : threadpool_(threadpool), thread_number_(thread_number)
78*fae548d3Szrj {
79*fae548d3Szrj pthread_attr_t attr;
80*fae548d3Szrj int err = pthread_attr_init(&attr);
81*fae548d3Szrj this->check("pthread_attr_init", err);
82*fae548d3Szrj
83*fae548d3Szrj err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
84*fae548d3Szrj this->check("pthread_attr_setdetachstate", err);
85*fae548d3Szrj
86*fae548d3Szrj err = pthread_create(&this->tid_, &attr, &Workqueue_thread::thread_body,
87*fae548d3Szrj reinterpret_cast<void*>(this));
88*fae548d3Szrj this->check("pthread_create", err);
89*fae548d3Szrj
90*fae548d3Szrj err = pthread_attr_destroy(&attr);
91*fae548d3Szrj this->check("pthread_attr_destroy", err);
92*fae548d3Szrj }
93*fae548d3Szrj
94*fae548d3Szrj // The destructor will be called when the thread is exiting.
95*fae548d3Szrj
~Workqueue_thread()96*fae548d3Szrj Workqueue_thread::~Workqueue_thread()
97*fae548d3Szrj {
98*fae548d3Szrj }
99*fae548d3Szrj
100*fae548d3Szrj // Check for an error.
101*fae548d3Szrj
102*fae548d3Szrj void
check(const char * function,int err) const103*fae548d3Szrj Workqueue_thread::check(const char* function, int err) const
104*fae548d3Szrj {
105*fae548d3Szrj if (err != 0)
106*fae548d3Szrj gold_fatal(_("%s failed: %s"), function, strerror(err));
107*fae548d3Szrj }
108*fae548d3Szrj
109*fae548d3Szrj // Passed to pthread_create.
110*fae548d3Szrj
111*fae548d3Szrj extern "C"
112*fae548d3Szrj void*
thread_body(void * arg)113*fae548d3Szrj Workqueue_thread::thread_body(void* arg)
114*fae548d3Szrj {
115*fae548d3Szrj Workqueue_thread* pwt = reinterpret_cast<Workqueue_thread*>(arg);
116*fae548d3Szrj
117*fae548d3Szrj pwt->threadpool_->process(pwt->thread_number_);
118*fae548d3Szrj
119*fae548d3Szrj // Delete the thread object as we exit.
120*fae548d3Szrj delete pwt;
121*fae548d3Szrj
122*fae548d3Szrj return NULL;
123*fae548d3Szrj }
124*fae548d3Szrj
125*fae548d3Szrj // Class Workqueue_threader_threadpool.
126*fae548d3Szrj
127*fae548d3Szrj // Constructor.
128*fae548d3Szrj
Workqueue_threader_threadpool(Workqueue * workqueue)129*fae548d3Szrj Workqueue_threader_threadpool::Workqueue_threader_threadpool(
130*fae548d3Szrj Workqueue* workqueue)
131*fae548d3Szrj : Workqueue_threader(workqueue),
132*fae548d3Szrj check_thread_count_(0),
133*fae548d3Szrj lock_(),
134*fae548d3Szrj desired_thread_count_(1),
135*fae548d3Szrj threads_(1)
136*fae548d3Szrj {
137*fae548d3Szrj }
138*fae548d3Szrj
139*fae548d3Szrj // Destructor.
140*fae548d3Szrj
~Workqueue_threader_threadpool()141*fae548d3Szrj Workqueue_threader_threadpool::~Workqueue_threader_threadpool()
142*fae548d3Szrj {
143*fae548d3Szrj // Tell the threads to exit.
144*fae548d3Szrj this->get_workqueue()->set_thread_count(0);
145*fae548d3Szrj }
146*fae548d3Szrj
147*fae548d3Szrj // Set the thread count.
148*fae548d3Szrj
149*fae548d3Szrj void
set_thread_count(int thread_count)150*fae548d3Szrj Workqueue_threader_threadpool::set_thread_count(int thread_count)
151*fae548d3Szrj {
152*fae548d3Szrj int create;
153*fae548d3Szrj {
154*fae548d3Szrj Hold_lock hl(this->lock_);
155*fae548d3Szrj
156*fae548d3Szrj this->desired_thread_count_ = thread_count;
157*fae548d3Szrj create = this->desired_thread_count_ - this->threads_;
158*fae548d3Szrj if (create < 0)
159*fae548d3Szrj this->check_thread_count_ = 1;
160*fae548d3Szrj }
161*fae548d3Szrj
162*fae548d3Szrj if (create > 0)
163*fae548d3Szrj {
164*fae548d3Szrj for (int i = 0; i < create; ++i)
165*fae548d3Szrj {
166*fae548d3Szrj // Note that threads delete themselves when they exit, so we
167*fae548d3Szrj // don't keep pointers to them.
168*fae548d3Szrj new Workqueue_thread(this, this->threads_);
169*fae548d3Szrj ++this->threads_;
170*fae548d3Szrj }
171*fae548d3Szrj }
172*fae548d3Szrj }
173*fae548d3Szrj
174*fae548d3Szrj // Return whether the current thread should be cancelled.
175*fae548d3Szrj
176*fae548d3Szrj bool
should_cancel_thread(int thread_number)177*fae548d3Szrj Workqueue_threader_threadpool::should_cancel_thread(int thread_number)
178*fae548d3Szrj {
179*fae548d3Szrj // Fast exit without taking a lock.
180*fae548d3Szrj if (!this->check_thread_count_)
181*fae548d3Szrj return false;
182*fae548d3Szrj
183*fae548d3Szrj {
184*fae548d3Szrj Hold_lock hl(this->lock_);
185*fae548d3Szrj if (thread_number > this->desired_thread_count_)
186*fae548d3Szrj {
187*fae548d3Szrj --this->threads_;
188*fae548d3Szrj if (this->threads_ <= this->desired_thread_count_)
189*fae548d3Szrj this->check_thread_count_ = 0;
190*fae548d3Szrj return true;
191*fae548d3Szrj }
192*fae548d3Szrj }
193*fae548d3Szrj
194*fae548d3Szrj return false;
195*fae548d3Szrj }
196*fae548d3Szrj
197*fae548d3Szrj } // End namespace gold.
198*fae548d3Szrj
199*fae548d3Szrj #endif // defined(ENABLE_THREADS)
200