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