1// gold-threads.h -- thread support for gold -*- C++ -*- 2 3// Copyright (C) 2006-2017 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 34namespace gold 35{ 36 37class Condvar; 38class Once_initialize; 39class Initialize_lock_once; 40 41// The interface for the implementation of a Lock. 42 43class 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 62class 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 94class 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 112class 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 137class 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 160class 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 198class 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 242class 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