/[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 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 11 months 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 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 william 62 #include "TraceLog.h"
25 william 31
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 william 62 // 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 william 31 // 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 william 62 class pxThread;
81 william 31 class RwMutex;
82    
83     extern void pxTestCancel();
84 william 62 extern pxThread* pxGetCurrentThread();
85 william 31 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 william 62 // pxThread. Unmanaged threads use standard Sleep.
91 william 31 extern void pxYield( int ms );
92     }
93    
94     namespace Exception
95     {
96 william 62 class BaseThreadError : public RuntimeError
97 william 31 {
98 william 62 DEFINE_EXCEPTION_COPYTORS( BaseThreadError, RuntimeError )
99     DEFINE_EXCEPTION_MESSAGES( BaseThreadError )
100    
101 william 31 public:
102 william 62 Threading::pxThread* m_thread;
103 william 31
104 william 62 protected:
105     BaseThreadError() {
106     m_thread = NULL;
107     }
108 william 31
109 william 62 public:
110     explicit BaseThreadError( Threading::pxThread* _thread )
111 william 31 {
112     m_thread = _thread;
113 william 62 m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
114 william 31 }
115    
116 william 62 explicit BaseThreadError( Threading::pxThread& _thread )
117 william 31 {
118     m_thread = &_thread;
119 william 62 m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
120 william 31 }
121    
122     virtual wxString FormatDiagnosticMessage() const;
123     virtual wxString FormatDisplayMessage() const;
124    
125 william 62 Threading::pxThread& Thread();
126     const Threading::pxThread& Thread() const;
127 william 31 };
128    
129 william 62 class ThreadCreationError : public BaseThreadError
130 william 31 {
131 william 62 DEFINE_EXCEPTION_COPYTORS( ThreadCreationError, BaseThreadError )
132    
133 william 31 public:
134 william 62 explicit ThreadCreationError( Threading::pxThread* _thread )
135 william 31 {
136     m_thread = _thread;
137 william 62 SetBothMsgs( L"Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
138 william 31 }
139    
140 william 62 explicit ThreadCreationError( Threading::pxThread& _thread )
141 william 31 {
142     m_thread = &_thread;
143 william 62 SetBothMsgs( L"Thread creation failure. An unspecified error occurred while trying to create the %s thread." );
144 william 31 }
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 william 62
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 william 31
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