aboutsummaryrefslogtreecommitdiff
path: root/stlport/stl/_threads.c
blob: b79e18810a7db0728e8c38d73619f52b3c8b626f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
 *
 *
 * 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: