/[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 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years ago) by william
File size: 8829 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     #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     if( IsSelf() || !IsRunning() ) return;
85    
86     // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
87     // from Resume or OnResumeReady code.
88     if( m_ExecMode == ExecMode_Closed ) return;
89    
90     {
91     ScopedLock locker( m_ExecModeMutex );
92    
93     switch( m_ExecMode )
94     {
95     // Check again -- status could have changed since above.
96     case ExecMode_Closed: return;
97    
98     case ExecMode_Pausing:
99     case ExecMode_Paused:
100     if( !isBlocking )
101     throw Exception::CancelEvent( "Cannot suspend in non-blocking fashion: Another thread is pausing the VM state." );
102    
103     m_ExecMode = ExecMode_Closing;
104     m_sem_Resume.Post();
105     m_sem_ChangingExecMode.Wait();
106     break;
107    
108     case ExecMode_Opened:
109     m_ExecMode = ExecMode_Closing;
110     break;
111     }
112    
113     pxAssumeDev( m_ExecMode == ExecMode_Closing, "ExecMode should be nothing other than Closing..." );
114     m_sem_event.Post();
115     }
116    
117     if( isBlocking )
118     m_RunningLock.Wait();
119     }
120    
121     // Returns:
122     // The previous suspension state; true if the thread was running or false if it was
123     // closed, not running, or paused.
124     //
125     void SysThreadBase::Pause()
126     {
127     if( IsSelf() || !IsRunning() ) return;
128    
129     // shortcut ExecMode check to avoid deadlocking on redundant calls to Suspend issued
130     // from Resume or OnResumeReady code.
131     if( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused) ) return;
132    
133     {
134     ScopedLock locker( m_ExecModeMutex );
135    
136     // Check again -- status could have changed since above.
137     if( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused) ) return;
138    
139     if( m_ExecMode == ExecMode_Opened )
140     m_ExecMode = ExecMode_Pausing;
141    
142     pxAssumeDev( m_ExecMode == ExecMode_Pausing, "ExecMode should be nothing other than Pausing..." );
143    
144     m_sem_event.Post();
145     }
146    
147     m_RunningLock.Wait();
148     }
149    
150     // Resumes the core execution state, or does nothing is the core is already running. If
151     // settings were changed, resets will be performed as needed and emulation state resumed from
152     // memory savestates.
153     //
154     // Note that this is considered a non-blocking action. Most times the state is safely resumed
155     // on return, but in the case of re-entrant or nested message handling the function may return
156     // before the thread has resumed. If you need explicit behavior tied to the completion of the
157     // Resume, you'll need to bind callbacks to either OnResumeReady or OnResumeInThread.
158     //
159     // Exceptions:
160     // PluginInitError - thrown if a plugin fails init (init is performed on the current thread
161     // on the first time the thread is resumed from it's initial idle state)
162     // ThreadCreationError - Insufficient system resources to create thread.
163     //
164     void SysThreadBase::Resume()
165     {
166     if( IsSelf() ) return;
167     if( m_ExecMode == ExecMode_Opened ) return;
168    
169     ScopedLock locker( m_ExecModeMutex );
170    
171     // Implementation Note:
172     // The entire state coming out of a Wait is indeterminate because of user input
173     // and pending messages being handled. So after each call we do some seemingly redundant
174     // sanity checks against m_ExecMode/m_Running status, and if something doesn't feel
175     // right, we should abort; the user may have canceled the action before it even finished.
176    
177     switch( m_ExecMode )
178     {
179     case ExecMode_Opened: return;
180    
181     case ExecMode_NoThreadYet:
182     {
183     Start();
184     if( !m_running || (m_ExecMode == ExecMode_NoThreadYet) )
185     throw Exception::ThreadCreationError();
186     if( m_ExecMode == ExecMode_Opened ) return;
187     }
188     // fall through...
189    
190     case ExecMode_Closing:
191     case ExecMode_Pausing:
192     // we need to make sure and wait for the emuThread to enter a fully suspended
193     // state before continuing...
194    
195     m_RunningLock.Wait();
196     if( !m_running ) return;
197     if( (m_ExecMode != ExecMode_Closed) && (m_ExecMode != ExecMode_Paused) ) return;
198     if( !GetCorePlugins().AreLoaded() ) return;
199     break;
200     }
201    
202     pxAssertDev( (m_ExecMode == ExecMode_Closed) || (m_ExecMode == ExecMode_Paused),
203     "SysThreadBase is not in a closed/paused state? wtf!" );
204    
205     OnResumeReady();
206     m_ExecMode = ExecMode_Opened;
207     m_sem_Resume.Post();
208     }
209    
210    
211     // --------------------------------------------------------------------------------------
212     // SysThreadBase *Worker* Implementations
213     // (Called from the context of this thread only)
214     // --------------------------------------------------------------------------------------
215    
216     void SysThreadBase::OnStartInThread()
217     {
218     m_RunningLock.Acquire();
219     _parent::OnStartInThread();
220     m_ExecMode = ExecMode_Closing;
221     }
222    
223     void SysThreadBase::OnCleanupInThread()
224     {
225     m_ExecMode = ExecMode_NoThreadYet;
226     _parent::OnCleanupInThread();
227     m_RunningLock.Release();
228     }
229    
230     void SysThreadBase::OnSuspendInThread() {}
231     void SysThreadBase::OnResumeInThread( bool isSuspended ) {}
232    
233     void SysThreadBase::StateCheckInThread()
234     {
235     switch( m_ExecMode )
236     {
237    
238     #ifdef PCSX2_DEVBUILD // optimize out handlers for these cases in release builds.
239     case ExecMode_NoThreadYet:
240     // threads should never have this state set while the thread is in any way
241     // active or alive. (for obvious reasons!!)
242     pxFailDev( "Invalid execution state detected." );
243     break;
244     #endif
245    
246     case ExecMode_Opened:
247     // Yup, need this a second time. Variable state could have changed while we
248     // were trying to acquire the lock above.
249     TestCancel();
250     break;
251    
252     // -------------------------------------
253     case ExecMode_Pausing:
254     {
255     OnPauseInThread();
256     m_ExecMode = ExecMode_Paused;
257     m_RunningLock.Release();
258     }
259     // fallthrough...
260    
261     case ExecMode_Paused:
262     while( m_ExecMode == ExecMode_Paused )
263     m_sem_Resume.WaitWithoutYield();
264    
265     m_RunningLock.Acquire();
266     if( m_ExecMode != ExecMode_Closing )
267     {
268     OnResumeInThread( false );
269     break;
270     }
271     m_sem_ChangingExecMode.Post();
272    
273     // fallthrough if we're switching to closing state...
274    
275     // -------------------------------------
276     case ExecMode_Closing:
277     {
278     OnSuspendInThread();
279     m_ExecMode = ExecMode_Closed;
280     m_RunningLock.Release();
281     }
282     // fallthrough...
283    
284     case ExecMode_Closed:
285     while( m_ExecMode == ExecMode_Closed )
286     m_sem_Resume.WaitWithoutYield();
287    
288     m_RunningLock.Acquire();
289     OnResumeInThread( true );
290     break;
291    
292     jNO_DEFAULT;
293     }
294     }

  ViewVC Help
Powered by ViewVC 1.1.22