/* SleepSelf Just like the sleep() but with some hacks for thread cancellation. Initially tested in the netcache and moved here later. Later reworked to use the DlThread cancellation mechanisms. */ void DlThread::SleepSelf(unsigned i_seconds) { TestCancel(); #if defined(_WIN32) /* This waits for cancellation, up to i_seconds seconds. */ WaitForSingleObject( m_data->m_cancellation_event, i_seconds * 1000u ); #else /* Enable cancellation while sleeping. */ pthread_cleanup_push(SleepCancel, this); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0x0); #ifdef DARWIN /* the cancellation point in sleep isn't implemented in OS X, see: http://lists.apple.com/archives/darwin-userlevel/2004/Mar/msg00016.html http://lists.apple.com/archives/darwin-kernel/2004/Jan/msg00032.html or google for 'pthread_cancel sleep OS X'. This means we have to check for cancellation explicitely. This will make the cancellation 'hang' a bit but there's no workaround until the OS X guys get their ass moving and implement decent threads. Update: It looks like the OS X people behind this are complete morons: http://lists.apple.com/archives/darwin-kernel/2007/Nov/msg00104.html Update(2): This got fixed at last in 10.6: http://lists.apple.com/archives/darwin-kernel/2009/Dec/msg00038.html We could remove this patch when we start targetting 10.6 and up. */ for (unsigned s = 0; s < i_seconds; ++s) { sleep(1); pthread_testcancel(); } #else sleep( i_seconds ); /* It seems redhat 7 (libc 2.2.5) will not cancel properly when in the sleep call. It will however get out of that call (probably due to receiving a signal) so this simple test keeps us from hanging. */ pthread_testcancel(); #endif pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0x0); pthread_cleanup_pop(0); #endif TestCancel(); }
// Tests for Pause and Suspend/Close requests. If the thread is trying to be paused or // closed, it will enter a wait/holding pattern here in this method until the managing // thread releases it. Use the return value to detect if changes to the thread's state // may have been changed (based on the rule that other threads are not allowed to modify // this thread's state without pausing or closing it first, to prevent race conditions). // // Return value: // TRUE if the thread was paused or closed; FALSE if the thread // continued execution unimpeded. bool SysThreadBase::StateCheckInThread() { switch( m_ExecMode ) { #ifdef PCSX2_DEVBUILD // optimize out handlers for these cases in release builds. case ExecMode_NoThreadYet: // threads should never have this state set while the thread is in any way // active or alive. (for obvious reasons!!) pxFailDev( "Invalid execution state detected." ); return false; #endif case ExecMode_Opened: // Other cases don't need TestCancel() because its built into the various // threading wait/signal actions. TestCancel(); return false; // ------------------------------------- case ExecMode_Pausing: { OnPauseInThread(); m_ExecMode = ExecMode_Paused; m_RunningLock.Release(); } // fallthrough... case ExecMode_Paused: while( m_ExecMode == ExecMode_Paused ) m_sem_Resume.WaitWithoutYield(); m_RunningLock.Acquire(); if( m_ExecMode != ExecMode_Closing ) { OnResumeInThread( false ); break; } m_sem_ChangingExecMode.Post(); // fallthrough if we're switching to closing state... // ------------------------------------- case ExecMode_Closing: { OnSuspendInThread(); m_ExecMode = ExecMode_Closed; m_RunningLock.Release(); } // fallthrough... case ExecMode_Closed: while( m_ExecMode == ExecMode_Closed ) m_sem_Resume.WaitWithoutYield(); m_RunningLock.Acquire(); OnResumeInThread( true ); break; jNO_DEFAULT; } return true; }