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