This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[c++0x] prototype <mutex> implementation


Attached is an implementation of <mutex> based on pthreads.

Does it make sense?

From building GCC from source I'm aware that a build without pthread support is possible.

How should we deal with this in the thread library?
Should we #error out?

--
 P.
// Copyright (C) 2008 Pedro Lamarão
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef MUTEX_HPP_
#define MUTEX_HPP_

#include <date_time>
#include <exception>
#include <utility>

#include <pthread.h>

namespace std {

  class mutex
  {
  public:
    mutex();
    ~mutex();

    // mutex(const mutex&) = delete;
    // mutex& operator=(const mutex&) = delete;
    
    void lock();
    bool try_lock();
    void unlock();
    
    typedef pthread_mutex_t* native_handle_type;
    native_handle_type native_handle()
    {
      return &m_handle;
    }
  
  private:
      pthread_mutex_t m_handle;
    
  private:
    mutex(const mutex&); // = delete;
    mutex& operator=(const mutex&); // = delete;
  };

  class recursive_mutex;
  class timed_mutex;
  class recursive_timed_mutex;
 
  struct defer_lock_t { };
  struct try_to_lock_t { };
  struct adopt_lock_t { };

  extern const defer_lock_t defer_lock;
  extern const try_to_lock_t try_to_lock;
  extern const adopt_lock_t adopt_lock;

  class lock_error : public exception
  {
  public:
    virtual const char* what() const throw();
  };

  template <class Mutex> class lock_guard;

  template <class Mutex>
  class unique_lock
  {
  public:

    typedef Mutex mutex_type;

    // 30.3.3.2.1 construct/copy/destroy

    unique_lock() : pm(0), owns(false) { }
    
    explicit unique_lock(mutex_type& m)
    : pm(&m), owns(true)
    {
      m.lock();
    }
    
    unique_lock(mutex_type& m, defer_lock_t)
    : pm(&m), owns(false) {    }
    
    
    unique_lock(mutex_type& m, try_to_lock_t)
    : pm(&m), owns(false)
    {
      owns = m.try_lock();
    }
    
    unique_lock(mutex_type& m, adopt_lock_t)
    : pm(&m), owns(true) { }
    
    unique_lock(mutex_type& m, const system_time& abs_time)
    : pm(&m), owns(false)
    {
      owns = m.timed_lock(abs_time);
    }
    
    template <class Duration>
      unique_lock(mutex_type& m, const Duration& rel_time)
    : pm(&m), owns(false)
    {
      owns = m.timed_lock(rel_time);
    }
    
    ~unique_lock()
    {
      if (owns)
        pm->unlock();
    }
    
    // unique_lock(unique_lock const&) = delete;
    
    // unique_lock& operator=(unique_lock const&) = delete;

#ifdef __GXX_EXPERIMENTAL_CXX0X__

    unique_lock(unique_lock&& u)
    : pm(u.pm), owns(u.owns)
    {
      u.pm = NULL;
      u.owns = false;
    }
    
    unique_lock& operator=(unique_lock&& u)
    {
      if (owns)
        pm->unlock();
      pm = u.pm;
      owns = u.owns;
      u.pm = 0;
      u.owns = false;
    }
    
#endif
    
    // 30.3.3.2.2 locking
    
    void lock()
    {
      if (!pm || owns) {
        // FIXME: throw lock_error.
      }
      pm->lock();
    }
    
    bool try_lock()
    {
      if (!pm || owns) {
        // FIXME: throw lock_error.
      }
      return pm->try_lock();        
    }
    
    template <class Duration>
      bool timed_lock(const Duration& rel_time)
    {
      if (!pm || owns) {
        // FIXME: throw lock_error.
      }
      return pm->timed_lock(rel_time);
    }
    
    bool timed_lock(const system_time& abs_time)
    {
      if (!pm || owns) {
        // FIXME: throw lock_error.
      }
      return pm->timed_lock(abs_time);
    }
    
    void unlock()
    {
      if (!owns) {
        // FIXME: throw lock_error.
      }
      return pm->unlock();
    }
    
    // 30.3.3.2.3 modifiers

#ifdef __GXX_EXPERIMENTAL_CXX0X__

    void swap(unique_lock&& u)
    {
      std::swap(pm, u.pm);
      std::swap(owns, u.owns);
    }

#else

    void swap(unique_lock& u)
    {
      std::swap(pm, u.pm);
      std::swap(owns, u.owns);
    }
    
#endif
    
    mutex_type* release()
    {
      mutex_type* tmp = pm;
      pm = 0;
      owns = false;
      return tmp;
    }
    
    // 30.3.3.2.4 observers
    
    bool owns_lock() const
    {
      return owns;
    }
    
    /*explicit*/ operator bool () const
    {
      return owns;
    }
    
    mutex_type* mutex() const
    {
      return pm;
    }
  
  private:
    mutex_type* pm;
    bool owns;

  private:
    unique_lock(unique_lock const&); // = delete;        
    unique_lock& operator=(unique_lock const&); // = delete;
  };
  
  template <class Mutex>
    void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)
    {
      x.swap(y);  
    }
  
#ifdef __GXX_EXPERIMENTAL_CXX0X__

  template <class Mutex>
    void swap(unique_lock<Mutex>&& x, unique_lock<Mutex>& y)
    {
      x.swap(y);  
    }

  template <class Mutex>
    void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&& y)
    {
      x.swap(y);  
    }

#endif

#ifdef __GXX_EXPERIMENTAL_CXX0X__
  template <class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
  template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
#endif
  
  struct once_flag {
    /*constexpr*/ once_flag();
  
    // once_flag(const once_flag&) = delete;
    // once_flag& operator=(const once_flag&) = delete;
    
  private:
    once_flag(const once_flag&); // = delete;
    once_flag& operator=(const once_flag&); // = delete;
  };

#ifdef __GXX_EXPERIMENTAL_CXX0X__
  template<class Callable, class ...Args>
    void call_once(once_flag& flag, Callable func, Args&&... args);
#endif
  template<class Callable>
    void call_once(once_flag& flag, Callable func);
  
} // std

#endif /*MUTEX_HPP_*/
// Copyright (C) 2008 Pedro Lamarão
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <mutex.hpp>

#include <cassert>
#include <cerrno>

namespace std {

	mutex::mutex () {
		pthread_mutex_init(&m_handle, 0);
	}
	
	mutex::~mutex () {
		pthread_mutex_destroy(&m_handle);
	}
	
	void mutex::lock () {
		pthread_mutex_lock(&m_handle);
	}

	bool mutex::try_lock () {
		int status = pthread_mutex_lock(&m_handle);		
		return status == 0 ? true : false;
	}

	void mutex::unlock () {
		pthread_mutex_unlock(&m_handle);
	}

}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]