Home | History | Annotate | Download | only in stl
      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