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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide 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 william 31 /* 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