1 /* 2 * 3 * 4 * Copyright (c) 1994 5 * Hewlett-Packard Company 6 * 7 * Copyright (c) 1996,1997 8 * Silicon Graphics Computer Systems, Inc. 9 * 10 * Copyright (c) 1997 11 * Moscow Center for SPARC Technology 12 * 13 * Copyright (c) 1999 14 * Boris Fomitchev 15 * 16 * This material is provided "as is", with absolutely no warranty expressed 17 * or implied. Any use is at your own risk. 18 * 19 * Permission to use or copy this software for any purpose is hereby granted 20 * without fee, provided the above notices are retained on all copies. 21 * Permission to modify the code and to distribute modified code is granted, 22 * provided the above notices are retained, and a notice that the code was 23 * modified is included with the above copyright notice. 24 * 25 */ 26 #ifndef _STLP_THREADS_C 27 #define _STLP_THREADS_C 28 29 #ifndef _STLP_INTERNAL_THREADS_H 30 # include <stl/_threads.h> 31 #endif 32 33 #if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION) 34 35 #if defined (_STLP_SGI_THREADS) 36 # include <time.h> 37 #elif defined (_STLP_UNIX) 38 # ifndef _STLP_INTERNAL_CTIME 39 # include <stl/_ctime.h> 40 # endif 41 # if defined (_STLP_USE_NAMESPACES) && !defined (_STLP_VENDOR_GLOBAL_CSTD) 42 using _STLP_VENDOR_CSTD::time_t; 43 # endif 44 # include <sys/time.h> 45 #endif 46 47 _STLP_BEGIN_NAMESPACE 48 49 #if defined (_STLP_USE_ATOMIC_SWAP_MUTEX) 50 template<int __32bits> 51 _STLP_STATIC_MUTEX 52 _Atomic_swap_struct<__32bits>::_S_swap_lock _STLP_MUTEX_INITIALIZER; 53 # undef _STLP_USE_ATOMIC_SWAP_MUTEX 54 #endif 55 56 #if defined (_STLP_THREADS) && !defined (_STLP_USE_PTHREAD_SPINLOCK) 57 template <int __inst> 58 unsigned _STLP_mutex_spin<__inst>::__max = _STLP_mutex_spin<__inst>::__low_max; 59 60 template <int __inst> 61 unsigned _STLP_mutex_spin<__inst>::__last = 0; 62 #endif // _STLP_USE_PTHREAD_SPINLOCK 63 64 #if defined (_STLP_THREADS) && !defined (_STLP_USE_PTHREAD_SPINLOCK) 65 66 # if defined (_STLP_SPARC_SOLARIS_THREADS) 67 // underground function in libc.so; we do not want dependance on librt 68 extern "C" int __nanosleep(const struct timespec*, struct timespec*); 69 # define _STLP_NANOSLEEP __nanosleep 70 # else 71 # define _STLP_NANOSLEEP nanosleep 72 # endif 73 74 template <int __inst> 75 void _STLP_CALL 76 _STLP_mutex_spin<__inst>::_S_nsec_sleep(int __log_nsec, unsigned int& __iteration) { 77 # if defined (_STLP_WIN32THREADS) 78 # if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) 79 if (__iteration <= 4000) { 80 // Use SwitchToThread because 81 // 1) Sleep(1) often takes ~15 ms 82 // 2) SwitchToThread yields to lower-priority threads 83 // 4000 is enough to avoid Sleep and is used just to prevent infinite looping 84 // This number is advised spin count for Heap management by Microsoft 85 SwitchToThread(); 86 } else { 87 # endif 88 if (__log_nsec <= 21) { 89 /* Note from boost (www.boost.org): 90 * Changed from Sleep(0) to Sleep(1). 91 * According to MSDN, Sleep(0) will never yield to a lower-priority thread, 92 * whereas Sleep(1) will. Performance seems not to be affected. */ 93 Sleep(1); 94 } else { 95 Sleep(1 << (__log_nsec - 20)); 96 } 97 # if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) 98 __iteration = 0; //reset to avoid sleeps sequence 99 } 100 # endif 101 # elif defined(_STLP_OS2THREADS) 102 if (__log_nsec <= 20) { 103 DosSleep(0); 104 } else { 105 DosSleep(1 << (__log_nsec - 20)); 106 } 107 # elif defined (_STLP_UNIX) 108 timespec __ts; 109 /* Max sleep is 2**27nsec ~ 60msec */ 110 __ts.tv_sec = 0; 111 __ts.tv_nsec = 1 << __log_nsec; 112 _STLP_NANOSLEEP(&__ts, 0); 113 # endif 114 } 115 116 template <int __inst> 117 void _STLP_CALL 118 _STLP_mutex_spin<__inst>::_M_do_lock(volatile __stl_atomic_t* __lock) { 119 # if defined(_STLP_ATOMIC_EXCHANGE) 120 if (_Atomic_swap(__lock, 1)) { 121 unsigned __my_spin_max = _STLP_mutex_spin<0>::__max; 122 unsigned __my_last_spins = _STLP_mutex_spin<0>::__last; 123 volatile unsigned __junk = 17; // Value doesn't matter. 124 unsigned __i; 125 126 for (__i = 0; __i < __my_spin_max; ++__i) { 127 if (__i < __my_last_spins/2 || *__lock) { 128 __junk *= __junk; __junk *= __junk; 129 __junk *= __junk; __junk *= __junk; 130 } else { 131 if (!_Atomic_swap(__lock, 1)) { 132 // got it! 133 // Spinning worked. Thus we're probably not being scheduled 134 // against the other process with which we were contending. 135 // Thus it makes sense to spin longer the next time. 136 _STLP_mutex_spin<0>::__last = __i; 137 _STLP_mutex_spin<0>::__max = _STLP_mutex_spin<0>::__high_max; 138 return; 139 } 140 } 141 } 142 143 // We are probably being scheduled against the other process. Sleep. 144 _STLP_mutex_spin<0>::__max = _STLP_mutex_spin<0>::__low_max; 145 146 for (__i = 0 ;; ++__i) { 147 int __log_nsec = __i + 6; 148 149 if (__log_nsec > 27) __log_nsec = 27; 150 if (!_Atomic_swap(__lock, 1)) { 151 break; 152 } 153 _S_nsec_sleep(__log_nsec, __i); 154 } 155 } /* first _Atomic_swap */ 156 # endif 157 } 158 #endif // _STLP_USE_PTHREAD_SPINLOCK 159 160 _STLP_END_NAMESPACE 161 162 #endif /* _STLP_EXPOSE_GLOBALS_IMPLEMENTATION */ 163 #endif /* _STLP_THREADS_C */ 164 165 // Local Variables: 166 // mode:C++ 167 // End: 168