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

Contents of /trunk/common/include/Utilities/PersistentThread.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: 11580 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 "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