1169691Skan// Support for concurrent programing -*- C++ -*-
2169691Skan
3169691Skan// Copyright (C) 2003, 2004, 2005, 2006
4169691Skan// Free Software Foundation, Inc.
5169691Skan//
6169691Skan// This file is part of the GNU ISO C++ Library.  This library is free
7169691Skan// software; you can redistribute it and/or modify it under the
8169691Skan// terms of the GNU General Public License as published by the
9169691Skan// Free Software Foundation; either version 2, or (at your option)
10169691Skan// any later version.
11169691Skan
12169691Skan// This library is distributed in the hope that it will be useful,
13169691Skan// but WITHOUT ANY WARRANTY; without even the implied warranty of
14169691Skan// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15169691Skan// GNU General Public License for more details.
16169691Skan
17169691Skan// You should have received a copy of the GNU General Public License along
18169691Skan// with this library; see the file COPYING.  If not, write to the Free
19169691Skan// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20169691Skan// USA.
21169691Skan
22169691Skan// As a special exception, you may use this file as part of a free software
23169691Skan// library without restriction.  Specifically, if other files instantiate
24169691Skan// templates or use macros or inline functions from this file, or you compile
25169691Skan// this file and link it with other files to produce an executable, this
26169691Skan// file does not by itself cause the resulting executable to be covered by
27169691Skan// the GNU General Public License.  This exception does not however
28169691Skan// invalidate any other reasons why the executable file might be covered by
29169691Skan// the GNU General Public License.
30169691Skan
31169691Skan/** @file concurrence.h
32169691Skan *  This is an internal header file, included by other library headers.
33169691Skan *  You should not attempt to use it directly.
34169691Skan */
35169691Skan
36169691Skan#ifndef _CONCURRENCE_H
37169691Skan#define _CONCURRENCE_H 1
38169691Skan
39169691Skan#include <cstdlib>
40169691Skan#include <exception>
41169691Skan#include <bits/gthr.h>
42169691Skan#include <bits/functexcept.h>
43169691Skan
44169691Skan_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
45169691Skan
46169691Skan  // Available locking policies:
47169691Skan  // _S_single    single-threaded code that doesn't need to be locked.
48169691Skan  // _S_mutex     multi-threaded code that requires additional support
49228780Spfg  //              from gthr.h or abstraction layers in concurrence.h.
50169691Skan  // _S_atomic    multi-threaded code using atomic operations.
51169691Skan  enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
52169691Skan
53169691Skan  // Compile time constant that indicates prefered locking policy in
54169691Skan  // the current configuration.
55169691Skan  static const _Lock_policy __default_lock_policy =
56169691Skan#ifdef __GTHREADS
57169691Skan  // NB: This macro doesn't actually exist yet in the compiler, but is
58169691Skan  // set somewhat haphazardly at configure time.
59169691Skan#ifdef _GLIBCXX_ATOMIC_BUILTINS
60169691Skan  _S_atomic;
61169691Skan#else
62169691Skan  _S_mutex;
63169691Skan#endif
64169691Skan#else
65169691Skan  _S_single;
66169691Skan#endif
67169691Skan
68169691Skan  // NB: As this is used in libsupc++, need to only depend on
69169691Skan  // exception. No stdexception classes, no use of std::string.
70169691Skan  class __concurrence_lock_error : public std::exception
71169691Skan  {
72169691Skan  public:
73169691Skan    virtual char const*
74169691Skan    what() const throw()
75169691Skan    { return "__gnu_cxx::__concurrence_lock_error"; }
76169691Skan  };
77169691Skan
78169691Skan  class __concurrence_unlock_error : public std::exception
79169691Skan  {
80169691Skan  public:
81169691Skan    virtual char const*
82169691Skan    what() const throw()
83169691Skan    { return "__gnu_cxx::__concurrence_unlock_error"; }
84169691Skan  };
85169691Skan
86169691Skan  // Substitute for concurrence_error object in the case of -fno-exceptions.
87169691Skan  inline void
88169691Skan  __throw_concurrence_lock_error()
89169691Skan  {
90169691Skan#if __EXCEPTIONS
91169691Skan    throw __concurrence_lock_error();
92169691Skan#else
93169691Skan    std::abort();
94169691Skan#endif
95169691Skan  }
96169691Skan
97169691Skan  inline void
98169691Skan  __throw_concurrence_unlock_error()
99169691Skan  {
100169691Skan#if __EXCEPTIONS
101169691Skan    throw __concurrence_unlock_error();
102169691Skan#else
103169691Skan    std::abort();
104169691Skan#endif
105169691Skan  }
106169691Skan
107169691Skan  class __mutex
108169691Skan  {
109169691Skan  private:
110169691Skan    __gthread_mutex_t _M_mutex;
111169691Skan
112169691Skan    __mutex(const __mutex&);
113169691Skan    __mutex& operator=(const __mutex&);
114169691Skan
115169691Skan  public:
116169691Skan    __mutex()
117169691Skan    {
118169691Skan#if __GTHREADS
119169691Skan      if (__gthread_active_p())
120169691Skan	{
121169691Skan#if defined __GTHREAD_MUTEX_INIT
122169691Skan	  __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
123169691Skan	  _M_mutex = __tmp;
124169691Skan#else
125169691Skan	  __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
126169691Skan#endif
127169691Skan	}
128169691Skan#endif
129169691Skan    }
130169691Skan
131169691Skan    void lock()
132169691Skan    {
133169691Skan#if __GTHREADS
134169691Skan      if (__gthread_active_p())
135169691Skan	{
136169691Skan	  if (__gthread_mutex_lock(&_M_mutex) != 0)
137169691Skan	    __throw_concurrence_lock_error();
138169691Skan	}
139169691Skan#endif
140169691Skan    }
141169691Skan
142169691Skan    void unlock()
143169691Skan    {
144169691Skan#if __GTHREADS
145169691Skan      if (__gthread_active_p())
146169691Skan	{
147169691Skan	  if (__gthread_mutex_unlock(&_M_mutex) != 0)
148169691Skan	    __throw_concurrence_unlock_error();
149169691Skan	}
150169691Skan#endif
151169691Skan    }
152169691Skan  };
153169691Skan
154169691Skan  class __recursive_mutex
155169691Skan  {
156169691Skan  private:
157169691Skan    __gthread_recursive_mutex_t _M_mutex;
158169691Skan
159169691Skan    __recursive_mutex(const __recursive_mutex&);
160169691Skan    __recursive_mutex& operator=(const __recursive_mutex&);
161169691Skan
162169691Skan  public:
163169691Skan    __recursive_mutex()
164169691Skan    {
165169691Skan#if __GTHREADS
166169691Skan      if (__gthread_active_p())
167169691Skan	{
168169691Skan#if defined __GTHREAD_RECURSIVE_MUTEX_INIT
169169691Skan	  __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
170169691Skan	  _M_mutex = __tmp;
171169691Skan#else
172169691Skan	  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
173169691Skan#endif
174169691Skan	}
175169691Skan#endif
176169691Skan    }
177169691Skan
178169691Skan    void lock()
179169691Skan    {
180169691Skan#if __GTHREADS
181169691Skan      if (__gthread_active_p())
182169691Skan	{
183169691Skan	  if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
184169691Skan	    __throw_concurrence_lock_error();
185169691Skan	}
186169691Skan#endif
187169691Skan    }
188169691Skan
189169691Skan    void unlock()
190169691Skan    {
191169691Skan#if __GTHREADS
192169691Skan      if (__gthread_active_p())
193169691Skan	{
194169691Skan	  if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
195169691Skan	    __throw_concurrence_unlock_error();
196169691Skan	}
197169691Skan#endif
198169691Skan    }
199169691Skan  };
200169691Skan
201169691Skan  /// @brief  Scoped lock idiom.
202169691Skan  // Acquire the mutex here with a constructor call, then release with
203169691Skan  // the destructor call in accordance with RAII style.
204169691Skan  class __scoped_lock
205169691Skan  {
206169691Skan  public:
207169691Skan    typedef __mutex __mutex_type;
208169691Skan
209169691Skan  private:
210169691Skan    __mutex_type& _M_device;
211169691Skan
212169691Skan    __scoped_lock(const __scoped_lock&);
213169691Skan    __scoped_lock& operator=(const __scoped_lock&);
214169691Skan
215169691Skan  public:
216169691Skan    explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
217169691Skan    { _M_device.lock(); }
218169691Skan
219169691Skan    ~__scoped_lock() throw()
220169691Skan    { _M_device.unlock(); }
221169691Skan  };
222169691Skan
223169691Skan_GLIBCXX_END_NAMESPACE
224169691Skan
225169691Skan#endif
226