/[pcsx2_0.9.7]/trunk/pcsx2/System/SysThreadBase.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/System/SysThreadBase.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (10 years, 1 month ago) by william
File size: 9492 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     #include "PrecompiledHeader.h"
17    
18     #include "System.h"
19     #include "SysThreads.h"
20    
21     // --------------------------------------------------------------------------------------
22     // SysThreadBase *External Thread* Implementations
23     // (Called form outside the context of this thread)
24     // --------------------------------------------------------------------------------------
25    
26     SysThreadBase::SysThreadBase() :
27     m_ExecMode( ExecMode_NoThreadYet )
28     , m_ExecModeMutex()
29     {
30     }
31    
32     SysThreadBase::~SysThreadBase() throw()
33     {
34     }
35    
36     void SysThreadBase::Start()
37     {
38     _parent::Start();
39    
40     Sleep( 1 );
41    
42     pxAssertDev( (m_ExecMode == ExecMode_Closing) || (m_ExecMode == ExecMode_Closed),
43     "Unexpected thread status during SysThread startup."
44     );
45    
46     m_sem_event.Post();
47     }
48    
49    
50     void SysThreadBase::OnStart()
51     {
52     if( !pxAssertDev( m_ExecMode == ExecMode_NoThreadYet, "SysSustainableThread:Start(): Invalid execution mode" ) ) return;
53    
54     m_sem_Resume.Reset();
55     m_sem_ChangingExecMode.Reset();
56    
57     FrankenMutex( m_ExecModeMutex );
58     FrankenMutex( m_RunningLock );
59    
60     _parent::OnStart();
61     }
62    
63     // Suspends emulation and closes the emulation state (including plugins) at the next PS2 vsync,
64     // and returns control to the calling thread; or does nothing if the core is already suspended.
65     //
66     // Parameters:
67     // isNonblocking - if set to true then the function will not block for emulation suspension.
68     // Defaults to false if parameter is not specified. Performing non-blocking suspension
69     // is mostly useful for starting certain non-Emu related gui activities (improves gui
70     // responsiveness).
71     //
72     // Returns:
73     // The previous suspension state; true if the thread was running or false if it was
74     // suspended.
75     //
76     // Exceptions:
77     // CancelEvent - thrown if the thread is already in a Paused or Closing state. Because
78     // actions that pause emulation typically rely on plugins remaining loaded/active,
79     // Suspension must cancel itself forcefully or risk crashing whatever other action is
80     // in progress.
81     //
82     void SysThreadBase::Suspend( bool isBlocking )
83     {
84 william 62 if (!pxAssertDev(!IsSelf(),"Suspend/Resume are not allowed from this thread.")) return;
85     if (!IsRunning()) return;
86 william 31
87     // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
88     // from Resume or OnResumeReady code.
89     if( m_ExecMode == ExecMode_Closed ) return;
90    
91     {
92     ScopedLock locker( m_ExecModeMutex );
93    
94     switch( m_ExecMode )
95     {
96     // Check again -- status could have changed since above.
97     case ExecMode_Closed: return;
98    
99     case ExecMode_Pausing:
100     case ExecMode_Paused:
101     if( !isBlocking )
102 william 62 throw Exception::CancelEvent( L"Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
103 william 31
104     m_ExecMode = ExecMode_Closing;
105     m_sem_Resume.Post();
106     m_sem_ChangingExecMode.Wait();
107     break;
108    
109     case ExecMode_Opened:
110     m_ExecMode = ExecMode_Closing;
111     break;
112     }
113    
114     pxAssumeDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
115     m_sem_event.Post();
116     }
117    
118     if( isBlocking )
119     m_RunningLock.Wait();
120     }
121    
122     // Returns:
123     // The previous suspension state; true if the thread was running or false if it was
124     // closed, not running, or paused.
125     //
126     void SysThreadBase::Pause()
127     {
128     if( IsSelf() || !IsRunning() ) return;
129    
130     // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
131     // from Resume or OnResumeReady code.
132     if( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused) ) return;
133    
134     {
135     ScopedLock locker( m_ExecModeMutex );
136    
137     // Check again -- status could have changed since above.
138     if( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused) ) return;
139    
140     if( m_ExecMode == ExecMode_Opened )
141     m_ExecMode = ExecMode_Pausing;
142    
143     pxAssumeDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
144    
145     m_sem_event.Post();
146     }
147    
148     m_RunningLock.Wait();
149     }
150    
151     // Resumes the core execution state, or does nothing is the core is already running. If
152     // settings were changed, resets will be performed as needed and emulation state resumed from
153     // memory savestates.
154     //
155     // Note that this is considered a non-blocking action. Most times the state is safely resumed
156     // on return, but in the case of re-entrant or nested message handling the function may return
157     // before the thread has resumed. If you need explicit behavior tied to the completion of the
158     // Resume, you'll need to bind callbacks to either OnResumeReady or OnResumeInThread.
159     //
160     // Exceptions:
161     // PluginInitError - thrown if a plugin fails init (init is performed on the current thread
162     // on the first time the thread is resumed from it's initial idle state)
163     // ThreadCreationError - Insufficient system resources to create thread.
164     //
165     void SysThreadBase::Resume()
166     {
167     if( IsSelf() ) return;
168     if( m_ExecMode == ExecMode_Opened ) return;
169    
170     ScopedLock locker( m_ExecModeMutex );
171    
172     // Implementation Note:
173     // The entire state coming out of a Wait is indeterminate because of user input
174     // and pending messages being handled. So after each call we do some seemingly redundant
175     // sanity checks against m_ExecMode/m_Running status, and if something doesn't feel
176     // right, we should abort; the user may have canceled the action before it even finished.
177    
178     switch( m_ExecMode )
179     {
180     case ExecMode_Opened: return;
181    
182     case ExecMode_NoThreadYet:
183     {
184     Start();
185     if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
186 william 62 throw Exception::ThreadCreationError(this);
187 william 31 if( m_ExecMode == ExecMode_Opened ) return;
188     }
189     // fall through...
190    
191     case ExecMode_Closing:
192     case ExecMode_Pausing:
193     // we need to make sure and wait for the emuThread to enter a fully suspended
194     // state before continuing...
195    
196     m_RunningLock.Wait();
197     if( !m_running ) return;
198     if( (m_ExecMode != ExecMode_Closed) && (m_ExecMode != ExecMode_Paused) ) return;
199     if( !GetCorePlugins().AreLoaded() ) return;
200     break;
201     }
202    
203     pxAssertDev( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused),
204     "SysThreadBase is not in a closed/paused state? wtf!" );
205    
206     OnResumeReady();
207     m_ExecMode = ExecMode_Opened;
208     m_sem_Resume.Post();
209     }
210    
211    
212     // --------------------------------------------------------------------------------------
213     // SysThreadBase *Worker* Implementations
214     // (Called from the context of this thread only)
215     // --------------------------------------------------------------------------------------
216    
217     void SysThreadBase::OnStartInThread()
218     {
219     m_RunningLock.Acquire();
220     _parent::OnStartInThread();
221     m_ExecMode = ExecMode_Closing;
222     }
223    
224     void SysThreadBase::OnCleanupInThread()
225     {
226     m_ExecMode = ExecMode_NoThreadYet;
227     _parent::OnCleanupInThread();
228     m_RunningLock.Release();
229     }
230    
231     void SysThreadBase::OnSuspendInThread() {}
232     void SysThreadBase::OnResumeInThread( bool isSuspended ) {}
233    
234 william 62 // Tests for Pause and Suspend/Close requests. If the thread is trying to be paused or
235     // closed, it will enter a wait/holding pattern here in this method until the managing
236     // thread releases it. Use the return value to detect if changes to the thread's state
237     // may have been changed (based on the rule that other threads are not allowed to modify
238     // this thread's state without pausing or closing it first, to prevent race conditions).
239     //
240     // Return value:
241     // TRUE if the thread was paused or closed; FALSE if the thread
242     // continued execution unimpeded.
243     bool SysThreadBase::StateCheckInThread()
244 william 31 {
245     switch( m_ExecMode )
246     {
247    
248     #ifdef PCSX2_DEVBUILD // optimize out handlers for these cases in release builds.
249     case ExecMode_NoThreadYet:
250     // threads should never have this state set while the thread is in any way
251     // active or alive. (for obvious reasons!!)
252     pxFailDev( "Invalid execution state detected." );
253 william 62 return false;
254 william 31 #endif
255    
256     case ExecMode_Opened:
257 william 62 // Other cases don't need TestCancel() because its built into the various
258     // threading wait/signal actions.
259 william 31 TestCancel();
260 william 62 return false;
261 william 31
262     // -------------------------------------
263     case ExecMode_Pausing:
264     {
265     OnPauseInThread();
266     m_ExecMode = ExecMode_Paused;
267     m_RunningLock.Release();
268     }
269     // fallthrough...
270    
271     case ExecMode_Paused:
272     while( m_ExecMode == ExecMode_Paused )
273     m_sem_Resume.WaitWithoutYield();
274    
275     m_RunningLock.Acquire();
276     if( m_ExecMode != ExecMode_Closing )
277     {
278     OnResumeInThread( false );
279     break;
280     }
281     m_sem_ChangingExecMode.Post();
282    
283     // fallthrough if we're switching to closing state...
284    
285     // -------------------------------------
286     case ExecMode_Closing:
287     {
288     OnSuspendInThread();
289     m_ExecMode = ExecMode_Closed;
290     m_RunningLock.Release();
291     }
292     // fallthrough...
293    
294     case ExecMode_Closed:
295     while( m_ExecMode == ExecMode_Closed )
296     m_sem_Resume.WaitWithoutYield();
297    
298     m_RunningLock.Acquire();
299     OnResumeInThread( true );
300     break;
301    
302     jNO_DEFAULT;
303     }
304 william 62
305     return true;
306 william 31 }

  ViewVC Help
Powered by ViewVC 1.1.22