text: /*
   *
   *
   * 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 <stl/_threads.h>
  #endif
  
  #if defined (_STLP_EXPOSE_GLOBALS_IMPLEMENTATION)
  
  #if defined (_STLP_SGI_THREADS)
  #  include <time.h>
  #elif defined (_STLP_UNIX)
  #  ifndef _STLP_INTERNAL_CTIME
  #    include <stl/_ctime.h>
  #  endif
  #  if defined (_STLP_USE_NAMESPACES) && !defined (_STLP_VENDOR_GLOBAL_CSTD)
  using _STLP_VENDOR_CSTD::time_t;
  #  endif
  #  include <sys/time.h>
  #endif
  
  _STLP_BEGIN_NAMESPACE
  
  #if defined (_STLP_USE_ATOMIC_SWAP_MUTEX)
  template<int __32bits>
  _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 <int __inst>
  unsigned _STLP_mutex_spin<__inst>::__max = _STLP_mutex_spin<__inst>::__low_max;
  
  template <int __inst>
  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 <int __inst>
  void _STLP_CALL
  _STLP_mutex_spin<__inst>::_S_nsec_sleep(int __log_nsec, unsigned int& _STLP_UNUSED(__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 <int __inst>
  void  _STLP_CALL
  _STLP_mutex_spin<__inst>::_M_do_lock(volatile __stl_atomic_t* _STLP_UNUSED(__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:
  