(root)/
binutils-2.41/
gold/
gold-threads.h
       1  // gold-threads.h -- thread support for gold  -*- C++ -*-
       2  
       3  // Copyright (C) 2006-2023 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)