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