1// Support for concurrent programing -*- C++ -*-
2
3// Copyright (C) 2003, 2004, 2005, 2006
4// Free Software Foundation, Inc.
5//
6// This file is part of the GNU ISO C++ Library.  This library is free
7// software; you can redistribute it and/or modify it under the
8// terms of the GNU General Public License as published by the
9// Free Software Foundation; either version 2, or (at your option)
10// any later version.
11
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16
17// You should have received a copy of the GNU General Public License along
18// with this library; see the file COPYING.  If not, write to the Free
19// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20// USA.
21
22// As a special exception, you may use this file as part of a free software
23// library without restriction.  Specifically, if other files instantiate
24// templates or use macros or inline functions from this file, or you compile
25// this file and link it with other files to produce an executable, this
26// file does not by itself cause the resulting executable to be covered by
27// the GNU General Public License.  This exception does not however
28// invalidate any other reasons why the executable file might be covered by
29// the GNU General Public License.
30
31/** @file concurrence.h
32 *  This is an internal header file, included by other library headers.
33 *  You should not attempt to use it directly.
34 */
35
36#ifndef _CONCURRENCE_H
37#define _CONCURRENCE_H 1
38
39#include <cstdlib>
40#include <exception>
41#include <bits/gthr.h>
42#include <bits/functexcept.h>
43
44_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
45
46  // Available locking policies:
47  // _S_single    single-threaded code that doesn't need to be locked.
48  // _S_mutex     multi-threaded code that requires additional support
49  //              from gthr.h or abstraction layers in concurrance.h.
50  // _S_atomic    multi-threaded code using atomic operations.
51  enum _Lock_policy { _S_single, _S_mutex, _S_atomic };
52
53  // Compile time constant that indicates prefered locking policy in
54  // the current configuration.
55  static const _Lock_policy __default_lock_policy =
56#ifdef __GTHREADS
57  // NB: This macro doesn't actually exist yet in the compiler, but is
58  // set somewhat haphazardly at configure time.
59#ifdef _GLIBCXX_ATOMIC_BUILTINS
60  _S_atomic;
61#else
62  _S_mutex;
63#endif
64#else
65  _S_single;
66#endif
67
68  // NB: As this is used in libsupc++, need to only depend on
69  // exception. No stdexception classes, no use of std::string.
70  class __concurrence_lock_error : public std::exception
71  {
72  public:
73    virtual char const*
74    what() const throw()
75    { return "__gnu_cxx::__concurrence_lock_error"; }
76  };
77
78  class __concurrence_unlock_error : public std::exception
79  {
80  public:
81    virtual char const*
82    what() const throw()
83    { return "__gnu_cxx::__concurrence_unlock_error"; }
84  };
85
86  // Substitute for concurrence_error object in the case of -fno-exceptions.
87  inline void
88  __throw_concurrence_lock_error()
89  {
90#if __EXCEPTIONS
91    throw __concurrence_lock_error();
92#else
93    std::abort();
94#endif
95  }
96
97  inline void
98  __throw_concurrence_unlock_error()
99  {
100#if __EXCEPTIONS
101    throw __concurrence_unlock_error();
102#else
103    std::abort();
104#endif
105  }
106
107  class __mutex
108  {
109  private:
110    __gthread_mutex_t _M_mutex;
111
112    __mutex(const __mutex&);
113    __mutex& operator=(const __mutex&);
114
115  public:
116    __mutex()
117    {
118#if __GTHREADS
119      if (__gthread_active_p())
120	{
121#if defined __GTHREAD_MUTEX_INIT
122	  __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
123	  _M_mutex = __tmp;
124#else
125	  __GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
126#endif
127	}
128#endif
129    }
130
131    void lock()
132    {
133#if __GTHREADS
134      if (__gthread_active_p())
135	{
136	  if (__gthread_mutex_lock(&_M_mutex) != 0)
137	    __throw_concurrence_lock_error();
138	}
139#endif
140    }
141
142    void unlock()
143    {
144#if __GTHREADS
145      if (__gthread_active_p())
146	{
147	  if (__gthread_mutex_unlock(&_M_mutex) != 0)
148	    __throw_concurrence_unlock_error();
149	}
150#endif
151    }
152  };
153
154  class __recursive_mutex
155  {
156  private:
157    __gthread_recursive_mutex_t _M_mutex;
158
159    __recursive_mutex(const __recursive_mutex&);
160    __recursive_mutex& operator=(const __recursive_mutex&);
161
162  public:
163    __recursive_mutex()
164    {
165#if __GTHREADS
166      if (__gthread_active_p())
167	{
168#if defined __GTHREAD_RECURSIVE_MUTEX_INIT
169	  __gthread_recursive_mutex_t __tmp = __GTHREAD_RECURSIVE_MUTEX_INIT;
170	  _M_mutex = __tmp;
171#else
172	  __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION(&_M_mutex);
173#endif
174	}
175#endif
176    }
177
178    void lock()
179    {
180#if __GTHREADS
181      if (__gthread_active_p())
182	{
183	  if (__gthread_recursive_mutex_lock(&_M_mutex) != 0)
184	    __throw_concurrence_lock_error();
185	}
186#endif
187    }
188
189    void unlock()
190    {
191#if __GTHREADS
192      if (__gthread_active_p())
193	{
194	  if (__gthread_recursive_mutex_unlock(&_M_mutex) != 0)
195	    __throw_concurrence_unlock_error();
196	}
197#endif
198    }
199  };
200
201  /// @brief  Scoped lock idiom.
202  // Acquire the mutex here with a constructor call, then release with
203  // the destructor call in accordance with RAII style.
204  class __scoped_lock
205  {
206  public:
207    typedef __mutex __mutex_type;
208
209  private:
210    __mutex_type& _M_device;
211
212    __scoped_lock(const __scoped_lock&);
213    __scoped_lock& operator=(const __scoped_lock&);
214
215  public:
216    explicit __scoped_lock(__mutex_type& __name) : _M_device(__name)
217    { _M_device.lock(); }
218
219    ~__scoped_lock() throw()
220    { _M_device.unlock(); }
221  };
222
223_GLIBCXX_END_NAMESPACE
224
225#endif
226