/[pcsx2_0.9.7]/trunk/common/include/Utilities/Threading.h
ViewVC logotype

Contents of /trunk/common/include/Utilities/Threading.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (10 years, 1 month ago) by william
File MIME type: text/plain
File size: 12185 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #pragma once
17
18 #include <semaphore.h>
19 #include <errno.h> // EBUSY
20 #include <pthread.h>
21
22 #include "Pcsx2Defs.h"
23 #include "ScopedPtr.h"
24 #include "TraceLog.h"
25
26 #undef Yield // release the burden of windows.h global namespace spam.
27
28 #define AffinityAssert_AllowFrom_MainUI() \
29 pxAssertMsg( wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only." )
30
31 // --------------------------------------------------------------------------------------
32 // pxThreadLog / ConsoleLogSource_Threading
33 // --------------------------------------------------------------------------------------
34
35 class ConsoleLogSource_Threading : ConsoleLogSource
36 {
37 typedef ConsoleLogSource _parent;
38
39 public:
40 using _parent::IsActive;
41
42 ConsoleLogSource_Threading();
43
44 bool Write( const wxString& thrname, const wxChar* msg ) {
45 return _parent::Write( wxsFormat(L"(thread:%s) ", thrname.c_str()) + msg );
46 }
47 bool Warn( const wxString& thrname, const wxChar* msg ) {
48 return _parent::Warn( wxsFormat(L"(thread:%s) ", thrname.c_str()) + msg );
49 }
50 bool Error( const wxString& thrname, const wxChar* msg ) {
51 return _parent::Error( wxsFormat(L"(thread:%s) ", thrname.c_str()) + msg );
52 }
53 };
54
55 extern ConsoleLogSource_Threading pxConLog_Thread;
56
57 #define pxThreadLog pxConLog_Thread.IsActive() && pxConLog_Thread
58
59
60 // --------------------------------------------------------------------------------------
61 // PCSX2_THREAD_LOCAL - Defines platform/operating system support for Thread Local Storage
62 // --------------------------------------------------------------------------------------
63 // For complimentary support for TLS, include Utilities/TlsVariable.inl, and use the
64 // DeclareTls macro in the place of __threadlocal.
65 //
66 //#define PCSX2_THREAD_LOCAL 0 // uncomment this line to force-disable native TLS (useful for testing TlsVariabel on windows/linux)
67
68 #ifndef PCSX2_THREAD_LOCAL
69 # ifdef __WXMAC__
70 # define PCSX2_THREAD_LOCAL 0
71 # else
72 # define PCSX2_THREAD_LOCAL 1
73 # endif
74 #endif
75
76 class wxTimeSpan;
77
78 namespace Threading
79 {
80 class pxThread;
81 class RwMutex;
82
83 extern void pxTestCancel();
84 extern pxThread* pxGetCurrentThread();
85 extern wxString pxGetCurrentThreadName();
86 extern u64 GetThreadCpuTime();
87 extern u64 GetThreadTicksPerSecond();
88
89 // Yields the current thread and provides cancellation points if the thread is managed by
90 // pxThread. Unmanaged threads use standard Sleep.
91 extern void pxYield( int ms );
92 }
93
94 namespace Exception
95 {
96 class BaseThreadError : public RuntimeError
97 {
98 DEFINE_EXCEPTION_COPYTORS( BaseThreadError, RuntimeError )
99 DEFINE_EXCEPTION_MESSAGES( BaseThreadError )
100
101 public:
102 Threading::pxThread* m_thread;
103
104 protected:
105 BaseThreadError() {
106 m_thread = NULL;
107 }
108
109 public:
110 explicit BaseThreadError( Threading::pxThread* _thread )
111 {
112 m_thread = _thread;
113 m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
114 }
115
116 explicit BaseThreadError( Threading::pxThread& _thread )
117 {
118 m_thread = &_thread;
119 m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
120 }
121
122 virtual wxString FormatDiagnosticMessage() const;
123 virtual wxString FormatDisplayMessage() const;
124
125 Threading::pxThread& Thread();
126 const Threading::pxThread& Thread() const;
127 };
128
129 class ThreadCreationError : public BaseThreadError
130 {
131 DEFINE_EXCEPTION_COPYTORS( ThreadCreationError, BaseThreadError )
132
133 public:
134 explicit ThreadCreationError( Threading::pxThread* _thread )
135 {
136 m_thread = _thread;
137 SetBothMsgs( L"Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
138 }
139
140 explicit ThreadCreationError( Threading::pxThread& _thread )
141 {
142 m_thread = &_thread;
143 SetBothMsgs( L"Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
144 }
145 };
146 }
147
148
149 namespace Threading
150 {
151 // --------------------------------------------------------------------------------------
152 // Platform Specific External APIs
153 // --------------------------------------------------------------------------------------
154 // The following set of documented functions have Linux/Win32 specific implementations,
155 // which are found in WinThreads.cpp and LnxThreads.cpp
156
157 // Releases a timeslice to other threads.
158 extern void Timeslice();
159
160 // For use in spin/wait loops.
161 extern void SpinWait();
162
163 // Use prior to committing data to another thread (internal memcpy_qwc does not use fencing,
164 // so that many memcpys can be issued in a row more efficiently)
165 extern void StoreFence();
166
167 // Optional implementation to enable hires thread/process scheduler for the operating system.
168 // Needed by Windows, but might not be relevant to other platforms.
169 extern void EnableHiresScheduler();
170 extern void DisableHiresScheduler();
171
172 // sleeps the current thread for the given number of milliseconds.
173 extern void Sleep( int ms );
174
175 // --------------------------------------------------------------------------------------
176 // AtomicExchange / AtomicIncrement
177 // --------------------------------------------------------------------------------------
178 // Our fundamental interlocking functions. All other useful interlocks can be derived
179 // from these little beasties! (these are all implemented internally using cross-platform
180 // implementations of _InterlockedExchange and such)
181
182 extern u32 AtomicExchange( volatile u32& Target, u32 value );
183 extern u32 AtomicExchangeAdd( volatile u32& Target, u32 value );
184 extern u32 AtomicIncrement( volatile u32& Target );
185 extern u32 AtomicDecrement( volatile u32& Target );
186 extern s32 AtomicExchange( volatile s32& Target, s32 value );
187 extern s32 AtomicExchangeAdd( volatile s32& Target, s32 value );
188 extern s32 AtomicExchangeSub( volatile s32& Target, s32 value );
189 extern s32 AtomicIncrement( volatile s32& Target );
190 extern s32 AtomicDecrement( volatile s32& Target );
191
192 extern bool AtomicBitTestAndReset( volatile u32& bitset, u8 bit );
193
194 extern void* _AtomicExchangePointer( volatile uptr& target, uptr value );
195 extern void* _AtomicCompareExchangePointer( volatile uptr& target, uptr value, uptr comparand );
196
197 #define AtomicExchangePointer( dest, src ) _AtomicExchangePointer( (uptr&)dest, (uptr)src )
198 #define AtomicCompareExchangePointer( dest, comp, src ) _AtomicExchangePointer( (uptr&)dest, (uptr)comp, (uptr)src )
199
200 // pthread Cond is an evil api that is not suited for Pcsx2 needs.
201 // Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
202 #if 0
203 struct WaitEvent
204 {
205 pthread_cond_t cond;
206 pthread_mutex_t mutex;
207
208 WaitEvent();
209 ~WaitEvent() throw();
210
211 void Set();
212 void Wait();
213 };
214 #endif
215
216 // --------------------------------------------------------------------------------------
217 // NonblockingMutex
218 // --------------------------------------------------------------------------------------
219 // This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
220 // trylock(), but without any of the extra overhead needed to set up a structure capable
221 // of blocking waits. It basically optimizes to a single InterlockedExchange.
222 //
223 // Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
224 // If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
225 // it later.
226 //
227 class NonblockingMutex
228 {
229 protected:
230 volatile int val;
231
232 public:
233 NonblockingMutex() : val( false ) {}
234 virtual ~NonblockingMutex() throw() {}
235
236 bool TryAcquire() throw()
237 {
238 return !AtomicExchange( val, true );
239 }
240
241 bool IsLocked()
242 { return !!val; }
243
244 void Release()
245 {
246 AtomicExchange( val, false );
247 }
248 };
249
250 class Semaphore
251 {
252 protected:
253 sem_t m_sema;
254
255 public:
256 Semaphore();
257 virtual ~Semaphore() throw();
258
259 void Reset();
260 void Post();
261 void Post( int multiple );
262
263 void WaitWithoutYield();
264 bool WaitWithoutYield( const wxTimeSpan& timeout );
265 void WaitNoCancel();
266 void WaitNoCancel( const wxTimeSpan& timeout );
267 int Count();
268
269 void Wait();
270 bool Wait( const wxTimeSpan& timeout );
271 };
272
273 class Mutex
274 {
275 protected:
276 pthread_mutex_t m_mutex;
277
278 public:
279 Mutex();
280 virtual ~Mutex() throw();
281 virtual bool IsRecursive() const { return false; }
282
283 void Recreate();
284 bool RecreateIfLocked();
285 void Detach();
286
287 void Acquire();
288 bool Acquire( const wxTimeSpan& timeout );
289 bool TryAcquire();
290 void Release();
291
292 void AcquireWithoutYield();
293 bool AcquireWithoutYield( const wxTimeSpan& timeout );
294
295 void Wait();
296 bool Wait( const wxTimeSpan& timeout );
297 void WaitWithoutYield();
298 bool WaitWithoutYield( const wxTimeSpan& timeout );
299
300 protected:
301 // empty constructor used by MutexLockRecursive
302 Mutex( bool ) {}
303 };
304
305 class MutexRecursive : public Mutex
306 {
307 public:
308 MutexRecursive();
309 virtual ~MutexRecursive() throw();
310 virtual bool IsRecursive() const { return true; }
311 };
312
313 // --------------------------------------------------------------------------------------
314 // ScopedLock
315 // --------------------------------------------------------------------------------------
316 // Helper class for using Mutexes. Using this class provides an exception-safe (and
317 // generally clean) method of locking code inside a function or conditional block. The lock
318 // will be automatically released on any return or exit from the function.
319 //
320 // Const qualification note:
321 // ScopedLock takes const instances of the mutex, even though the mutex is modified
322 // by locking and unlocking. Two rationales:
323 //
324 // 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
325 // this class needs a const hack to allow those accessors to be const (which is typically
326 // *very* important).
327 //
328 // 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
329 // scope exits, by any means. Only via manual calls to Release or Acquire does that
330 // change, and typically those are only used in very special circumstances of their own.
331 //
332 class ScopedLock
333 {
334 DeclareNoncopyableObject(ScopedLock);
335
336 protected:
337 Mutex* m_lock;
338 bool m_IsLocked;
339
340 public:
341 virtual ~ScopedLock() throw();
342 explicit ScopedLock( const Mutex* locker=NULL );
343 explicit ScopedLock( const Mutex& locker );
344 void AssignAndLock( const Mutex& locker );
345 void AssignAndLock( const Mutex* locker );
346
347 void Assign( const Mutex& locker );
348 void Assign( const Mutex* locker );
349
350 void Release();
351 void Acquire();
352
353 bool IsLocked() const { return m_IsLocked; }
354
355 protected:
356 // Special constructor used by ScopedTryLock
357 ScopedLock( const Mutex& locker, bool isTryLock );
358 };
359
360 class ScopedTryLock : public ScopedLock
361 {
362 public:
363 ScopedTryLock( const Mutex& locker ) : ScopedLock( locker, true ) { }
364 virtual ~ScopedTryLock() throw() {}
365 bool Failed() const { return !m_IsLocked; }
366 };
367
368 // --------------------------------------------------------------------------------------
369 // ScopedNonblockingLock
370 // --------------------------------------------------------------------------------------
371 // A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
372 //
373 class ScopedNonblockingLock
374 {
375 DeclareNoncopyableObject(ScopedNonblockingLock);
376
377 protected:
378 NonblockingMutex& m_lock;
379 bool m_IsLocked;
380
381 public:
382 ScopedNonblockingLock( NonblockingMutex& locker ) :
383 m_lock( locker )
384 , m_IsLocked( m_lock.TryAcquire() )
385 {
386 }
387
388 virtual ~ScopedNonblockingLock() throw()
389 {
390 if( m_IsLocked )
391 m_lock.Release();
392 }
393
394 bool Failed() const { return !m_IsLocked; }
395 };
396 }
397

  ViewVC Help
Powered by ViewVC 1.1.22