1 // Threading support -*- C++ -*- 2 3 // Copyright (C) 2001, 2002 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 2, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // You should have received a copy of the GNU General Public License along 17 // with this library; see the file COPYING. If not, write to the Free 18 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 // USA. 20 21 // As a special exception, you may use this file as part of a free software 22 // library without restriction. Specifically, if other files instantiate 23 // templates or use macros or inline functions from this file, or you compile 24 // this file and link it with other files to produce an executable, this 25 // file does not by itself cause the resulting executable to be covered by 26 // the GNU General Public License. This exception does not however 27 // invalidate any other reasons why the executable file might be covered by 28 // the GNU General Public License. 29 30 /* 31 * Copyright (c) 1997-1999 32 * Silicon Graphics Computer Systems, Inc. 33 * 34 * Permission to use, copy, modify, distribute and sell this software 35 * and its documentation for any purpose is hereby granted without fee, 36 * provided that the above copyright notice appear in all copies and 37 * that both that copyright notice and this permission notice appear 38 * in supporting documentation. Silicon Graphics makes no 39 * representations about the suitability of this software for any 40 * purpose. It is provided "as is" without express or implied warranty. 41 */ 42 43 /** @file stl_threads.h 44 * This is an internal header file, included by other library headers. 45 * You should not attempt to use it directly. 46 */ 47 48 #ifndef __SGI_STL_INTERNAL_THREADS_H 49 #define __SGI_STL_INTERNAL_THREADS_H 50 51 // The only supported threading model is GCC's own gthr.h abstraction layer. 52 #include "bits/gthr.h" 53 54 namespace std 55 { 56 // Class _Refcount_Base provides a type, _RC_t, a data member, 57 // _M_ref_count, and member functions _M_incr and _M_decr, which perform 58 // atomic preincrement/predecrement. The constructor initializes 59 // _M_ref_count. 60 struct _Refcount_Base 61 { 62 // The type _RC_t 63 typedef size_t _RC_t; 64 65 // The data member _M_ref_count 66 volatile _RC_t _M_ref_count; 67 68 // Constructor 69 __gthread_mutex_t _M_ref_count_lock; 70 _Refcount_Base_Refcount_Base71 _Refcount_Base(_RC_t __n) : _M_ref_count(__n) 72 { 73 #ifdef __GTHREAD_MUTEX_INIT 74 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT; 75 _M_ref_count_lock = __tmp; 76 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION) 77 __GTHREAD_MUTEX_INIT_FUNCTION (&_M_ref_count_lock); 78 #else 79 #error __GTHREAD_MUTEX_INIT or __GTHREAD_MUTEX_INIT_FUNCTION should be defined by gthr.h abstraction layer, report problem to libstdc++@gcc.gnu.org. 80 #endif 81 } 82 83 void _M_incr_Refcount_Base84 _M_incr() 85 { 86 __gthread_mutex_lock(&_M_ref_count_lock); 87 ++_M_ref_count; 88 __gthread_mutex_unlock(&_M_ref_count_lock); 89 } 90 91 _RC_t _M_decr_Refcount_Base92 _M_decr() 93 { 94 __gthread_mutex_lock(&_M_ref_count_lock); 95 volatile _RC_t __tmp = --_M_ref_count; 96 __gthread_mutex_unlock(&_M_ref_count_lock); 97 return __tmp; 98 } 99 }; 100 101 // Atomic swap on unsigned long 102 // This is guaranteed to behave as though it were atomic only if all 103 // possibly concurrent updates use _Atomic_swap. 104 // In some cases the operation is emulated with a lock. 105 #if defined (__GTHREAD_MUTEX_INIT) 106 // This could be optimized to use the atomicity.h abstraction layer. 107 // vyzo: simple _Atomic_swap implementation following the guidelines above 108 // We use a template here only to get a unique initialized instance. 109 template<int __dummy> 110 struct _Swap_lock_struct 111 { static __gthread_mutex_t _S_swap_lock; }; 112 113 template<int __dummy> 114 __gthread_mutex_t 115 _Swap_lock_struct<__dummy>::_S_swap_lock = __GTHREAD_MUTEX_INIT; 116 117 // This should be portable, but performance is expected to be quite 118 // awful. This really needs platform specific code. 119 inline unsigned long _Atomic_swap(unsigned long * __p,unsigned long __q)120 _Atomic_swap(unsigned long * __p, unsigned long __q) 121 { 122 __gthread_mutex_lock(&_Swap_lock_struct<0>::_S_swap_lock); 123 unsigned long __result = *__p; 124 *__p = __q; 125 __gthread_mutex_unlock(&_Swap_lock_struct<0>::_S_swap_lock); 126 return __result; 127 } 128 #endif 129 } //namespace std 130 131 // Locking class. Note that this class *does not have a 132 // constructor*. It must be initialized either statically, with 133 // __STL_MUTEX_INITIALIZER, or dynamically, by explicitly calling 134 // the _M_initialize member function. (This is similar to the ways 135 // that a pthreads mutex can be initialized.) There are explicit 136 // member functions for acquiring and releasing the lock. 137 138 // There is no constructor because static initialization is 139 // essential for some uses, and only a class aggregate (see section 140 // 8.5.1 of the C++ standard) can be initialized that way. That 141 // means we must have no constructors, no base classes, no virtual 142 // functions, and no private or protected members. 143 144 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION) 145 namespace __gnu_cxx 146 { 147 extern __gthread_mutex_t _GLIBCPP_mutex; 148 extern __gthread_mutex_t *_GLIBCPP_mutex_address; 149 extern __gthread_once_t _GLIBCPP_once; 150 extern void _GLIBCPP_mutex_init (void); 151 extern void _GLIBCPP_mutex_address_init (void); 152 } 153 #endif 154 155 namespace std 156 { 157 struct _STL_mutex_lock 158 { 159 // The class must be statically initialized with __STL_MUTEX_INITIALIZER. 160 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION) 161 volatile int _M_init_flag; 162 __gthread_once_t _M_once; 163 #endif 164 __gthread_mutex_t _M_lock; 165 166 void _M_initialize_STL_mutex_lock167 _M_initialize() 168 { 169 #ifdef __GTHREAD_MUTEX_INIT 170 // There should be no code in this path given the usage rules above. 171 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION) 172 if (_M_init_flag) return; 173 if (__gthread_once (&__gnu_cxx::_GLIBCPP_once, 174 __gnu_cxx::_GLIBCPP_mutex_init) != 0 175 && __gthread_active_p ()) 176 abort (); 177 __gthread_mutex_lock (&__gnu_cxx::_GLIBCPP_mutex); 178 if (!_M_init_flag) 179 { 180 // Even though we have a global lock, we use __gthread_once to be 181 // absolutely certain the _M_lock mutex is only initialized once on 182 // multiprocessor systems. 183 __gnu_cxx::_GLIBCPP_mutex_address = &_M_lock; 184 if (__gthread_once (&_M_once, 185 __gnu_cxx::_GLIBCPP_mutex_address_init) != 0 186 && __gthread_active_p ()) 187 abort (); 188 _M_init_flag = 1; 189 } 190 __gthread_mutex_unlock (&__gnu_cxx::_GLIBCPP_mutex); 191 #endif 192 } 193 194 void _M_acquire_lock_STL_mutex_lock195 _M_acquire_lock() 196 { 197 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION) 198 if (!_M_init_flag) _M_initialize(); 199 #endif 200 __gthread_mutex_lock(&_M_lock); 201 } 202 203 void _M_release_lock_STL_mutex_lock204 _M_release_lock() 205 { 206 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION) 207 if (!_M_init_flag) _M_initialize(); 208 #endif 209 __gthread_mutex_unlock(&_M_lock); 210 } 211 }; 212 213 #ifdef __GTHREAD_MUTEX_INIT 214 #define __STL_MUTEX_INITIALIZER = { __GTHREAD_MUTEX_INIT } 215 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION) 216 #ifdef __GTHREAD_MUTEX_INIT_DEFAULT 217 #define __STL_MUTEX_INITIALIZER \ 218 = { 0, __GTHREAD_ONCE_INIT, __GTHREAD_MUTEX_INIT_DEFAULT } 219 #else 220 #define __STL_MUTEX_INITIALIZER = { 0, __GTHREAD_ONCE_INIT } 221 #endif 222 #endif 223 224 // A locking class that uses _STL_mutex_lock. The constructor takes a 225 // reference to an _STL_mutex_lock, and acquires a lock. The 226 // destructor releases the lock. It's not clear that this is exactly 227 // the right functionality. It will probably change in the future. 228 struct _STL_auto_lock 229 { 230 _STL_mutex_lock& _M_lock; 231 _STL_auto_lock_STL_auto_lock232 _STL_auto_lock(_STL_mutex_lock& __lock) : _M_lock(__lock) 233 { _M_lock._M_acquire_lock(); } 234 ~_STL_auto_lock_STL_auto_lock235 ~_STL_auto_lock() { _M_lock._M_release_lock(); } 236 237 private: 238 void operator=(const _STL_auto_lock&); 239 _STL_auto_lock(const _STL_auto_lock&); 240 }; 241 242 } // namespace std 243 244 #endif 245