175fd0b74Schristos // gold-threads.h -- thread support for gold -*- C++ -*- 275fd0b74Schristos 3*e992f068Schristos // Copyright (C) 2006-2022 Free Software Foundation, Inc. 475fd0b74Schristos // Written by Ian Lance Taylor <iant@google.com>. 575fd0b74Schristos 675fd0b74Schristos // This file is part of gold. 775fd0b74Schristos 875fd0b74Schristos // This program is free software; you can redistribute it and/or modify 975fd0b74Schristos // it under the terms of the GNU General Public License as published by 1075fd0b74Schristos // the Free Software Foundation; either version 3 of the License, or 1175fd0b74Schristos // (at your option) any later version. 1275fd0b74Schristos 1375fd0b74Schristos // This program is distributed in the hope that it will be useful, 1475fd0b74Schristos // but WITHOUT ANY WARRANTY; without even the implied warranty of 1575fd0b74Schristos // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1675fd0b74Schristos // GNU General Public License for more details. 1775fd0b74Schristos 1875fd0b74Schristos // You should have received a copy of the GNU General Public License 1975fd0b74Schristos // along with this program; if not, write to the Free Software 2075fd0b74Schristos // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 2175fd0b74Schristos // MA 02110-1301, USA. 2275fd0b74Schristos 2375fd0b74Schristos // gold can be configured to support threads. If threads are 2475fd0b74Schristos // supported, the user can specify at runtime whether or not to 2575fd0b74Schristos // support them. This provides an interface to manage locking 2675fd0b74Schristos // accordingly. 2775fd0b74Schristos 2875fd0b74Schristos // Lock 2975fd0b74Schristos // A simple lock class. 3075fd0b74Schristos 3175fd0b74Schristos #ifndef GOLD_THREADS_H 3275fd0b74Schristos #define GOLD_THREADS_H 3375fd0b74Schristos 3475fd0b74Schristos namespace gold 3575fd0b74Schristos { 3675fd0b74Schristos 3775fd0b74Schristos class Condvar; 3875fd0b74Schristos class Once_initialize; 3975fd0b74Schristos class Initialize_lock_once; 4075fd0b74Schristos 4175fd0b74Schristos // The interface for the implementation of a Lock. 4275fd0b74Schristos 4375fd0b74Schristos class Lock_impl 4475fd0b74Schristos { 4575fd0b74Schristos public: Lock_impl()4675fd0b74Schristos Lock_impl() 4775fd0b74Schristos { } 4875fd0b74Schristos 4975fd0b74Schristos virtual ~Lock_impl()5075fd0b74Schristos ~Lock_impl() 5175fd0b74Schristos { } 5275fd0b74Schristos 5375fd0b74Schristos virtual void 5475fd0b74Schristos acquire() = 0; 5575fd0b74Schristos 5675fd0b74Schristos virtual void 5775fd0b74Schristos release() = 0; 5875fd0b74Schristos }; 5975fd0b74Schristos 6075fd0b74Schristos // A simple lock class. 6175fd0b74Schristos 6275fd0b74Schristos class Lock 6375fd0b74Schristos { 6475fd0b74Schristos public: 6575fd0b74Schristos Lock(); 6675fd0b74Schristos 6775fd0b74Schristos ~Lock(); 6875fd0b74Schristos 6975fd0b74Schristos // Acquire the lock. 7075fd0b74Schristos void acquire()7175fd0b74Schristos acquire() 7275fd0b74Schristos { this->lock_->acquire(); } 7375fd0b74Schristos 7475fd0b74Schristos // Release the lock. 7575fd0b74Schristos void release()7675fd0b74Schristos release() 7775fd0b74Schristos { this->lock_->release(); } 7875fd0b74Schristos 7975fd0b74Schristos private: 8075fd0b74Schristos // This class can not be copied. 8175fd0b74Schristos Lock(const Lock&); 8275fd0b74Schristos Lock& operator=(const Lock&); 8375fd0b74Schristos 8475fd0b74Schristos friend class Condvar; 8575fd0b74Schristos Lock_impl* get_impl()8675fd0b74Schristos get_impl() const 8775fd0b74Schristos { return this->lock_; } 8875fd0b74Schristos 8975fd0b74Schristos Lock_impl* lock_; 9075fd0b74Schristos }; 9175fd0b74Schristos 9275fd0b74Schristos // RAII for Lock. 9375fd0b74Schristos 9475fd0b74Schristos class Hold_lock 9575fd0b74Schristos { 9675fd0b74Schristos public: Hold_lock(Lock & lock)9775fd0b74Schristos Hold_lock(Lock& lock) 9875fd0b74Schristos : lock_(lock) 9975fd0b74Schristos { this->lock_.acquire(); } 10075fd0b74Schristos ~Hold_lock()10175fd0b74Schristos ~Hold_lock() 10275fd0b74Schristos { this->lock_.release(); } 10375fd0b74Schristos 10475fd0b74Schristos private: 10575fd0b74Schristos // This class can not be copied. 10675fd0b74Schristos Hold_lock(const Hold_lock&); 10775fd0b74Schristos Hold_lock& operator=(const Hold_lock&); 10875fd0b74Schristos 10975fd0b74Schristos Lock& lock_; 11075fd0b74Schristos }; 11175fd0b74Schristos 11275fd0b74Schristos class Hold_optional_lock 11375fd0b74Schristos { 11475fd0b74Schristos public: Hold_optional_lock(Lock * lock)11575fd0b74Schristos Hold_optional_lock(Lock* lock) 11675fd0b74Schristos : lock_(lock) 11775fd0b74Schristos { 11875fd0b74Schristos if (this->lock_ != NULL) 11975fd0b74Schristos this->lock_->acquire(); 12075fd0b74Schristos } 12175fd0b74Schristos ~Hold_optional_lock()12275fd0b74Schristos ~Hold_optional_lock() 12375fd0b74Schristos { 12475fd0b74Schristos if (this->lock_ != NULL) 12575fd0b74Schristos this->lock_->release(); 12675fd0b74Schristos } 12775fd0b74Schristos 12875fd0b74Schristos private: 12975fd0b74Schristos Hold_optional_lock(const Hold_optional_lock&); 13075fd0b74Schristos Hold_optional_lock& operator=(const Hold_optional_lock&); 13175fd0b74Schristos 13275fd0b74Schristos Lock* lock_; 13375fd0b74Schristos }; 13475fd0b74Schristos 13575fd0b74Schristos // The interface for the implementation of a condition variable. 13675fd0b74Schristos 13775fd0b74Schristos class Condvar_impl 13875fd0b74Schristos { 13975fd0b74Schristos public: Condvar_impl()14075fd0b74Schristos Condvar_impl() 14175fd0b74Schristos { } 14275fd0b74Schristos 14375fd0b74Schristos virtual ~Condvar_impl()14475fd0b74Schristos ~Condvar_impl() 14575fd0b74Schristos { } 14675fd0b74Schristos 14775fd0b74Schristos virtual void 14875fd0b74Schristos wait(Lock_impl*) = 0; 14975fd0b74Schristos 15075fd0b74Schristos virtual void 15175fd0b74Schristos signal() = 0; 15275fd0b74Schristos 15375fd0b74Schristos virtual void 15475fd0b74Schristos broadcast() = 0; 15575fd0b74Schristos }; 15675fd0b74Schristos 15775fd0b74Schristos // A simple condition variable class. It is always associated with a 15875fd0b74Schristos // specific lock. 15975fd0b74Schristos 16075fd0b74Schristos class Condvar 16175fd0b74Schristos { 16275fd0b74Schristos public: 16375fd0b74Schristos Condvar(Lock& lock); 16475fd0b74Schristos ~Condvar(); 16575fd0b74Schristos 16675fd0b74Schristos // Wait for the condition variable to be signalled. This should 16775fd0b74Schristos // only be called when the lock is held. 16875fd0b74Schristos void wait()16975fd0b74Schristos wait() 17075fd0b74Schristos { this->condvar_->wait(this->lock_.get_impl()); } 17175fd0b74Schristos 17275fd0b74Schristos // Signal the condition variable--wake up at least one thread 17375fd0b74Schristos // waiting on the condition variable. This should only be called 17475fd0b74Schristos // when the lock is held. 17575fd0b74Schristos void signal()17675fd0b74Schristos signal() 17775fd0b74Schristos { this->condvar_->signal(); } 17875fd0b74Schristos 17975fd0b74Schristos // Broadcast the condition variable--wake up all threads waiting on 18075fd0b74Schristos // the condition variable. This should only be called when the lock 18175fd0b74Schristos // is held. 18275fd0b74Schristos void broadcast()18375fd0b74Schristos broadcast() 18475fd0b74Schristos { this->condvar_->broadcast(); } 18575fd0b74Schristos 18675fd0b74Schristos private: 18775fd0b74Schristos // This class can not be copied. 18875fd0b74Schristos Condvar(const Condvar&); 18975fd0b74Schristos Condvar& operator=(const Condvar&); 19075fd0b74Schristos 19175fd0b74Schristos Lock& lock_; 19275fd0b74Schristos Condvar_impl* condvar_; 19375fd0b74Schristos }; 19475fd0b74Schristos 19575fd0b74Schristos // A class used to do something once. This is an abstract parent 19675fd0b74Schristos // class; any actual use will involve a child of this. 19775fd0b74Schristos 19875fd0b74Schristos class Once 19975fd0b74Schristos { 20075fd0b74Schristos public: 20175fd0b74Schristos Once(); 20275fd0b74Schristos 20375fd0b74Schristos virtual ~Once()20475fd0b74Schristos ~Once() 20575fd0b74Schristos { } 20675fd0b74Schristos 20775fd0b74Schristos // Call this function to do whatever it is. We pass an argument 20875fd0b74Schristos // even though you have to use a child class because in some uses 20975fd0b74Schristos // setting the argument would itself require a Once class. 21075fd0b74Schristos void 21175fd0b74Schristos run_once(void* arg); 21275fd0b74Schristos 21375fd0b74Schristos // This is an internal function, which must be public because it is 21475fd0b74Schristos // run by an extern "C" function called via pthread_once. 21575fd0b74Schristos void 21675fd0b74Schristos internal_run(void* arg); 21775fd0b74Schristos 21875fd0b74Schristos protected: 21975fd0b74Schristos // This must be implemented by the child class. 22075fd0b74Schristos virtual void 22175fd0b74Schristos do_run_once(void* arg) = 0; 22275fd0b74Schristos 22375fd0b74Schristos private: 22475fd0b74Schristos // True if we have already run the function. 22575fd0b74Schristos bool was_run_; 22675fd0b74Schristos #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) 22775fd0b74Schristos // Internal compare-and-swap lock on was_run_; 22875fd0b74Schristos uint32_t was_run_lock_; 22975fd0b74Schristos #endif 23075fd0b74Schristos // The lock to run the function only once. 23175fd0b74Schristos Once_initialize* once_; 23275fd0b74Schristos }; 23375fd0b74Schristos 23475fd0b74Schristos // A class used to initialize a lock exactly once, after the options 23575fd0b74Schristos // have been read. This is needed because the implementation of locks 23675fd0b74Schristos // depends on whether we've seen the --threads option. Before the 23775fd0b74Schristos // options have been read, we know we are single-threaded, so we can 23875fd0b74Schristos // get by without using a lock. This class should be an instance 23975fd0b74Schristos // variable of the class which has a lock which needs to be 24075fd0b74Schristos // initialized. 24175fd0b74Schristos 24275fd0b74Schristos class Initialize_lock : public Once 24375fd0b74Schristos { 24475fd0b74Schristos public: 24575fd0b74Schristos // The class which uses this will have a pointer to a lock. This 24675fd0b74Schristos // must be constructed with a pointer to that pointer. Initialize_lock(Lock ** pplock)24775fd0b74Schristos Initialize_lock(Lock** pplock) 24875fd0b74Schristos : pplock_(pplock) 24975fd0b74Schristos { } 25075fd0b74Schristos 25175fd0b74Schristos // Initialize the lock. Return true if the lock is now initialized, 25275fd0b74Schristos // false if it is not (because the options have not yet been read). 25375fd0b74Schristos bool 25475fd0b74Schristos initialize(); 25575fd0b74Schristos 25675fd0b74Schristos protected: 25775fd0b74Schristos void 25875fd0b74Schristos do_run_once(void*); 25975fd0b74Schristos 26075fd0b74Schristos private: 26175fd0b74Schristos // A pointer to the lock pointer which must be initialized. 26275fd0b74Schristos Lock** const pplock_; 26375fd0b74Schristos }; 26475fd0b74Schristos 26575fd0b74Schristos } // End namespace gold. 26675fd0b74Schristos 26775fd0b74Schristos #endif // !defined(GOLD_THREADS_H) 268