|
Whole document tree stl_threads.hGo to the documentation of this file.00001 // Threading support -*- C++ -*-
00002
00003 // Copyright (C) 2001 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library. This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 2, or (at your option)
00009 // any later version.
00010
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014 // GNU General Public License for more details.
00015
00016 // You should have received a copy of the GNU General Public License along
00017 // with this library; see the file COPYING. If not, write to the Free
00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00019 // USA.
00020
00021 // As a special exception, you may use this file as part of a free software
00022 // library without restriction. Specifically, if other files instantiate
00023 // templates or use macros or inline functions from this file, or you compile
00024 // this file and link it with other files to produce an executable, this
00025 // file does not by itself cause the resulting executable to be covered by
00026 // the GNU General Public License. This exception does not however
00027 // invalidate any other reasons why the executable file might be covered by
00028 // the GNU General Public License.
00029
00030 /*
00031 * Copyright (c) 1997-1999
00032 * Silicon Graphics Computer Systems, Inc.
00033 *
00034 * Permission to use, copy, modify, distribute and sell this software
00035 * and its documentation for any purpose is hereby granted without fee,
00036 * provided that the above copyright notice appear in all copies and
00037 * that both that copyright notice and this permission notice appear
00038 * in supporting documentation. Silicon Graphics makes no
00039 * representations about the suitability of this software for any
00040 * purpose. It is provided "as is" without express or implied warranty.
00041 */
00042
00043 // WARNING: This is an internal header file, included by other C++
00044 // standard library headers. You should not attempt to use this header
00045 // file directly.
00046 // Stl_config.h should be included before this file.
00047
00048 #ifndef __SGI_STL_INTERNAL_THREADS_H
00049 #define __SGI_STL_INTERNAL_THREADS_H
00050
00051 // Supported threading models are native SGI, pthreads, uithreads
00052 // (similar to pthreads, but based on an earlier draft of the Posix
00053 // threads standard), and Win32 threads. Uithread support by Jochen
00054 // Schlick, 1999.
00055
00056 // GCC extension begin
00057 // In order to present a stable threading configuration, in all cases,
00058 // gcc looks for it's own abstraction layer before all others. All
00059 // modifications to this file are marked to allow easier importation of
00060 // STL upgrades.
00061 #if defined(__STL_GTHREADS)
00062 #include "bits/gthr.h"
00063 #else
00064 // GCC extension end
00065 #if defined(__STL_SGI_THREADS)
00066 #include <mutex.h>
00067 #include <time.h>
00068 #elif defined(__STL_PTHREADS)
00069 #include <pthread.h>
00070 #elif defined(__STL_UITHREADS)
00071 #include <thread.h>
00072 #include <synch.h>
00073 #elif defined(__STL_WIN32THREADS)
00074 #include <windows.h>
00075 #endif
00076 // GCC extension begin
00077 #endif
00078 // GCC extension end
00079
00080 namespace std
00081 {
00082
00083 // Class _Refcount_Base provides a type, _RC_t, a data member,
00084 // _M_ref_count, and member functions _M_incr and _M_decr, which perform
00085 // atomic preincrement/predecrement. The constructor initializes
00086 // _M_ref_count.
00087
00088 // Hack for SGI o32 compilers.
00089 #if defined(__STL_SGI_THREADS) && !defined(__add_and_fetch) && \
00090 (__mips < 3 || !(defined (_ABIN32) || defined(_ABI64)))
00091 # define __add_and_fetch(__l,__v) add_then_test((unsigned long*)__l,__v)
00092 # define __test_and_set(__l,__v) test_and_set(__l,__v)
00093 #endif /* o32 */
00094
00095 struct _Refcount_Base
00096 {
00097 // The type _RC_t
00098 # ifdef __STL_WIN32THREADS
00099 typedef long _RC_t;
00100 # else
00101 typedef size_t _RC_t;
00102 #endif
00103
00104 // The data member _M_ref_count
00105 volatile _RC_t _M_ref_count;
00106
00107 // Constructor
00108 // GCC extension begin
00109 #ifdef __STL_GTHREADS
00110 __gthread_mutex_t _M_ref_count_lock;
00111 _Refcount_Base(_RC_t __n) : _M_ref_count(__n)
00112 {
00113 #ifdef __GTHREAD_MUTEX_INIT
00114 __gthread_mutex_t __tmp = __GTHREAD_MUTEX_INIT;
00115 _M_ref_count_lock = __tmp;
00116 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00117 __GTHREAD_MUTEX_INIT_FUNCTION (&_M_ref_count_lock);
00118 #else
00119 #error __GTHREAD_MUTEX_INIT or __GTHREAD_MUTEX_INIT_FUNCTION should be defined by gthr.h abstraction layer, report problem to libstdc++@gcc.gnu.org.
00120 #endif
00121 }
00122 #else
00123 // GCC extension end
00124 # ifdef __STL_PTHREADS
00125 pthread_mutex_t _M_ref_count_lock;
00126 _Refcount_Base(_RC_t __n) : _M_ref_count(__n)
00127 { pthread_mutex_init(&_M_ref_count_lock, 0); }
00128 # elif defined(__STL_UITHREADS)
00129 mutex_t _M_ref_count_lock;
00130 _Refcount_Base(_RC_t __n) : _M_ref_count(__n)
00131 { mutex_init(&_M_ref_count_lock, USYNC_THREAD, 0); }
00132 # else
00133 _Refcount_Base(_RC_t __n) : _M_ref_count(__n) {}
00134 # endif
00135 // GCC extension begin
00136 #endif
00137 // GCC extension end
00138
00139 // GCC extension begin
00140 #ifdef __STL_GTHREADS
00141 void _M_incr() {
00142 __gthread_mutex_lock(&_M_ref_count_lock);
00143 ++_M_ref_count;
00144 __gthread_mutex_unlock(&_M_ref_count_lock);
00145 }
00146 _RC_t _M_decr() {
00147 __gthread_mutex_lock(&_M_ref_count_lock);
00148 volatile _RC_t __tmp = --_M_ref_count;
00149 __gthread_mutex_unlock(&_M_ref_count_lock);
00150 return __tmp;
00151 }
00152 #else
00153 // GCC extension end
00154 // _M_incr and _M_decr
00155 # ifdef __STL_SGI_THREADS
00156 void _M_incr() { __add_and_fetch(&_M_ref_count, 1); }
00157 _RC_t _M_decr() { return __add_and_fetch(&_M_ref_count, (size_t) -1); }
00158 # elif defined (__STL_WIN32THREADS)
00159 void _M_incr() { InterlockedIncrement((_RC_t*)&_M_ref_count); }
00160 _RC_t _M_decr() { return InterlockedDecrement((_RC_t*)&_M_ref_count); }
00161 # elif defined(__STL_PTHREADS)
00162 void _M_incr() {
00163 pthread_mutex_lock(&_M_ref_count_lock);
00164 ++_M_ref_count;
00165 pthread_mutex_unlock(&_M_ref_count_lock);
00166 }
00167 _RC_t _M_decr() {
00168 pthread_mutex_lock(&_M_ref_count_lock);
00169 volatile _RC_t __tmp = --_M_ref_count;
00170 pthread_mutex_unlock(&_M_ref_count_lock);
00171 return __tmp;
00172 }
00173 # elif defined(__STL_UITHREADS)
00174 void _M_incr() {
00175 mutex_lock(&_M_ref_count_lock);
00176 ++_M_ref_count;
00177 mutex_unlock(&_M_ref_count_lock);
00178 }
00179 _RC_t _M_decr() {
00180 mutex_lock(&_M_ref_count_lock);
00181 /*volatile*/ _RC_t __tmp = --_M_ref_count;
00182 mutex_unlock(&_M_ref_count_lock);
00183 return __tmp;
00184 }
00185 # else /* No threads */
00186 void _M_incr() { ++_M_ref_count; }
00187 _RC_t _M_decr() { return --_M_ref_count; }
00188 # endif
00189 // GCC extension begin
00190 #endif
00191 // GCC extension end
00192 };
00193
00194 // Atomic swap on unsigned long
00195 // This is guaranteed to behave as though it were atomic only if all
00196 // possibly concurrent updates use _Atomic_swap.
00197 // In some cases the operation is emulated with a lock.
00198 // GCC extension begin
00199 #ifdef __STL_GTHREADS
00200 // We don't provide an _Atomic_swap in this configuration. This only
00201 // affects the use of ext/rope with threads. Someone could add this
00202 // later, if required. You can start by cloning the __STL_PTHREADS
00203 // path while making the obvious changes. Later it could be optimized
00204 // to use the atomicity.h abstraction layer from libstdc++-v3.
00205 #else
00206 // GCC extension end
00207 # ifdef __STL_SGI_THREADS
00208 inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) {
00209 # if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64))
00210 return test_and_set(__p, __q);
00211 # else
00212 return __test_and_set(__p, (unsigned long)__q);
00213 # endif
00214 }
00215 # elif defined(__STL_WIN32THREADS)
00216 inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) {
00217 return (unsigned long) InterlockedExchange((LPLONG)__p, (LONG)__q);
00218 }
00219 # elif defined(__STL_PTHREADS)
00220 // We use a template here only to get a unique initialized instance.
00221 template<int __dummy>
00222 struct _Swap_lock_struct {
00223 static pthread_mutex_t _S_swap_lock;
00224 };
00225
00226 template<int __dummy>
00227 pthread_mutex_t
00228 _Swap_lock_struct<__dummy>::_S_swap_lock = PTHREAD_MUTEX_INITIALIZER;
00229
00230 // This should be portable, but performance is expected
00231 // to be quite awful. This really needs platform specific
00232 // code.
00233 inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) {
00234 pthread_mutex_lock(&_Swap_lock_struct<0>::_S_swap_lock);
00235 unsigned long __result = *__p;
00236 *__p = __q;
00237 pthread_mutex_unlock(&_Swap_lock_struct<0>::_S_swap_lock);
00238 return __result;
00239 }
00240 # elif defined(__STL_UITHREADS)
00241 // We use a template here only to get a unique initialized instance.
00242 template<int __dummy>
00243 struct _Swap_lock_struct {
00244 static mutex_t _S_swap_lock;
00245 };
00246
00247 template<int __dummy>
00248 mutex_t
00249 _Swap_lock_struct<__dummy>::_S_swap_lock = DEFAULTMUTEX;
00250
00251 // This should be portable, but performance is expected
00252 // to be quite awful. This really needs platform specific
00253 // code.
00254 inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) {
00255 mutex_lock(&_Swap_lock_struct<0>::_S_swap_lock);
00256 unsigned long __result = *__p;
00257 *__p = __q;
00258 mutex_unlock(&_Swap_lock_struct<0>::_S_swap_lock);
00259 return __result;
00260 }
00261 # elif defined (__STL_SOLARIS_THREADS)
00262 // any better solutions ?
00263 // We use a template here only to get a unique initialized instance.
00264 template<int __dummy>
00265 struct _Swap_lock_struct {
00266 static mutex_t _S_swap_lock;
00267 };
00268
00269 # if ( __STL_STATIC_TEMPLATE_DATA > 0 )
00270 template<int __dummy>
00271 mutex_t
00272 _Swap_lock_struct<__dummy>::_S_swap_lock = DEFAULTMUTEX;
00273 # else
00274 __DECLARE_INSTANCE(mutex_t, _Swap_lock_struct<__dummy>::_S_swap_lock,
00275 =DEFAULTMUTEX);
00276 # endif /* ( __STL_STATIC_TEMPLATE_DATA > 0 ) */
00277
00278 // This should be portable, but performance is expected
00279 // to be quite awful. This really needs platform specific
00280 // code.
00281 inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) {
00282 mutex_lock(&_Swap_lock_struct<0>::_S_swap_lock);
00283 unsigned long __result = *__p;
00284 *__p = __q;
00285 mutex_unlock(&_Swap_lock_struct<0>::_S_swap_lock);
00286 return __result;
00287 }
00288 # else
00289 static inline unsigned long _Atomic_swap(unsigned long * __p, unsigned long __q) {
00290 unsigned long __result = *__p;
00291 *__p = __q;
00292 return __result;
00293 }
00294 # endif
00295 // GCC extension begin
00296 #endif
00297 // GCC extension end
00298
00299 // Locking class. Note that this class *does not have a constructor*.
00300 // It must be initialized either statically, with __STL_MUTEX_INITIALIZER,
00301 // or dynamically, by explicitly calling the _M_initialize member function.
00302 // (This is similar to the ways that a pthreads mutex can be initialized.)
00303 // There are explicit member functions for acquiring and releasing the lock.
00304
00305 // There is no constructor because static initialization is essential for
00306 // some uses, and only a class aggregate (see section 8.5.1 of the C++
00307 // standard) can be initialized that way. That means we must have no
00308 // constructors, no base classes, no virtual functions, and no private or
00309 // protected members.
00310
00311 // Helper struct. This is a workaround for various compilers that don't
00312 // handle static variables in inline functions properly.
00313 template <int __inst>
00314 struct _STL_mutex_spin {
00315 enum { __low_max = 30, __high_max = 1000 };
00316 // Low if we suspect uniprocessor, high for multiprocessor.
00317
00318 static unsigned __max;
00319 static unsigned __last;
00320 };
00321
00322 template <int __inst>
00323 unsigned _STL_mutex_spin<__inst>::__max = _STL_mutex_spin<__inst>::__low_max;
00324
00325 template <int __inst>
00326 unsigned _STL_mutex_spin<__inst>::__last = 0;
00327
00328 // GCC extension begin
00329 #if defined(__STL_GTHREADS)
00330 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00331 extern __gthread_mutex_t _GLIBCPP_mutex;
00332 extern __gthread_mutex_t *_GLIBCPP_mutex_address;
00333 extern __gthread_once_t _GLIBCPP_once;
00334 extern void _GLIBCPP_mutex_init (void);
00335 extern void _GLIBCPP_mutex_address_init (void);
00336 #endif
00337 #endif
00338 // GCC extension end
00339
00340 struct _STL_mutex_lock
00341 {
00342 // GCC extension begin
00343 #if defined(__STL_GTHREADS)
00344 // The class must be statically initialized with __STL_MUTEX_INITIALIZER.
00345 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00346 volatile int _M_init_flag;
00347 __gthread_once_t _M_once;
00348 #endif
00349 __gthread_mutex_t _M_lock;
00350 void _M_initialize() {
00351 #ifdef __GTHREAD_MUTEX_INIT
00352 // There should be no code in this path given the usage rules above.
00353 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00354 if (_M_init_flag) return;
00355 if (__gthread_once (&_GLIBCPP_once, _GLIBCPP_mutex_init) != 0
00356 && __gthread_active_p ())
00357 abort ();
00358 __gthread_mutex_lock (&_GLIBCPP_mutex);
00359 if (!_M_init_flag) {
00360 // Even though we have a global lock, we use __gthread_once to be
00361 // absolutely certain the _M_lock mutex is only initialized once on
00362 // multiprocessor systems.
00363 _GLIBCPP_mutex_address = &_M_lock;
00364 if (__gthread_once (&_M_once, _GLIBCPP_mutex_address_init) != 0
00365 && __gthread_active_p ())
00366 abort ();
00367 _M_init_flag = 1;
00368 }
00369 __gthread_mutex_unlock (&_GLIBCPP_mutex);
00370 #endif
00371 }
00372 void _M_acquire_lock() {
00373 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00374 if (!_M_init_flag) _M_initialize();
00375 #endif
00376 __gthread_mutex_lock(&_M_lock);
00377 }
00378 void _M_release_lock() {
00379 #if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00380 if (!_M_init_flag) _M_initialize();
00381 #endif
00382 __gthread_mutex_unlock(&_M_lock);
00383 }
00384 #else
00385 // GCC extension end
00386 #if defined(__STL_SGI_THREADS) || defined(__STL_WIN32THREADS)
00387 // It should be relatively easy to get this to work on any modern Unix.
00388 volatile unsigned long _M_lock;
00389 void _M_initialize() { _M_lock = 0; }
00390 static void _S_nsec_sleep(int __log_nsec) {
00391 # ifdef __STL_SGI_THREADS
00392 struct timespec __ts;
00393 /* Max sleep is 2**27nsec ~ 60msec */
00394 __ts.tv_sec = 0;
00395 __ts.tv_nsec = 1L << __log_nsec;
00396 nanosleep(&__ts, 0);
00397 # elif defined(__STL_WIN32THREADS)
00398 if (__log_nsec <= 20) {
00399 Sleep(0);
00400 } else {
00401 Sleep(1 << (__log_nsec - 20));
00402 }
00403 # else
00404 # error unimplemented
00405 # endif
00406 }
00407 void _M_acquire_lock() {
00408 volatile unsigned long* __lock = &this->_M_lock;
00409
00410 if (!_Atomic_swap((unsigned long*)__lock, 1)) {
00411 return;
00412 }
00413 unsigned __my_spin_max = _STL_mutex_spin<0>::__max;
00414 unsigned __my_last_spins = _STL_mutex_spin<0>::__last;
00415 volatile unsigned __junk = 17; // Value doesn't matter.
00416 unsigned __i;
00417 for (__i = 0; __i < __my_spin_max; __i++) {
00418 if (__i < __my_last_spins/2 || *__lock) {
00419 __junk *= __junk; __junk *= __junk;
00420 __junk *= __junk; __junk *= __junk;
00421 continue;
00422 }
00423 if (!_Atomic_swap((unsigned long*)__lock, 1)) {
00424 // got it!
00425 // Spinning worked. Thus we're probably not being scheduled
00426 // against the other process with which we were contending.
00427 // Thus it makes sense to spin longer the next time.
00428 _STL_mutex_spin<0>::__last = __i;
00429 _STL_mutex_spin<0>::__max = _STL_mutex_spin<0>::__high_max;
00430 return;
00431 }
00432 }
00433 // We are probably being scheduled against the other process. Sleep.
00434 _STL_mutex_spin<0>::__max = _STL_mutex_spin<0>::__low_max;
00435 for (__i = 0 ;; ++__i) {
00436 int __log_nsec = __i + 6;
00437
00438 if (__log_nsec > 27) __log_nsec = 27;
00439 if (!_Atomic_swap((unsigned long *)__lock, 1)) {
00440 return;
00441 }
00442 _S_nsec_sleep(__log_nsec);
00443 }
00444 }
00445 void _M_release_lock() {
00446 volatile unsigned long* __lock = &_M_lock;
00447 # if defined(__STL_SGI_THREADS) && defined(__GNUC__) && __mips >= 3
00448 asm("sync");
00449 *__lock = 0;
00450 # elif defined(__STL_SGI_THREADS) && __mips >= 3 \
00451 && (defined (_ABIN32) || defined(_ABI64))
00452 __lock_release(__lock);
00453 # else
00454 *__lock = 0;
00455 // This is not sufficient on many multiprocessors, since
00456 // writes to protected variables and the lock may be reordered.
00457 # endif
00458 }
00459
00460 // We no longer use win32 critical sections.
00461 // They appear to be slower in the contention-free case,
00462 // and they appear difficult to initialize without introducing a race.
00463
00464 #elif defined(__STL_PTHREADS)
00465 pthread_mutex_t _M_lock;
00466 void _M_initialize() { pthread_mutex_init(&_M_lock, NULL); }
00467 void _M_acquire_lock() { pthread_mutex_lock(&_M_lock); }
00468 void _M_release_lock() { pthread_mutex_unlock(&_M_lock); }
00469 #elif defined(__STL_UITHREADS)
00470 mutex_t _M_lock;
00471 void _M_initialize() { mutex_init(&_M_lock, USYNC_THREAD, 0); }
00472 void _M_acquire_lock() { mutex_lock(&_M_lock); }
00473 void _M_release_lock() { mutex_unlock(&_M_lock); }
00474 #else /* No threads */
00475 void _M_initialize() {}
00476 void _M_acquire_lock() {}
00477 void _M_release_lock() {}
00478 #endif
00479 // GCC extension begin
00480 #endif
00481 // GCC extension end
00482 };
00483
00484 // GCC extension begin
00485 #if defined(__STL_GTHREADS)
00486 #ifdef __GTHREAD_MUTEX_INIT
00487 #define __STL_MUTEX_INITIALIZER = { __GTHREAD_MUTEX_INIT }
00488 #elif defined(__GTHREAD_MUTEX_INIT_FUNCTION)
00489 #ifdef __GTHREAD_MUTEX_INIT_DEFAULT
00490 #define __STL_MUTEX_INITIALIZER \
00491 = { 0, __GTHREAD_ONCE_INIT, __GTHREAD_MUTEX_INIT_DEFAULT }
00492 #else
00493 #define __STL_MUTEX_INITIALIZER = { 0, __GTHREAD_ONCE_INIT }
00494 #endif
00495 #endif
00496 #else
00497 // GCC extension end
00498 #ifdef __STL_PTHREADS
00499 // Pthreads locks must be statically initialized to something other than
00500 // the default value of zero.
00501 # define __STL_MUTEX_INITIALIZER = { PTHREAD_MUTEX_INITIALIZER }
00502 #elif defined(__STL_UITHREADS)
00503 // UIthreads locks must be statically initialized to something other than
00504 // the default value of zero.
00505 # define __STL_MUTEX_INITIALIZER = { DEFAULTMUTEX }
00506 #elif defined(__STL_SGI_THREADS) || defined(__STL_WIN32THREADS)
00507 # define __STL_MUTEX_INITIALIZER = { 0 }
00508 #else
00509 # define __STL_MUTEX_INITIALIZER
00510 #endif
00511 // GCC extension begin
00512 #endif
00513 // GCC extension end
00514
00515
00516 // A locking class that uses _STL_mutex_lock. The constructor takes a
00517 // reference to an _STL_mutex_lock, and acquires a lock. The
00518 // destructor releases the lock. It's not clear that this is exactly
00519 // the right functionality. It will probably change in the future.
00520
00521 struct _STL_auto_lock
00522 {
00523 _STL_mutex_lock& _M_lock;
00524
00525 _STL_auto_lock(_STL_mutex_lock& __lock) : _M_lock(__lock)
00526 { _M_lock._M_acquire_lock(); }
00527 ~_STL_auto_lock() { _M_lock._M_release_lock(); }
00528
00529 private:
00530 void operator=(const _STL_auto_lock&);
00531 _STL_auto_lock(const _STL_auto_lock&);
00532 };
00533
00534 } // namespace std
00535
00536 #endif /* __SGI_STL_INTERNAL_THREADS_H */
00537
00538 // Local Variables:
00539 // mode:C++
00540 // End:
00541
Generated on Mon Apr 8 03:11:44 2002 for libstdc++-v3 Source by 1.2.15
|