xref: /dflybsd-src/contrib/binutils-2.27/gold/workqueue.h (revision e656dc90e3d65d744d534af2f5ea88cf8101ebcf)
1*a9fa9459Szrj // workqueue.h -- the work queue for gold   -*- C++ -*-
2*a9fa9459Szrj 
3*a9fa9459Szrj // Copyright (C) 2006-2016 Free Software Foundation, Inc.
4*a9fa9459Szrj // Written by Ian Lance Taylor <iant@google.com>.
5*a9fa9459Szrj 
6*a9fa9459Szrj // This file is part of gold.
7*a9fa9459Szrj 
8*a9fa9459Szrj // This program is free software; you can redistribute it and/or modify
9*a9fa9459Szrj // it under the terms of the GNU General Public License as published by
10*a9fa9459Szrj // the Free Software Foundation; either version 3 of the License, or
11*a9fa9459Szrj // (at your option) any later version.
12*a9fa9459Szrj 
13*a9fa9459Szrj // This program is distributed in the hope that it will be useful,
14*a9fa9459Szrj // but WITHOUT ANY WARRANTY; without even the implied warranty of
15*a9fa9459Szrj // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*a9fa9459Szrj // GNU General Public License for more details.
17*a9fa9459Szrj 
18*a9fa9459Szrj // You should have received a copy of the GNU General Public License
19*a9fa9459Szrj // along with this program; if not, write to the Free Software
20*a9fa9459Szrj // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21*a9fa9459Szrj // MA 02110-1301, USA.
22*a9fa9459Szrj 
23*a9fa9459Szrj // After processing the command line, everything the linker does is
24*a9fa9459Szrj // driven from a work queue.  This permits us to parallelize the
25*a9fa9459Szrj // linker where possible.
26*a9fa9459Szrj 
27*a9fa9459Szrj #ifndef GOLD_WORKQUEUE_H
28*a9fa9459Szrj #define GOLD_WORKQUEUE_H
29*a9fa9459Szrj 
30*a9fa9459Szrj #include <string>
31*a9fa9459Szrj 
32*a9fa9459Szrj #include "gold-threads.h"
33*a9fa9459Szrj #include "token.h"
34*a9fa9459Szrj 
35*a9fa9459Szrj namespace gold
36*a9fa9459Szrj {
37*a9fa9459Szrj 
38*a9fa9459Szrj class General_options;
39*a9fa9459Szrj class Workqueue;
40*a9fa9459Szrj 
41*a9fa9459Szrj // The superclass for tasks to be placed on the workqueue.  Each
42*a9fa9459Szrj // specific task class will inherit from this one.
43*a9fa9459Szrj 
44*a9fa9459Szrj class Task
45*a9fa9459Szrj {
46*a9fa9459Szrj  public:
Task()47*a9fa9459Szrj   Task()
48*a9fa9459Szrj     : list_next_(NULL), name_(), should_run_soon_(false)
49*a9fa9459Szrj   { }
~Task()50*a9fa9459Szrj   virtual ~Task()
51*a9fa9459Szrj   { }
52*a9fa9459Szrj 
53*a9fa9459Szrj   // Check whether the Task can be run now.  This method is only
54*a9fa9459Szrj   // called with the workqueue lock held.  If the Task can run, this
55*a9fa9459Szrj   // returns NULL.  Otherwise it returns a pointer to a token which
56*a9fa9459Szrj   // must be released before the Task can run.
57*a9fa9459Szrj   virtual Task_token*
58*a9fa9459Szrj   is_runnable() = 0;
59*a9fa9459Szrj 
60*a9fa9459Szrj   // Lock all the resources required by the Task, and store the locks
61*a9fa9459Szrj   // in a Task_locker.  This method does not need to do anything if no
62*a9fa9459Szrj   // locks are required.  This method is only called with the
63*a9fa9459Szrj   // workqueue lock held.
64*a9fa9459Szrj   virtual void
65*a9fa9459Szrj   locks(Task_locker*) = 0;
66*a9fa9459Szrj 
67*a9fa9459Szrj   // Run the task.
68*a9fa9459Szrj   virtual void
69*a9fa9459Szrj   run(Workqueue*) = 0;
70*a9fa9459Szrj 
71*a9fa9459Szrj   // Return whether this task should run soon.
72*a9fa9459Szrj   bool
should_run_soon()73*a9fa9459Szrj   should_run_soon() const
74*a9fa9459Szrj   { return this->should_run_soon_; }
75*a9fa9459Szrj 
76*a9fa9459Szrj   // Note that this task should run soon.
77*a9fa9459Szrj   void
set_should_run_soon()78*a9fa9459Szrj   set_should_run_soon()
79*a9fa9459Szrj   { this->should_run_soon_ = true; }
80*a9fa9459Szrj 
81*a9fa9459Szrj   // Get the next Task on the list of Tasks.  Called by Task_list.
82*a9fa9459Szrj   Task*
list_next()83*a9fa9459Szrj   list_next() const
84*a9fa9459Szrj   { return this->list_next_; }
85*a9fa9459Szrj 
86*a9fa9459Szrj   // Set the next Task on the list of Tasks.  Called by Task_list.
87*a9fa9459Szrj   void
set_list_next(Task * t)88*a9fa9459Szrj   set_list_next(Task* t)
89*a9fa9459Szrj   {
90*a9fa9459Szrj     gold_assert(this->list_next_ == NULL);
91*a9fa9459Szrj     this->list_next_ = t;
92*a9fa9459Szrj   }
93*a9fa9459Szrj 
94*a9fa9459Szrj   // Clear the next Task on the list of Tasks.  Called by Task_list.
95*a9fa9459Szrj   void
clear_list_next()96*a9fa9459Szrj   clear_list_next()
97*a9fa9459Szrj   { this->list_next_ = NULL; }
98*a9fa9459Szrj 
99*a9fa9459Szrj   // Return the name of the Task.  This is only used for debugging
100*a9fa9459Szrj   // purposes.
101*a9fa9459Szrj   const std::string&
name()102*a9fa9459Szrj   name()
103*a9fa9459Szrj   {
104*a9fa9459Szrj     if (this->name_.empty())
105*a9fa9459Szrj       this->name_ = this->get_name();
106*a9fa9459Szrj     return this->name_;
107*a9fa9459Szrj   }
108*a9fa9459Szrj 
109*a9fa9459Szrj  protected:
110*a9fa9459Szrj   // Get the name of the task.  This must be implemented by the child
111*a9fa9459Szrj   // class.
112*a9fa9459Szrj   virtual std::string
113*a9fa9459Szrj   get_name() const = 0;
114*a9fa9459Szrj 
115*a9fa9459Szrj  private:
116*a9fa9459Szrj   // Tasks may not be copied.
117*a9fa9459Szrj   Task(const Task&);
118*a9fa9459Szrj   Task& operator=(const Task&);
119*a9fa9459Szrj 
120*a9fa9459Szrj   // If this Task is on a list, this is a pointer to the next Task on
121*a9fa9459Szrj   // the list.  We use this simple list structure rather than building
122*a9fa9459Szrj   // a container, in order to avoid memory allocation while holding
123*a9fa9459Szrj   // the Workqueue lock.
124*a9fa9459Szrj   Task* list_next_;
125*a9fa9459Szrj   // Task name, for debugging purposes.
126*a9fa9459Szrj   std::string name_;
127*a9fa9459Szrj   // Whether this Task should be executed soon.  This is used for
128*a9fa9459Szrj   // Tasks which can be run after some data is read.
129*a9fa9459Szrj   bool should_run_soon_;
130*a9fa9459Szrj };
131*a9fa9459Szrj 
132*a9fa9459Szrj // An interface for Task_function.  This is a convenience class to run
133*a9fa9459Szrj // a single function.
134*a9fa9459Szrj 
135*a9fa9459Szrj class Task_function_runner
136*a9fa9459Szrj {
137*a9fa9459Szrj  public:
~Task_function_runner()138*a9fa9459Szrj   virtual ~Task_function_runner()
139*a9fa9459Szrj   { }
140*a9fa9459Szrj 
141*a9fa9459Szrj   virtual void
142*a9fa9459Szrj   run(Workqueue*, const Task*) = 0;
143*a9fa9459Szrj };
144*a9fa9459Szrj 
145*a9fa9459Szrj // A simple task which waits for a blocker and then runs a function.
146*a9fa9459Szrj 
147*a9fa9459Szrj class Task_function : public Task
148*a9fa9459Szrj {
149*a9fa9459Szrj  public:
150*a9fa9459Szrj   // RUNNER and BLOCKER should be allocated using new, and will be
151*a9fa9459Szrj   // deleted after the task runs.
Task_function(Task_function_runner * runner,Task_token * blocker,const char * name)152*a9fa9459Szrj   Task_function(Task_function_runner* runner, Task_token* blocker,
153*a9fa9459Szrj 		const char* name)
154*a9fa9459Szrj     : runner_(runner), blocker_(blocker), name_(name)
155*a9fa9459Szrj   { gold_assert(blocker != NULL); }
156*a9fa9459Szrj 
~Task_function()157*a9fa9459Szrj   ~Task_function()
158*a9fa9459Szrj   {
159*a9fa9459Szrj     delete this->runner_;
160*a9fa9459Szrj     delete this->blocker_;
161*a9fa9459Szrj   }
162*a9fa9459Szrj 
163*a9fa9459Szrj   // The standard task methods.
164*a9fa9459Szrj 
165*a9fa9459Szrj   // Wait until the task is unblocked.
166*a9fa9459Szrj   Task_token*
is_runnable()167*a9fa9459Szrj   is_runnable()
168*a9fa9459Szrj   { return this->blocker_->is_blocked() ? this->blocker_ : NULL; }
169*a9fa9459Szrj 
170*a9fa9459Szrj   // This type of task does not normally hold any locks.
171*a9fa9459Szrj   virtual void
locks(Task_locker *)172*a9fa9459Szrj   locks(Task_locker*)
173*a9fa9459Szrj   { }
174*a9fa9459Szrj 
175*a9fa9459Szrj   // Run the action.
176*a9fa9459Szrj   void
run(Workqueue * workqueue)177*a9fa9459Szrj   run(Workqueue* workqueue)
178*a9fa9459Szrj   { this->runner_->run(workqueue, this); }
179*a9fa9459Szrj 
180*a9fa9459Szrj   // The debugging name.
181*a9fa9459Szrj   std::string
get_name()182*a9fa9459Szrj   get_name() const
183*a9fa9459Szrj   { return this->name_; }
184*a9fa9459Szrj 
185*a9fa9459Szrj  private:
186*a9fa9459Szrj   Task_function(const Task_function&);
187*a9fa9459Szrj   Task_function& operator=(const Task_function&);
188*a9fa9459Szrj 
189*a9fa9459Szrj   Task_function_runner* runner_;
190*a9fa9459Szrj   Task_token* blocker_;
191*a9fa9459Szrj   const char* name_;
192*a9fa9459Szrj };
193*a9fa9459Szrj 
194*a9fa9459Szrj // The workqueue itself.
195*a9fa9459Szrj 
196*a9fa9459Szrj class Workqueue_threader;
197*a9fa9459Szrj 
198*a9fa9459Szrj class Workqueue
199*a9fa9459Szrj {
200*a9fa9459Szrj  public:
201*a9fa9459Szrj   Workqueue(const General_options&);
202*a9fa9459Szrj   ~Workqueue();
203*a9fa9459Szrj 
204*a9fa9459Szrj   // Add a new task to the work queue.
205*a9fa9459Szrj   void
206*a9fa9459Szrj   queue(Task*);
207*a9fa9459Szrj 
208*a9fa9459Szrj   // Add a new task to the work queue which should run soon.  If the
209*a9fa9459Szrj   // task is ready, it will be run before any tasks added using
210*a9fa9459Szrj   // queue().
211*a9fa9459Szrj   void
212*a9fa9459Szrj   queue_soon(Task*);
213*a9fa9459Szrj 
214*a9fa9459Szrj   // Add a new task to the work queue which should run next if it is
215*a9fa9459Szrj   // ready.
216*a9fa9459Szrj   void
217*a9fa9459Szrj   queue_next(Task*);
218*a9fa9459Szrj 
219*a9fa9459Szrj   // Process all the tasks on the work queue.  This function runs
220*a9fa9459Szrj   // until all tasks have completed.  The argument is the thread
221*a9fa9459Szrj   // number, used only for debugging.
222*a9fa9459Szrj   void
223*a9fa9459Szrj   process(int);
224*a9fa9459Szrj 
225*a9fa9459Szrj   // Set the desired thread count--the number of threads we want to
226*a9fa9459Szrj   // have running.
227*a9fa9459Szrj   void
228*a9fa9459Szrj   set_thread_count(int);
229*a9fa9459Szrj 
230*a9fa9459Szrj   // Add a new blocker to an existing Task_token. This must be done
231*a9fa9459Szrj   // with the workqueue lock held.  This should not be done routinely,
232*a9fa9459Szrj   // only in special circumstances.
233*a9fa9459Szrj   void
234*a9fa9459Szrj   add_blocker(Task_token*);
235*a9fa9459Szrj 
236*a9fa9459Szrj  private:
237*a9fa9459Szrj   // This class can not be copied.
238*a9fa9459Szrj   Workqueue(const Workqueue&);
239*a9fa9459Szrj   Workqueue& operator=(const Workqueue&);
240*a9fa9459Szrj 
241*a9fa9459Szrj   // Add a task to a queue.
242*a9fa9459Szrj   void
243*a9fa9459Szrj   add_to_queue(Task_list* queue, Task* t, bool front);
244*a9fa9459Szrj 
245*a9fa9459Szrj   // Find a runnable task, or wait for one.
246*a9fa9459Szrj   Task*
247*a9fa9459Szrj   find_runnable_or_wait(int thread_number);
248*a9fa9459Szrj 
249*a9fa9459Szrj   // Find a runnable task.
250*a9fa9459Szrj   Task*
251*a9fa9459Szrj   find_runnable();
252*a9fa9459Szrj 
253*a9fa9459Szrj   // Find a runnable task in a list.
254*a9fa9459Szrj   Task*
255*a9fa9459Szrj   find_runnable_in_list(Task_list*);
256*a9fa9459Szrj 
257*a9fa9459Szrj   // Find an run a task.
258*a9fa9459Szrj   bool
259*a9fa9459Szrj   find_and_run_task(int);
260*a9fa9459Szrj 
261*a9fa9459Szrj   // Release the locks for a Task.  Return the next Task to run.
262*a9fa9459Szrj   Task*
263*a9fa9459Szrj   release_locks(Task*, Task_locker*);
264*a9fa9459Szrj 
265*a9fa9459Szrj   // Store T into *PRET, or queue it as appropriate.
266*a9fa9459Szrj   bool
267*a9fa9459Szrj   return_or_queue(Task* t, bool is_blocker, Task** pret);
268*a9fa9459Szrj 
269*a9fa9459Szrj   // Return whether to cancel this thread.
270*a9fa9459Szrj   bool
271*a9fa9459Szrj   should_cancel_thread(int thread_number);
272*a9fa9459Szrj 
273*a9fa9459Szrj   // Master Workqueue lock.  This controls access to the following
274*a9fa9459Szrj   // member variables.
275*a9fa9459Szrj   Lock lock_;
276*a9fa9459Szrj   // List of tasks to execute soon.
277*a9fa9459Szrj   Task_list first_tasks_;
278*a9fa9459Szrj   // List of tasks to execute after the ones in first_tasks_.
279*a9fa9459Szrj   Task_list tasks_;
280*a9fa9459Szrj   // Number of tasks currently running.
281*a9fa9459Szrj   int running_;
282*a9fa9459Szrj   // Number of tasks waiting for a lock to release.
283*a9fa9459Szrj   int waiting_;
284*a9fa9459Szrj   // Condition variable associated with lock_.  This is signalled when
285*a9fa9459Szrj   // there may be a new Task to execute.
286*a9fa9459Szrj   Condvar condvar_;
287*a9fa9459Szrj 
288*a9fa9459Szrj   // The threading implementation.  This is set at construction time
289*a9fa9459Szrj   // and not changed thereafter.
290*a9fa9459Szrj   Workqueue_threader* threader_;
291*a9fa9459Szrj };
292*a9fa9459Szrj 
293*a9fa9459Szrj } // End namespace gold.
294*a9fa9459Szrj 
295*a9fa9459Szrj #endif // !defined(GOLD_WORKQUEUE_H)
296