text: // gold-threads.h -- thread support for gold  -*- C++ -*-
  
  // Copyright (C) 2006-2021 Free Software Foundation, Inc.
  // Written by Ian Lance Taylor <iant@google.com>.
  
  // This file is part of gold.
  
  // This program is free software; you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation; either version 3 of the License, or
  // (at your option) any later version.
  
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  
  // You should have received a copy of the GNU General Public License
  // along with this program; if not, write to the Free Software
  // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  // MA 02110-1301, USA.
  
  // gold can be configured to support threads.  If threads are
  // supported, the user can specify at runtime whether or not to
  // support them.  This provides an interface to manage locking
  // accordingly.
  
  // Lock
  //   A simple lock class.
  
  #ifndef GOLD_THREADS_H
  #define GOLD_THREADS_H
  
  namespace gold
  {
  
  class Condvar;
  class Once_initialize;
  class Initialize_lock_once;
  
  // The interface for the implementation of a Lock.
  
  class Lock_impl
  {
   public:
    Lock_impl()
    { }
  
    virtual
    ~Lock_impl()
    { }
  
    virtual void
    acquire() = 0;
  
    virtual void
    release() = 0;
  };
  
  // A simple lock class.
  
  class Lock
  {
   public:
    Lock();
  
    ~Lock();
  
    // Acquire the lock.
    void
    acquire()
    { this->lock_->acquire(); }
  
    // Release the lock.
    void
    release()
    { this->lock_->release(); }
  
   private:
    // This class can not be copied.
    Lock(const Lock&);
    Lock& operator=(const Lock&);
  
    friend class Condvar;
    Lock_impl*
    get_impl() const
    { return this->lock_; }
  
    Lock_impl* lock_;
  };
  
  // RAII for Lock.
  
  class Hold_lock
  {
   public:
    Hold_lock(Lock& lock)
      : lock_(lock)
    { this->lock_.acquire(); }
  
    ~Hold_lock()
    { this->lock_.release(); }
  
   private:
    // This class can not be copied.
    Hold_lock(const Hold_lock&);
    Hold_lock& operator=(const Hold_lock&);
  
    Lock& lock_;
  };
  
  class Hold_optional_lock
  {
   public:
    Hold_optional_lock(Lock* lock)
      : lock_(lock)
    {
      if (this->lock_ != NULL)
        this->lock_->acquire();
    }
  
    ~Hold_optional_lock()
    {
      if (this->lock_ != NULL)
        this->lock_->release();
    }
  
   private:
    Hold_optional_lock(const Hold_optional_lock&);
    Hold_optional_lock& operator=(const Hold_optional_lock&);
  
    Lock* lock_;
  };
  
  // The interface for the implementation of a condition variable.
  
  class Condvar_impl
  {
   public:
    Condvar_impl()
    { }
  
    virtual
    ~Condvar_impl()
    { }
  
    virtual void
    wait(Lock_impl*) = 0;
  
    virtual void
    signal() = 0;
  
    virtual void
    broadcast() = 0;
  };
  
  // A simple condition variable class.  It is always associated with a
  // specific lock.
  
  class Condvar
  {
   public:
    Condvar(Lock& lock);
    ~Condvar();
  
    // Wait for the condition variable to be signalled.  This should
    // only be called when the lock is held.
    void
    wait()
    { this->condvar_->wait(this->lock_.get_impl()); }
  
    // Signal the condition variable--wake up at least one thread
    // waiting on the condition variable.  This should only be called
    // when the lock is held.
    void
    signal()
    { this->condvar_->signal(); }
  
    // Broadcast the condition variable--wake up all threads waiting on
    // the condition variable.  This should only be called when the lock
    // is held.
    void
    broadcast()
    { this->condvar_->broadcast(); }
  
   private:
    // This class can not be copied.
    Condvar(const Condvar&);
    Condvar& operator=(const Condvar&);
  
    Lock& lock_;
    Condvar_impl* condvar_;
  };
  
  // A class used to do something once.  This is an abstract parent
  // class; any actual use will involve a child of this.
  
  class Once
  {
   public:
    Once();
  
    virtual
    ~Once()
    { }
  
    // Call this function to do whatever it is.  We pass an argument
    // even though you have to use a child class because in some uses
    // setting the argument would itself require a Once class.
    void
    run_once(void* arg);
  
    // This is an internal function, which must be public because it is
    // run by an extern "C" function called via pthread_once.
    void
    internal_run(void* arg);
  
   protected:
    // This must be implemented by the child class.
    virtual void
    do_run_once(void* arg) = 0;
  
   private:
    // True if we have already run the function.
    bool was_run_;
  #if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
    // Internal compare-and-swap lock on was_run_;
    uint32_t was_run_lock_;
  #endif
    // The lock to run the function only once.
    Once_initialize* once_;
  };
  
  // A class used to initialize a lock exactly once, after the options
  // have been read.  This is needed because the implementation of locks
  // depends on whether we've seen the --threads option.  Before the
  // options have been read, we know we are single-threaded, so we can
  // get by without using a lock.  This class should be an instance
  // variable of the class which has a lock which needs to be
  // initialized.
  
  class Initialize_lock : public Once
  {
   public:
    // The class which uses this will have a pointer to a lock.  This
    // must be constructed with a pointer to that pointer.
    Initialize_lock(Lock** pplock)
      : pplock_(pplock)
    { }
  
    // Initialize the lock.  Return true if the lock is now initialized,
    // false if it is not (because the options have not yet been read).
    bool
    initialize();
  
   protected:
    void
    do_run_once(void*);
  
   private:
    // A pointer to the lock pointer which must be initialized.
    Lock** const pplock_;
  };
  
  } // End namespace gold.
  
  #endif // !defined(GOLD_THREADS_H)
  