williamr@2: /* williamr@2: * Copyright (c) 1997-1999 williamr@2: * Silicon Graphics Computer Systems, Inc. williamr@2: * williamr@2: * Copyright (c) 1999 williamr@2: * Boris Fomitchev williamr@2: * williamr@2: * This material is provided "as is", with absolutely no warranty expressed williamr@2: * or implied. Any use is at your own risk. williamr@2: * williamr@2: * Permission to use or copy this software for any purpose is hereby granted williamr@2: * without fee, provided the above notices are retained on all copies. williamr@2: * Permission to modify the code and to distribute modified code is granted, williamr@2: * provided the above notices are retained, and a notice that the code was williamr@2: * modified is included with the above copyright notice. williamr@2: * williamr@2: */ williamr@2: williamr@2: // WARNING: This is an internal header file, included by other C++ williamr@2: // standard library headers. You should not attempt to use this header williamr@2: // file directly. williamr@2: // Stl_config.h should be included before this file. williamr@2: williamr@2: williamr@2: #ifndef _STLP_INTERNAL_THREADS_H williamr@2: #define _STLP_INTERNAL_THREADS_H williamr@2: williamr@2: // Supported threading models are native SGI, pthreads, uithreads williamr@2: // (similar to pthreads, but based on an earlier draft of the Posix williamr@2: // threads standard), and Win32 threads. Uithread support by Jochen williamr@2: // Schlick, 1999, and Solaris threads generalized to them. williamr@2: williamr@2: #ifndef _STLP_CONFIG_H williamr@2: #include williamr@2: #endif williamr@2: williamr@2: # if ! defined (_STLP_CSTDDEF) williamr@2: # include williamr@2: # endif williamr@2: williamr@2: # if ! defined (_STLP_CSTDLIB) williamr@2: # include williamr@2: # endif williamr@2: williamr@2: // On SUN and Mac OS X gcc, zero-initialization works just fine... williamr@2: # if defined (__sun) || ( defined(__GNUC__) && defined(__APPLE__) ) williamr@2: # define _STLP_MUTEX_INITIALIZER williamr@2: # endif williamr@2: williamr@2: # if defined (_STLP_WIN32) || defined (__sgi) || defined (_STLP_SPARC_SOLARIS_THREADS) williamr@2: typedef long __stl_atomic_t; williamr@2: # else williamr@2: # if defined (_STLP_USE_NAMESPACES) && ! defined (_STLP_VENDOR_GLOBAL_CSTD) williamr@2: // using _STLP_VENDOR_CSTD::size_t; williamr@2: using namespace _STLP_VENDOR_CSTD; williamr@2: # endif williamr@2: typedef size_t __stl_atomic_t; williamr@2: #endif williamr@2: williamr@2: # if defined(_STLP_SGI_THREADS) williamr@2: # include williamr@2: // Hack for SGI o32 compilers. williamr@2: #if !defined(__add_and_fetch) && \ williamr@2: (__mips < 3 || !(defined (_ABIN32) || defined(_ABI64))) williamr@2: # define __add_and_fetch(__l,__v) add_then_test((unsigned long*)__l,__v) williamr@2: # define __test_and_set(__l,__v) test_and_set(__l,__v) williamr@2: #endif /* o32 */ williamr@2: williamr@2: # if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) williamr@2: # define _STLP_ATOMIC_EXCHANGE(__p, __q) test_and_set(__p, __q) williamr@2: # else williamr@2: # define _STLP_ATOMIC_EXCHANGE(__p, __q) __test_and_set((unsigned long*)__p, (unsigned long)__q) williamr@2: # endif williamr@2: williamr@2: # define _STLP_ATOMIC_INCREMENT(__x) __add_and_fetch(__x, 1) williamr@2: # define _STLP_ATOMIC_DECREMENT(__x) __add_and_fetch(__x, (size_t) -1) williamr@2: williamr@2: # elif defined (__GNUC__) && defined (__i386__) && defined (__unix__) && defined (_STLP_USE_INLINE_X86_SPINLOCK) williamr@2: williamr@2: // gcc on i386 linux, freebsd, etc. williamr@2: williamr@2: // This enables the memory caching on x86 linux. It is critical for SMP williamr@2: // without it the performace is DISMAL! williamr@2: static inline unsigned long __xchg(volatile __stl_atomic_t* target, int source) williamr@2: { williamr@2: williamr@2: // The target is refernce in memory rather than the register williamr@2: // because making a copy of it from memory to the register and williamr@2: // back again would ruin the atomic nature of the call. williamr@2: // the source does not need to be delt with atomicly so it can williamr@2: // be copied about as needed. williamr@2: // williamr@2: // The casting of the source is used to prevent gcc from optimizing williamr@2: // in such a way that breaks the atomic nature of this call. williamr@2: // williamr@2: __asm__ __volatile__("xchgl %1,%0" williamr@2: :"=m" (*(volatile long *) target), "=r" (source) williamr@2: :"m" (*(volatile long *) target), "r" (source) ); williamr@2: return source; williamr@2: williamr@2: // The assembly above does the following atomicly: williamr@2: // int temp=source; williamr@2: // source=(int)(*target); williamr@2: // (int)(*target)=temp; williamr@2: // return source williamr@2: } williamr@2: williamr@2: static inline void __inc_and_fetch(volatile __stl_atomic_t* __x) williamr@2: { williamr@2: // Referenced in memory rather than register to preserve the atomic nature. williamr@2: // williamr@2: __asm__ __volatile__( williamr@2: "lock; incl %0" williamr@2: :"=m" (*__x) williamr@2: :"m" (*__x) ); williamr@2: williamr@2: // The assembly above does the following atomicly: williamr@2: // ++(int)(*__x); williamr@2: williamr@2: } williamr@2: static inline void __dec_and_fetch(volatile __stl_atomic_t* __x) williamr@2: { williamr@2: // Referenced in memory rather than register to preserve the atomic nature. williamr@2: // williamr@2: __asm__ __volatile__( williamr@2: "lock; decl %0" williamr@2: :"=m" (*__x) williamr@2: :"m" (*__x) ); williamr@2: williamr@2: // The assembly above does the following atomicly: williamr@2: // --(int)(*__x); williamr@2: } williamr@2: williamr@2: # define _STLP_ATOMIC_EXCHANGE(target, newValue) ((__xchg(target, newValue))) williamr@2: # define _STLP_ATOMIC_INCREMENT(__x) __inc_and_fetch(__x) williamr@2: # define _STLP_ATOMIC_DECREMENT(__x) __dec_and_fetch(__x) williamr@2: williamr@2: # elif defined(_STLP_PTHREADS) williamr@2: williamr@2: # include williamr@2: # ifndef _STLP_USE_PTHREAD_SPINLOCK williamr@2: # if defined(PTHREAD_MUTEX_INITIALIZER) && !defined(_STLP_MUTEX_INITIALIZER) williamr@2: # define _STLP_MUTEX_INITIALIZER = { PTHREAD_MUTEX_INITIALIZER } williamr@2: # endif williamr@2: williamr@2: //HPUX variants have (on some platforms optional) non-standard "DCE" pthreads impl williamr@2: # if defined(_DECTHREADS_) && (defined(_PTHREAD_USE_D4) || defined(__hpux)) && !defined(_CMA_SUPPRESS_EXTERNALS_) williamr@2: # define _STLP_PTHREAD_ATTR_DEFAULT pthread_mutexattr_default williamr@2: # else williamr@2: # define _STLP_PTHREAD_ATTR_DEFAULT 0 williamr@2: # endif williamr@2: # endif // !_STLP_USE_PTHREAD_SPINLOCK williamr@2: williamr@2: # elif defined(_STLP_WIN32THREADS) williamr@2: # if !defined (_STLP_WINDOWS_H_INCLUDED) && ! defined (_WINDOWS_H) williamr@2: # if ! (defined ( _STLP_MSVC ) || defined (__BORLANDC__) || defined (__ICL) || defined (__WATCOMC__) || defined (__MINGW32__) || defined (__DMC__)) williamr@2: # ifdef _STLP_USE_MFC williamr@2: # include williamr@2: # else williamr@2: # include williamr@2: # endif williamr@2: # define _STLP_WINDOWS_H_INCLUDED williamr@2: # else williamr@2: // This section serves as a replacement for windows.h header for Visual C++ williamr@2: extern "C" { williamr@2: # if (defined(_M_MRX000) || defined(_M_ALPHA) \ williamr@2: || (defined(_M_PPC) && (_MSC_VER >= 1000))) && !defined(RC_INVOKED) williamr@2: # define InterlockedIncrement _InterlockedIncrement williamr@2: # define InterlockedDecrement _InterlockedDecrement williamr@2: # define InterlockedExchange _InterlockedExchange williamr@2: # define _STLP_STDCALL williamr@2: # else williamr@2: # ifdef _MAC williamr@2: # define _STLP_STDCALL _cdecl williamr@2: # else williamr@2: # define _STLP_STDCALL __stdcall williamr@2: # endif williamr@2: # endif williamr@2: williamr@2: #if (_MSC_VER >= 1300) || defined (_STLP_NEW_PLATFORM_SDK) williamr@2: _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedIncrement(long volatile *); williamr@2: _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedDecrement(long volatile *); williamr@2: _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedExchange(long volatile *, long); williamr@2: #else williamr@2: // boris : for the latest SDK, you may actually need the other version of the declaration (above) williamr@2: // even for earlier VC++ versions. There is no way to tell SDK versions apart, sorry ... williamr@2: _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedIncrement(long*); williamr@2: _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedDecrement(long*); williamr@2: _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedExchange(long*, long); williamr@2: #endif williamr@2: williamr@2: _STLP_IMPORT_DECLSPEC void _STLP_STDCALL Sleep(unsigned long); williamr@2: _STLP_IMPORT_DECLSPEC void _STLP_STDCALL OutputDebugStringA( const char* lpOutputString ); williamr@2: williamr@2: #ifdef _STLP_DEBUG williamr@2: typedef unsigned long DWORD; williamr@2: _STLP_IMPORT_DECLSPEC DWORD _STLP_STDCALL GetCurrentThreadId(); williamr@2: #endif /* _STLP_DEBUG */ williamr@2: williamr@2: # if defined (InterlockedIncrement) williamr@2: # pragma intrinsic(_InterlockedIncrement) williamr@2: # pragma intrinsic(_InterlockedDecrement) williamr@2: # pragma intrinsic(_InterlockedExchange) williamr@2: # endif williamr@2: } /* extern "C" */ williamr@2: williamr@2: # endif /* STL_MSVC */ williamr@2: williamr@2: # define _STLP_WINDOWS_H_INCLUDED williamr@2: williamr@2: # endif /* _STLP_WIN32 */ williamr@2: williamr@2: # ifndef _STLP_ATOMIC_INCREMENT williamr@2: # define _STLP_ATOMIC_INCREMENT(__x) InterlockedIncrement((long*)__x) williamr@2: # define _STLP_ATOMIC_DECREMENT(__x) InterlockedDecrement((long*)__x) williamr@2: # define _STLP_ATOMIC_EXCHANGE(__x, __y) InterlockedExchange((long*)__x, (long)__y) williamr@2: # endif williamr@2: # elif defined(__DECC) || defined(__DECCXX) williamr@2: # include williamr@2: # define _STLP_ATOMIC_EXCHANGE __ATOMIC_EXCH_LONG williamr@2: # define _STLP_ATOMIC_INCREMENT(__x) __ATOMIC_ADD_LONG(__x, 1) williamr@2: # define _STLP_ATOMIC_DECREMENT(__x) __ATOMIC_ADD_LONG(__x, -1) williamr@2: # elif defined(_STLP_SPARC_SOLARIS_THREADS) williamr@2: # include williamr@2: # elif defined (_STLP_UITHREADS) williamr@2: // this inclusion is potential hazard to bring up all sorts williamr@2: // of old-style headers. Let's assume vendor already know how williamr@2: // to deal with that. williamr@2: # include williamr@2: # if defined (_STLP_USE_NAMESPACES) && ! defined (_STLP_VENDOR_GLOBAL_CSTD) williamr@2: using _STLP_VENDOR_CSTD::time_t; williamr@2: # endif williamr@2: # include williamr@2: # include williamr@2: # include williamr@2: # elif defined (_STLP_BETHREADS) williamr@2: # include williamr@2: #include williamr@2: #include williamr@2: # define _STLP_MUTEX_INITIALIZER = { 0 } williamr@2: #elif defined(_STLP_OS2THREADS) williamr@2: # ifdef __GNUC__ williamr@2: # define INCL_DOSSEMAPHORES williamr@2: # include williamr@2: # else williamr@2: // This section serves to replace os2.h for VisualAge C++ williamr@2: typedef unsigned long ULONG; williamr@2: #ifndef __HEV__ /* INCL_SEMAPHORE may also define HEV */ williamr@2: #define __HEV__ williamr@2: typedef ULONG HEV; williamr@2: typedef HEV* PHEV; williamr@2: #endif williamr@2: typedef ULONG APIRET; williamr@2: typedef ULONG HMTX; williamr@2: typedef HMTX* PHMTX; williamr@2: typedef const char* PCSZ; williamr@2: typedef ULONG BOOL32; williamr@2: APIRET _System DosCreateMutexSem(PCSZ pszName, PHEV phev, ULONG flAttr, BOOL32 fState); williamr@2: APIRET _System DosRequestMutexSem(HMTX hmtx, ULONG ulTimeout); williamr@2: APIRET _System DosReleaseMutexSem(HMTX hmtx); williamr@2: APIRET _System DosCloseMutexSem(HMTX hmtx); williamr@2: # define _STLP_MUTEX_INITIALIZER = { 0 }; williamr@2: # endif /* GNUC */ williamr@2: # elif defined(_STLP_VXWORKS_THREADS) williamr@2: # include "semLib.h" williamr@2: # endif williamr@2: williamr@2: # ifndef _STLP_MUTEX_INITIALIZER williamr@2: # if defined(_STLP_ATOMIC_EXCHANGE) williamr@2: // we are using our own spinlock. williamr@2: # define _STLP_MUTEX_INITIALIZER = { 0 } williamr@2: # elif defined(_STLP_UITHREADS) williamr@2: // known case williamr@2: # define _STLP_MUTEX_INITIALIZER = { DEFAULTMUTEX } williamr@2: # else williamr@2: // we do not have static initializer available. therefore, on-demand synchronization is needed. williamr@2: # define _STLP_MUTEX_INITIALIZER williamr@2: # define _STLP_MUTEX_NEEDS_ONDEMAND_INITIALIZATION williamr@2: # endif williamr@2: # endif williamr@2: williamr@2: _STLP_BEGIN_NAMESPACE williamr@2: williamr@2: #ifndef _STLP_USE_PTHREAD_SPINLOCK williamr@2: // Helper struct. This is a workaround for various compilers that don't williamr@2: // handle static variables in inline functions properly. williamr@2: template williamr@2: struct _STLP_mutex_spin { williamr@2: enum { __low_max = 30, __high_max = 1000 }; williamr@2: // Low if we suspect uniprocessor, high for multiprocessor. williamr@2: static unsigned __max; williamr@2: static unsigned __last; williamr@2: static void _STLP_CALL _M_do_lock(volatile __stl_atomic_t* __lock); williamr@2: static void _STLP_CALL _S_nsec_sleep(int __log_nsec); williamr@2: }; williamr@2: #endif // !_STLP_USE_PTHREAD_SPINLOCK williamr@2: williamr@2: williamr@2: // Locking class. Note that this class *does not have a constructor*. williamr@2: // It must be initialized either statically, with _STLP_MUTEX_INITIALIZER, williamr@2: // or dynamically, by explicitly calling the _M_initialize member function. williamr@2: // (This is similar to the ways that a pthreads mutex can be initialized.) williamr@2: // There are explicit member functions for acquiring and releasing the lock. williamr@2: williamr@2: // There is no constructor because static initialization is essential for williamr@2: // some uses, and only a class aggregate (see section 8.5.1 of the C++ williamr@2: // standard) can be initialized that way. That means we must have no williamr@2: // constructors, no base classes, no virtual functions, and no private or williamr@2: // protected members. williamr@2: williamr@2: // For non-static cases, clients should use _STLP_mutex. williamr@2: williamr@2: struct _STLP_CLASS_DECLSPEC _STLP_mutex_base williamr@2: { williamr@2: #if defined(_STLP_ATOMIC_EXCHANGE) || defined(_STLP_SGI_THREADS) williamr@2: // It should be relatively easy to get this to work on any modern Unix. williamr@2: volatile __stl_atomic_t _M_lock; williamr@2: #endif williamr@2: williamr@2: #ifdef _STLP_THREADS williamr@2: williamr@2: # ifdef _STLP_ATOMIC_EXCHANGE williamr@2: inline void _M_initialize() { _M_lock=0; } williamr@2: inline void _M_destroy() {} williamr@2: williamr@2: void _M_acquire_lock() { williamr@2: _STLP_mutex_spin<0>::_M_do_lock(&_M_lock); williamr@2: } williamr@2: williamr@2: inline void _M_release_lock() { williamr@2: volatile __stl_atomic_t* __lock = &_M_lock; williamr@2: # if defined(_STLP_SGI_THREADS) && defined(__GNUC__) && __mips >= 3 williamr@2: asm("sync"); williamr@2: *__lock = 0; williamr@2: # elif defined(_STLP_SGI_THREADS) && __mips >= 3 \ williamr@2: && (defined (_ABIN32) || defined(_ABI64)) williamr@2: __lock_release(__lock); williamr@2: # elif defined (_STLP_SPARC_SOLARIS_THREADS) williamr@2: # if defined (__WORD64) || defined (__arch64__) || defined (__sparcv9) || defined (__sparcv8plus) williamr@2: asm("membar #StoreStore ; membar #LoadStore"); williamr@2: # else williamr@2: asm(" stbar "); williamr@2: # endif williamr@2: *__lock = 0; williamr@2: # else williamr@2: *__lock = 0; williamr@2: // This is not sufficient on many multiprocessors, since williamr@2: // writes to protected variables and the lock may be reordered. williamr@2: # endif williamr@2: } williamr@2: # elif defined(_STLP_PTHREADS) williamr@2: # ifdef _STLP_USE_PTHREAD_SPINLOCK williamr@2: pthread_spinlock_t _M_lock; williamr@2: inline void _M_initialize() { pthread_spin_init( &_M_lock, 0 ); } williamr@2: inline void _M_destroy() { pthread_spin_destroy( &_M_lock ); } williamr@2: williamr@2: inline void _M_acquire_lock() { williamr@2: // we do not care about race conditions here : there is only one thread at this point williamr@2: if(!_M_lock) pthread_spin_init( &_M_lock, 0 ); williamr@2: williamr@2: // fbp: here, initialization on demand should happen before the lock williamr@2: // we use simple strategy as we are sure this only happens on initialization williamr@2: pthread_spin_lock( &_M_lock ); williamr@2: } williamr@2: williamr@2: inline void _M_acquire_lock_nodemand() { williamr@2: pthread_spin_lock( &_M_lock ); williamr@2: } williamr@2: inline void _M_release_lock() { pthread_spin_unlock( &_M_lock ); } williamr@2: # else // !_STLP_USE_PTHREAD_SPINLOCK williamr@2: pthread_mutex_t _M_lock; williamr@2: williamr@2: inline void _M_initialize() { williamr@2: pthread_mutex_init(&_M_lock,_STLP_PTHREAD_ATTR_DEFAULT); williamr@2: } williamr@2: inline void _M_destroy() { williamr@2: pthread_mutex_destroy(&_M_lock); williamr@2: } williamr@2: inline void _M_acquire_lock_nodemand() { williamr@2: pthread_mutex_lock(&_M_lock); williamr@2: } williamr@2: williamr@2: inline void _M_acquire_lock() { williamr@2: # if defined (__hpux) && !defined (PTHREAD_MUTEX_INITIALIZER) williamr@2: if (!_M_lock.field1) _M_initialize(); williamr@2: # endif williamr@2: pthread_mutex_lock(&_M_lock); williamr@2: } williamr@2: inline void _M_release_lock() { pthread_mutex_unlock(&_M_lock); } williamr@2: # endif // !_STLP_USE_PTHREAD_SPINLOCK williamr@2: williamr@2: # elif defined (_STLP_UITHREADS) williamr@2: mutex_t _M_lock; williamr@2: inline void _M_initialize() { williamr@2: mutex_init(&_M_lock,0,NULL); williamr@2: } williamr@2: inline void _M_destroy() { williamr@2: mutex_destroy(&_M_lock); williamr@2: } williamr@2: inline void _M_acquire_lock() { mutex_lock(&_M_lock); } williamr@2: inline void _M_release_lock() { mutex_unlock(&_M_lock); } williamr@2: williamr@2: # elif defined(_STLP_OS2THREADS) williamr@2: HMTX _M_lock; williamr@2: inline void _M_initialize() { DosCreateMutexSem(NULL, &_M_lock, 0, false); } williamr@2: inline void _M_destroy() { DosCloseMutexSem(_M_lock); } williamr@2: inline void _M_acquire_lock_nodemand() { williamr@2: DosRequestMutexSem(_M_lock, SEM_INDEFINITE_WAIT); williamr@2: } williamr@2: inline void _M_acquire_lock() { williamr@2: if(!_M_lock) _M_initialize(); williamr@2: DosRequestMutexSem(_M_lock, SEM_INDEFINITE_WAIT); williamr@2: } williamr@2: inline void _M_release_lock() { DosReleaseMutexSem(_M_lock); } williamr@2: # elif defined(_STLP_BETHREADS) williamr@2: sem_id sem; williamr@2: inline void _M_initialize() williamr@2: { williamr@2: sem = create_sem(1, "STLPort"); williamr@2: assert(sem > 0); williamr@2: } williamr@2: inline void _M_destroy() williamr@2: { williamr@2: int t = delete_sem(sem); williamr@2: assert(t == B_NO_ERROR); williamr@2: } williamr@2: inline void _M_acquire_lock_nodemand() williamr@2: { williamr@2: status_t t; williamr@2: t = acquire_sem(sem); williamr@2: assert(t == B_NO_ERROR); williamr@2: } williamr@2: inline void _M_acquire_lock(); williamr@2: inline void _M_release_lock() williamr@2: { williamr@2: status_t t = release_sem(sem); williamr@2: assert(t == B_NO_ERROR); williamr@2: } williamr@2: # elif defined(_STLP_VXWORKS_THREADS) williamr@2: SEM_ID _M_sem; williamr@2: inline void _M_initialize() williamr@2: { williamr@2: _M_sem = semMCreate(SEM_Q_FIFO); williamr@2: assert(_M_sem > 0); williamr@2: } williamr@2: inline void _M_destroy() williamr@2: { williamr@2: STATUS __s; williamr@2: semDelete (_M_sem); williamr@2: assert(__s == OK); williamr@2: } williamr@2: inline void _M_acquire_lock_nodemand() williamr@2: { williamr@2: STATUS __s; williamr@2: semTake (_M_sem, WAIT_FOREVER); williamr@2: assert(__s == OK); williamr@2: } williamr@2: inline void _M_acquire_lock() williamr@2: { williamr@2: if (!_M_sem) williamr@2: _M_initialize(); williamr@2: _M_acquire_lock_nodemand(); williamr@2: } williamr@2: inline void _M_release_lock() williamr@2: { williamr@2: STATUS __s; williamr@2: semGive (_M_sem, WAIT_FOREVER); williamr@2: assert(__s == OK); williamr@2: } williamr@2: # else //*ty 11/24/2001 - added configuration check williamr@2: # error "Unknown thread facility configuration" williamr@2: # endif williamr@2: #else /* No threads */ williamr@2: inline void _M_initialize() {} williamr@2: inline void _M_destroy() {} williamr@2: inline void _M_acquire_lock() {} williamr@2: inline void _M_release_lock() {} williamr@2: #endif // _STLP_PTHREADS williamr@2: }; williamr@2: williamr@2: williamr@2: #if defined (_STLP_THREADS) && defined (_STLP_MUTEX_NEEDS_ONDEMAND_INITIALIZATION) williamr@2: // for use in _STLP_mutex, our purposes do not require ondemand initialization williamr@2: // also, mutex_base may use some hacks to determine uninitialized state by zero data, which only works for globals. williamr@2: class _STLP_CLASS_DECLSPEC _STLP_mutex_nodemand : public _STLP_mutex_base { williamr@2: inline void _M_acquire_lock() { williamr@2: _M_acquire_lock_nodemand(); williamr@2: } williamr@2: }; williamr@2: #else williamr@2: typedef _STLP_mutex_base _STLP_mutex_nodemand; williamr@2: #endif williamr@2: williamr@2: williamr@2: // Locking class. The constructor initializes the lock, the destructor destroys it. williamr@2: // Well - behaving class, does not need static initializer williamr@2: class _STLP_CLASS_DECLSPEC _STLP_mutex : public _STLP_mutex_nodemand { williamr@2: public: williamr@2: inline _STLP_mutex () { _M_initialize(); } williamr@2: inline ~_STLP_mutex () { _M_destroy(); } williamr@2: private: williamr@2: _STLP_mutex(const _STLP_mutex&); williamr@2: void operator=(const _STLP_mutex&); williamr@2: }; williamr@2: williamr@2: williamr@2: williamr@2: /* williamr@2: * Class _Refcount_Base provides a type, __stl_atomic_t, a data member, williamr@2: * _M_ref_count, and member functions _M_incr and _M_decr, which perform williamr@2: * atomic preincrement/predecrement. The constructor initializes williamr@2: * _M_ref_count. williamr@2: */ williamr@2: struct _STLP_CLASS_DECLSPEC _Refcount_Base williamr@2: { williamr@2: // The data member _M_ref_count williamr@2: volatile __stl_atomic_t _M_ref_count; williamr@2: williamr@2: # if !defined (_STLP_ATOMIC_EXCHANGE) williamr@2: _STLP_mutex _M_mutex; williamr@2: # endif williamr@2: williamr@2: // Constructor williamr@2: _Refcount_Base(__stl_atomic_t __n) : _M_ref_count(__n) {} williamr@2: williamr@2: // _M_incr and _M_decr williamr@2: # if defined (_STLP_THREADS) && defined (_STLP_ATOMIC_EXCHANGE) williamr@2: void _M_incr() { _STLP_ATOMIC_INCREMENT((__stl_atomic_t*)&_M_ref_count); } williamr@2: void _M_decr() { _STLP_ATOMIC_DECREMENT((__stl_atomic_t*)&_M_ref_count); } williamr@2: # elif defined(_STLP_THREADS) williamr@2: void _M_incr() { williamr@2: _M_mutex._M_acquire_lock(); williamr@2: ++_M_ref_count; williamr@2: _M_mutex._M_release_lock(); williamr@2: } williamr@2: void _M_decr() { williamr@2: _M_mutex._M_acquire_lock(); williamr@2: --_M_ref_count; williamr@2: _M_mutex._M_release_lock(); williamr@2: } williamr@2: # else /* No threads */ williamr@2: void _M_incr() { ++_M_ref_count; } williamr@2: void _M_decr() { --_M_ref_count; } williamr@2: # endif williamr@2: }; williamr@2: williamr@2: // Atomic swap on unsigned long williamr@2: // This is guaranteed to behave as though it were atomic only if all williamr@2: // possibly concurrent updates use _Atomic_swap. williamr@2: // In some cases the operation is emulated with a lock. williamr@2: # if defined (_STLP_THREADS) williamr@2: # ifdef _STLP_ATOMIC_EXCHANGE williamr@2: inline __stl_atomic_t _Atomic_swap(volatile __stl_atomic_t * __p, __stl_atomic_t __q) { williamr@2: return (__stl_atomic_t) _STLP_ATOMIC_EXCHANGE(__p,__q); williamr@2: } williamr@2: # elif defined(_STLP_PTHREADS) || defined (_STLP_UITHREADS) || defined (_STLP_OS2THREADS) || defined(_STLP_USE_PTHREAD_SPINLOCK) williamr@2: // We use a template here only to get a unique initialized instance. williamr@2: template williamr@2: struct _Swap_lock_struct { williamr@2: static _STLP_STATIC_MUTEX _S_swap_lock; williamr@2: }; williamr@2: williamr@2: williamr@2: // This should be portable, but performance is expected williamr@2: // to be quite awful. This really needs platform specific williamr@2: // code. williamr@2: inline __stl_atomic_t _Atomic_swap(volatile __stl_atomic_t * __p, __stl_atomic_t __q) { williamr@2: _Swap_lock_struct<0>::_S_swap_lock._M_acquire_lock(); williamr@2: __stl_atomic_t __result = *__p; williamr@2: *__p = __q; williamr@2: _Swap_lock_struct<0>::_S_swap_lock._M_release_lock(); williamr@2: return __result; williamr@2: } williamr@2: # endif // _STLP_PTHREADS || _STLP_UITHREADS || _STLP_OS2THREADS || _STLP_USE_PTHREAD_SPINLOCK williamr@2: # else // !_STLP_THREADS williamr@2: /* no threads */ williamr@2: static inline __stl_atomic_t _STLP_CALL williamr@2: _Atomic_swap(volatile __stl_atomic_t * __p, __stl_atomic_t __q) { williamr@2: __stl_atomic_t __result = *__p; williamr@2: *__p = __q; williamr@2: return __result; williamr@2: } williamr@2: # endif // _STLP_THREADS williamr@2: williamr@2: // A locking class that uses _STLP_STATIC_MUTEX. The constructor takes williamr@2: // a reference to an _STLP_STATIC_MUTEX, and acquires a lock. The destructor williamr@2: // releases the lock. williamr@2: williamr@2: struct _STLP_CLASS_DECLSPEC _STLP_auto_lock williamr@2: { williamr@2: _STLP_STATIC_MUTEX& _M_lock; williamr@2: williamr@2: _STLP_auto_lock(_STLP_STATIC_MUTEX& __lock) : _M_lock(__lock) williamr@2: { _M_lock._M_acquire_lock(); } williamr@2: ~_STLP_auto_lock() { _M_lock._M_release_lock(); } williamr@2: williamr@2: private: williamr@2: void operator=(const _STLP_auto_lock&); williamr@2: _STLP_auto_lock(const _STLP_auto_lock&); williamr@2: }; williamr@2: williamr@2: typedef _STLP_auto_lock _STLP_mutex_lock; williamr@2: williamr@2: #ifdef _STLP_BETHREADS williamr@2: williamr@2: template williamr@2: struct _STLP_beos_static_lock_data williamr@2: { williamr@2: static bool is_init; williamr@2: struct mutex_t : public _STLP_mutex williamr@2: { williamr@2: mutex_t() williamr@2: { williamr@2: _STLP_beos_static_lock_data<0>::is_init = true; williamr@2: } williamr@2: ~mutex_t() williamr@2: { williamr@2: _STLP_beos_static_lock_data<0>::is_init = false; williamr@2: } williamr@2: }; williamr@2: static mutex_t mut; williamr@2: }; williamr@2: williamr@2: template williamr@2: bool _STLP_beos_static_lock_data<__inst>::is_init = false; williamr@2: template williamr@2: typename _STLP_beos_static_lock_data<__inst>::mutex_t _STLP_beos_static_lock_data<__inst>::mut; williamr@2: williamr@2: williamr@2: inline void _STLP_mutex_base::_M_acquire_lock() williamr@2: { williamr@2: if(sem == 0) williamr@2: { williamr@2: // we need to initialise on demand here williamr@2: // to prevent race conditions use our global williamr@2: // mutex if it's available: williamr@2: if(_STLP_beos_static_lock_data<0>::is_init) williamr@2: { williamr@2: _STLP_auto_lock al(_STLP_beos_static_lock_data<0>::mut); williamr@2: if(sem == 0) _M_initialize(); williamr@2: } williamr@2: else williamr@2: { williamr@2: // no lock available, we must still be williamr@2: // in startup code, THERE MUST BE ONE THREAD williamr@2: // ONLY active at this point. williamr@2: _M_initialize(); williamr@2: } williamr@2: } williamr@2: _M_acquire_lock_nodemand(); williamr@2: } williamr@2: williamr@2: #endif williamr@2: williamr@2: _STLP_END_NAMESPACE williamr@2: williamr@2: # if !defined (_STLP_LINK_TIME_INSTANTIATION) williamr@2: # include williamr@2: # endif williamr@2: williamr@2: #endif /* _STLP_INTERNAL_THREADS_H */ williamr@2: williamr@2: // Local Variables: williamr@2: // mode:C++ williamr@2: // End: williamr@2: