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