* Implemented Skip Bios (settings still not saved tho)

* Fixed a bug in how I was (not) handling pthreads return codes.  It's errno you need to check, *not* the function's return value. ;)
 * Changed MTGS over to use the pthread_cleanup api.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1779 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-09-08 03:44:35 +00:00
parent 50446e6930
commit 976d5ec539
17 changed files with 189 additions and 187 deletions

View File

@ -62,9 +62,9 @@ namespace Threading
if( !_InterlockedExchange( &m_detached, true ) )
{
#if wxUSE_GUI
m_sem_finished.WaitGui( wxTimeSpan( 0, 0, 3 ) );
m_sem_finished.WaitGui();
#else
m_sem_finished.Wait( wxTimeSpan( 0, 0, 3 ) );
m_sem_finished.Wait();
#endif
m_running = false;
}
@ -74,6 +74,7 @@ namespace Threading
void PersistentThread::Start()
{
if( m_running ) return;
m_sem_finished.Reset();
if( pthread_create( &m_thread, NULL, _internal_callback, this ) != 0 )
throw Exception::ThreadCreationError();
@ -107,7 +108,6 @@ namespace Threading
if( _InterlockedExchange( &m_detached, true ) )
{
if( m_running )
Console::Notice( "Threading Warning: Attempted to cancel detached thread; Ignoring..." );
return;
}
@ -118,9 +118,9 @@ namespace Threading
if( isBlocking )
{
#if wxUSE_GUI
m_sem_finished.WaitGui( wxTimeSpan( 0, 0, 3 ) );
m_sem_finished.WaitGui();
#else
m_sem_finished.Wait( wxTimeSpan( 0, 0, 3 ) );
m_sem_finished.Wait();
#endif
}
else
@ -152,9 +152,9 @@ namespace Threading
DevAssert( !IsSelf(), "Thread deadlock detected; Block() should never be called by the owner thread." );
#if wxUSE_GUI
m_sem_finished.WaitGui( wxTimeSpan( 0, 0, 3 ) );
m_sem_finished.WaitGui();
#else
m_sem_finished.Wait( wxTimeSpan( 0, 0, 3 ) );
m_sem_finished.Wait();
#endif
return m_returncode;
}
@ -189,6 +189,7 @@ namespace Threading
{
wxASSERT( IsSelf() ); // only allowed from our own thread, thanks.
_InterlockedExchange( &m_running, false );
m_sem_finished.Post();
}
void* PersistentThread::_internal_callback( void* itsme )
@ -280,7 +281,7 @@ namespace Threading
do {
wxTheApp->ProcessPendingEvents();
} while( sem_timedwait( &sema, &ts_msec_200 ) == ETIMEDOUT );
} while( (sem_timedwait( &sema, &ts_msec_200 ) == -1) && (errno == ETIMEDOUT) );
}
}
@ -300,7 +301,7 @@ namespace Threading
static const wxTimeSpan pass( 0, 0, 0, 200 );
do {
wxTheApp->ProcessPendingEvents();
if( sem_timedwait( &sema, &ts_msec_200 ) != ETIMEDOUT )
if( (sem_timedwait( &sema, &ts_msec_200 ) == -1) && (errno == ETIMEDOUT) )
break;
countdown -= pass;
} while( countdown.GetMilliseconds() > 0 );
@ -318,7 +319,7 @@ namespace Threading
bool Semaphore::Wait( const wxTimeSpan& timeout )
{
const timespec fail = { timeout.GetSeconds().GetLo(), 0 };
return sem_timedwait( &sema, &fail ) != ETIMEDOUT;
return sem_timedwait( &sema, &fail ) != -1;
}
// Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state

View File

@ -128,9 +128,9 @@ static void FindLayer1Start()
{
// search for it
int off = iso->blockofs;
u8 tempbuffer[2352];
u8 tempbuffer[CD_FRAMESIZE_RAW];
Console::Status("CDVD ISO: searching for layer1...");
Console::Status("CDVDiso: searching for layer1...");
//tempbuffer = (u8*)malloc(CD_FRAMESIZE_RAW);
for (layer1start = (iso->blocks / 2 - 0x10) & ~0xf; layer1start < 0x200010; layer1start += 16)
{
@ -148,11 +148,12 @@ static void FindLayer1Start()
if(layer1start == 0x200010)
{
Console::Status("Couldn't find second layer on dual layer... ignoring\n");
Console::Status("\tCouldn't find second layer on dual layer... ignoring");
layer1start=-2;
}
if(layer1start>=0) Console::Status("found at 0x%8.8x\n", params layer1start);
if(layer1start>=0)
Console::Status("\tfound at 0x%8.8x", params layer1start);
}
}

View File

@ -450,7 +450,7 @@ __forceinline void rcntUpdate_vSync()
{
eeRecIsReset = false;
cpuSetBranch();
throw Exception::RecompilerReset();
throw Exception::ForceDispatcherReg();
}
VSyncEnd(vsyncCounter.sCycle);

View File

@ -180,10 +180,6 @@ protected:
// used to regulate thread startup and gsInit
Threading::Semaphore m_sem_InitDone;
// used for quitting the ringbuffer thread only -- is posted by the ringbuffer when
// a QUIT message is processed (signals that the GS has been closed).
Threading::Semaphore m_sem_Quitter;
Threading::MutexLock m_lock_RingRestart;
// used to keep multiple threads from sending packets to the ringbuffer concurrently.
@ -251,17 +247,7 @@ public:
void PostVsyncEnd( bool updategs );
uptr FnPtr_SimplePacket() const
{
#ifndef __LINUX__
__asm mov eax, SendSimplePacket
#else
__asm__ (".intel_syntax noprefix\n"
"mov eax, SendSimplePacket\n"
".att_syntax\n");
#endif
//return (uptr)&SendSimplePacket;
}
void _close_gs();
protected:
// Saves MMX/XMM regs, posts an event to the mtgsThread flag and releases a timeslice.
@ -279,7 +265,7 @@ protected:
// Used internally by SendSimplePacket type functions
uint _PrepForSimplePacket();
void _FinishSimplePacket( uint future_writepos );
void _RingbufferLoop();
sptr ExecuteTask();
};

View File

@ -222,13 +222,13 @@ mtgsThreadObject::~mtgsThreadObject()
mtgsThreadObject::Cancel();
}
// Closes the GS "forcefully" without waiting for it to finish rendering it's pending
// queue of GS data.
void mtgsThreadObject::Cancel()
{
SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
SetEvent();
m_sem_Quitter.Wait( wxTimeSpan( 0, 0, 5, 0 ) );
Sleep( 2 );
PersistentThread::Cancel( true );
//SendSimplePacket( GS_RINGTYPE_QUIT, 0, 0, 0 );
//SetEvent();
PersistentThread::Cancel();
}
void mtgsThreadObject::Reset()
@ -498,24 +498,22 @@ struct PacketTagType
u32 data[3];
};
sptr mtgsThreadObject::ExecuteTask()
extern bool renderswitch;
void mtgsThreadObject::_close_gs()
{
memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(PS2MEM_GS) );
GSsetBaseMem( m_gsMem );
GSirqCallback( NULL );
if( g_plugins != NULL )
g_plugins->m_info[PluginId_GS].CommonBindings.Close();
}
GetPluginManager().Open( PluginId_GS );
DbgCon::WriteLn( "MTGS: GSopen Finished, return code: 0x%x", params m_returncode );
GSCSRr = 0x551B4000; // 0x55190000
m_sem_InitDone.Post();
if (m_returncode != 0) { return m_returncode; } // error msg will be issued to the user by Plugins.c
#ifdef RINGBUF_DEBUG_STACK
PacketTagType prevCmd;
#endif
static void _clean_close_gs( void* obj )
{
((mtgsThreadObject*)obj)->_close_gs();
}
void mtgsThreadObject::_RingbufferLoop()
{
pthread_cleanup_push( _clean_close_gs, this );
while( true )
{
m_sem_event.Wait();
@ -526,7 +524,7 @@ sptr mtgsThreadObject::ExecuteTask()
// ever be modified by this thread.
while( m_RingPos != volatize(m_WritePos))
{
assert( m_RingPos < m_RingBufferSize );
wxASSERT( m_RingPos < m_RingBufferSize );
const PacketTagType& tag = (PacketTagType&)m_RingBuffer[m_RingPos];
u32 ringposinc = 1;
@ -540,7 +538,7 @@ sptr mtgsThreadObject::ExecuteTask()
{
Console::Error( "MTGS Ringbuffer Critical Failure ---> %x to %x (prevCmd: %x)\n", params stackpos, m_RingPos, prevCmd.command );
}
assert( stackpos == m_RingPos );
wxASSERT( stackpos == m_RingPos );
prevCmd = tag;
ringposStack.pop_back();
m_lock_Stack.Unlock();
@ -664,14 +662,14 @@ sptr mtgsThreadObject::ExecuteTask()
break;
case GS_RINGTYPE_QUIT:
GetPluginManager().Close( PluginId_GS );
m_sem_Quitter.Post();
return 0;
// have to use some low level code, because all the standard Close api does is
// trigger this very ringbuffer message!
return;
#ifdef PCSX2_DEVBUILD
default:
Console::Error("GSThreadProc, bad packet (%x) at m_RingPos: %x, m_WritePos: %x", params tag.command, m_RingPos, m_WritePos);
assert(0);
wxASSERT_MSG( false, L"Bad packet encountered in the MTGS Ringbuffer." );
m_RingPos = m_WritePos;
continue;
#else
@ -681,12 +679,35 @@ sptr mtgsThreadObject::ExecuteTask()
}
uint newringpos = m_RingPos + ringposinc;
assert( newringpos <= m_RingBufferSize );
wxASSERT( newringpos <= m_RingBufferSize );
newringpos &= m_RingBufferMask;
AtomicExchange( m_RingPos, newringpos );
}
AtomicExchange( m_RingBufferIsBusy, 0 );
}
pthread_cleanup_pop( true );
}
sptr mtgsThreadObject::ExecuteTask()
{
memcpy_aligned( m_gsMem, PS2MEM_GS, sizeof(PS2MEM_GS) );
GSsetBaseMem( m_gsMem );
GSirqCallback( NULL );
Console::WriteLn( (wxString)L"\t\tForced software switch: " + (renderswitch ? L"Enabled" : L"Disabled") );
m_returncode = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
DevCon::WriteLn( "MTGS: GSopen Finished, return code: 0x%x", params m_returncode );
GSCSRr = 0x551B4000; // 0x55190000
m_sem_InitDone.Post();
if (m_returncode != 0) { return m_returncode; } // error msg will be issued to the user by Plugins.c
#ifdef RINGBUF_DEBUG_STACK
PacketTagType prevCmd;
#endif
_RingbufferLoop();
return 0;
}
// Waits for the GS to empty out the entire ring buffer contents.

View File

@ -717,20 +717,12 @@ static bool OpenPlugin_CDVD()
static bool OpenPlugin_GS()
{
if( mtgsThread == NULL )
{
if( mtgsThread != NULL ) return true;
mtgsOpen(); // mtgsOpen raises its own exception on error
return true;
}
if( !mtgsThread->IsSelf() ) return true; // already opened?
return !GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
// Note: renderswitch is us abusing the isMultiThread parameter for that so
// we don't need a new callback
}
static bool OpenPlugin_PAD()
{
return !PADopen( (void*)&pDsp );
@ -815,29 +807,22 @@ void PluginManager::Open()
void PluginManager::Close( PluginsEnum_t pid )
{
if( !m_info[pid].IsOpened ) return;
DevCon::Status( "\tClosing %s", params tbl_PluginInfo[pid].shortname );
if( pid == PluginId_GS )
{
if( mtgsThread == NULL ) return;
if( !mtgsThread->IsSelf() )
{
// force-close PAD before GS, because the PAD depends on the GS window.
Close( PluginId_PAD );
safe_delete( mtgsThread );
return;
}
}
else if( pid == PluginId_CDVD )
{
DoCDVDclose();
return;
}
else
m_info[pid].CommonBindings.Close();
m_info[pid].IsOpened = false;
m_info[pid].CommonBindings.Close();
}
void PluginManager::Close( bool closegs )

View File

@ -137,6 +137,7 @@ struct LegacyPluginAPI_Common
};
class SaveState;
class mtgsThreadObject;
//////////////////////////////////////////////////////////////////////////////////////////
// IPluginManager
@ -228,6 +229,8 @@ protected:
void BindCommon( PluginsEnum_t pid );
void BindRequired( PluginsEnum_t pid );
void BindOptional( PluginsEnum_t pid );
friend class mtgsThreadObject;
};
extern const PluginInfo tbl_PluginInfo[];

View File

@ -560,6 +560,7 @@ void cpuExecuteBios()
Console::Status( "Executing Bios Stub..." );
PCSX2_MEM_PROTECT_BEGIN();
g_ExecBiosHack = true;
while( cpuRegs.pc != 0x00200008 &&
cpuRegs.pc != 0x00100008 )
@ -567,6 +568,7 @@ void cpuExecuteBios()
Cpu->Execute();
}
g_ExecBiosHack = false;
PCSX2_MEM_PROTECT_END();
// {
// FILE* f = fopen("eebios.bin", "wb");

View File

@ -36,10 +36,16 @@ namespace Exception
// Implementation Note: this exception has no meaningful type information and we don't
// care to have it be caught by any BaseException handlers lying about, so let's not
// derive from BaseException :D
class RecompilerReset
class ForceDispatcherReg
{
public:
explicit RecompilerReset() { }
explicit ForceDispatcherReg() { }
};
class ExitRecExecute
{
public:
explicit ExitRecExecute() { }
};
}
#ifndef __LINUX__

View File

@ -362,9 +362,9 @@ void SysLoadState( const wxString& file )
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
}
void SysReset()
void SysShutdown()
{
Console::Status( _("Resetting...") );
Console::Status( "Resetting..." );
safe_delete( g_EmuThread );
GetPluginManager().Shutdown();

View File

@ -33,7 +33,7 @@ class CoreEmuThread;
extern bool SysInit();
extern void SysDetect(); // Detects cpu type and fills cpuInfo structs.
extern void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers.
extern void SysShutdown(); // Resets the various PS2 cpus, sub-systems, and recompilers.
extern void SysExecute( CoreEmuThread* newThread );
extern void SysExecute( CoreEmuThread* newThread, CDVD_SourceType cdvdsrc );

View File

@ -319,7 +319,7 @@ protected:
wxKeyEvent m_kevt;
public:
AppEmuThread( const wxString& elf_file=wxEmptyString );
AppEmuThread();
virtual ~AppEmuThread() { }
virtual void Resume();

View File

@ -111,6 +111,8 @@ void MainEmuFrame::Menu_BootCdvd_Click( wxCommandEvent &event )
SysEndExecution();
InitPlugins();
EmuConfig.SkipBiosSplash = GetMenuBar()->IsChecked( MenuId_SkipBiosToggle );
CDVDsys_SetFile( CDVDsrc_Iso, g_Conf->CurrentIso );
SysExecute( new AppEmuThread(), g_Conf->CdvdSource );
}
@ -134,33 +136,8 @@ void MainEmuFrame::Menu_RunIso_Click( wxCommandEvent &event )
SysEndExecution();
wxString elf_file;
if( EmuConfig.SkipBiosSplash )
{
// Fetch the ELF filename and CD type from the CDVD provider.
wxString ename( g_Conf->CurrentIso );
int result = GetPS2ElfName( ename );
switch( result )
{
case 0:
Msgbox::Alert( _("Boot failed: CDVD image is not a PS1 or PS2 game.") );
return;
case 1:
Msgbox::Alert( _("Boot failed: PCSX2 does not support emulation of PS1 games.") );
return;
case 2:
// PS2 game. Valid!
elf_file = ename;
break;
jNO_DEFAULT
}
}
InitPlugins();
SysExecute( new AppEmuThread( elf_file ), CDVDsrc_Iso );
SysExecute( new AppEmuThread(), CDVDsrc_Iso );
}
/*void MainEmuFrame::Menu_RunWithoutDisc_Click(wxCommandEvent &event)
@ -218,13 +195,13 @@ void MainEmuFrame::Menu_SaveStateOther_Click(wxCommandEvent &event)
void MainEmuFrame::Menu_Exit_Click(wxCommandEvent &event)
{
SysReset();
SysShutdown();
Close();
}
void MainEmuFrame::Menu_EmuClose_Click(wxCommandEvent &event)
{
SysReset();
SysEndExecution();
GetMenuBar()->Check( MenuId_Emu_Pause, false );
}
@ -239,7 +216,7 @@ void MainEmuFrame::Menu_EmuPause_Click(wxCommandEvent &event)
void MainEmuFrame::Menu_EmuReset_Click(wxCommandEvent &event)
{
bool wasRunning = EmulationInProgress();
SysReset();
SysShutdown();
GetMenuBar()->Check( MenuId_Emu_Pause, false );

View File

@ -59,9 +59,9 @@ namespace Exception
};
}
AppEmuThread::AppEmuThread( const wxString& elf_file ) :
m_kevt()
, CoreEmuThread( elf_file )
AppEmuThread::AppEmuThread() :
CoreEmuThread()
, m_kevt()
{
MemoryCard::Init();
}
@ -414,7 +414,7 @@ void Pcsx2App::OnMessageBox( pxMessageBoxEvent& evt )
void Pcsx2App::CleanupMess()
{
SysReset();
SysShutdown();
safe_delete( m_Bitmap_Logo );
safe_delete( g_Conf );
}

View File

@ -43,9 +43,6 @@ void CoreEmuThread::CpuInitializeMess()
SysClearExecutionCache();
GetPluginManager().Open();
if( GSsetGameCRC != NULL )
GSsetGameCRC( ElfCRC, 0 );
if( StateRecovery::HasState() )
{
// no need to boot bios or detect CDs when loading savestates.
@ -56,7 +53,30 @@ void CoreEmuThread::CpuInitializeMess()
}
else
{
if( !m_elf_file.IsEmpty() )
wxString elf_file;
if( EmuConfig.SkipBiosSplash )
{
// Fetch the ELF filename and CD type from the CDVD provider.
wxString ename;
int result = GetPS2ElfName( ename );
switch( result )
{
case 0:
throw Exception::RuntimeError( wxLt("Fast Boot failed: CDVD image is not a PS1 or PS2 game.") );
case 1:
throw Exception::RuntimeError( wxLt("Fast Boot failed: PCSX2 does not support emulation of PS1 games.") );
case 2:
// PS2 game. Valid!
elf_file = ename;
break;
jNO_DEFAULT
}
}
if( !elf_file.IsEmpty() )
{
// Skip Bios Hack -- Runs the PS2 BIOS stub, and then manually loads the ELF
// executable data, and injects the cpuRegs.pc with the address of the
@ -66,9 +86,12 @@ void CoreEmuThread::CpuInitializeMess()
// (though not recommended for games because of rare ill side effects).
cpuExecuteBios();
loadElfFile( m_elf_file );
loadElfFile( elf_file );
}
}
if( GSsetGameCRC != NULL )
GSsetGameCRC( ElfCRC, 0 );
}
// special macro which disables inlining on functions that require their own function stackframe.
@ -140,14 +163,13 @@ void CoreEmuThread::StateCheck()
}
}
CoreEmuThread::CoreEmuThread( const wxString& elf_file ) :
CoreEmuThread::CoreEmuThread() :
m_ExecMode( ExecMode_Idle )
, m_ResumeEvent()
, m_SuspendEvent()
, m_resetRecompilers( false )
, m_resetProfilers( false )
, m_elf_file( elf_file )
, m_lock_ExecMode()
{
PersistentThread::Start();
@ -156,8 +178,8 @@ CoreEmuThread::CoreEmuThread( const wxString& elf_file ) :
// Invoked by the pthread_exit or pthread_cancel
void CoreEmuThread::DoThreadCleanup()
{
PersistentThread::DoThreadCleanup();
GetPluginManager().Close();
PersistentThread::DoThreadCleanup();
}
CoreEmuThread::~CoreEmuThread()

View File

@ -45,15 +45,13 @@ protected:
bool m_resetRecompilers;
bool m_resetProfilers;
const wxString m_elf_file;
MutexLock m_lock_ExecMode;
public:
static CoreEmuThread& Get();
public:
explicit CoreEmuThread( const wxString& elf_file=wxEmptyString );
explicit CoreEmuThread();
virtual ~CoreEmuThread();
bool IsSuspended() const { return (m_ExecMode == ExecMode_Suspended); }

View File

@ -288,7 +288,7 @@ u32* recGetImm64(u32 hi, u32 lo)
if (recConstBufPtr >= recConstBuf + RECCONSTBUF_SIZE)
{
Console::Status( "EErec const buffer filled; Resetting..." );
throw Exception::RecompilerReset();
throw Exception::ForceDispatcherReg();
/*for (u32 *p = recConstBuf; p < recConstBuf + RECCONSTBUF_SIZE; p += 2)
{
@ -579,6 +579,8 @@ static void recExecute()
g_EEFreezeRegs = true;
try
{
while( true )
{
try
@ -620,10 +622,14 @@ static void recExecute()
);
#endif
}
catch( Exception::RecompilerReset& )
catch( Exception::ForceDispatcherReg& )
{
}
}
}
catch( Exception::ExitRecExecute& )
{
}
g_EEFreezeRegs = false;
}
@ -750,27 +756,21 @@ void recClear(u32 addr, u32 size)
ClearRecLUT(PC_GETBLOCK(lowerextent), (upperextent - lowerextent) / 4);
}
static void ExitRec()
{
throw Exception::ExitRecExecute();
}
// check for end of bios
void CheckForBIOSEnd()
{
MOV32MtoR(EAX, (int)&cpuRegs.pc);
xMOV( eax, &cpuRegs.pc );
CMP32ItoR(EAX, 0x00200008);
j8Ptr[0] = JE8(0);
xCMP( eax, 0x00200008 );
xJE( ExitRec );
CMP32ItoR(EAX, 0x00100008);
j8Ptr[1] = JE8(0);
// return
j8Ptr[2] = JMP8(0);
x86SetJ8( j8Ptr[0] );
x86SetJ8( j8Ptr[1] );
// bios end
RET();
x86SetJ8( j8Ptr[2] );
xCMP( eax, 0x00100008 );
xJE( ExitRec );
}
static int *s_pCode;