_threads.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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. #ifndef _STLP_INTERNAL_THREADS_H
  29. # include <stl/_threads.h>
  30. #endif
  31. #if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION)
  32. #if defined (_STLP_SGI_THREADS)
  33. # include <time.h>
  34. #elif defined (_STLP_UNIX)
  35. # ifndef _STLP_INTERNAL_CTIME
  36. # include <stl/_ctime.h>
  37. # endif
  38. # if defined (_STLP_USE_NAMESPACES) && !defined (_STLP_VENDOR_GLOBAL_CSTD)
  39. using _STLP_VENDOR_CSTD::time_t;
  40. # endif
  41. # include <sys/time.h>
  42. #endif
  43. _STLP_BEGIN_NAMESPACE
  44. #if defined (_STLP_USE_ATOMIC_SWAP_MUTEX)
  45. template<int __32bits>
  46. _STLP_STATIC_MUTEX
  47. _Atomic_swap_struct<__32bits>::_S_swap_lock _STLP_MUTEX_INITIALIZER;
  48. # undef _STLP_USE_ATOMIC_SWAP_MUTEX
  49. #endif
  50. #if defined (_STLP_THREADS) && !defined (_STLP_USE_PTHREAD_SPINLOCK)
  51. template <int __inst>
  52. unsigned _STLP_mutex_spin<__inst>::__max = _STLP_mutex_spin<__inst>::__low_max;
  53. template <int __inst>
  54. unsigned _STLP_mutex_spin<__inst>::__last = 0;
  55. #endif // _STLP_USE_PTHREAD_SPINLOCK
  56. #if defined (_STLP_THREADS) && !defined (_STLP_USE_PTHREAD_SPINLOCK)
  57. # if defined (_STLP_SPARC_SOLARIS_THREADS)
  58. // underground function in libc.so; we do not want dependance on librt
  59. extern "C" int __nanosleep(const struct timespec*, struct timespec*);
  60. # define _STLP_NANOSLEEP __nanosleep
  61. # else
  62. # define _STLP_NANOSLEEP nanosleep
  63. # endif
  64. template <int __inst>
  65. void _STLP_CALL
  66. _STLP_mutex_spin<__inst>::_S_nsec_sleep(int __log_nsec, unsigned int& __iteration) {
  67. # if defined (_STLP_WIN32THREADS)
  68. # if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
  69. if (__iteration <= 4000) {
  70. // Use SwitchToThread because
  71. // 1) Sleep(1) often takes ~15 ms
  72. // 2) SwitchToThread yields to lower-priority threads
  73. // 4000 is enough to avoid Sleep and is used just to prevent infinite looping
  74. // This number is advised spin count for Heap management by Microsoft
  75. SwitchToThread();
  76. } else {
  77. # endif
  78. if (__log_nsec <= 21) {
  79. /* Note from boost (www.boost.org):
  80. * Changed from Sleep(0) to Sleep(1).
  81. * According to MSDN, Sleep(0) will never yield to a lower-priority thread,
  82. * whereas Sleep(1) will. Performance seems not to be affected. */
  83. Sleep(1);
  84. } else {
  85. Sleep(1 << (__log_nsec - 20));
  86. }
  87. # if defined (_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
  88. __iteration = 0; //reset to avoid sleeps sequence
  89. }
  90. # endif
  91. # elif defined(_STLP_OS2THREADS)
  92. if (__log_nsec <= 20) {
  93. DosSleep(0);
  94. } else {
  95. DosSleep(1 << (__log_nsec - 20));
  96. }
  97. # elif defined (_STLP_UNIX)
  98. timespec __ts;
  99. /* Max sleep is 2**27nsec ~ 60msec */
  100. __ts.tv_sec = 0;
  101. __ts.tv_nsec = 1 << __log_nsec;
  102. _STLP_NANOSLEEP(&__ts, 0);
  103. # endif
  104. }
  105. template <int __inst>
  106. void _STLP_CALL
  107. _STLP_mutex_spin<__inst>::_M_do_lock(volatile __stl_atomic_t* __lock) {
  108. # if defined(_STLP_ATOMIC_EXCHANGE)
  109. if (_Atomic_swap(__lock, 1)) {
  110. unsigned __my_spin_max = _STLP_mutex_spin<0>::__max;
  111. unsigned __my_last_spins = _STLP_mutex_spin<0>::__last;
  112. volatile unsigned __junk = 17; // Value doesn't matter.
  113. unsigned __i;
  114. for (__i = 0; __i < __my_spin_max; ++__i) {
  115. if (__i < __my_last_spins/2 || *__lock) {
  116. __junk *= __junk; __junk *= __junk;
  117. __junk *= __junk; __junk *= __junk;
  118. } else {
  119. if (!_Atomic_swap(__lock, 1)) {
  120. // got it!
  121. // Spinning worked. Thus we're probably not being scheduled
  122. // against the other process with which we were contending.
  123. // Thus it makes sense to spin longer the next time.
  124. _STLP_mutex_spin<0>::__last = __i;
  125. _STLP_mutex_spin<0>::__max = _STLP_mutex_spin<0>::__high_max;
  126. return;
  127. }
  128. }
  129. }
  130. // We are probably being scheduled against the other process. Sleep.
  131. _STLP_mutex_spin<0>::__max = _STLP_mutex_spin<0>::__low_max;
  132. for (__i = 0 ;; ++__i) {
  133. int __log_nsec = __i + 6;
  134. if (__log_nsec > 27) __log_nsec = 27;
  135. if (!_Atomic_swap(__lock, 1)) {
  136. break;
  137. }
  138. _S_nsec_sleep(__log_nsec, __i);
  139. }
  140. } /* first _Atomic_swap */
  141. # endif
  142. }
  143. #endif // _STLP_USE_PTHREAD_SPINLOCK
  144. _STLP_END_NAMESPACE
  145. #endif /* _STLP_EXPOSE_GLOBALS_IMPLEMENTATION */
  146. #endif /* _STLP_THREADS_C */
  147. // Local Variables:
  148. // mode:C++
  149. // End: