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