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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 10 months ago) by william
File MIME type: text/plain
File size: 11580 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 "Threading.h"
19     #include "ScopedPtrMT.h"
20     #include "EventSource.h"
21    
22     namespace Threading
23     {
24    
25     // --------------------------------------------------------------------------------------
26     // IThread - Interface for the public access to PersistentThread.
27     // --------------------------------------------------------------------------------------
28     // Class usage: Can be used for allowing safe nullification of a thread handle. Rather
29     // than being NULL'd, the handle can be mapped to an IThread implementation which acts
30     // as a do-nothing placebo or an assertion generator.
31     //
32     class IThread
33     {
34     DeclareNoncopyableObject(IThread);
35    
36     public:
37     IThread() {}
38     virtual ~IThread() throw() {}
39    
40     virtual bool IsSelf() const { return false; }
41     virtual bool IsRunning() { return false; }
42    
43     virtual void Start() {}
44     virtual void Cancel( bool isBlocking = true ) {}
45     virtual void Block() {}
46     virtual bool Detach() { return false; }
47     };
48    
49     // --------------------------------------------------------------------------------------
50     // ThreadDeleteEvent
51     // --------------------------------------------------------------------------------------
52     class EventListener_Thread : public IEventDispatcher<int>
53     {
54     public:
55     typedef int EvtParams;
56    
57     protected:
58     PersistentThread* m_thread;
59    
60     public:
61     EventListener_Thread()
62     {
63     m_thread = NULL;
64     }
65    
66     virtual ~EventListener_Thread() throw() {}
67    
68     void SetThread( PersistentThread& thr ) { m_thread = &thr; }
69     void SetThread( PersistentThread* thr ) { m_thread = thr; }
70    
71     void DispatchEvent( const int& params )
72     {
73     OnThreadCleanup();
74     }
75    
76     protected:
77     // Invoked by the PersistentThread when the thread execution is ending. This is
78     // typically more useful than a delete listener since the extended thread information
79     // provided by virtualized functions/methods will be available.
80     // Important! This event is executed *by the thread*, so care must be taken to ensure
81     // thread sync when necessary (posting messages to the main thread, etc).
82     virtual void OnThreadCleanup()=0;
83     };
84    
85     // --------------------------------------------------------------------------------------
86     // PersistentThread - Helper class for the basics of starting/managing persistent threads.
87     // --------------------------------------------------------------------------------------
88     // This class is meant to be a helper for the typical threading model of "start once and
89     // reuse many times." This class incorporates a lot of extra overhead in stopping and
90     // starting threads, but in turn provides most of the basic thread-safety and event-handling
91     // functionality needed for a threaded operation. In practice this model is usually an
92     // ideal one for efficiency since Operating Systems themselves typically subscribe to a
93     // design where sleeping, suspending, and resuming threads is very efficient, but starting
94     // new threads has quite a bit of overhead.
95     //
96     // To use this as a base class for your threaded procedure, overload the following virtual
97     // methods:
98     // void OnStart();
99     // void ExecuteTaskInThread();
100     // void OnCleanupInThread();
101     //
102     // Use the public methods Start() and Cancel() to start and shutdown the thread, and use
103     // m_sem_event internally to post/receive events for the thread (make a public accessor for
104     // it in your derived class if your thread utilizes the post).
105     //
106     // Notes:
107     // * Constructing threads as static global vars isn't recommended since it can potentially
108     // confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
109     // no dependency options for ensuring correct static var initializations). Use heap
110     // allocation to create thread objects instead.
111     //
112     class PersistentThread : public virtual IThread
113     {
114     DeclareNoncopyableObject(PersistentThread);
115    
116     friend void pxYield( int ms );
117    
118     protected:
119     wxString m_name; // diagnostic name for our thread.
120     pthread_t m_thread;
121     uptr m_native_id; // typically an id, but implementing platforms can do whatever.
122     uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
123    
124     Semaphore m_sem_event; // general wait event that's needed by most threads
125     Semaphore m_sem_startup; // startup sync tool
126     Mutex m_lock_InThread; // used for canceling and closing threads in a deadlock-safe manner
127     MutexRecursive m_lock_start; // used to lock the Start() code from starting simultaneous threads accidentally.
128    
129     volatile long m_detached; // a boolean value which indicates if the m_thread handle is valid
130     volatile long m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
131    
132     // exception handle, set non-NULL if the thread terminated with an exception
133     // Use RethrowException() to re-throw the exception using its original exception type.
134     ScopedPtrMT<BaseException> m_except;
135    
136     EventSource<EventListener_Thread> m_evtsrc_OnDelete;
137    
138    
139     public:
140     virtual ~PersistentThread() throw();
141     PersistentThread();
142     PersistentThread( const char* name );
143    
144     pthread_t GetId() const { return m_thread; }
145     u64 GetCpuTime() const;
146    
147     virtual void Start();
148     virtual void Cancel( bool isBlocking = true );
149     virtual bool Cancel( const wxTimeSpan& timeout );
150     virtual bool Detach();
151     virtual void Block();
152     virtual bool Block( const wxTimeSpan& timeout );
153     virtual void RethrowException() const;
154    
155     void AddListener( EventListener_Thread& evt );
156     void AddListener( EventListener_Thread* evt )
157     {
158     if( evt == NULL ) return;
159     AddListener( *evt );
160     }
161    
162     void WaitOnSelf( Semaphore& mutex ) const;
163     void WaitOnSelf( Mutex& mutex ) const;
164     bool WaitOnSelf( Semaphore& mutex, const wxTimeSpan& timeout ) const;
165     bool WaitOnSelf( Mutex& mutex, const wxTimeSpan& timeout ) const;
166    
167     bool IsRunning() const;
168     bool IsSelf() const;
169     wxString GetName() const;
170     bool HasPendingException() const { return !!m_except; }
171    
172     protected:
173     // Extending classes should always implement your own OnStart(), which is called by
174     // Start() once necessary locks have been obtained. Do not override Start() directly
175     // unless you're really sure that's what you need to do. ;)
176     virtual void OnStart();
177    
178     virtual void OnStartInThread();
179    
180     // This is called when the thread has been canceled or exits normally. The PersistentThread
181     // automatically binds it to the pthread cleanup routines as soon as the thread starts.
182     virtual void OnCleanupInThread();
183    
184     // Implemented by derived class to perform actual threaded task!
185     virtual void ExecuteTaskInThread()=0;
186    
187     void TestCancel() const;
188    
189     // Yields this thread to other threads and checks for cancellation. A sleeping thread should
190     // always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
191     // or better yet, disable cancellation of the thread completely with DisableCancellation().
192     //
193     // Parameters:
194     // ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
195     // depending on operating system/platform). If ms is 0 or unspecified, then a single
196     // timeslice is yielded to other contending threads. If no threads are contending for
197     // time when ms==0, then no yield is done, but cancellation is still tested.
198     void Yield( int ms = 0 )
199     {
200     pxAssert( IsSelf() );
201     Threading::Sleep( ms );
202     TestCancel();
203     }
204    
205     void FrankenMutex( Mutex& mutex );
206    
207     bool AffinityAssert_AllowFromSelf( const DiagnosticOrigin& origin ) const;
208     bool AffinityAssert_DisallowFromSelf( const DiagnosticOrigin& origin ) const;
209    
210     // ----------------------------------------------------------------------------
211     // Section of methods for internal use only.
212    
213     void _platform_specific_OnStartInThread();
214     void _platform_specific_OnCleanupInThread();
215     bool _basecancel();
216     void _selfRunningTest( const wxChar* name ) const;
217     void _DoSetThreadName( const wxString& name );
218     void _DoSetThreadName( const char* name );
219     void _internal_execute();
220     void _try_virtual_invoke( void (PersistentThread::*method)() );
221     void _ThreadCleanup();
222    
223     static void* _internal_callback( void* func );
224     static void _pt_callback_cleanup( void* handle );
225     };
226    
227    
228     // --------------------------------------------------------------------------------------
229     // BaseTaskThread
230     // --------------------------------------------------------------------------------------
231     // an abstract base class which provides simple parallel execution of single tasks.
232     //
233     // FIXME: This class is incomplete and untested! Don't use, unless you want to fix it
234     // while you're at it. :D
235     //
236     // Implementation:
237     // To use this class your derived class will need to implement its own Task() function
238     // and also a "StartTask( parameters )" function which suits the need of your task, along
239     // with any local variables your task needs to do its job. You may additionally want to
240     // implement a "GetResult()" function, which would be a combination of WaitForResult()
241     // and a return value of the computational result.
242     //
243     // Thread Safety:
244     // If operating on local variables, you must execute WaitForResult() before leaving the
245     // variable scope -- or alternatively have your StartTask() implementation make full
246     // copies of dependent data. Also, by default PostTask() always assumes the previous
247     // task has completed. If your system can post a new task before the previous one has
248     // completed, then it needs to explicitly call WaitForResult() or provide a mechanism
249     // to cancel the previous task (which is probably more work than it's worth).
250     //
251     // Performance notes:
252     // * Remember that thread creation is generally slow, so you should make your object
253     // instance once early and then feed it tasks repeatedly over the course of program
254     // execution.
255     //
256     // * For threading to be a successful speedup, the task being performed should be as lock
257     // free as possible. For example using STL containers in parallel usually fails to
258     // yield any speedup due to the gratuitous amount of locking that the STL performs
259     // internally.
260     //
261     // * The best application of tasking threads is to divide a large loop over a linear array
262     // into smaller sections. For example, if you have 20,000 items to process, the task
263     // can be divided into two threads of 10,000 items each.
264     //
265     class BaseTaskThread : public PersistentThread
266     {
267     protected:
268     volatile bool m_Done;
269     volatile bool m_TaskPending;
270     Semaphore m_post_TaskComplete;
271     Mutex m_lock_TaskComplete;
272    
273     public:
274     virtual ~BaseTaskThread() throw() {}
275     BaseTaskThread() :
276     m_Done( false )
277     , m_TaskPending( false )
278     , m_post_TaskComplete()
279     {
280     }
281    
282     void Block();
283     void PostTask();
284     void WaitForResult();
285    
286     protected:
287     // Abstract method run when a task has been posted. Implementing classes should do
288     // all your necessary processing work here.
289     virtual void Task()=0;
290    
291     virtual void ExecuteTaskInThread();
292     };
293     }

  ViewVC Help
Powered by ViewVC 1.1.22