1 _threads.h |
1 /* |
|
2 * Copyright (c) 1997-1999 |
|
3 * Silicon Graphics Computer Systems, Inc. |
|
4 * |
|
5 * Copyright (c) 1999 |
|
6 * Boris Fomitchev |
|
7 * |
|
8 * This material is provided "as is", with absolutely no warranty expressed |
|
9 * or implied. Any use is at your own risk. |
|
10 * |
|
11 * Permission to use or copy this software for any purpose is hereby granted |
|
12 * without fee, provided the above notices are retained on all copies. |
|
13 * Permission to modify the code and to distribute modified code is granted, |
|
14 * provided the above notices are retained, and a notice that the code was |
|
15 * modified is included with the above copyright notice. |
|
16 * |
|
17 */ |
|
18 |
|
19 // WARNING: This is an internal header file, included by other C++ |
|
20 // standard library headers. You should not attempt to use this header |
|
21 // file directly. |
|
22 // Stl_config.h should be included before this file. |
|
23 |
|
24 |
|
25 #ifndef _STLP_INTERNAL_THREADS_H |
|
26 #define _STLP_INTERNAL_THREADS_H |
|
27 |
|
28 // Supported threading models are native SGI, pthreads, uithreads |
|
29 // (similar to pthreads, but based on an earlier draft of the Posix |
|
30 // threads standard), and Win32 threads. Uithread support by Jochen |
|
31 // Schlick, 1999, and Solaris threads generalized to them. |
|
32 |
|
33 #ifndef _STLP_CONFIG_H |
|
34 #include <stl/_config.h> |
|
35 #endif |
|
36 |
|
37 # if ! defined (_STLP_CSTDDEF) |
|
38 # include <cstddef> |
|
39 # endif |
|
40 |
|
41 # if ! defined (_STLP_CSTDLIB) |
|
42 # include <cstdlib> |
|
43 # endif |
|
44 |
|
45 // On SUN and Mac OS X gcc, zero-initialization works just fine... |
|
46 # if defined (__sun) || ( defined(__GNUC__) && defined(__APPLE__) ) |
|
47 # define _STLP_MUTEX_INITIALIZER |
|
48 # endif |
|
49 |
|
50 # if defined (_STLP_WIN32) || defined (__sgi) || defined (_STLP_SPARC_SOLARIS_THREADS) |
|
51 typedef long __stl_atomic_t; |
|
52 # else |
|
53 # if defined (_STLP_USE_NAMESPACES) && ! defined (_STLP_VENDOR_GLOBAL_CSTD) |
|
54 // using _STLP_VENDOR_CSTD::size_t; |
|
55 using namespace _STLP_VENDOR_CSTD; |
|
56 # endif |
|
57 typedef size_t __stl_atomic_t; |
|
58 #endif |
|
59 |
|
60 # if defined(_STLP_SGI_THREADS) |
|
61 # include <mutex.h> |
|
62 // Hack for SGI o32 compilers. |
|
63 #if !defined(__add_and_fetch) && \ |
|
64 (__mips < 3 || !(defined (_ABIN32) || defined(_ABI64))) |
|
65 # define __add_and_fetch(__l,__v) add_then_test((unsigned long*)__l,__v) |
|
66 # define __test_and_set(__l,__v) test_and_set(__l,__v) |
|
67 #endif /* o32 */ |
|
68 |
|
69 # if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) |
|
70 # define _STLP_ATOMIC_EXCHANGE(__p, __q) test_and_set(__p, __q) |
|
71 # else |
|
72 # define _STLP_ATOMIC_EXCHANGE(__p, __q) __test_and_set((unsigned long*)__p, (unsigned long)__q) |
|
73 # endif |
|
74 |
|
75 # define _STLP_ATOMIC_INCREMENT(__x) __add_and_fetch(__x, 1) |
|
76 # define _STLP_ATOMIC_DECREMENT(__x) __add_and_fetch(__x, (size_t) -1) |
|
77 |
|
78 # elif defined (__GNUC__) && defined (__i386__) && defined (__unix__) && defined (_STLP_USE_INLINE_X86_SPINLOCK) |
|
79 |
|
80 // gcc on i386 linux, freebsd, etc. |
|
81 |
|
82 // This enables the memory caching on x86 linux. It is critical for SMP |
|
83 // without it the performace is DISMAL! |
|
84 static inline unsigned long __xchg(volatile __stl_atomic_t* target, int source) |
|
85 { |
|
86 |
|
87 // The target is refernce in memory rather than the register |
|
88 // because making a copy of it from memory to the register and |
|
89 // back again would ruin the atomic nature of the call. |
|
90 // the source does not need to be delt with atomicly so it can |
|
91 // be copied about as needed. |
|
92 // |
|
93 // The casting of the source is used to prevent gcc from optimizing |
|
94 // in such a way that breaks the atomic nature of this call. |
|
95 // |
|
96 __asm__ __volatile__("xchgl %1,%0" |
|
97 :"=m" (*(volatile long *) target), "=r" (source) |
|
98 :"m" (*(volatile long *) target), "r" (source) ); |
|
99 return source; |
|
100 |
|
101 // The assembly above does the following atomicly: |
|
102 // int temp=source; |
|
103 // source=(int)(*target); |
|
104 // (int)(*target)=temp; |
|
105 // return source |
|
106 } |
|
107 |
|
108 static inline void __inc_and_fetch(volatile __stl_atomic_t* __x) |
|
109 { |
|
110 // Referenced in memory rather than register to preserve the atomic nature. |
|
111 // |
|
112 __asm__ __volatile__( |
|
113 "lock; incl %0" |
|
114 :"=m" (*__x) |
|
115 :"m" (*__x) ); |
|
116 |
|
117 // The assembly above does the following atomicly: |
|
118 // ++(int)(*__x); |
|
119 |
|
120 } |
|
121 static inline void __dec_and_fetch(volatile __stl_atomic_t* __x) |
|
122 { |
|
123 // Referenced in memory rather than register to preserve the atomic nature. |
|
124 // |
|
125 __asm__ __volatile__( |
|
126 "lock; decl %0" |
|
127 :"=m" (*__x) |
|
128 :"m" (*__x) ); |
|
129 |
|
130 // The assembly above does the following atomicly: |
|
131 // --(int)(*__x); |
|
132 } |
|
133 |
|
134 # define _STLP_ATOMIC_EXCHANGE(target, newValue) ((__xchg(target, newValue))) |
|
135 # define _STLP_ATOMIC_INCREMENT(__x) __inc_and_fetch(__x) |
|
136 # define _STLP_ATOMIC_DECREMENT(__x) __dec_and_fetch(__x) |
|
137 |
|
138 # elif defined(_STLP_PTHREADS) |
|
139 |
|
140 # include <pthread.h> |
|
141 # ifndef _STLP_USE_PTHREAD_SPINLOCK |
|
142 # if defined(PTHREAD_MUTEX_INITIALIZER) && !defined(_STLP_MUTEX_INITIALIZER) |
|
143 # define _STLP_MUTEX_INITIALIZER = { PTHREAD_MUTEX_INITIALIZER } |
|
144 # endif |
|
145 |
|
146 //HPUX variants have (on some platforms optional) non-standard "DCE" pthreads impl |
|
147 # if defined(_DECTHREADS_) && (defined(_PTHREAD_USE_D4) || defined(__hpux)) && !defined(_CMA_SUPPRESS_EXTERNALS_) |
|
148 # define _STLP_PTHREAD_ATTR_DEFAULT pthread_mutexattr_default |
|
149 # else |
|
150 # define _STLP_PTHREAD_ATTR_DEFAULT 0 |
|
151 # endif |
|
152 # endif // !_STLP_USE_PTHREAD_SPINLOCK |
|
153 |
|
154 # elif defined(_STLP_WIN32THREADS) |
|
155 # if !defined (_STLP_WINDOWS_H_INCLUDED) && ! defined (_WINDOWS_H) |
|
156 # if ! (defined ( _STLP_MSVC ) || defined (__BORLANDC__) || defined (__ICL) || defined (__WATCOMC__) || defined (__MINGW32__) || defined (__DMC__)) |
|
157 # ifdef _STLP_USE_MFC |
|
158 # include <afx.h> |
|
159 # else |
|
160 # include <windows.h> |
|
161 # endif |
|
162 # define _STLP_WINDOWS_H_INCLUDED |
|
163 # else |
|
164 // This section serves as a replacement for windows.h header for Visual C++ |
|
165 extern "C" { |
|
166 # if (defined(_M_MRX000) || defined(_M_ALPHA) \ |
|
167 || (defined(_M_PPC) && (_MSC_VER >= 1000))) && !defined(RC_INVOKED) |
|
168 # define InterlockedIncrement _InterlockedIncrement |
|
169 # define InterlockedDecrement _InterlockedDecrement |
|
170 # define InterlockedExchange _InterlockedExchange |
|
171 # define _STLP_STDCALL |
|
172 # else |
|
173 # ifdef _MAC |
|
174 # define _STLP_STDCALL _cdecl |
|
175 # else |
|
176 # define _STLP_STDCALL __stdcall |
|
177 # endif |
|
178 # endif |
|
179 |
|
180 #if (_MSC_VER >= 1300) || defined (_STLP_NEW_PLATFORM_SDK) |
|
181 _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedIncrement(long volatile *); |
|
182 _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedDecrement(long volatile *); |
|
183 _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedExchange(long volatile *, long); |
|
184 #else |
|
185 // boris : for the latest SDK, you may actually need the other version of the declaration (above) |
|
186 // even for earlier VC++ versions. There is no way to tell SDK versions apart, sorry ... |
|
187 _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedIncrement(long*); |
|
188 _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedDecrement(long*); |
|
189 _STLP_IMPORT_DECLSPEC long _STLP_STDCALL InterlockedExchange(long*, long); |
|
190 #endif |
|
191 |
|
192 _STLP_IMPORT_DECLSPEC void _STLP_STDCALL Sleep(unsigned long); |
|
193 _STLP_IMPORT_DECLSPEC void _STLP_STDCALL OutputDebugStringA( const char* lpOutputString ); |
|
194 |
|
195 #ifdef _STLP_DEBUG |
|
196 typedef unsigned long DWORD; |
|
197 _STLP_IMPORT_DECLSPEC DWORD _STLP_STDCALL GetCurrentThreadId(); |
|
198 #endif /* _STLP_DEBUG */ |
|
199 |
|
200 # if defined (InterlockedIncrement) |
|
201 # pragma intrinsic(_InterlockedIncrement) |
|
202 # pragma intrinsic(_InterlockedDecrement) |
|
203 # pragma intrinsic(_InterlockedExchange) |
|
204 # endif |
|
205 } /* extern "C" */ |
|
206 |
|
207 # endif /* STL_MSVC */ |
|
208 |
|
209 # define _STLP_WINDOWS_H_INCLUDED |
|
210 |
|
211 # endif /* _STLP_WIN32 */ |
|
212 |
|
213 # ifndef _STLP_ATOMIC_INCREMENT |
|
214 # define _STLP_ATOMIC_INCREMENT(__x) InterlockedIncrement((long*)__x) |
|
215 # define _STLP_ATOMIC_DECREMENT(__x) InterlockedDecrement((long*)__x) |
|
216 # define _STLP_ATOMIC_EXCHANGE(__x, __y) InterlockedExchange((long*)__x, (long)__y) |
|
217 # endif |
|
218 # elif defined(__DECC) || defined(__DECCXX) |
|
219 # include <machine/builtins.h> |
|
220 # define _STLP_ATOMIC_EXCHANGE __ATOMIC_EXCH_LONG |
|
221 # define _STLP_ATOMIC_INCREMENT(__x) __ATOMIC_ADD_LONG(__x, 1) |
|
222 # define _STLP_ATOMIC_DECREMENT(__x) __ATOMIC_ADD_LONG(__x, -1) |
|
223 # elif defined(_STLP_SPARC_SOLARIS_THREADS) |
|
224 # include <stl/_sparc_atomic.h> |
|
225 # elif defined (_STLP_UITHREADS) |
|
226 // this inclusion is potential hazard to bring up all sorts |
|
227 // of old-style headers. Let's assume vendor already know how |
|
228 // to deal with that. |
|
229 # include <ctime> |
|
230 # if defined (_STLP_USE_NAMESPACES) && ! defined (_STLP_VENDOR_GLOBAL_CSTD) |
|
231 using _STLP_VENDOR_CSTD::time_t; |
|
232 # endif |
|
233 # include <synch.h> |
|
234 # include <cstdio> |
|
235 # include <stl/_cwchar.h> |
|
236 # elif defined (_STLP_BETHREADS) |
|
237 # include <OS.h> |
|
238 #include <cassert> |
|
239 #include <stdio.h> |
|
240 # define _STLP_MUTEX_INITIALIZER = { 0 } |
|
241 #elif defined(_STLP_OS2THREADS) |
|
242 # ifdef __GNUC__ |
|
243 # define INCL_DOSSEMAPHORES |
|
244 # include <os2.h> |
|
245 # else |
|
246 // This section serves to replace os2.h for VisualAge C++ |
|
247 typedef unsigned long ULONG; |
|
248 #ifndef __HEV__ /* INCL_SEMAPHORE may also define HEV */ |
|
249 #define __HEV__ |
|
250 typedef ULONG HEV; |
|
251 typedef HEV* PHEV; |
|
252 #endif |
|
253 typedef ULONG APIRET; |
|
254 typedef ULONG HMTX; |
|
255 typedef HMTX* PHMTX; |
|
256 typedef const char* PCSZ; |
|
257 typedef ULONG BOOL32; |
|
258 APIRET _System DosCreateMutexSem(PCSZ pszName, PHEV phev, ULONG flAttr, BOOL32 fState); |
|
259 APIRET _System DosRequestMutexSem(HMTX hmtx, ULONG ulTimeout); |
|
260 APIRET _System DosReleaseMutexSem(HMTX hmtx); |
|
261 APIRET _System DosCloseMutexSem(HMTX hmtx); |
|
262 # define _STLP_MUTEX_INITIALIZER = { 0 }; |
|
263 # endif /* GNUC */ |
|
264 # elif defined(_STLP_VXWORKS_THREADS) |
|
265 # include "semLib.h" |
|
266 # endif |
|
267 |
|
268 # ifndef _STLP_MUTEX_INITIALIZER |
|
269 # if defined(_STLP_ATOMIC_EXCHANGE) |
|
270 // we are using our own spinlock. |
|
271 # define _STLP_MUTEX_INITIALIZER = { 0 } |
|
272 # elif defined(_STLP_UITHREADS) |
|
273 // known case |
|
274 # define _STLP_MUTEX_INITIALIZER = { DEFAULTMUTEX } |
|
275 # else |
|
276 // we do not have static initializer available. therefore, on-demand synchronization is needed. |
|
277 # define _STLP_MUTEX_INITIALIZER |
|
278 # define _STLP_MUTEX_NEEDS_ONDEMAND_INITIALIZATION |
|
279 # endif |
|
280 # endif |
|
281 |
|
282 _STLP_BEGIN_NAMESPACE |
|
283 |
|
284 #ifndef _STLP_USE_PTHREAD_SPINLOCK |
|
285 // Helper struct. This is a workaround for various compilers that don't |
|
286 // handle static variables in inline functions properly. |
|
287 template <int __inst> |
|
288 struct _STLP_mutex_spin { |
|
289 enum { __low_max = 30, __high_max = 1000 }; |
|
290 // Low if we suspect uniprocessor, high for multiprocessor. |
|
291 static unsigned __max; |
|
292 static unsigned __last; |
|
293 static void _STLP_CALL _M_do_lock(volatile __stl_atomic_t* __lock); |
|
294 static void _STLP_CALL _S_nsec_sleep(int __log_nsec); |
|
295 }; |
|
296 #endif // !_STLP_USE_PTHREAD_SPINLOCK |
|
297 |
|
298 |
|
299 // Locking class. Note that this class *does not have a constructor*. |
|
300 // It must be initialized either statically, with _STLP_MUTEX_INITIALIZER, |
|
301 // or dynamically, by explicitly calling the _M_initialize member function. |
|
302 // (This is similar to the ways that a pthreads mutex can be initialized.) |
|
303 // There are explicit member functions for acquiring and releasing the lock. |
|
304 |
|
305 // There is no constructor because static initialization is essential for |
|
306 // some uses, and only a class aggregate (see section 8.5.1 of the C++ |
|
307 // standard) can be initialized that way. That means we must have no |
|
308 // constructors, no base classes, no virtual functions, and no private or |
|
309 // protected members. |
|
310 |
|
311 // For non-static cases, clients should use _STLP_mutex. |
|
312 |
|
313 struct _STLP_CLASS_DECLSPEC _STLP_mutex_base |
|
314 { |
|
315 #if defined(_STLP_ATOMIC_EXCHANGE) || defined(_STLP_SGI_THREADS) |
|
316 // It should be relatively easy to get this to work on any modern Unix. |
|
317 volatile __stl_atomic_t _M_lock; |
|
318 #endif |
|
319 |
|
320 #ifdef _STLP_THREADS |
|
321 |
|
322 # ifdef _STLP_ATOMIC_EXCHANGE |
|
323 inline void _M_initialize() { _M_lock=0; } |
|
324 inline void _M_destroy() {} |
|
325 |
|
326 void _M_acquire_lock() { |
|
327 _STLP_mutex_spin<0>::_M_do_lock(&_M_lock); |
|
328 } |
|
329 |
|
330 inline void _M_release_lock() { |
|
331 volatile __stl_atomic_t* __lock = &_M_lock; |
|
332 # if defined(_STLP_SGI_THREADS) && defined(__GNUC__) && __mips >= 3 |
|
333 asm("sync"); |
|
334 *__lock = 0; |
|
335 # elif defined(_STLP_SGI_THREADS) && __mips >= 3 \ |
|
336 && (defined (_ABIN32) || defined(_ABI64)) |
|
337 __lock_release(__lock); |
|
338 # elif defined (_STLP_SPARC_SOLARIS_THREADS) |
|
339 # if defined (__WORD64) || defined (__arch64__) || defined (__sparcv9) || defined (__sparcv8plus) |
|
340 asm("membar #StoreStore ; membar #LoadStore"); |
|
341 # else |
|
342 asm(" stbar "); |
|
343 # endif |
|
344 *__lock = 0; |
|
345 # else |
|
346 *__lock = 0; |
|
347 // This is not sufficient on many multiprocessors, since |
|
348 // writes to protected variables and the lock may be reordered. |
|
349 # endif |
|
350 } |
|
351 # elif defined(_STLP_PTHREADS) |
|
352 # ifdef _STLP_USE_PTHREAD_SPINLOCK |
|
353 pthread_spinlock_t _M_lock; |
|
354 inline void _M_initialize() { pthread_spin_init( &_M_lock, 0 ); } |
|
355 inline void _M_destroy() { pthread_spin_destroy( &_M_lock ); } |
|
356 |
|
357 inline void _M_acquire_lock() { |
|
358 // we do not care about race conditions here : there is only one thread at this point |
|
359 if(!_M_lock) pthread_spin_init( &_M_lock, 0 ); |
|
360 |
|
361 // fbp: here, initialization on demand should happen before the lock |
|
362 // we use simple strategy as we are sure this only happens on initialization |
|
363 pthread_spin_lock( &_M_lock ); |
|
364 } |
|
365 |
|
366 inline void _M_acquire_lock_nodemand() { |
|
367 pthread_spin_lock( &_M_lock ); |
|
368 } |
|
369 inline void _M_release_lock() { pthread_spin_unlock( &_M_lock ); } |
|
370 # else // !_STLP_USE_PTHREAD_SPINLOCK |
|
371 pthread_mutex_t _M_lock; |
|
372 |
|
373 inline void _M_initialize() { |
|
374 pthread_mutex_init(&_M_lock,_STLP_PTHREAD_ATTR_DEFAULT); |
|
375 } |
|
376 inline void _M_destroy() { |
|
377 pthread_mutex_destroy(&_M_lock); |
|
378 } |
|
379 inline void _M_acquire_lock_nodemand() { |
|
380 pthread_mutex_lock(&_M_lock); |
|
381 } |
|
382 |
|
383 inline void _M_acquire_lock() { |
|
384 # if defined (__hpux) && !defined (PTHREAD_MUTEX_INITIALIZER) |
|
385 if (!_M_lock.field1) _M_initialize(); |
|
386 # endif |
|
387 pthread_mutex_lock(&_M_lock); |
|
388 } |
|
389 inline void _M_release_lock() { pthread_mutex_unlock(&_M_lock); } |
|
390 # endif // !_STLP_USE_PTHREAD_SPINLOCK |
|
391 |
|
392 # elif defined (_STLP_UITHREADS) |
|
393 mutex_t _M_lock; |
|
394 inline void _M_initialize() { |
|
395 mutex_init(&_M_lock,0,NULL); |
|
396 } |
|
397 inline void _M_destroy() { |
|
398 mutex_destroy(&_M_lock); |
|
399 } |
|
400 inline void _M_acquire_lock() { mutex_lock(&_M_lock); } |
|
401 inline void _M_release_lock() { mutex_unlock(&_M_lock); } |
|
402 |
|
403 # elif defined(_STLP_OS2THREADS) |
|
404 HMTX _M_lock; |
|
405 inline void _M_initialize() { DosCreateMutexSem(NULL, &_M_lock, 0, false); } |
|
406 inline void _M_destroy() { DosCloseMutexSem(_M_lock); } |
|
407 inline void _M_acquire_lock_nodemand() { |
|
408 DosRequestMutexSem(_M_lock, SEM_INDEFINITE_WAIT); |
|
409 } |
|
410 inline void _M_acquire_lock() { |
|
411 if(!_M_lock) _M_initialize(); |
|
412 DosRequestMutexSem(_M_lock, SEM_INDEFINITE_WAIT); |
|
413 } |
|
414 inline void _M_release_lock() { DosReleaseMutexSem(_M_lock); } |
|
415 # elif defined(_STLP_BETHREADS) |
|
416 sem_id sem; |
|
417 inline void _M_initialize() |
|
418 { |
|
419 sem = create_sem(1, "STLPort"); |
|
420 assert(sem > 0); |
|
421 } |
|
422 inline void _M_destroy() |
|
423 { |
|
424 int t = delete_sem(sem); |
|
425 assert(t == B_NO_ERROR); |
|
426 } |
|
427 inline void _M_acquire_lock_nodemand() |
|
428 { |
|
429 status_t t; |
|
430 t = acquire_sem(sem); |
|
431 assert(t == B_NO_ERROR); |
|
432 } |
|
433 inline void _M_acquire_lock(); |
|
434 inline void _M_release_lock() |
|
435 { |
|
436 status_t t = release_sem(sem); |
|
437 assert(t == B_NO_ERROR); |
|
438 } |
|
439 # elif defined(_STLP_VXWORKS_THREADS) |
|
440 SEM_ID _M_sem; |
|
441 inline void _M_initialize() |
|
442 { |
|
443 _M_sem = semMCreate(SEM_Q_FIFO); |
|
444 assert(_M_sem > 0); |
|
445 } |
|
446 inline void _M_destroy() |
|
447 { |
|
448 STATUS __s; |
|
449 semDelete (_M_sem); |
|
450 assert(__s == OK); |
|
451 } |
|
452 inline void _M_acquire_lock_nodemand() |
|
453 { |
|
454 STATUS __s; |
|
455 semTake (_M_sem, WAIT_FOREVER); |
|
456 assert(__s == OK); |
|
457 } |
|
458 inline void _M_acquire_lock() |
|
459 { |
|
460 if (!_M_sem) |
|
461 _M_initialize(); |
|
462 _M_acquire_lock_nodemand(); |
|
463 } |
|
464 inline void _M_release_lock() |
|
465 { |
|
466 STATUS __s; |
|
467 semGive (_M_sem, WAIT_FOREVER); |
|
468 assert(__s == OK); |
|
469 } |
|
470 # else //*ty 11/24/2001 - added configuration check |
|
471 # error "Unknown thread facility configuration" |
|
472 # endif |
|
473 #else /* No threads */ |
|
474 inline void _M_initialize() {} |
|
475 inline void _M_destroy() {} |
|
476 inline void _M_acquire_lock() {} |
|
477 inline void _M_release_lock() {} |
|
478 #endif // _STLP_PTHREADS |
|
479 }; |
|
480 |
|
481 |
|
482 #if defined (_STLP_THREADS) && defined (_STLP_MUTEX_NEEDS_ONDEMAND_INITIALIZATION) |
|
483 // for use in _STLP_mutex, our purposes do not require ondemand initialization |
|
484 // also, mutex_base may use some hacks to determine uninitialized state by zero data, which only works for globals. |
|
485 class _STLP_CLASS_DECLSPEC _STLP_mutex_nodemand : public _STLP_mutex_base { |
|
486 inline void _M_acquire_lock() { |
|
487 _M_acquire_lock_nodemand(); |
|
488 } |
|
489 }; |
|
490 #else |
|
491 typedef _STLP_mutex_base _STLP_mutex_nodemand; |
|
492 #endif |
|
493 |
|
494 |
|
495 // Locking class. The constructor initializes the lock, the destructor destroys it. |
|
496 // Well - behaving class, does not need static initializer |
|
497 class _STLP_CLASS_DECLSPEC _STLP_mutex : public _STLP_mutex_nodemand { |
|
498 public: |
|
499 inline _STLP_mutex () { _M_initialize(); } |
|
500 inline ~_STLP_mutex () { _M_destroy(); } |
|
501 private: |
|
502 _STLP_mutex(const _STLP_mutex&); |
|
503 void operator=(const _STLP_mutex&); |
|
504 }; |
|
505 |
|
506 |
|
507 |
|
508 /* |
|
509 * Class _Refcount_Base provides a type, __stl_atomic_t, a data member, |
|
510 * _M_ref_count, and member functions _M_incr and _M_decr, which perform |
|
511 * atomic preincrement/predecrement. The constructor initializes |
|
512 * _M_ref_count. |
|
513 */ |
|
514 struct _STLP_CLASS_DECLSPEC _Refcount_Base |
|
515 { |
|
516 // The data member _M_ref_count |
|
517 volatile __stl_atomic_t _M_ref_count; |
|
518 |
|
519 # if !defined (_STLP_ATOMIC_EXCHANGE) |
|
520 _STLP_mutex _M_mutex; |
|
521 # endif |
|
522 |
|
523 // Constructor |
|
524 _Refcount_Base(__stl_atomic_t __n) : _M_ref_count(__n) {} |
|
525 |
|
526 // _M_incr and _M_decr |
|
527 # if defined (_STLP_THREADS) && defined (_STLP_ATOMIC_EXCHANGE) |
|
528 void _M_incr() { _STLP_ATOMIC_INCREMENT((__stl_atomic_t*)&_M_ref_count); } |
|
529 void _M_decr() { _STLP_ATOMIC_DECREMENT((__stl_atomic_t*)&_M_ref_count); } |
|
530 # elif defined(_STLP_THREADS) |
|
531 void _M_incr() { |
|
532 _M_mutex._M_acquire_lock(); |
|
533 ++_M_ref_count; |
|
534 _M_mutex._M_release_lock(); |
|
535 } |
|
536 void _M_decr() { |
|
537 _M_mutex._M_acquire_lock(); |
|
538 --_M_ref_count; |
|
539 _M_mutex._M_release_lock(); |
|
540 } |
|
541 # else /* No threads */ |
|
542 void _M_incr() { ++_M_ref_count; } |
|
543 void _M_decr() { --_M_ref_count; } |
|
544 # endif |
|
545 }; |
|
546 |
|
547 // Atomic swap on unsigned long |
|
548 // This is guaranteed to behave as though it were atomic only if all |
|
549 // possibly concurrent updates use _Atomic_swap. |
|
550 // In some cases the operation is emulated with a lock. |
|
551 # if defined (_STLP_THREADS) |
|
552 # ifdef _STLP_ATOMIC_EXCHANGE |
|
553 inline __stl_atomic_t _Atomic_swap(volatile __stl_atomic_t * __p, __stl_atomic_t __q) { |
|
554 return (__stl_atomic_t) _STLP_ATOMIC_EXCHANGE(__p,__q); |
|
555 } |
|
556 # elif defined(_STLP_PTHREADS) || defined (_STLP_UITHREADS) || defined (_STLP_OS2THREADS) || defined(_STLP_USE_PTHREAD_SPINLOCK) |
|
557 // We use a template here only to get a unique initialized instance. |
|
558 template<int __dummy> |
|
559 struct _Swap_lock_struct { |
|
560 static _STLP_STATIC_MUTEX _S_swap_lock; |
|
561 }; |
|
562 |
|
563 |
|
564 // This should be portable, but performance is expected |
|
565 // to be quite awful. This really needs platform specific |
|
566 // code. |
|
567 inline __stl_atomic_t _Atomic_swap(volatile __stl_atomic_t * __p, __stl_atomic_t __q) { |
|
568 _Swap_lock_struct<0>::_S_swap_lock._M_acquire_lock(); |
|
569 __stl_atomic_t __result = *__p; |
|
570 *__p = __q; |
|
571 _Swap_lock_struct<0>::_S_swap_lock._M_release_lock(); |
|
572 return __result; |
|
573 } |
|
574 # endif // _STLP_PTHREADS || _STLP_UITHREADS || _STLP_OS2THREADS || _STLP_USE_PTHREAD_SPINLOCK |
|
575 # else // !_STLP_THREADS |
|
576 /* no threads */ |
|
577 static inline __stl_atomic_t _STLP_CALL |
|
578 _Atomic_swap(volatile __stl_atomic_t * __p, __stl_atomic_t __q) { |
|
579 __stl_atomic_t __result = *__p; |
|
580 *__p = __q; |
|
581 return __result; |
|
582 } |
|
583 # endif // _STLP_THREADS |
|
584 |
|
585 // A locking class that uses _STLP_STATIC_MUTEX. The constructor takes |
|
586 // a reference to an _STLP_STATIC_MUTEX, and acquires a lock. The destructor |
|
587 // releases the lock. |
|
588 |
|
589 struct _STLP_CLASS_DECLSPEC _STLP_auto_lock |
|
590 { |
|
591 _STLP_STATIC_MUTEX& _M_lock; |
|
592 |
|
593 _STLP_auto_lock(_STLP_STATIC_MUTEX& __lock) : _M_lock(__lock) |
|
594 { _M_lock._M_acquire_lock(); } |
|
595 ~_STLP_auto_lock() { _M_lock._M_release_lock(); } |
|
596 |
|
597 private: |
|
598 void operator=(const _STLP_auto_lock&); |
|
599 _STLP_auto_lock(const _STLP_auto_lock&); |
|
600 }; |
|
601 |
|
602 typedef _STLP_auto_lock _STLP_mutex_lock; |
|
603 |
|
604 #ifdef _STLP_BETHREADS |
|
605 |
|
606 template <int __inst> |
|
607 struct _STLP_beos_static_lock_data |
|
608 { |
|
609 static bool is_init; |
|
610 struct mutex_t : public _STLP_mutex |
|
611 { |
|
612 mutex_t() |
|
613 { |
|
614 _STLP_beos_static_lock_data<0>::is_init = true; |
|
615 } |
|
616 ~mutex_t() |
|
617 { |
|
618 _STLP_beos_static_lock_data<0>::is_init = false; |
|
619 } |
|
620 }; |
|
621 static mutex_t mut; |
|
622 }; |
|
623 |
|
624 template <int __inst> |
|
625 bool _STLP_beos_static_lock_data<__inst>::is_init = false; |
|
626 template <int __inst> |
|
627 typename _STLP_beos_static_lock_data<__inst>::mutex_t _STLP_beos_static_lock_data<__inst>::mut; |
|
628 |
|
629 |
|
630 inline void _STLP_mutex_base::_M_acquire_lock() |
|
631 { |
|
632 if(sem == 0) |
|
633 { |
|
634 // we need to initialise on demand here |
|
635 // to prevent race conditions use our global |
|
636 // mutex if it's available: |
|
637 if(_STLP_beos_static_lock_data<0>::is_init) |
|
638 { |
|
639 _STLP_auto_lock al(_STLP_beos_static_lock_data<0>::mut); |
|
640 if(sem == 0) _M_initialize(); |
|
641 } |
|
642 else |
|
643 { |
|
644 // no lock available, we must still be |
|
645 // in startup code, THERE MUST BE ONE THREAD |
|
646 // ONLY active at this point. |
|
647 _M_initialize(); |
|
648 } |
|
649 } |
|
650 _M_acquire_lock_nodemand(); |
|
651 } |
|
652 |
|
653 #endif |
|
654 |
|
655 _STLP_END_NAMESPACE |
|
656 |
|
657 # if !defined (_STLP_LINK_TIME_INSTANTIATION) |
|
658 # include <stl/_threads.c> |
|
659 # endif |
|
660 |
|
661 #endif /* _STLP_INTERNAL_THREADS_H */ |
|
662 |
|
663 // Local Variables: |
|
664 // mode:C++ |
|
665 // End: |
|
666 |