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

  ViewVC Help
Powered by ViewVC 1.1.22