xref: /dflybsd-src/contrib/binutils-2.34/gold/workqueue-threads.cc (revision b52ef7118d1621abed722c5bbbd542210290ecef)
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