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