/[pcsx2_0.9.7]/branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/pxEventThread.h
ViewVC logotype

Contents of /branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/pxEventThread.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 330 - (show annotations) (download)
Tue Dec 28 04:24:23 2010 UTC (9 years, 9 months ago) by william
File MIME type: text/plain
File size: 11083 byte(s)
merged upstream r4154-r4160
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 "Utilities/PersistentThread.h"
19 #include "Utilities/pxEvents.h"
20
21
22 // TODO!! Make the system defined in this header system a bit more generic, and then move
23 // it to the Utilities library.
24
25 class pxEvtQueue;
26 class SysExecEvent;
27
28 // --------------------------------------------------------------------------------------
29 // pxEvtLog / ConsoleLogSource_Event
30 // --------------------------------------------------------------------------------------
31
32 class ConsoleLogSource_Event : ConsoleLogSource
33 {
34 typedef ConsoleLogSource _parent;
35
36 public:
37 using _parent::IsActive;
38
39 ConsoleLogSource_Event();
40
41 bool Write( const pxEvtQueue* evtHandler, const SysExecEvent* evt, const wxChar* msg );
42 bool Warn( const pxEvtQueue* evtHandler, const SysExecEvent* evt, const wxChar* msg );
43 bool Error( const pxEvtQueue* evtHandler, const SysExecEvent* evt, const wxChar* msg );
44 };
45
46 extern ConsoleLogSource_Event pxConLog_Event;
47
48 #define pxEvtLog pxConLog_Event.IsActive() && pxConLog_Event
49
50
51 // --------------------------------------------------------------------------------------
52 // SysExecEvent
53 // --------------------------------------------------------------------------------------
54 // Base class for all pxEvtQueue processable events.
55 //
56 // Rules for deriving:
57 // * Override InvokeEvent(), *NOT* _DoInvokeEvent(). _DoInvokeEvent() performs setup and
58 // wraps exceptions for transport to the invoking context/thread, and then itself calls
59 // InvokeEvent() to perform the derived class implementation.
60 //
61 // * Derived classes must implement their own versions of an empty constructor and
62 // Clone(), or else the class will fail to be copied to the event handler's thread
63 // context correctly.
64 //
65 // * This class is not abstract, and gives no error if the invocation method is not
66 // overridden: It can be used as a simple ping device against the event queue, Re-
67 // awaking the invoking thread as soon as the queue has caught up to and processed
68 // the event.
69 //
70 // * Avoid using virtual class inheritence to 'cleverly' bind a SysExecEvent to another
71 // existing class. Multiple inheritence is unreliable at best, and virtual inheritence
72 // is even worse. Create a SysExecEvent wrapper class instead, and embed an instance of
73 // the other class you want to turn into an event within it. It might feel like more work
74 // but it *will* be less work in the long run.
75 //
76 class SysExecEvent : public ICloneable
77 {
78 protected:
79 SynchronousActionState* m_sync;
80
81 public:
82 virtual ~SysExecEvent() throw() {}
83 SysExecEvent* Clone() const { return new SysExecEvent( *this ); }
84
85 SysExecEvent( SynchronousActionState* sync=NULL )
86 {
87 m_sync = sync;
88 }
89
90 SysExecEvent( SynchronousActionState& sync )
91 {
92 m_sync = &sync;
93 }
94
95 const SynchronousActionState* GetSyncState() const { return m_sync; }
96 SynchronousActionState* GetSyncState() { return m_sync; }
97
98 SysExecEvent& SetSyncState( SynchronousActionState* obj ) { m_sync = obj; return *this; }
99 SysExecEvent& SetSyncState( SynchronousActionState& obj ) { m_sync = &obj; return *this; }
100
101 // Tells the Event Handler whether or not this event can be skipped when the system
102 // is being quit or reset. Typically set this to true for events which shut down the
103 // system, since program crashes can occur if the program tries to exit while threads
104 // are running.
105 virtual bool IsCriticalEvent() const { return false; }
106
107 // Tells the Event Handler whether or not this event can be canceled. Typically events
108 // should not prohibit cancellation, since it expedites program termination and helps
109 // avoid permanent deadlock. Some actions like saving states and shutdown procedures
110 // should not allow cancellation since they could result in program crashes or corrupted
111 // data.
112 virtual bool AllowCancelOnExit() const { return true; }
113
114 virtual void _DoInvokeEvent();
115 virtual void PostResult() const;
116
117 virtual wxString GetEventName() const;
118 virtual wxString GetEventMessage() const;
119
120 virtual int GetResult()
121 {
122 if( !pxAssertDev( m_sync != NULL, "SysEvent: Expecting return value, but no sync object provided." ) ) return 0;
123 return m_sync->return_value;
124 }
125
126 virtual void SetException( BaseException* ex );
127
128 void SetException( const BaseException& ex );
129
130 protected:
131 virtual void InvokeEvent();
132 virtual void CleanupEvent();
133 };
134
135 // --------------------------------------------------------------------------------------
136 // SysExecEvent_MethodVoid
137 // --------------------------------------------------------------------------------------
138 class SysExecEvent_MethodVoid : public SysExecEvent
139 {
140 protected:
141 FnType_Void* m_method;
142 bool m_IsCritical;
143 wxString m_TraceName;
144
145 public:
146 wxString GetEventName() const { return m_TraceName; }
147
148 virtual ~SysExecEvent_MethodVoid() throw() {}
149 SysExecEvent_MethodVoid* Clone() const { return new SysExecEvent_MethodVoid( *this ); }
150
151 bool AllowCancelOnExit() const { return !m_IsCritical; }
152 bool IsCriticalEvent() const { return m_IsCritical; }
153
154 explicit SysExecEvent_MethodVoid( FnType_Void* method = NULL, const wxChar* traceName=NULL )
155 : m_TraceName( traceName ? traceName : L"VoidMethod" )
156 {
157 m_method = method;
158 m_IsCritical = false;
159 }
160
161 SysExecEvent_MethodVoid& Critical()
162 {
163 m_IsCritical = true;
164 return *this;
165 }
166
167 protected:
168 void InvokeEvent()
169 {
170 if( m_method ) m_method();
171 }
172 };
173
174 #ifdef _MSC_VER
175 typedef std::list< SysExecEvent*, wxObjectAllocator<SysExecEvent*> > pxEvtList;
176 #else
177 typedef std::list<SysExecEvent*> pxEvtList;
178 #endif
179
180 // --------------------------------------------------------------------------------------
181 // pxEvtQueue
182 // --------------------------------------------------------------------------------------
183 // Thread-safe platform-independent message queue, intended to act as a proxy between
184 // control threads (such as the Main/UI thread) and worker threads.
185 //
186 // Proxy message queues provide a safe environment for queuing tasks that must be executed
187 // in sequential order (in blocking fashion) on one or more worker threads. The queue is
188 // deadlock-free, which means the Main/UI thread can queue events into this EventQueue without
189 // fear of causing unresponsiveness within the user interface.
190 //
191 // Rationales:
192 // * Using the main event handler of wxWidgets is dangerous because it must call itself
193 // recursively when waiting on threaded events such as semaphore and mutexes. Thus,
194 // tasks such as suspending the VM would invoke the event queue while waiting,
195 // running events that expect the suspend to be complete while the suspend was still
196 // pending.
197 //
198 // * wxWidgets Event Queue (wxEvtHandler) isn't thread-safe and isn't even intended for
199 // use for anything other than wxWindow events (it uses static vars and checks/modifies
200 // wxApp globals while processing), so it's useless to us. Have to roll our own. -_-
201 //
202 class pxEvtQueue
203 {
204 protected:
205 pxEvtList m_pendingEvents;
206 pxEvtList m_idleEvents;
207
208 Threading::MutexRecursive m_mtx_pending;
209 Threading::Semaphore m_wakeup;
210 wxThreadIdType m_OwnerThreadId;
211 volatile u32 m_Quitting;
212
213 // Used for performance measuring the execution of individual events,
214 // and also for detecting deadlocks during message processing.
215 volatile u64 m_qpc_Start;
216
217 public:
218 pxEvtQueue();
219 virtual ~pxEvtQueue() throw() {}
220
221 virtual wxString GetEventHandlerName() const { return L"pxEvtQueue"; }
222
223 virtual void ShutdownQueue();
224 bool IsShuttingDown() const { return !!m_Quitting; }
225
226 void ProcessEvents( pxEvtList& list, bool isIdle=false );
227 void ProcessPendingEvents();
228 void ProcessIdleEvents();
229 void Idle();
230
231 void AddPendingEvent( SysExecEvent& evt );
232 void PostEvent( SysExecEvent* evt );
233 void PostEvent( const SysExecEvent& evt );
234 void PostIdleEvent( SysExecEvent* evt );
235 void PostIdleEvent( const SysExecEvent& evt );
236
237 void ProcessEvent( SysExecEvent* evt );
238 void ProcessEvent( SysExecEvent& evt );
239
240 bool Rpc_TryInvokeAsync( FnType_Void* method, const wxChar* traceName=NULL );
241 bool Rpc_TryInvoke( FnType_Void* method, const wxChar* traceName=NULL );
242 void SetActiveThread();
243
244 protected:
245 virtual void _DoIdle() {}
246 };
247
248 // --------------------------------------------------------------------------------------
249 // ExecutorThread
250 // --------------------------------------------------------------------------------------
251 // Threaded wrapper class for implementing a pxEvtQueue on its own thread, to serve as a
252 // proxy between worker threads and response threads (which cannot be allowed to stall or
253 // deadlock). Simply create the desired EvtHandler, start the thread, and enjoy queued
254 // event execution in fully blocking fashion.
255 //
256 // Deadlock Protection Notes:
257 // The ExecutorThread utilizes an underlying pxEventQueue, which only locks the queue for
258 // adding and removing items only. Events are processed during an unlocked queue state,
259 // which allows other threads to add events with a guarantee that the add operation will
260 // take very little time.
261 //
262 // Implementation Notes:
263 // We use object encapsulation instead of multiple inheritance in order to avoid the many
264 // unavoidable catastrophes and pitfalls involved in multi-inheritance that would ruin our
265 // will to live. The alternative requires manually exposing the interface of the underlying
266 // instance of pxEventQueue; and that's ok really when you consider the alternative. --air
267 //
268 class ExecutorThread : public Threading::pxThread
269 {
270 typedef Threading::pxThread _parent;
271
272 protected:
273 ScopedPtr<wxTimer> m_ExecutorTimer;
274 ScopedPtr<pxEvtQueue> m_EvtHandler;
275
276 public:
277 ExecutorThread( pxEvtQueue* evtandler = NULL );
278 virtual ~ExecutorThread() throw() { }
279
280 virtual void ShutdownQueue();
281 bool IsRunning() const;
282
283 void PostEvent( SysExecEvent* evt );
284 void PostEvent( const SysExecEvent& evt );
285
286 void PostIdleEvent( SysExecEvent* evt );
287 void PostIdleEvent( const SysExecEvent& evt );
288
289 void ProcessEvent( SysExecEvent* evt );
290 void ProcessEvent( SysExecEvent& evt );
291
292 bool Rpc_TryInvokeAsync( void (*evt)(), const wxChar* traceName=NULL )
293 {
294 return m_EvtHandler ? m_EvtHandler->Rpc_TryInvokeAsync( evt, traceName ) : false;
295 }
296
297 bool Rpc_TryInvoke( void (*evt)(), const wxChar* traceName=NULL )
298 {
299 return m_EvtHandler ? m_EvtHandler->Rpc_TryInvoke( evt, traceName ) : false;
300 }
301
302 protected:
303 void OnStart();
304 void ExecuteTaskInThread();
305 void OnCleanupInThread();
306 };
307

  ViewVC Help
Powered by ViewVC 1.1.22