mirror of https://github.com/PCSX2/pcsx2.git
Common: Remove Exceptions
The satisfaction is immeasurable.
This commit is contained in:
parent
2ae78f6e2f
commit
6beaec8ba1
|
@ -0,0 +1,133 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Threading.h"
|
||||
#include "General.h"
|
||||
#include "Assertions.h"
|
||||
#include "CrashHandler.h"
|
||||
|
||||
#include <mutex>
|
||||
#include "fmt/core.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "RedtapeWindows.h"
|
||||
#include <intrin.h>
|
||||
#include <tlhelp32.h>
|
||||
#endif
|
||||
|
||||
#ifdef __UNIX__
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
static std::mutex s_assertion_failed_mutex;
|
||||
|
||||
static inline void FreezeThreads(void** handle)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ResumeThreads(void* handle)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
THREADENTRY32 threadEntry;
|
||||
if (Thread32First(reinterpret_cast<HANDLE>(handle), &threadEntry))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (threadEntry.th32ThreadID == GetCurrentThreadId())
|
||||
continue;
|
||||
|
||||
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));
|
||||
}
|
||||
#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);
|
||||
|
||||
#if defined(_WIN32)
|
||||
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\nPress 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("\nAborting application.\n", stderr);
|
||||
fflush(stderr);
|
||||
AbortWithMessage(full_msg);
|
||||
#endif
|
||||
|
||||
ResumeThreads(handle);
|
||||
}
|
|
@ -10,12 +10,12 @@ add_library(common)
|
|||
# x86emitter sources
|
||||
target_sources(common PRIVATE
|
||||
AlignedMalloc.cpp
|
||||
Assertions.cpp
|
||||
SafeArray.inl
|
||||
Console.cpp
|
||||
CrashHandler.cpp
|
||||
DynamicLibrary.cpp
|
||||
Error.cpp
|
||||
Exceptions.cpp
|
||||
FastJmp.cpp
|
||||
FileSystem.cpp
|
||||
General.cpp
|
||||
|
@ -72,7 +72,6 @@ target_sources(common PRIVATE
|
|||
Easing.h
|
||||
EnumOps.h
|
||||
Error.h
|
||||
Exceptions.h
|
||||
FastJmp.h
|
||||
FileSystem.h
|
||||
General.h
|
||||
|
|
|
@ -1,346 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Threading.h"
|
||||
#include "General.h"
|
||||
#include "Exceptions.h"
|
||||
#include "CrashHandler.h"
|
||||
|
||||
#include <mutex>
|
||||
#include "fmt/core.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "RedtapeWindows.h"
|
||||
#include <intrin.h>
|
||||
#include <tlhelp32.h>
|
||||
#endif
|
||||
|
||||
#ifdef __UNIX__
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
static std::mutex s_assertion_failed_mutex;
|
||||
|
||||
static inline void FreezeThreads(void** handle)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void ResumeThreads(void* handle)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
THREADENTRY32 threadEntry;
|
||||
if (Thread32First(reinterpret_cast<HANDLE>(handle), &threadEntry))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (threadEntry.th32ThreadID == GetCurrentThreadId())
|
||||
continue;
|
||||
|
||||
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));
|
||||
}
|
||||
#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);
|
||||
|
||||
#if defined(_WIN32)
|
||||
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\nPress 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("\nAborting application.\n", stderr);
|
||||
fflush(stderr);
|
||||
AbortWithMessage(full_msg);
|
||||
#endif
|
||||
|
||||
ResumeThreads(handle);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
BaseException& BaseException::SetBothMsgs(const char* msg_diag)
|
||||
{
|
||||
m_message_user = msg_diag ? std::string(msg_diag) : std::string();
|
||||
return SetDiagMsg(msg_diag);
|
||||
}
|
||||
|
||||
BaseException& BaseException::SetDiagMsg(std::string msg_diag)
|
||||
{
|
||||
m_message_diag = std::move(msg_diag);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseException& BaseException::SetUserMsg(std::string msg_user)
|
||||
{
|
||||
m_message_user = std::move(msg_user);
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string BaseException::FormatDiagnosticMessage() const
|
||||
{
|
||||
return m_message_diag;
|
||||
}
|
||||
|
||||
std::string BaseException::FormatDisplayMessage() const
|
||||
{
|
||||
return m_message_user.empty() ? m_message_diag : m_message_user;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::RuntimeError (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
Exception::RuntimeError::RuntimeError(const std::runtime_error& ex, const char* prefix /* = nullptr */)
|
||||
{
|
||||
IsSilent = false;
|
||||
|
||||
const bool has_prefix = prefix && prefix[0] != 0;
|
||||
|
||||
SetDiagMsg(fmt::format("STL Runtime Error{}{}{}: {}",
|
||||
has_prefix ? " (" : "", prefix ? prefix : "", has_prefix ? ")" : "",
|
||||
ex.what()));
|
||||
}
|
||||
|
||||
Exception::RuntimeError::RuntimeError(const std::exception& ex, const char* prefix /* = nullptr */)
|
||||
{
|
||||
IsSilent = false;
|
||||
|
||||
const bool has_prefix = prefix && prefix[0] != 0;
|
||||
|
||||
SetDiagMsg(fmt::format("STL Exception{}{}{}: {}",
|
||||
has_prefix ? " (" : "", prefix ? prefix : "", has_prefix ? ")" : "",
|
||||
ex.what()));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::BadStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string Exception::BadStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string Exception::BadStream::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Exception::BadStream::_formatDiagMsg(std::string& dest) const
|
||||
{
|
||||
fmt::format_to(std::back_inserter(dest), "Path: ");
|
||||
if (!StreamName.empty())
|
||||
fmt::format_to(std::back_inserter(dest), "{}", StreamName);
|
||||
else
|
||||
dest += "[Unnamed or unknown]";
|
||||
|
||||
if (!m_message_diag.empty())
|
||||
fmt::format_to(std::back_inserter(dest), "\n{}", m_message_diag);
|
||||
}
|
||||
|
||||
void Exception::BadStream::_formatUserMsg(std::string& dest) const
|
||||
{
|
||||
fmt::format_to(std::back_inserter(dest), "Path: ");
|
||||
if (!StreamName.empty())
|
||||
fmt::format_to(std::back_inserter(dest), "{}", StreamName);
|
||||
else
|
||||
dest += "[Unnamed or unknown]";
|
||||
|
||||
if (!m_message_user.empty())
|
||||
fmt::format_to(std::back_inserter(dest), "\n{}", m_message_user);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::CannotCreateStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string Exception::CannotCreateStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "File could not be created.";
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string Exception::CannotCreateStream::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "A file could not be created.\n";
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::FileNotFound (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string Exception::FileNotFound::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "File not found.\n";
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string Exception::FileNotFound::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "File not found.\n";
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::AccessDenied (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string Exception::AccessDenied::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "Permission denied to file.\n";
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string Exception::AccessDenied::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "Permission denied while trying to open file, likely due to insufficient user account rights.\n";
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Exception::EndOfStream (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string Exception::EndOfStream::FormatDiagnosticMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "Unexpected end of file or stream.\n";
|
||||
_formatDiagMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string Exception::EndOfStream::FormatDisplayMessage() const
|
||||
{
|
||||
std::string retval;
|
||||
retval = "Unexpected end of file or stream encountered. File is probably truncated or corrupted.\n";
|
||||
_formatUserMsg(retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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)
|
||||
std::unique_ptr<BaseException> Exception::FromErrno(std::string streamname, int errcode)
|
||||
{
|
||||
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
|
||||
|
||||
switch (errcode)
|
||||
{
|
||||
case EINVAL:
|
||||
pxFailDev("Invalid argument");
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Invalid argument? (likely caused by an unforgivable programmer error!)"));
|
||||
|
||||
case EACCES: // Access denied!
|
||||
return std::unique_ptr<BaseException>(new Exception::AccessDenied(streamname));
|
||||
|
||||
case EMFILE: // Too many open files!
|
||||
return std::unique_ptr<BaseException>(&(new Exception::CannotCreateStream(streamname))->SetDiagMsg("Too many open files")); // File handle allocation failure
|
||||
|
||||
case EEXIST:
|
||||
return std::unique_ptr<BaseException>(&(new Exception::CannotCreateStream(streamname))->SetDiagMsg("File already exists"));
|
||||
|
||||
case ENOENT: // File not found!
|
||||
return std::unique_ptr<BaseException>(new Exception::FileNotFound(streamname));
|
||||
|
||||
case EPIPE:
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Broken pipe"));
|
||||
|
||||
case EBADF:
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Bad file number"));
|
||||
|
||||
default:
|
||||
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg(fmt::format("General file/stream error [errno: {}]", errcode)));
|
||||
}
|
||||
}
|
|
@ -1,255 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
namespace Exception
|
||||
{
|
||||
class BaseException;
|
||||
|
||||
std::unique_ptr<BaseException> FromErrno(std::string streamname, int errcode);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// BaseException
|
||||
// --------------------------------------------------------------------------------------
|
||||
// std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
|
||||
// so I made a replacement. The internal messages are non-const, which means that a
|
||||
// catch clause can optionally modify them and then re-throw to a top-level handler.
|
||||
//
|
||||
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
|
||||
// Use Exception::RuntimeError instead for generic exceptions.
|
||||
//
|
||||
// Because exceptions are the (only!) really useful example of multiple inheritance,
|
||||
// this class has only a trivial constructor, and must be manually initialized using
|
||||
// InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence
|
||||
// is, by design, a lot of fail, especially when class initializers are mixed in.
|
||||
//
|
||||
// [TODO] : Add an InnerException component, and Clone() facility.
|
||||
//
|
||||
class BaseException
|
||||
{
|
||||
protected:
|
||||
std::string m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
|
||||
std::string m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
|
||||
|
||||
public:
|
||||
virtual ~BaseException() = default;
|
||||
|
||||
const std::string& DiagMsg() const { return m_message_diag; }
|
||||
const std::string& UserMsg() const { return m_message_user; }
|
||||
|
||||
std::string& DiagMsg() { return m_message_diag; }
|
||||
std::string& UserMsg() { return m_message_user; }
|
||||
|
||||
BaseException& SetBothMsgs(const char* msg_diag);
|
||||
BaseException& SetDiagMsg(std::string msg_diag);
|
||||
BaseException& SetUserMsg(std::string msg_user);
|
||||
|
||||
// Returns a message suitable for diagnostic / logging purposes.
|
||||
// This message is always in English, and includes a full stack trace.
|
||||
virtual std::string FormatDiagnosticMessage() const;
|
||||
|
||||
// Returns a message suitable for end-user display.
|
||||
// This message is usually meant for display in a user popup or such.
|
||||
virtual std::string FormatDisplayMessage() const;
|
||||
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual BaseException* Clone() const = 0;
|
||||
};
|
||||
|
||||
// Some helper macros for defining the standard constructors of internationalized constructors
|
||||
// Parameters:
|
||||
// classname - Yeah, the name of this class being defined. :)
|
||||
//
|
||||
// defmsg - default message (in english), which will be used for both english and i18n messages.
|
||||
// The text string will be passed through the translator, so if it's int he gettext database
|
||||
// it will be optionally translated.
|
||||
//
|
||||
// BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
|
||||
// ambiguity errors on virtual inheritance (it really shouldn't!). So I have to force it to the
|
||||
// BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
|
||||
//
|
||||
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
|
||||
//
|
||||
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||
private: \
|
||||
typedef parent _parent; \
|
||||
\
|
||||
public: \
|
||||
virtual ~classname() = default; \
|
||||
\
|
||||
virtual void Rethrow() const override \
|
||||
{ \
|
||||
throw *this; \
|
||||
} \
|
||||
\
|
||||
virtual classname* Clone() const override \
|
||||
{ \
|
||||
return new classname(*this); \
|
||||
}
|
||||
|
||||
#define DEFINE_EXCEPTION_MESSAGES(classname) \
|
||||
public: \
|
||||
classname& SetBothMsgs(const char* msg_diag) \
|
||||
{ \
|
||||
BaseException::SetBothMsgs(msg_diag); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
classname& SetDiagMsg(std::string msg_diag) \
|
||||
{ \
|
||||
m_message_diag = msg_diag; \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
classname& SetUserMsg(std::string msg_user) \
|
||||
{ \
|
||||
m_message_user = std::move(msg_user); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
|
||||
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
|
||||
classname() \
|
||||
{ \
|
||||
SetDiagMsg(message); \
|
||||
} \
|
||||
DEFINE_EXCEPTION_MESSAGES(classname)
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// RuntimeError - Generalized Exceptions with Recoverable Traits!
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
class RuntimeError : public BaseException
|
||||
{
|
||||
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
|
||||
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
|
||||
|
||||
public:
|
||||
bool IsSilent;
|
||||
|
||||
RuntimeError() { IsSilent = false; }
|
||||
RuntimeError(const std::runtime_error& ex, const char* prefix = nullptr);
|
||||
RuntimeError(const std::exception& ex, const char* prefix = nullptr);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Streaming (file) Exceptions:
|
||||
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
|
||||
DEFINE_RUNTIME_EXCEPTION(classname, parent, "") \
|
||||
classname(std::string filename) \
|
||||
{ \
|
||||
StreamName = filename; \
|
||||
} \
|
||||
virtual classname& SetStreamName(std::string name) override \
|
||||
{ \
|
||||
StreamName = std::move(name); \
|
||||
return *this; \
|
||||
} \
|
||||
\
|
||||
virtual classname& SetStreamName(const char* name) override \
|
||||
{ \
|
||||
StreamName = name; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
|
||||
// connection, or anything else that would indicate a failure to open a stream or read the
|
||||
// data after the stream was successfully opened.
|
||||
//
|
||||
class BadStream : public RuntimeError
|
||||
{
|
||||
DEFINE_RUNTIME_EXCEPTION(BadStream, RuntimeError, "")
|
||||
|
||||
public:
|
||||
BadStream(std::string filename)
|
||||
: StreamName(std::move(filename))
|
||||
{
|
||||
}
|
||||
virtual BadStream& SetStreamName(std::string name)
|
||||
{
|
||||
StreamName = std::move(name);
|
||||
return *this;
|
||||
}
|
||||
virtual BadStream& SetStreamName(const char* name)
|
||||
{
|
||||
StreamName = name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string StreamName; // name of the stream (if applicable)
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
|
||||
protected:
|
||||
void _formatDiagMsg(std::string& dest) const;
|
||||
void _formatUserMsg(std::string& dest) const;
|
||||
};
|
||||
|
||||
// A generic exception for odd-ball stream creation errors.
|
||||
//
|
||||
class CannotCreateStream : public BadStream
|
||||
{
|
||||
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
};
|
||||
|
||||
// Exception thrown when an attempt to open a non-existent file is made.
|
||||
// (this exception can also mean file permissions are invalid)
|
||||
//
|
||||
class FileNotFound : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
};
|
||||
|
||||
class AccessDenied : public CannotCreateStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
};
|
||||
|
||||
// EndOfStream can be used either as an error, or used just as a shortcut for manual
|
||||
// feof checks.
|
||||
//
|
||||
class EndOfStream : public BadStream
|
||||
{
|
||||
public:
|
||||
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
|
||||
|
||||
virtual std::string FormatDiagnosticMessage() const override;
|
||||
virtual std::string FormatDisplayMessage() const override;
|
||||
};
|
||||
} // namespace Exception
|
||||
|
||||
using Exception::BaseException;
|
|
@ -19,7 +19,6 @@
|
|||
#include "common/RedtapeWindows.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/AlignedMalloc.h"
|
||||
#include "common/Assertions.h"
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Threading.h"
|
||||
#include "common/General.h"
|
||||
|
|
|
@ -46,11 +46,11 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AlignedMalloc.cpp" />
|
||||
<ClCompile Include="Assertions.cpp" />
|
||||
<ClCompile Include="Console.cpp" />
|
||||
<ClCompile Include="CrashHandler.cpp" />
|
||||
<ClCompile Include="DynamicLibrary.cpp" />
|
||||
<ClCompile Include="Error.cpp" />
|
||||
<ClCompile Include="Exceptions.cpp" />
|
||||
<ClCompile Include="FastJmp.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
@ -133,7 +133,6 @@
|
|||
<ClInclude Include="SettingsWrapper.h" />
|
||||
<ClInclude Include="Assertions.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="Exceptions.h" />
|
||||
<ClInclude Include="General.h" />
|
||||
<ClInclude Include="MathUtils.h" />
|
||||
<ClInclude Include="Path.h" />
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
<ClCompile Include="emitter\cpudetect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Exceptions.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\fpu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -142,6 +139,9 @@
|
|||
<ClCompile Include="Error.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Assertions.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AlignedMalloc.h">
|
||||
|
@ -162,9 +162,6 @@
|
|||
<ClInclude Include="emitter\implement\dwshift.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Exceptions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="General.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/MemorySettingsInterface.h"
|
||||
#include "common/Path.h"
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/SettingsWrapper.h"
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "IsoFileFormats.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
#include "IsoFileFormats.h"
|
||||
#include "AsyncFileReader.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "common/Exceptions.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "CDVD/IsoFileFormats.h"
|
||||
#include "Host.h"
|
||||
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "SysForwardDefs.h"
|
||||
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/SafeArray.h"
|
||||
#include "common/Threading.h"
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#include "VUops.h"
|
||||
#include "R5900.h"
|
||||
|
||||
#include "common/Exceptions.h"
|
||||
|
||||
static const uint VU0_MEMSIZE = 0x1000; // 4kb
|
||||
static const uint VU0_PROGSIZE = 0x1000; // 4kb
|
||||
static const uint VU1_MEMSIZE = 0x4000; // 16kb
|
||||
|
|
Loading…
Reference in New Issue