xref: /netbsd-src/external/gpl3/binutils.old/dist/gold/gold-threads.h (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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