/* * * * Copyright (c) 1994 * Hewlett-Packard Company * * Copyright (c) 1996,1997 * Silicon Graphics Computer Systems, Inc. * * Copyright (c) 1997 * Moscow Center for SPARC Technology * * Copyright (c) 1999 * Boris Fomitchev * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * */ #ifndef _STLP_THREADS_C #define _STLP_THREADS_C #ifndef _STLP_INTERNAL_THREADS_H # include #endif #if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION) #if defined (_STLP_SGI_THREADS) # include #elif defined (_STLP_UNIX) # ifndef _STLP_INTERNAL_CTIME # include # endif # if defined (_STLP_USE_NAMESPACES) && !defined (_STLP_VENDOR_GLOBAL_CSTD) using _STLP_VENDOR_CSTD::time_t; # endif # include #endif _STLP_BEGIN_NAMESPACE #if defined (_STLP_USE_ATOMIC_SWAP_MUTEX) template _STLP_STATIC_MUTEX _Atomic_swap_struct<__32bits>::_S_swap_lock _STLP_MUTEX_INITIALIZER; # undef _STLP_USE_ATOMIC_SWAP_MUTEX #endif #if defined (_STLP_THREADS) && !defined (_STLP_USE_PTHREAD_SPINLOCK) template unsigned _STLP_mutex_spin<__inst>::__max = _STLP_mutex_spin<__inst>::__low_max; template unsigned _STLP_mutex_spin<__inst>::__last = 0; #endif // _STLP_USE_PTHREAD_SPINLOCK #if defined (_STLP_THREADS) && !defined (_STLP_USE_PTHREAD_SPINLOCK) # if defined (_STLP_SPARC_SOLARIS_THREADS) // underground function in libc.so; we do not want dependance on librt extern "C" int __nanosleep(const struct timespec*, struct timespec*); # define _STLP_NANOSLEEP __nanosleep # else # define _STLP_NANOSLEEP nanosleep # endif template void _STLP_CALL _STLP_mutex_spin<__inst>::_S_nsec_sleep(int __log_nsec, unsigned int& __iteration) { # if defined (_STLP_WIN32THREADS) # if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) if (__iteration <= 4000) { // Use SwitchToThread because // 1) Sleep(1) often takes ~15 ms // 2) SwitchToThread yields to lower-priority threads // 4000 is enough to avoid Sleep and is used just to prevent infinite looping // This number is advised spin count for Heap management by Microsoft SwitchToThread(); } else { # endif if (__log_nsec <= 21) { /* Note from boost (www.boost.org): * Changed from Sleep(0) to Sleep(1). * According to MSDN, Sleep(0) will never yield to a lower-priority thread, * whereas Sleep(1) will. Performance seems not to be affected. */ Sleep(1); } else { Sleep(1 << (__log_nsec - 20)); } # if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) __iteration = 0; //reset to avoid sleeps sequence } # endif # elif defined(_STLP_OS2THREADS) if (__log_nsec <= 20) { DosSleep(0); } else { DosSleep(1 << (__log_nsec - 20)); } # elif defined (_STLP_UNIX) timespec __ts; /* Max sleep is 2**27nsec ~ 60msec */ __ts.tv_sec = 0; __ts.tv_nsec = 1 << __log_nsec; _STLP_NANOSLEEP(&__ts, 0); # endif } template void _STLP_CALL _STLP_mutex_spin<__inst>::_M_do_lock(volatile __stl_atomic_t* __lock) { # if defined(_STLP_ATOMIC_EXCHANGE) if (_Atomic_swap(__lock, 1)) { unsigned __my_spin_max = _STLP_mutex_spin<0>::__max; unsigned __my_last_spins = _STLP_mutex_spin<0>::__last; volatile unsigned __junk = 17; // Value doesn't matter. unsigned __i; for (__i = 0; __i < __my_spin_max; ++__i) { if (__i < __my_last_spins/2 || *__lock) { __junk *= __junk; __junk *= __junk; __junk *= __junk; __junk *= __junk; } else { if (!_Atomic_swap(__lock, 1)) { // got it! // Spinning worked. Thus we're probably not being scheduled // against the other process with which we were contending. // Thus it makes sense to spin longer the next time. _STLP_mutex_spin<0>::__last = __i; _STLP_mutex_spin<0>::__max = _STLP_mutex_spin<0>::__high_max; return; } } } // We are probably being scheduled against the other process. Sleep. _STLP_mutex_spin<0>::__max = _STLP_mutex_spin<0>::__low_max; for (__i = 0 ;; ++__i) { int __log_nsec = __i + 6; if (__log_nsec > 27) __log_nsec = 27; if (!_Atomic_swap(__lock, 1)) { break; } _S_nsec_sleep(__log_nsec, __i); } } /* first _Atomic_swap */ # endif } #endif // _STLP_USE_PTHREAD_SPINLOCK _STLP_END_NAMESPACE #endif /* _STLP_EXPOSE_GLOBALS_IMPLEMENTATION */ #endif /* _STLP_THREADS_C */ // Local Variables: // mode:C++ // End: