2009-09-08 12:08:10 +00:00
/* PCSX2 - PS2 Emulator for PCs
2010-05-03 14:08:02 +00:00
* Copyright (C) 2002-2010 PCSX2 Dev Team
2009-10-04 09:00:07 +00:00
*
2009-09-08 12:08:10 +00:00
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
2009-04-27 02:04:31 +00:00
*
2009-09-08 12:08:10 +00:00
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
2009-04-28 05:56:22 +00:00
*
2009-09-08 12:08:10 +00:00
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
2009-04-27 02:04:31 +00:00
*/
2022-05-18 23:27:23 +10:00
#include "Threading.h"
#include "General.h"
#include "Exceptions.h"
2022-05-24 21:21:31 +10:00
#include "CrashHandler.h"
2021-09-03 06:43:33 -04:00
2022-05-24 21:21:31 +10:00
#include <mutex>
2022-05-18 23:27:23 +10:00
#include "fmt/core.h"
#ifdef _WIN32
#include "RedtapeWindows.h"
2022-05-24 21:21:31 +10:00
#include <intrin.h>
#include <tlhelp32.h>
2009-12-25 18:58:25 +00:00
#endif
2022-05-18 23:27:23 +10:00
#ifdef __UNIX__
#include <signal.h>
#endif
2010-11-05 01:33:01 +00:00
2009-12-25 18:00:51 +00:00
// Because wxTrap isn't available on Linux builds of wxWidgets (non-Debug, typically)
void pxTrap ()
{
2022-05-18 23:27:23 +10:00
#if defined(_WIN32)
2021-09-06 14:28:26 -04:00
__debugbreak ();
2009-12-25 18:00:51 +00:00
#elif defined(__UNIX__)
2021-09-06 14:28:26 -04:00
raise ( SIGTRAP );
2009-12-25 18:00:51 +00:00
#else
2022-05-18 23:27:23 +10:00
abort ();
#endif
2009-12-25 18:00:51 +00:00
}
2022-05-24 21:21:31 +10:00
static std :: mutex s_assertion_failed_mutex ;
2010-10-22 19:47:02 +00:00
2022-05-24 21:21:31 +10:00
static inline void FreezeThreads ( void ** handle )
2010-10-22 19:47:02 +00:00
{
2022-08-27 18:30:33 +10:00
#if defined(_WIN32)
2022-05-24 21:21:31 +10:00
HANDLE snapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD , 0 );
if ( snapshot != INVALID_HANDLE_VALUE )
{
THREADENTRY32 threadEntry ;
if ( Thread32First ( snapshot , & threadEntry ))
{
do
{
if ( threadEntry . th32ThreadID == GetCurrentThreadId ())
continue ;
HANDLE hThread = OpenThread ( THREAD_SUSPEND_RESUME , FALSE , threadEntry . th32ThreadID );
if ( hThread != nullptr )
{
SuspendThread ( hThread );
CloseHandle ( hThread );
}
} while ( Thread32Next ( snapshot , & threadEntry ));
}
}
* handle = static_cast < void *> ( snapshot );
#else
* handle = nullptr ;
2022-05-18 23:27:23 +10:00
#endif
2010-10-22 19:47:02 +00:00
}
2022-05-24 21:21:31 +10:00
static inline void ResumeThreads ( void * handle )
2009-12-14 12:18:55 +00:00
{
2022-08-27 18:30:33 +10:00
#if defined(_WIN32)
2022-05-24 21:21:31 +10:00
if ( handle != INVALID_HANDLE_VALUE )
2021-09-06 14:28:26 -04:00
{
2022-05-24 21:21:31 +10:00
THREADENTRY32 threadEntry ;
if ( Thread32First ( reinterpret_cast < HANDLE > ( handle ), & threadEntry ))
{
do
{
if ( threadEntry . th32ThreadID == GetCurrentThreadId ())
continue ;
2009-12-14 12:18:55 +00:00
2022-05-24 21:21:31 +10:00
HANDLE hThread = OpenThread ( THREAD_SUSPEND_RESUME , FALSE , threadEntry . th32ThreadID );
if ( hThread != nullptr )
{
ResumeThread ( hThread );
CloseHandle ( hThread );
}
} while ( Thread32Next ( reinterpret_cast < HANDLE > ( handle ), & threadEntry ));
}
CloseHandle ( reinterpret_cast < HANDLE > ( handle ));
2021-09-06 14:28:26 -04:00
}
2022-05-24 21:21:31 +10:00
#else
#endif
}
void pxOnAssertFail ( const char * file , int line , const char * func , const char * msg )
{
std :: unique_lock guard ( s_assertion_failed_mutex );
void * handle ;
FreezeThreads ( & handle );
char full_msg [ 512 ];
std :: snprintf ( full_msg , sizeof ( full_msg ), "%s:%d: assertion failed in function %s: %s \n " , file , line , func , msg );
2022-08-27 18:30:33 +10:00
#if defined(_WIN32)
2022-05-24 21:21:31 +10:00
HANDLE error_handle = GetStdHandle ( STD_ERROR_HANDLE );
if ( error_handle != INVALID_HANDLE_VALUE )
WriteConsoleA ( GetStdHandle ( STD_ERROR_HANDLE ), full_msg , static_cast < DWORD > ( std :: strlen ( full_msg )), NULL , NULL );
OutputDebugStringA ( full_msg );
std :: snprintf (
full_msg , sizeof ( full_msg ),
"Assertion failed in function %s (%s:%d): \n\n %s \n\n Press Abort to exit, Retry to break to debugger, or Ignore to attempt to continue." ,
func , file , line , msg );
int result = MessageBoxA ( NULL , full_msg , NULL , MB_ABORTRETRYIGNORE | MB_ICONERROR );
if ( result == IDRETRY )
{
__debugbreak ();
}
else if ( result != IDIGNORE )
{
// try to save a crash dump before exiting
CrashHandler :: WriteDumpForCaller ();
TerminateProcess ( GetCurrentProcess (), 0xBAADC0DE );
}
#else
fputs ( full_msg , stderr );
fputs ( " \n Aborting application. \n " , stderr );
fflush ( stderr );
2022-05-30 00:49:07 -05:00
AbortWithMessage ( full_msg );
2022-05-24 21:21:31 +10:00
#endif
ResumeThreads ( handle );
2009-09-12 02:58:22 +00:00
}
2009-09-20 20:54:45 +00:00
// --------------------------------------------------------------------------------------
2010-06-28 18:03:54 +00:00
// BaseException (implementations)
2009-09-20 20:54:45 +00:00
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
BaseException & BaseException :: SetBothMsgs ( const char * msg_diag )
2009-04-27 02:04:31 +00:00
{
2022-05-18 23:27:23 +10:00
m_message_user = msg_diag ? std :: string ( msg_diag ) : std :: string ();
2021-09-06 14:28:26 -04:00
return SetDiagMsg ( msg_diag );
2009-09-20 20:54:45 +00:00
}
2009-04-28 05:56:22 +00:00
2022-05-18 23:27:23 +10:00
BaseException & BaseException :: SetDiagMsg ( std :: string msg_diag )
2009-09-20 20:54:45 +00:00
{
2022-05-18 23:27:23 +10:00
m_message_diag = std :: move ( msg_diag );
2021-09-06 14:28:26 -04:00
return * this ;
2010-06-28 18:03:54 +00:00
}
2009-09-01 00:43:28 +00:00
2022-05-18 23:27:23 +10:00
BaseException & BaseException :: SetUserMsg ( std :: string msg_user )
2010-06-28 18:03:54 +00:00
{
2022-05-18 23:27:23 +10:00
m_message_user = std :: move ( msg_user );
2021-09-06 14:28:26 -04:00
return * this ;
2009-09-20 20:54:45 +00:00
}
2009-04-27 02:04:31 +00:00
2022-05-18 23:27:23 +10:00
std :: string BaseException :: FormatDiagnosticMessage () const
2009-09-20 20:54:45 +00:00
{
2021-09-06 14:28:26 -04:00
return m_message_diag ;
2009-09-20 20:54:45 +00:00
}
2009-04-27 02:04:31 +00:00
2022-05-18 23:27:23 +10:00
std :: string BaseException :: FormatDisplayMessage () const
2010-06-28 18:03:54 +00:00
{
2022-05-18 23:27:23 +10:00
return m_message_user . empty () ? m_message_diag : m_message_user ;
2010-06-28 18:03:54 +00:00
}
// --------------------------------------------------------------------------------------
// Exception::RuntimeError (implementations)
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
Exception :: RuntimeError :: RuntimeError ( const std :: runtime_error & ex , const char * prefix /* = nullptr */ )
2010-04-27 13:12:03 +00:00
{
2021-09-06 14:28:26 -04:00
IsSilent = false ;
2010-06-28 18:03:54 +00:00
2022-05-18 23:27:23 +10:00
const bool has_prefix = prefix && prefix [ 0 ] != 0 ;
SetDiagMsg ( fmt :: format ( "STL Runtime Error{}{}{}: {}" ,
has_prefix ? " (" : "" , prefix ? prefix : "" , has_prefix ? ")" : "" ,
ex . what ()));
2010-05-07 03:20:58 +00:00
}
2022-05-18 23:27:23 +10:00
Exception :: RuntimeError :: RuntimeError ( const std :: exception & ex , const char * prefix /* = nullptr */ )
2010-05-07 03:20:58 +00:00
{
2021-09-06 14:28:26 -04:00
IsSilent = false ;
2010-06-28 18:03:54 +00:00
2022-05-18 23:27:23 +10:00
const bool has_prefix = prefix && prefix [ 0 ] != 0 ;
SetDiagMsg ( fmt :: format ( "STL Exception{}{}{}: {}" ,
has_prefix ? " (" : "" , prefix ? prefix : "" , has_prefix ? ")" : "" ,
ex . what ()));
2010-04-27 13:12:03 +00:00
}
2010-11-05 01:33:01 +00:00
// --------------------------------------------------------------------------------------
// Exception::BadStream (implementations)
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
std :: string Exception :: BadStream :: FormatDiagnosticMessage () const
2009-09-20 20:54:45 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
2021-09-06 14:28:26 -04:00
_formatDiagMsg ( retval );
return retval ;
2009-09-20 20:54:45 +00:00
}
2009-04-27 02:04:31 +00:00
2022-05-18 23:27:23 +10:00
std :: string Exception :: BadStream :: FormatDisplayMessage () const
2009-09-20 20:54:45 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
2021-09-06 14:28:26 -04:00
_formatUserMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
2010-06-28 18:03:54 +00:00
2022-05-18 23:27:23 +10:00
void Exception :: BadStream :: _formatDiagMsg ( std :: string & dest ) const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
fmt :: format_to ( std :: back_inserter ( dest ), "Path: " );
if ( ! StreamName . empty ())
fmt :: format_to ( std :: back_inserter ( dest ), "{}" , StreamName );
2021-09-06 14:28:26 -04:00
else
2022-05-18 23:27:23 +10:00
dest += "[Unnamed or unknown]" ;
2010-11-05 01:33:01 +00:00
2022-05-18 23:27:23 +10:00
if ( ! m_message_diag . empty ())
fmt :: format_to ( std :: back_inserter ( dest ), " \n {}" , m_message_diag );
2010-11-05 01:33:01 +00:00
}
2022-05-18 23:27:23 +10:00
void Exception :: BadStream :: _formatUserMsg ( std :: string & dest ) const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
fmt :: format_to ( std :: back_inserter ( dest ), "Path: " );
if ( ! StreamName . empty ())
fmt :: format_to ( std :: back_inserter ( dest ), "{}" , StreamName );
2021-09-06 14:28:26 -04:00
else
2022-05-18 23:27:23 +10:00
dest += "[Unnamed or unknown]" ;
2010-11-05 01:33:01 +00:00
2022-05-18 23:27:23 +10:00
if ( ! m_message_user . empty ())
fmt :: format_to ( std :: back_inserter ( dest ), " \n {}" , m_message_user );
2010-11-05 01:33:01 +00:00
}
// --------------------------------------------------------------------------------------
// Exception::CannotCreateStream (implementations)
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
std :: string Exception :: CannotCreateStream :: FormatDiagnosticMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "File could not be created." ;
2021-09-06 14:28:26 -04:00
_formatDiagMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
2022-05-18 23:27:23 +10:00
std :: string Exception :: CannotCreateStream :: FormatDisplayMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "A file could not be created. \n " ;
2021-09-06 14:28:26 -04:00
_formatUserMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
// --------------------------------------------------------------------------------------
// Exception::FileNotFound (implementations)
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
std :: string Exception :: FileNotFound :: FormatDiagnosticMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "File not found. \n " ;
2021-09-06 14:28:26 -04:00
_formatDiagMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
2022-05-18 23:27:23 +10:00
std :: string Exception :: FileNotFound :: FormatDisplayMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "File not found. \n " ;
2021-09-06 14:28:26 -04:00
_formatUserMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
// --------------------------------------------------------------------------------------
// Exception::AccessDenied (implementations)
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
std :: string Exception :: AccessDenied :: FormatDiagnosticMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "Permission denied to file. \n " ;
2021-09-06 14:28:26 -04:00
_formatDiagMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
2022-05-18 23:27:23 +10:00
std :: string Exception :: AccessDenied :: FormatDisplayMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "Permission denied while trying to open file, likely due to insufficient user account rights. \n " ;
2021-09-06 14:28:26 -04:00
_formatUserMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
// --------------------------------------------------------------------------------------
// Exception::EndOfStream (implementations)
// --------------------------------------------------------------------------------------
2022-05-18 23:27:23 +10:00
std :: string Exception :: EndOfStream :: FormatDiagnosticMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "Unexpected end of file or stream. \n " ;
2021-09-06 14:28:26 -04:00
_formatDiagMsg ( retval );
return retval ;
2010-11-05 01:33:01 +00:00
}
2022-05-18 23:27:23 +10:00
std :: string Exception :: EndOfStream :: FormatDisplayMessage () const
2010-11-05 01:33:01 +00:00
{
2022-05-18 23:27:23 +10:00
std :: string retval ;
retval = "Unexpected end of file or stream encountered. File is probably truncated or corrupted. \n " ;
2021-09-06 14:28:26 -04:00
_formatUserMsg ( retval );
return retval ;
2009-09-20 20:54:45 +00:00
}
2009-04-27 02:04:31 +00:00
2010-10-18 01:40:49 +00:00
// --------------------------------------------------------------------------------------
// Exceptions from Errno (POSIX)
// --------------------------------------------------------------------------------------
// Translates an Errno code into an exception.
// Throws an exception based on the given error code (usually taken from ANSI C's errno)
2022-10-13 01:42:36 +10:00
std :: unique_ptr < BaseException > Exception :: FromErrno ( std :: string streamname , int errcode )
2010-10-18 01:40:49 +00:00
{
2021-09-06 14:28:26 -04:00
pxAssumeDev ( errcode != 0 , "Invalid NULL error code? (errno)" );
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
switch ( errcode )
{
case EINVAL :
2022-05-18 23:27:23 +10:00
pxFailDev ( "Invalid argument" );
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( & ( new Exception :: BadStream ( streamname )) -> SetDiagMsg ( "Invalid argument? (likely caused by an unforgivable programmer error!)" ));
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
case EACCES : // Access denied!
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( new Exception :: AccessDenied ( streamname ));
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
case EMFILE : // Too many open files!
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( & ( new Exception :: CannotCreateStream ( streamname )) -> SetDiagMsg ( "Too many open files" )); // File handle allocation failure
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
case EEXIST :
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( & ( new Exception :: CannotCreateStream ( streamname )) -> SetDiagMsg ( "File already exists" ));
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
case ENOENT : // File not found!
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( new Exception :: FileNotFound ( streamname ));
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
case EPIPE :
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( & ( new Exception :: BadStream ( streamname )) -> SetDiagMsg ( "Broken pipe" ));
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
case EBADF :
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( & ( new Exception :: BadStream ( streamname )) -> SetDiagMsg ( "Bad file number" ));
2010-10-18 01:40:49 +00:00
2021-09-06 14:28:26 -04:00
default :
2022-10-13 01:42:36 +10:00
return std :: unique_ptr < BaseException > ( & ( new Exception :: BadStream ( streamname )) -> SetDiagMsg ( fmt :: format ( "General file/stream error [errno: {}]" , errcode )));
2021-09-06 14:28:26 -04:00
}
2010-10-18 01:40:49 +00:00
}