1*a9fa9459Szrj // gold-threads.h -- thread support 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 // gold can be configured to support threads. If threads are 24*a9fa9459Szrj // supported, the user can specify at runtime whether or not to 25*a9fa9459Szrj // support them. This provides an interface to manage locking 26*a9fa9459Szrj // accordingly. 27*a9fa9459Szrj 28*a9fa9459Szrj // Lock 29*a9fa9459Szrj // A simple lock class. 30*a9fa9459Szrj 31*a9fa9459Szrj #ifndef GOLD_THREADS_H 32*a9fa9459Szrj #define GOLD_THREADS_H 33*a9fa9459Szrj 34*a9fa9459Szrj namespace gold 35*a9fa9459Szrj { 36*a9fa9459Szrj 37*a9fa9459Szrj class Condvar; 38*a9fa9459Szrj class Once_initialize; 39*a9fa9459Szrj class Initialize_lock_once; 40*a9fa9459Szrj 41*a9fa9459Szrj // The interface for the implementation of a Lock. 42*a9fa9459Szrj 43*a9fa9459Szrj class Lock_impl 44*a9fa9459Szrj { 45*a9fa9459Szrj public: Lock_impl()46*a9fa9459Szrj Lock_impl() 47*a9fa9459Szrj { } 48*a9fa9459Szrj 49*a9fa9459Szrj virtual ~Lock_impl()50*a9fa9459Szrj ~Lock_impl() 51*a9fa9459Szrj { } 52*a9fa9459Szrj 53*a9fa9459Szrj virtual void 54*a9fa9459Szrj acquire() = 0; 55*a9fa9459Szrj 56*a9fa9459Szrj virtual void 57*a9fa9459Szrj release() = 0; 58*a9fa9459Szrj }; 59*a9fa9459Szrj 60*a9fa9459Szrj // A simple lock class. 61*a9fa9459Szrj 62*a9fa9459Szrj class Lock 63*a9fa9459Szrj { 64*a9fa9459Szrj public: 65*a9fa9459Szrj Lock(); 66*a9fa9459Szrj 67*a9fa9459Szrj ~Lock(); 68*a9fa9459Szrj 69*a9fa9459Szrj // Acquire the lock. 70*a9fa9459Szrj void acquire()71*a9fa9459Szrj acquire() 72*a9fa9459Szrj { this->lock_->acquire(); } 73*a9fa9459Szrj 74*a9fa9459Szrj // Release the lock. 75*a9fa9459Szrj void release()76*a9fa9459Szrj release() 77*a9fa9459Szrj { this->lock_->release(); } 78*a9fa9459Szrj 79*a9fa9459Szrj private: 80*a9fa9459Szrj // This class can not be copied. 81*a9fa9459Szrj Lock(const Lock&); 82*a9fa9459Szrj Lock& operator=(const Lock&); 83*a9fa9459Szrj 84*a9fa9459Szrj friend class Condvar; 85*a9fa9459Szrj Lock_impl* get_impl()86*a9fa9459Szrj get_impl() const 87*a9fa9459Szrj { return this->lock_; } 88*a9fa9459Szrj 89*a9fa9459Szrj Lock_impl* lock_; 90*a9fa9459Szrj }; 91*a9fa9459Szrj 92*a9fa9459Szrj // RAII for Lock. 93*a9fa9459Szrj 94*a9fa9459Szrj class Hold_lock 95*a9fa9459Szrj { 96*a9fa9459Szrj public: Hold_lock(Lock & lock)97*a9fa9459Szrj Hold_lock(Lock& lock) 98*a9fa9459Szrj : lock_(lock) 99*a9fa9459Szrj { this->lock_.acquire(); } 100*a9fa9459Szrj ~Hold_lock()101*a9fa9459Szrj ~Hold_lock() 102*a9fa9459Szrj { this->lock_.release(); } 103*a9fa9459Szrj 104*a9fa9459Szrj private: 105*a9fa9459Szrj // This class can not be copied. 106*a9fa9459Szrj Hold_lock(const Hold_lock&); 107*a9fa9459Szrj Hold_lock& operator=(const Hold_lock&); 108*a9fa9459Szrj 109*a9fa9459Szrj Lock& lock_; 110*a9fa9459Szrj }; 111*a9fa9459Szrj 112*a9fa9459Szrj class Hold_optional_lock 113*a9fa9459Szrj { 114*a9fa9459Szrj public: Hold_optional_lock(Lock * lock)115*a9fa9459Szrj Hold_optional_lock(Lock* lock) 116*a9fa9459Szrj : lock_(lock) 117*a9fa9459Szrj { 118*a9fa9459Szrj if (this->lock_ != NULL) 119*a9fa9459Szrj this->lock_->acquire(); 120*a9fa9459Szrj } 121*a9fa9459Szrj ~Hold_optional_lock()122*a9fa9459Szrj ~Hold_optional_lock() 123*a9fa9459Szrj { 124*a9fa9459Szrj if (this->lock_ != NULL) 125*a9fa9459Szrj this->lock_->release(); 126*a9fa9459Szrj } 127*a9fa9459Szrj 128*a9fa9459Szrj private: 129*a9fa9459Szrj Hold_optional_lock(const Hold_optional_lock&); 130*a9fa9459Szrj Hold_optional_lock& operator=(const Hold_optional_lock&); 131*a9fa9459Szrj 132*a9fa9459Szrj Lock* lock_; 133*a9fa9459Szrj }; 134*a9fa9459Szrj 135*a9fa9459Szrj // The interface for the implementation of a condition variable. 136*a9fa9459Szrj 137*a9fa9459Szrj class Condvar_impl 138*a9fa9459Szrj { 139*a9fa9459Szrj public: Condvar_impl()140*a9fa9459Szrj Condvar_impl() 141*a9fa9459Szrj { } 142*a9fa9459Szrj 143*a9fa9459Szrj virtual ~Condvar_impl()144*a9fa9459Szrj ~Condvar_impl() 145*a9fa9459Szrj { } 146*a9fa9459Szrj 147*a9fa9459Szrj virtual void 148*a9fa9459Szrj wait(Lock_impl*) = 0; 149*a9fa9459Szrj 150*a9fa9459Szrj virtual void 151*a9fa9459Szrj signal() = 0; 152*a9fa9459Szrj 153*a9fa9459Szrj virtual void 154*a9fa9459Szrj broadcast() = 0; 155*a9fa9459Szrj }; 156*a9fa9459Szrj 157*a9fa9459Szrj // A simple condition variable class. It is always associated with a 158*a9fa9459Szrj // specific lock. 159*a9fa9459Szrj 160*a9fa9459Szrj class Condvar 161*a9fa9459Szrj { 162*a9fa9459Szrj public: 163*a9fa9459Szrj Condvar(Lock& lock); 164*a9fa9459Szrj ~Condvar(); 165*a9fa9459Szrj 166*a9fa9459Szrj // Wait for the condition variable to be signalled. This should 167*a9fa9459Szrj // only be called when the lock is held. 168*a9fa9459Szrj void wait()169*a9fa9459Szrj wait() 170*a9fa9459Szrj { this->condvar_->wait(this->lock_.get_impl()); } 171*a9fa9459Szrj 172*a9fa9459Szrj // Signal the condition variable--wake up at least one thread 173*a9fa9459Szrj // waiting on the condition variable. This should only be called 174*a9fa9459Szrj // when the lock is held. 175*a9fa9459Szrj void signal()176*a9fa9459Szrj signal() 177*a9fa9459Szrj { this->condvar_->signal(); } 178*a9fa9459Szrj 179*a9fa9459Szrj // Broadcast the condition variable--wake up all threads waiting on 180*a9fa9459Szrj // the condition variable. This should only be called when the lock 181*a9fa9459Szrj // is held. 182*a9fa9459Szrj void broadcast()183*a9fa9459Szrj broadcast() 184*a9fa9459Szrj { this->condvar_->broadcast(); } 185*a9fa9459Szrj 186*a9fa9459Szrj private: 187*a9fa9459Szrj // This class can not be copied. 188*a9fa9459Szrj Condvar(const Condvar&); 189*a9fa9459Szrj Condvar& operator=(const Condvar&); 190*a9fa9459Szrj 191*a9fa9459Szrj Lock& lock_; 192*a9fa9459Szrj Condvar_impl* condvar_; 193*a9fa9459Szrj }; 194*a9fa9459Szrj 195*a9fa9459Szrj // A class used to do something once. This is an abstract parent 196*a9fa9459Szrj // class; any actual use will involve a child of this. 197*a9fa9459Szrj 198*a9fa9459Szrj class Once 199*a9fa9459Szrj { 200*a9fa9459Szrj public: 201*a9fa9459Szrj Once(); 202*a9fa9459Szrj 203*a9fa9459Szrj virtual ~Once()204*a9fa9459Szrj ~Once() 205*a9fa9459Szrj { } 206*a9fa9459Szrj 207*a9fa9459Szrj // Call this function to do whatever it is. We pass an argument 208*a9fa9459Szrj // even though you have to use a child class because in some uses 209*a9fa9459Szrj // setting the argument would itself require a Once class. 210*a9fa9459Szrj void 211*a9fa9459Szrj run_once(void* arg); 212*a9fa9459Szrj 213*a9fa9459Szrj // This is an internal function, which must be public because it is 214*a9fa9459Szrj // run by an extern "C" function called via pthread_once. 215*a9fa9459Szrj void 216*a9fa9459Szrj internal_run(void* arg); 217*a9fa9459Szrj 218*a9fa9459Szrj protected: 219*a9fa9459Szrj // This must be implemented by the child class. 220*a9fa9459Szrj virtual void 221*a9fa9459Szrj do_run_once(void* arg) = 0; 222*a9fa9459Szrj 223*a9fa9459Szrj private: 224*a9fa9459Szrj // True if we have already run the function. 225*a9fa9459Szrj bool was_run_; 226*a9fa9459Szrj #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) 227*a9fa9459Szrj // Internal compare-and-swap lock on was_run_; 228*a9fa9459Szrj uint32_t was_run_lock_; 229*a9fa9459Szrj #endif 230*a9fa9459Szrj // The lock to run the function only once. 231*a9fa9459Szrj Once_initialize* once_; 232*a9fa9459Szrj }; 233*a9fa9459Szrj 234*a9fa9459Szrj // A class used to initialize a lock exactly once, after the options 235*a9fa9459Szrj // have been read. This is needed because the implementation of locks 236*a9fa9459Szrj // depends on whether we've seen the --threads option. Before the 237*a9fa9459Szrj // options have been read, we know we are single-threaded, so we can 238*a9fa9459Szrj // get by without using a lock. This class should be an instance 239*a9fa9459Szrj // variable of the class which has a lock which needs to be 240*a9fa9459Szrj // initialized. 241*a9fa9459Szrj 242*a9fa9459Szrj class Initialize_lock : public Once 243*a9fa9459Szrj { 244*a9fa9459Szrj public: 245*a9fa9459Szrj // The class which uses this will have a pointer to a lock. This 246*a9fa9459Szrj // must be constructed with a pointer to that pointer. Initialize_lock(Lock ** pplock)247*a9fa9459Szrj Initialize_lock(Lock** pplock) 248*a9fa9459Szrj : pplock_(pplock) 249*a9fa9459Szrj { } 250*a9fa9459Szrj 251*a9fa9459Szrj // Initialize the lock. Return true if the lock is now initialized, 252*a9fa9459Szrj // false if it is not (because the options have not yet been read). 253*a9fa9459Szrj bool 254*a9fa9459Szrj initialize(); 255*a9fa9459Szrj 256*a9fa9459Szrj protected: 257*a9fa9459Szrj void 258*a9fa9459Szrj do_run_once(void*); 259*a9fa9459Szrj 260*a9fa9459Szrj private: 261*a9fa9459Szrj // A pointer to the lock pointer which must be initialized. 262*a9fa9459Szrj Lock** const pplock_; 263*a9fa9459Szrj }; 264*a9fa9459Szrj 265*a9fa9459Szrj } // End namespace gold. 266*a9fa9459Szrj 267*a9fa9459Szrj #endif // !defined(GOLD_THREADS_H) 268